update authentication system to Devise

This commit is contained in:
Lee Lawlor
2014-03-13 19:16:35 -04:00
parent 4c9886612f
commit 774543e678
78 changed files with 1257 additions and 385 deletions

View File

@ -1,6 +1,19 @@
// when the document is ready
$(document).ready(function() {
// allow flash notices to be dismissed
if ($(".flash").length > 0) {
$(".flash").on("click", function() {
$(this).hide("slow");
});
// hide flash automatically after 15 seconds
setTimeout(function() {
if ($(".flash").length > 0) {
$(".flash").hide("slow");
}
}, 15000);
}
// show form to add a talkback command
$('#talkback_command_add').click(function() {
$(this).hide();

View File

@ -7,6 +7,7 @@
body { padding-top: 70px; }
.break-word { word-break: break-word; }
.col-pad { padding: 0 15px; }
.dismiss { float: right; cursor: pointer; position: relative; top: -12px; left: 7px; }
/* multiline forms */
.form-horizontal .multiline-label { margin-top: -10px; }
@ -229,10 +230,9 @@ input[type="text"].midfield { width: 120px; }
textarea.tweet { margin-top: 0.5em; width: 40em; height: 3em; }
/* error messages */
.errorExplanation { width: 95%; background-color: #ffffe0; display: table; margin-bottom: 20px; padding: 10px; border: 1px solid #aaaaaa; }
#error {
color: red;
}
.errorExplanation,
#error_explanation { padding: 15px; margin-bottom: 20px; border: 1px solid transparent; border-radius: 4px; background-color: #f2dede; border-color: #ebccd1; color: #a94442; }
#error { color: red; }
.field_with_errors { display: inline; }
/*.error_box { margin-top: 15px; padding: 5px; background-color: #f99; color: #300; border: 1px solid #f66; }*/
.warning_box { margin: 15px 0 15px 0; padding: 10px; background-color: #fc3; color: #000; border: 1px solid #f90; }

View File

@ -1,11 +1,14 @@
class ApplicationController < ActionController::Base
skip_before_filter :verify_authenticity_token
# include all helpers for controllers
helper :all
# include these helper methods for views
helper_method :current_user_session, :current_user, :logged_in?, :is_admin?, :get_header_value, :to_bytes
protect_from_forgery
before_filter :allow_cross_domain_access, :set_variables
before_filter :configure_permitted_parameters, if: :devise_controller?
after_filter :remove_headers
before_filter :authenticate_user_from_token!
# responds with blank
def respond_with_blank
@ -44,6 +47,9 @@ class ApplicationController < ActionController::Base
params[:sum] = '1440' if params[:sum] == 'daily'
end
# change default devise sign_in page
def after_sign_in_path_for(resource); channels_path; end
# get the locale, but don't fail if header value doesn't exist
def get_locale
locale = get_header_value('HTTP_ACCEPT_LANGUAGE')
@ -59,8 +65,30 @@ class ApplicationController < ActionController::Base
return locale
end
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:login, :email, :password, :password_confirmation, :remember_me) }
devise_parameter_sanitizer.for(:sign_in) { |u| u.permit(:login, :email, :password, :remember_me) }
devise_parameter_sanitizer.for(:account_update) { |u| u.permit(:login, :email, :password, :password_confirmation, :time_zone, :password_current) }
end
private
# authenticates user based on token from users#api_login
def authenticate_user_from_token!
# exit if no login or token
return false if params[:login].blank? || params[:token].blank?
# get the user by login or email
user = User.find_by_login_or_email(params[:login])
# safe compare, avoids timing attacks
if user.present? && Devise.secure_compare(user.authentication_token, params[:token])
sign_in user, store: false
end
end
# remove headers if necessary
def remove_headers
response.headers.delete_if {|key| true} if params[:headers] == 'false'
@ -80,7 +108,7 @@ class ApplicationController < ActionController::Base
# check that user's email address matches admin
def is_admin?
current_user && ADMIN_EMAILS.include?(current_user.email)
current_user.present? && ADMIN_EMAILS.include?(current_user.email)
end
def set_admin_menu
@ -104,16 +132,6 @@ class ApplicationController < ActionController::Base
def set_plugins_menu; @menu = 'plugins'; end
def set_devices_menu; @menu = 'devices'; 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
def require_user
logger.info "Require User"
if current_user.nil?
@ -273,9 +291,6 @@ class ApplicationController < ActionController::Base
# 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)
# allow more past data if necessary
get_old_data = (params[:results].present? || params[:start].present? || params[:days].present?) ? true : false
@ -290,8 +305,6 @@ class ApplicationController < ActionController::Base
return date_range
end
def set_time_zone(params)
# set timezone correctly
if params[:offset]

View File

@ -35,20 +35,20 @@ class ChannelsController < ApplicationController
# get channels by ids
if params[:channel_ids].present?
flash[:notice] = t(:selected_channels)
@header = t(:selected_channels)
@channels = Channel.public_viewable.by_array(params[:channel_ids]).order('ranking desc, updated_at DESC').paginate :page => params[:page]
# get channels that match a user
elsif params[:username].present?
flash[:notice] = "#{t(:user).capitalize}: #{params[:username]}"
@header = "#{t(:user).capitalize}: #{params[:username]}"
searched_user = User.find_by_login(params[:username])
@channels = searched_user.channels.public_viewable.active.order('ranking desc, updated_at DESC').paginate :page => params[:page] if searched_user.present?
# get channels that match a tag
elsif params[:tag].present?
flash[:notice] = "#{t(:tag).capitalize}: #{params[:tag]}"
@header = "#{t(:tag).capitalize}: #{params[:tag]}"
@channels = Channel.public_viewable.active.order('ranking desc, updated_at DESC').with_tag(params[:tag]).paginate :page => params[:page]
# normal channel list
else
flash[:notice] = t(:featured_channels)
@header = t(:featured_channels)
respond_with_error(:error_resource_not_found) and return if params[:page] == '0'
@channels = Channel.public_viewable.active.order('ranking desc, updated_at DESC').paginate :page => params[:page]
end

View File

@ -16,7 +16,7 @@ class CommentsController < ApplicationController
@comment.body = params[:comment][:body].gsub(/<\/?[^>]*>/, '').gsub(/\n/, '<br />')
# save comment
if @comment.save
flash[:success] = "Thanks for adding a comment!"
flash[:notice] = "Thanks for adding a comment!"
else
flash[:error] = "Comment can't be blank!"
end
@ -45,3 +45,4 @@ class CommentsController < ApplicationController
redirect_to :back
end
end

View File

@ -0,0 +1,22 @@
class RegistrationsController < Devise::RegistrationsController
include KeyUtilities
after_filter :add_api_key, :only => :create
# use defaults from devise
def new; super; end
def new; super; end
def create; super; end
private
# adds an api key to the new user
def add_api_key
@user = current_user
if @user.present?
@user.api_key = generate_api_key(16, 'user')
@user.save
end
end
end

View File

@ -0,0 +1,32 @@
class SessionsController < Devise::SessionsController
after_filter :log_failed_login, :only => :new
# don't modify default devise controllers
def create; super; end
def new; super; end
private
# logs failed login attempts
def log_failed_login
if failed_login?
# log to failedlogins
failed = Failedlogin.new
failed.login = params['user']['login']
failed.password = params['user']['password']
failed.ip_address = get_header_value('X_REAL_IP')
failed.save
# prevent timing and brute force password attacks
sleep 1
end
end
# true if a login fails
def failed_login?
options = env["warden.options"]
return (options.present? && options[:action] == "unauthenticated")
end
end

View File

@ -1,55 +0,0 @@
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
# if link_back, redirect back
redirect_to session[:link_back] and return if session[:link_back]
redirect_to channels_path and return
else
# log to failedlogins
failed = Failedlogin.new
failed.login = params[:user_session][:login]
failed.password = params[:user_session][:password]
failed.ip_address = get_header_value('X_REAL_IP')
failed.save
# prevent timing and brute force password attacks
sleep 1
@failed = true
render :action => :new
end
end
end
def destroy
session[:link_back] = nil
current_user_session.destroy
reset_session
redirect_to root_path
end
end

View File

@ -1,7 +1,27 @@
class UsersController < ApplicationController
include KeyUtilities
before_filter :require_no_user, :only => [:new, :create, :forgot_password]
before_filter :require_user, :only => [:show, :edit, :update, :change_password, :edit_profile]
skip_before_filter :verify_authenticity_token, :only => [:api_login]
before_filter :require_user, :only => [:show, :edit, :update, :edit_profile]
# allow login via api
def api_login
# get the user by login or email
user = User.find_by_login_or_email(params[:login])
# exit if no user or invalid password
respond_with_error(:error_auth_required) and return if user.blank? || !user.valid_password?(params[:password])
# save new authentication token
user.authentication_token = Devise.friendly_token
user.save
# output the user with token
respond_to do |format|
format.json { render :json => user.as_json(User.private_options_plus(:authentication_token)) }
format.xml { render :xml => user.to_xml(User.private_options_plus(:authentication_token)) }
format.any { render :text => user.authentication_token }
end
end
# generates a new api key
def new_api_key
@ -34,8 +54,8 @@ class UsersController < ApplicationController
# if a json or xml request
if request.format == :json || request.format == :xml
# authenticate the user if api key matches the target user
authenticated = (User.find_by_api_key(get_apikey) == @user)
# authenticate the user if the user is logged in (can be via token) or api key matches the target user
authenticated = (current_user == @user) || (User.find_by_api_key(get_apikey) == @user)
# set options correctly
options = authenticated ? User.private_options : User.public_options(@user)
end
@ -75,27 +95,6 @@ class UsersController < ApplicationController
end
end
def new
@title = t(:signup)
@user = User.new
end
def create
@user = User.new(user_params)
@user.api_key = generate_api_key(16, 'user')
# save user
if @user.valid?
if @user.save
redirect_back_or_default channels_path and return
end
else
render :action => :new
end
end
def show
@menu = 'account'
@user = @current_user
@ -106,48 +105,18 @@ class UsersController < ApplicationController
@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(: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
@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(user_params)
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
# delete password and confirmation from params if not present
params[:user].delete(:password) if params[:user][:password].blank?
# check current password and update
if @user.valid_password?(params[:password_current]) && @user.update_attributes(user_params)
if @user.valid_password?(params[:user][:password_current]) && @user.update_attributes(user_params)
# sign the user back in, since devise will log the user out on update
sign_in(current_user, :bypass => true)
flash[:notice] = t('devise.registrations.updated')
redirect_to account_path
else
@user.errors.add(:base, t(:password_incorrect))

View File

@ -81,6 +81,13 @@ class Channel < ActiveRecord::Base
cattr_reader :per_page
@@per_page = 15
# how often the channel is updated
def update_rate
last_feeds = self.feeds.order('entry_id desc').limit(2)
rate = (last_feeds.first.created_at - last_feeds.last.created_at) if last_feeds.length == 2
return rate
end
# write key for a channel
def write_api_key
self.api_keys.where(:write_flag => true).first.api_key

View File

@ -2,24 +2,27 @@
#
# Table name: users
#
# 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)
# last_login_ip :string(255)
# created_at :datetime
# updated_at :datetime
# time_zone :string(255)
# public_flag :boolean default(FALSE)
# bio :text
# website :string(255)
# api_key :string(16)
# id :integer not null, primary key
# login :string(255) not null
# email :string(255) not null
# encrypted_password :string(255) not null
# password_salt :string(255)
# current_sign_in_at :datetime
# last_sign_in_at :datetime
# current_sign_in_ip :string(255)
# last_sign_in_ip :string(255)
# created_at :datetime
# updated_at :datetime
# time_zone :string(255)
# public_flag :boolean default(FALSE)
# bio :text
# website :string(255)
# api_key :string(16)
# reset_password_token :string(255)
# reset_password_sent_at :datetime
# remember_created_at :datetime
# sign_in_count :integer default(0), not null
# authentication_token :string(255)
#
####### NOTE #######
@ -28,6 +31,7 @@
####################
class User < ActiveRecord::Base
include KeyUtilities
devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable
has_many :channels
has_many :twitter_accounts, :dependent => :destroy
has_many :thinghttps, :dependent => :destroy
@ -42,14 +46,45 @@ class User < ActiveRecord::Base
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
# allow login by login name also
def self.find_first_by_auth_conditions(warden_conditions)
conditions = warden_conditions.dup
if login_param = conditions.delete(:login)
where(conditions).where(["lower(login) = :value OR lower(email) = :value", { :value => login_param.downcase }]).first
else
where(conditions).first
end
end
# allow users to sign in with passwords from old authlogic authentication
alias :devise_valid_password? :valid_password?
def valid_password?(password)
begin
devise_valid_password?(password)
rescue BCrypt::Errors::InvalidHash
stretches = 20
digest = "#{password}#{self.password_salt}"
stretches.times {digest = Digest::SHA512.hexdigest(digest)}
if digest == self.encrypted_password
#Here update old Authlogic SHA512 Password with new Devise ByCrypt password
# SOURCE: https://github.com/plataformatec/devise/blob/master/lib/devise/models/database_authenticatable.rb
# Digests the password using bcrypt.
self.encrypted_password = self.password_digest(password)
self.save
return true
else
# If not BCryt password and not old Authlogic SHA512 password don't authenticate user
return false
end
end
end
# 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)
@ -81,6 +116,12 @@ class User < ActiveRecord::Base
{ :only => [:id, :login, :created_at, :email, :website, :bio] }
end
# add an extra attribute to private_options
def self.private_options_plus(array)
{ :only => User.private_options[:only].push(array).flatten }
end
# set new api key
def set_new_api_key!
new_api_key = generate_api_key(16, 'user')
@ -90,4 +131,3 @@ class User < ActiveRecord::Base
end

View File

@ -1,11 +1,11 @@
<div class="FL">
<h3><%= t(:api_key_write) %></h3>
<%= @write_key %>
<br /><br />
<br><br>
<%= button_to t(:api_key_write_new), channel_api_keys_path(@channel, :write => 1), :data => { :confirm => t(:confirm_new_api_key) } %>
<br /><br />
<br><br>
<h3><%= t(:api_key_read) %></h3>
<% @read_keys.each do |read_key| %>
@ -29,12 +29,12 @@
<%= button_to t(:api_key_delete), channel_api_key_path(@channel, read_key), :method => 'delete', :data => { :confirm => t(:confirm_read_key_delete) } %></td>
</tr>
</table>
<br /><br />
<br><br>
<% end %>
<%= button_to t(:api_key_read_new), channel_api_keys_path(@channel, :write => 0) %>
<br />
<br>
</div>
<div id="sidebar_old">
<ul>
@ -42,9 +42,9 @@
<div class="helplink">(<a target="_blank" href="/docs/channels#api_keys"><%= t(:help_options) %></a>)</div>
<h2><%= t(:help) %></h2>
<%= t(:help_channel_write_key) %>
<br /><br />
<br><br>
<%= t(:help_channel_read_key) %>
<br /><br />
<br><br>
<%= t(:help_channel_read_key_note) %>
</li>
</ul>

View File

@ -8,7 +8,7 @@
<div class="apps">
<%= link_to thingtweets_path do %>
<%= image_tag 'thingtweet.png', :size => '104x104' %>
<br />
<br>
<%= t(:thingtweet) %>
<% end %>
</div>
@ -16,7 +16,7 @@
<div class="apps">
<%= link_to thinghttp_index_path do %>
<%= image_tag 'thinghttp.png', :size => '104x104' %>
<br />
<br>
<%= t(:thinghttp) %>
<% end %>
</div>
@ -24,7 +24,7 @@
<div class="apps">
<%= link_to tweetcontrol_index_path do %>
<%= image_tag 'tweetcontrol.png', :size => '104x104' %>
<br />
<br>
<%= t(:tweetcontrol) %>
<% end %>
</div>
@ -32,7 +32,7 @@
<div class="apps">
<%= link_to reacts_path do %>
<%= image_tag 'react.png', :size => '104x104' %>
<br />
<br>
<%= t(:react) %>
<% end %>
</div>
@ -40,7 +40,7 @@
<div class="apps">
<%= link_to talkbacks_path do %>
<%= image_tag 'talkback.png', :size => '104x104' %>
<br />
<br>
<%= t(:talkback) %>
<% end %>
</div>
@ -49,7 +49,7 @@
<div class="apps">
<%= link_to scheduled_thinghttps_path do %>
<%= image_tag 'scheduled_thinghttp.png', :size => '104x104' %>
<br />
<br>
<%= t(:scheduled_thinghttp) %>
<% end %>
</div>

View File

@ -1,10 +1,5 @@
<div class="FL">
<% flash.each do |name, msg| %>
<div id="<%= name %>" class="fade" >
<p><%= msg %></p>
<div class="clear"></div>
</div>
<% end %>
<%= form_for @channel, :html => {:method => 'put'} do |c| %>
<% unless session[:errors].nil?
session[:errors].each do |attr, msg|
@ -109,12 +104,12 @@
</table>
<% end %>
<br /><br />
<br><br>
<h4><%= t(:channel_clear_message) %></h4>
<%= button_to t(:channel_clear), { :controller => 'channels', :action => 'clear', :id => @channel.id }, :data => { :confirm => t(:confirm_channel_clear) } %>
<br /><br />
<br><br>
<h4><%= t(:channel_delete_message) %></h4>
<%= button_to t(:channel_delete), channel_path(@channel.id), :method => 'delete', :data => { :confirm => t(:confirm_channel_delete) } %>
@ -124,17 +119,17 @@
<li>
<h2><%= t(:help) %></h2>
<%= t(:help_channel_public) %>
<br /><br />
<br><br>
<%= t(:help_channel_url) %>
<br /><br />
<br><br>
<%= t(:help_channel_video) %>
<br /><br />
<br><br>
<%= t(:help_channel_fields) %>
<br /><br />
<br><br>
<%= t(:help_channel_clear) %>
<br /><br />
<br><br>
<%= t(:help_channel_ranking) %>
<br /><br />
<br><br>
</li>
</ul>
</div>

View File

@ -1,18 +1,13 @@
<div class="FL">
<%= t(:upload_select) %>
<br /><br />
<% flash.each do |name, msg| %>
<div id="<%= name %>" class="fade" >
<p><%= msg %></p>
<div class="clear"></div>
</div>
<% end %>
<br>
<%= form_for :upload, :url => upload_channel_path(@channel), :html => { :multipart => true } do |f| %>
<%= f.file_field :csv %>
<br /><br />
<br><br>
<%= t(:time_zone) %>
<%= time_zone_select 'feed', 'time_zone', nil, :default => 'UTC' %>
<br /><br />
<br><br>
<%= f.submit t(:upload), :disable_with => t(:uploading) %>
<% end %>
@ -28,14 +23,14 @@
<div class="code"><%= "#{@api_domain}update" %></div>
<%= t(:help_channel_post_example) %>
<div class="code"><%= "#{@api_domain}update?key=#{@key}&field1=0" %></div>
<br /><br />
<br><br>
<div class="helplink">(<a target="_blank" href="/docs/channels#get_feed"><%= t(:help_options) %></a>)</div>
<h2><%= t(:help_channel_feed) %></h2>
<%= t(:help_channel_view) %>
<br />
<br>
<div class="code"><%= link_to "#{@api_domain}channels/#{@channel.id}/feed.json?key=#{@key}", "#{@api_domain}channels/#{@channel.id}/feed.json?key=#{@key}", :target => '_blank' %></div>
<br />
<br>
</li>

View File

@ -18,7 +18,7 @@
<%= f.error_messages %>
<input name='userlogin' class='userlogin' />
<%= f.text_area :body, :rows => 7, :cols => 54 %>
<br />
<br>
<%= submit_tag %>
<% end %>
</div>
@ -56,7 +56,7 @@ function commentflag(m_id, user_id)
type: 'POST',
data: {user_id : user_id},
success: function(data) {
$('#commentflag' + m_id).parent().parent().append("<span id='votemsg" + m_id + "'><br /><br /><%= t(:comment_reported) %></span>");
$('#commentflag' + m_id).parent().parent().append("<span id='votemsg" + m_id + "'><br><br><%= t(:comment_reported) %></span>");
$('#imgflag' + m_id).attr('src', '/images/flag_red.gif');
$('#flaglink' + m_id).removeAttr('onclick');
$('#flaglink' + m_id).unbind('mouseenter mouseleave');

View File

@ -32,7 +32,7 @@
</table>
<br />
<br>
<% end %>
@ -43,16 +43,16 @@
<% if is_admin? %>
<br /><br /><br />
<br><br><br>
<% @channels.each do |c| %>
<% if c.social %>
<%= t(:social_channel) %>: <%= link_to c.name, (Rails.env == 'production') ? "http://www.socialsensornetwork.com/#{c.slug}" : "/s/#{c.slug}" %>
<br />
<br>
<% end %>
<% end %>
<br />
<br>
<%= link_to t(:social_channel_create), :controller => 'channels', :action => 'social_new' %>
<% end %>

View File

@ -1,9 +1,9 @@
<div class="row">
<div class="col-xs-12 col-sm-9">
<h4 class="breadcrumb"><%= flash[:notice] %></h4>
<h4 class="breadcrumb"><%= @header %></h4>
<%= render :partial => 'list' %>
<br />
<br>
<%= will_paginate @channels %>
</div>

View File

@ -76,9 +76,9 @@
<li>
<h2><%= t(:help) %></h2>
<%= t(:help_social_channel) %>
<br /><br />
<br><br>
<div class="code">http://www.socialsensornetwork.com/<b>slug</b></div>
<br />
<br>
<%= t(:help_social_channel_public) %>
</li>
</ul>

View File

@ -93,7 +93,7 @@
<% if !@channel.description.blank? %>
<div class="default_text"><%= t(:channel_directions) %>: <%= @channel.description %></div>
<br />
<br>
<% end %>
<%= form_tag "#{@post_url}" do %>
@ -122,19 +122,19 @@
</table>
<% end %>
<br /><br />
<br><br>
<div style="float: left; width: 600px;">
<iframe width="600" height="300" frameborder="0" scrolling="no" style="border: 1px solid #cccccc;" src="<%= @api_domain %>channels/<%= @channel.id %>/maps/default?width=600&height=300&results=100&round=2&status=true&dynamic=true"></iframe>
<% @fields.each do |f| %>
<br /><br />
<br><br>
<iframe width="600" height="300" frameborder="0" style="border: 1px solid #cccccc;" src="<%= @api_domain %>channels/<%= @channel.id %>/charts/<%= f[-1] %>?width=600&height=300&results=100&round=2&color=C46353&location=true&dynamic=true&push=false&max=20000&min=-20000"></iframe>
<% end %>
<div id="footer">
<br /><br />
<br><br>
&copy;2011 Social Sensor Network - Powered by <a href="https://www.thingspeak.com/">ThingSpeak</a>
</div>

View File

@ -5,7 +5,7 @@
<% if @channels.empty? %>
<%= t(:watched_empty) %>
<br /><br />
<br><br>
<%= link_to t(:watched_find), public_channels_path %>
<% else %>
<%= render :partial => 'list' %>

View File

@ -2,10 +2,10 @@
<iframe id="iframe<%= index %>" width="<%= width %>" height="<%= height %>" style="border: 1px solid #cccccc;" src="" default_src="<%= src %>"></iframe>
<br /><br />
<br><br>
<%= t(:chart_embed_code) %>:
<br />
<br>
<textarea id="embed<%= index %>" rows="5" cols="53">&lt;iframe width="<%= width %>" height="<%= height %>" style="border: 1px solid #cccccc;" src="<%= src %>">&lt;/iframe></textarea>
<br /><br /><br />
<br><br><br>

View File

@ -46,9 +46,9 @@
<div class="helplink">(<a href="/docs/charts"><%= t(:help_options) %></a>)</div>
<h2><%= t(:help_charts) %></h2>
<%= t(:help_charts_options) %>
<br /><br />
<br><br>
<%= t(:help_charts_embed) %>
<br /><br />
<br><br>
&bull; <a href="http://community.thingspeak.com/tutorials/wordpress/how-to-embed-a-thingspeak-chart-on-your-wordpress-blog/">WordPress Tutorial</a>
</li>
</ul>

View File

@ -13,7 +13,7 @@
<% end %>
<span class="username"><%= link_to User.find(comment.user_id).login, list_channels_path(User.find(comment.user_id).login) %></span>
<span class="prettydate"><%= time_ago_in_words(comment.created_at) %> <%= t(:ago) %></span>
<br />
<br>
<div>
<%= auto_link_urls(comment.body) %>
</div>
@ -32,7 +32,7 @@
<input name='userlogin' class='userlogin' />
<%= hidden_field_tag :parent_id, comment.id %>
<%= f.text_area :body, :value => '', :class => 'commentarea' %>
<br />
<br>
<%= submit_tag %>
<% end %>
</div>

View File

@ -0,0 +1,13 @@
<h2>Resend confirmation instructions</h2>
<%= form_for(resource, :as => resource_name, :url => confirmation_path(resource_name), :html => { :method => :post }) do |f| %>
<%= devise_error_messages! %>
<div><%= f.label :login %><br>
<%= f.text_field :login, :autofocus => true %></div>
<div><%= f.submit "Resend confirmation instructions" %></div>
<% end %>
<%= render "devise/shared/links" %>

View File

@ -0,0 +1,5 @@
<p>Welcome <%= @email %>!</p>
<p>You can confirm your account email through the link below:</p>
<p><%= link_to 'Confirm my account', confirmation_url(@resource, :confirmation_token => @token) %></p>

View File

@ -0,0 +1,8 @@
<p>Hello <%= @resource.email %>!</p>
<p>Someone has requested a link to change your password. You can do this through the link below.</p>
<p><%= link_to 'Change my password', edit_password_url(@resource, :reset_password_token => @token) %></p>
<p>If you didn't request this, please ignore this email.</p>
<p>Your password won't change until you access the link above and create a new one.</p>

View File

@ -0,0 +1,7 @@
<p>Hello <%= @resource.email %>!</p>
<p>Your account has been locked due to an excessive number of unsuccessful sign in attempts.</p>
<p>Click the link below to unlock your account:</p>
<p><%= link_to 'Unlock my account', unlock_url(@resource, :unlock_token => @token) %></p>

View File

@ -0,0 +1,28 @@
<div class="row">
<div class="col-sm-6 col-xs-12">
<h4 class="breadcrumb"><%= t(:password_new) %></h4>
<%= form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :put, :class => 'form-horizontal' }) do |f| %>
<%= devise_error_messages! %>
<%= f.hidden_field :reset_password_token %>
<div class="form-group">
<label class="col-sm-4 col-xs-3 control-label"><%= t(:password) %></label>
<div class="col-sm-8 col-xs-6"><%= f.password_field :password, :autofocus => true, :class => 'form-control' %></div>
</div>
<div class="form-group">
<label class="col-sm-4 col-xs-3 control-label"><%= t(:password_confirmation) %></label>
<div class="col-sm-8 col-xs-6"><%= f.password_field :password_confirmation, :class => 'form-control' %></div>
</div>
<div class="form-group">
<label class="col-sm-4 control-label"></label>
<div class="col-sm-8"><p class="form-control-static"><%= f.submit t(:password_change), :class => 'btn btn-primary' %></p></div>
</div>
<% end %>
</div>
</div>

View File

@ -0,0 +1,35 @@
<div class="col-sm-7 col-xs-12">
<h4 class="breadcrumb"><%= t(:password_forgot) %></h4>
<div class="col-pad">
<%= t(:password_forgot_message) %>
<br><br>
<%= form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :post, :class => 'form-horizontal' }) do |f| %>
<%= devise_error_messages! %>
<input name='userlogin' class='userlogin' />
<div class="form-group">
<label class="col-sm-3 col-xs-3 control-label"><%= t(:email) %></label>
<div class="col-sm-9 col-xs-9"><%= f.text_field :login, :class => 'form-control' %></div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9 col-xs-offset-3 col-xs-9"><p class="form-control-static"><%= f.submit t(:submit), :class => 'btn btn-primary' %></p></div>
</div>
<% end %>
</div>
</div>
<script type="text/javascript">
document.getElementById('user_login').focus();
</script>

View File

@ -0,0 +1,30 @@
<h2>Edit <%= resource_name.to_s.humanize %></h2>
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :method => :put }) do |f| %>
<%= devise_error_messages! %>
<div><%= f.label :login %><br>
<%= f.text_field :login, :autofocus => true %></div>
<% if devise_mapping.confirmable? && resource.pending_reconfirmation? %>
<div>Currently waiting confirmation for: <%= resource.unconfirmed_email %></div>
<% end %>
<div><%= f.label :password %> <i>(leave blank if you don't want to change it)</i><br>
<%= f.password_field :password, :autocomplete => "off" %></div>
<div><%= f.label :password_confirmation %><br>
<%= f.password_field :password_confirmation %></div>
<div><%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i><br>
<%= f.password_field :current_password %></div>
<div><%= f.submit "Update" %></div>
<% end %>
<h3>Cancel my account</h3>
<p>Unhappy? <%= button_to "Cancel my account", registration_path(resource_name), :data => { :confirm => "Are you sure?" }, :method => :delete %></p>
<%= link_to "Back", :back %>

View File

@ -0,0 +1,51 @@
<div class="row">
<div class="col-sm-8 col-xs-12">
<h4 class="breadcrumb"><%= t(:signup_header) %></h4>
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => {:class => 'form-horizontal'}) do |f| %>
<%= devise_error_messages! %>
<input name='userlogin' class='userlogin' />
<div class="form-group">
<label class="col-sm-4 col-xs-3 control-label"><%= t(:userid) %></label>
<div class="col-sm-8 col-xs-6"><%= f.text_field :login, :class => 'form-control' %></div>
</div>
<div class="form-group">
<label class="col-sm-4 col-xs-3 control-label"><%= t(:email) %></label>
<div class="col-sm-8 col-xs-6"><%= f.text_field :email, :class => 'form-control' %></div>
</div>
<div class="form-group">
<label class="col-sm-4 col-xs-3 control-label"><%= t(:time_zone) %></label>
<div class="col-sm-8 col-xs-8">
<p class="form-control-static">
<%= time_zone_select 'user', 'time_zone', nil, {:default => 'Eastern Time (US & Canada)'}, {:class => 'form-control'} %>
</p>
</div>
</div>
<div class="form-group">
<label class="col-sm-4 col-xs-3 control-label"><%= t(:password) %></label>
<div class="col-sm-8 col-xs-6"><%= f.password_field :password, :class => 'form-control' %></div>
</div>
<div class="form-group">
<label class="col-sm-4 col-xs-3 control-label"><%= t(:password_confirmation) %></label>
<div class="col-sm-8 col-xs-6"><%= f.password_field :password_confirmation, :class => 'form-control' %></div>
</div>
<div class="form-group">
<label class="col-sm-4 control-label"></label>
<div class="col-sm-8"><p class="form-control-static"><%= f.submit t(:create_account), :id => "user_submit", :class => 'btn btn-primary' %></p></div>
</div>
<% end %>
</div>
</div>
<script type="text/javascript">
document.getElementById('user_login').focus();
</script>

View File

@ -0,0 +1,57 @@
<div class="row">
<div class="col-sm-6 col-xs-12">
<h4 class="breadcrumb">
<% if @failed %>
<%= t(:signin_failure) %>
<% else %>
<%= t(:signin_please) %>
<% end %>
</h4>
<% if @failed %><%= t(:signin_try_again) %><br><br><% end %>
<% if @mail_message.present? %><%= @mail_message %><br><br><% end %>
<%= form_for(resource, :as => resource_name, :url => session_path(resource_name), :html => { :id => 'loginform', :class => 'form-horizontal' }) do |f| %>
<input name='userlogin' class='userlogin' />
<div class="form-group">
<label class="col-sm-4 col-xs-3 control-label"><%= t(:userid) %></label>
<div class="col-sm-8 col-xs-9"><%= f.text_field :login, :value => cookies['user_id'], :class => 'form-control' %></div>
</div>
<div class="form-group">
<label class="col-sm-4 col-xs-3 control-label"><%= t(:password) %></label>
<div class="col-sm-8 col-xs-9">
<%= f.password_field :password, :class => 'form-control' %>
<%= link_to t(:forgot), new_user_password_path, :id => 'forgot_password' %>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-4 col-sm-8 col-xs-offset-3 col-xs-9">
<div class="checkbox">
<label>
<%= f.check_box :remember_me, :checked => true %>
<%= t(:remember_me) %>
</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-4 col-sm-8 col-xs-offset-3 col-xs-9"><p class="form-control-static"><%= f.submit t(:signin), :class => 'btn btn-primary' %></p></div>
</div>
<% end %>
</div>
</div>
<script type="text/javascript">
var login = document.getElementById('user_login');
if (login.value.length == 0)
login.focus();
else
document.getElementById('user_password').focus();
</script>

View File

@ -0,0 +1,12 @@
<%- if controller_name != 'sessions' %>
<%= link_to t(:signin), new_session_path(resource_name) %><br>
<% end -%>
<%- if devise_mapping.registerable? && controller_name != 'registrations' %>
<%= link_to t(:signup), new_registration_path(resource_name) %><br>
<% end -%>
<%- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %>
<%= link_to t(:password_forgot), new_password_path(resource_name) %><br>
<% end -%>

View File

@ -0,0 +1,12 @@
<h2>Resend unlock instructions</h2>
<%= form_for(resource, :as => resource_name, :url => unlock_path(resource_name), :html => { :method => :post }) do |f| %>
<%= devise_error_messages! %>
<div><%= f.label :email %><br>
<%= f.email_field :email, :autofocus => true %></div>
<div><%= f.submit "Resend unlock instructions" %></div>
<% end %>
<%= render "devise/shared/links" %>

View File

@ -58,7 +58,7 @@
<li><%= link_to t(:signout), logout_path %></li>
<% else %>
<li><%= link_to t(:signin), login_path %></li>
<li><%= link_to t(:signup), new_account_path %></li>
<li><%= link_to t(:signup), new_user_registration_path %></li>
<% end %>
</ul>

View File

@ -23,6 +23,12 @@
<div id="wrap">
<%= render 'layouts/header' %>
<div class="container">
<% if notice.present? %>
<p class="flash alert alert-success"><%= notice %><span class="dismiss">X</span></p>
<% end %>
<% if alert.present? %>
<p class="flash alert alert-danger"><%= alert %><span class="dismiss">X</span></p>
<% end %>
<%= yield %>
</div>
</div>

View File

@ -6,11 +6,11 @@
<body>
<p>
<%= t(:password_reset_message1) %>
<br />
<br>
<%= t(:password_reset_message2) %>
<br />
<br>
<%= t(:password_reset_message3) %>
<br /><br />
<br><br>
<a href="<%= @webpage %>"><%= @webpage %></a>
</p>
</body>

View File

@ -111,6 +111,6 @@
</script>
<br />
<br>
<div id="chart-container" style="width: 500px; height: 260px; padding-left: 20px; float: left;"></div>

View File

@ -1,7 +1,8 @@
<table border="1">
<% for header in request.env.select {|k,v| k.match("^HTTP.*")} %>
<tr>
<td><%=header[0].split('_',2)[1]%></td><td><%=header[1]%></td>
<td><%=header[0].split('_',2)[1]%></td><td><%=header[1]%></td>
</tr>
<% end %>
</table>

View File

@ -87,10 +87,10 @@
<img src='<%= "#{@api_domain}images/social_sensor_network_main.png "%>' width='600' height='415' border='0' />
<% end %>
<h2>the social sensor network is forming.</h2>
<h3>We have one thing in common. At almost all times we are connected to the web.<br />
<h3>We have one thing in common. At almost all times we are connected to the web.<br>
The Social Sensor Network allows everyone to report and share data in an open and meaningful way.</h3>
<br />
<br>
<form method=post action="https://app.icontact.com/icp/signup.php" name="icpsignup" id="icpsignup2312" accept-charset="UTF-8" onsubmit="return verifyRequired2312();" >
<input type=hidden name=redirect value="http://www.socialsensornetwork.com?invite=success" />
@ -128,12 +128,12 @@
}
</script>
<br />
<br />
<br>
<br>
<span id="demo_text">demo channels</span>
<br />
<br>
<span id="demo"><a href="http://www.socialsensornetwork.com/irs-refund">IRS Refunds</a></span>
<span id="demo"><a href="http://www.socialsensornetwork.com/online-poker">Frozen Online Poker Money</a></span>

View File

@ -1,7 +1,7 @@
<h2>Pipes</h2>
<%= link_to 'New Pipe', new_pipe_path %>
<br /><br />
<br><br>
<table class="nicetable">
<tr class="header"><td>ID</td><td>Name</td><td>Slug</td><td>URL</td><td>Date</td></tr>
@ -15,5 +15,5 @@
</tr>
<% end %>
</table>
<br />
<br>
<%= will_paginate @pipes %>

View File

@ -48,7 +48,7 @@
<% end %>
<br /><br />
<br><br>
<h3><%= t(:plugin_delete_message) %></h3>
<%= button_to t(:plugin_delete), plugin_path(@plugin.id), :method => 'delete', :data => { :confirm => t(:confirm_plugin_delete) }, :class => 'btn btn-danger' %>

View File

@ -23,7 +23,7 @@
</table>
<br /><br />
<br><br>
<% end %>
<%= form_for :plugin do |p| %>

View File

@ -8,8 +8,8 @@
<body>
<div class="recent_status">
<% @statuses.each do |r| %>
<div ><span class="status_messages" id="<%= r.entry_id %>"><%= r.status %><br /><abbr class="timeago" title="<%= r.created_at %>"><%= r.created_at %></abbr></div>
<br />
<div ><span class="status_messages" id="<%= r.entry_id %>"><%= r.status %><br><abbr class="timeago" title="<%= r.created_at %>"><%= r.created_at %></abbr></div>
<br>
<% end %>
<div>
<script>
@ -31,7 +31,7 @@ function refreshStatus() {
$(".recent_status").prepend("<div><span class=\"status_messages\" id=\"" +
data[i].entry_id + "\">"+
data[i].status +
"</span><br /><abbr class=\"timeago\" title=\"" +
"</span><br><abbr class=\"timeago\" title=\"" +
data[i].created_at + "\">" +
data[i].created_at + "</abbr></div></br>");
}

View File

@ -6,14 +6,14 @@
<td><%= t.text_field :name %><%= t.submit t(:submit) %></td>
</tr>
</table>
<br />
<br>
<% if @tag_name %>
<% if @results %>
<% @results.each do |channel| %>
<%= link_to channel.name, channel_path(channel.id) %>
<br />
<br>
<% end %>
<% else %>

View File

@ -33,12 +33,6 @@
<div class="col-sm-8 col-xs-8"><%= f.password_field :password, :class => 'form-control' %></div>
</div>
<div class="form-group">
<label class="col-sm-4 col-xs-4 control-label"><%= t(:password_confirmation) %></label>
<div class="col-sm-8 col-xs-8"><%= f.password_field :password_confirmation, :class => 'form-control' %></div>
</div>
<div class="form-group">
<label class="col-sm-4 col-xs-4 control-label"><%= t(:password_current) %></label>
<div class="col-sm-8 col-xs-8"><%= f.password_field :password_current, :class => 'form-control' %></div>

View File

@ -11,7 +11,7 @@
</tr>
<% end %>
</table>
<br />
<br>
<%= will_paginate @channels %>
<% else %>
<%= t(:user_no_public_channels) %>

View File

@ -1,17 +1,17 @@
<% if @user.public_flag == true %>
<div class="FR">
<br /><br />
<br><br>
<%= gravatar_tag @user, :default => 'wavatar', :secure => true %>
</div>
<h2><%= t(:profile_for) %> <%= @user.login %></h2>
<%= link_to t(:channels_public_view), list_channels_path(@user.login) %>
<br /><br />
<br><br>
<%= t(:member_since) %> <%= @user.created_at.strftime('%B %-d, %Y') %>
<br /><br />
<br><br>
<%= t(:profile_website) %>: <%= link_to @user.website, @user.website %>
<br /><br />
<br><br>
<%= t(:profile_bio) %>: <%= @user.bio %>
<% else %>

View File

@ -4,7 +4,7 @@
<div class="col-pad">
<%= link_to t(:account_edit), edit_account_path, :class => 'btn btn-primary btn-sm' %>
<br /><br />
<br><br>
<table class="table">
<tr>
<td><%= t(:userid) %></td>
@ -29,13 +29,13 @@
</table>
</div>
<br /><br />
<br><br>
<h4 class="breadcrumb"><%= t(:public_profile) %></h4>
<div class="col-pad">
<%= link_to t(:profile_edit), edit_profile_path, :class => 'btn btn-primary btn-sm' %>
<br /><br />
<br><br>
<%= link_to t(:profile_view), user_profile_path(@user.login) %>
<br /><br />
<br><br>
<% if @user.public_flag %>
<table class="table">
<tr>