Permalink
Browse files

subscriber list, top changed tweet, top changed emails through amazon…

… ses
  • Loading branch information...
browep committed Feb 26, 2011
1 parent f6aaf1a commit efa0fcca83fdf591d67ad74400d4e079ac9952b5
Showing with 608 additions and 13 deletions.
  1. +1 −1 Gemfile
  2. +10 −0 Gemfile.lock
  3. +5 −1 app/controllers/entries_controller.rb
  4. +55 −0 app/controllers/subscribers_controller.rb
  5. +2 −0 app/helpers/subscriber_helper.rb
  6. +2 −0 app/helpers/subscribers_helper.rb
  7. +12 −0 app/mailers/alert_mailer.rb
  8. +8 −0 app/models/subscriber.rb
  9. +6 −0 app/views/alert_mailer/top_changed_email.html.erb
  10. +1 −0 app/views/alert_mailer/top_changed_text.html.erb
  11. +4 −0 app/views/base/_flash.html.erb
  12. +17 −0 app/views/entries/index.html.erb
  13. +1 −3 app/views/layouts/application.html.erb
  14. +23 −0 app/views/layouts/email.html.erb
  15. +17 −0 app/views/subscribers/_form.html.erb
  16. +6 −0 app/views/subscribers/edit.html.erb
  17. +21 −0 app/views/subscribers/index.html.erb
  18. +5 −0 app/views/subscribers/new.html.erb
  19. +5 −0 app/views/subscribers/show.html.erb
  20. +3 −0 config/application.rb
  21. +2 −0 config/environments/development.rb
  22. +3 −0 config/initializers/amazon_ses.rb
  23. +2 −0 config/routes.rb
  24. +12 −0 db/migrate/20110225030804_add_emails_contacts.rb
  25. +9 −0 db/migrate/20110226013757_add_index_on_subscriber_address.rb
  26. +9 −1 db/schema.rb
  27. +18 −4 lib/core.rb
  28. +12 −0 lib/tasks/update.rake
  29. +5 −0 lib/util.rb
  30. +3 −3 public/stylesheets/application.css
  31. +56 −0 public/stylesheets/scaffold.css
  32. +5 −0 spec/controllers/subscriber_controller_spec.rb
  33. +127 −0 spec/controllers/subscribers_controller_spec.rb
  34. +15 −0 spec/helpers/subscriber_helper_spec.rb
  35. +15 −0 spec/helpers/subscribers_helper_spec.rb
  36. +5 −0 spec/mailers/alert_mailer_spec.rb
  37. +5 −0 spec/models/subscriber_spec.rb
  38. +11 −0 spec/requests/subscribers_spec.rb
  39. +35 −0 spec/routing/subscribers_routing_spec.rb
  40. +15 −0 spec/views/subscribers/edit.html.erb_spec.rb
  41. +14 −0 spec/views/subscribers/index.html.erb_spec.rb
  42. +15 −0 spec/views/subscribers/new.html.erb_spec.rb
  43. +11 −0 spec/views/subscribers/show.html.erb_spec.rb
View
@@ -20,7 +20,7 @@ gem 'oauth'
gem 'rspec'
gem 'rspec-rails'
gem 'httparty'
-#gem 'parsedate'
+gem "aws-ses", "~> 0.4.1", :require => 'aws/ses'
# Use unicorn as the web server
# gem 'unicorn'
View
@@ -30,6 +30,14 @@ GEM
activesupport (3.0.3)
addressable (2.2.2)
arel (2.0.6)
+ aws-ses (0.4.1)
+ builder
+ builder
+ mail (~> 2.2.5)
+ mime-types
+ mime-types
+ xml-simple
+ xml-simple
builder (2.1.2)
crack (0.1.8)
daemons (1.0.10)
@@ -103,11 +111,13 @@ GEM
treetop (1.4.9)
polyglot (>= 0.3.1)
tzinfo (0.3.23)
+ xml-simple (1.0.14)
PLATFORMS
ruby
DEPENDENCIES
+ aws-ses (~> 0.4.1)
dispatcher
em-http-request
eventmachine
@@ -10,8 +10,12 @@ def index
@symbols = Factor.top
-
@recent_entries = Entry.all(:select=>"symbol,source_id,sent_at",:order=>"sent_at DESC",:limit=>45)
+
+ @subscriber = Subscriber.new
+
+ @flash_inner = true
+
end
@@ -0,0 +1,55 @@
+require 'util'
+
+class SubscribersController < ApplicationController
+ include Util
+ def new
+ @subscriber = Subscriber.new
+
+ respond_to do |format|
+ format.html # new.html.erb
+ format.xml { render :xml => @subscriber }
+ end
+ end
+
+ # GET /subscribers/1/edit
+ def edit
+ @subscriber = Subscriber.find(params[:id])
+ end
+
+ # POST /subscribers
+ # POST /subscribers.xml
+ def create
+ # look for subscriber with this email already
+ @skip_flash = true
+ found = Subscriber.find_by_address(params[:subscriber][:address])
+ if found
+ flash[:error] = "The email address \"#{params[:subscriber][:address]}\" has already been subscribed."
+ else
+ @subscriber = Subscriber.new(params[:subscriber])
+ if @subscriber.save
+ flash[:notice] = "You have been successfully subscribed."
+ else
+ @subscriber.errors.each do |attr_name,message|
+ attr_name = "email address" unless attr_name.to_s != "address"
+ flash[:error] = "I'm sorry, #{attr_name} #{message}"
+ end
+
+ end
+ end
+ redirect_to root_url
+
+ end
+
+ def destroy
+ #check to make sure the signature matches
+ if params[:signature] == sign_text(params[:id].to_s)
+ @subscriber = Subscriber.find(params[:id])
+ @subscriber.destroy
+ flash[:notice] = "#{@subscriber.address} has been successfully unsubscribed."
+ else
+ flash[:error] ="signatures did not match, please contact us if there was an error."
+ end
+ redirect_to root_url
+ end
+
+end
@@ -0,0 +1,2 @@
+module SubscriberHelper
+end
@@ -0,0 +1,2 @@
+module SubscribersHelper
+end
@@ -0,0 +1,12 @@
+class AlertMailer < ActionMailer::Base
+ default :from => "'The Stock Factor' <thestockfactor@gmail.com>"
+ layout 'email'
+ include Util
+ def top_changed_email(subscriber,symbol)
+ @signature = sign_text(subscriber.id.to_s)
+ @subscriber = subscriber
+ @symbol = symbol
+ mail(:to => subscriber.address,
+ :subject => "#{symbol} is now the symbol with the highest stock factor!")
+ end
+end
View
@@ -0,0 +1,8 @@
+class Subscriber < ActiveRecord::Base
+ attr_accessible :address
+ validates :address, :presence => true,
+ :length => {:minimum => 3, :maximum => 254},
+ :uniqueness => true,
+ :format => {:with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i}
+
+end
@@ -0,0 +1,6 @@
+<%= @symbol %> is not the symbol with the highest stock factor.
+<br />
+<ul>
+ <li><%= link_to "See it on the graph",:only_path=>false,:host=>APP_CONFIG[:domain],:controller=>:entries,:action=>:symbol,:id=>@symbol %></li>
+ <li><a href="http://<%= APP_CONFIG[:domain] %>">See the list of the stocks with the highest factor</a> </li>
+</ul>
@@ -0,0 +1 @@
+the symbol with the highest stock factor has changed
@@ -0,0 +1,4 @@
+ <%- flash.each do |name, msg| -%>
+
+ <%= content_tag :div, msg, :id => "flash_#{name}" %>
+ <%- end -%>
@@ -9,6 +9,23 @@
<br/>
<hr>
<br/>
+ Want to be alerted when the stock with the highest factor changes? Enter your email below and we will send you
+ an email each time the top ones change. (Oh yeah, and we promise not to spam you or sell your email address.)
+ <div style="text-align:center"><% form_for @subscriber do |f| %>
+ <%= render :partial => "base/flash",:object => flash %>
+
+ <p>
+ <label>Email Address: </label>
+ <%= f.text_field :address,:id=>"tb" %>
+ <script>
+ var txtBox=document.getElementById("tb" );
+ if (txtBox!=null ) txtBox.focus();
+ </script>
+
+ <%= f.submit "Subscribe" %></p>
+ <% end %></div>
+
+ <hr>
</div>
@@ -27,9 +27,7 @@
<body>
<div id="header"><span id="title"><a style="text-decoration:none;color:white" href="/">The Stock Factor</a></span><span class="title-link"><a target="_blank" href="https://twitter.com/thestockfactor">twitter</a><a href="mailto:thestockfactor@gmail.com">email us</a><span> </div>
<div id="container">
- <%- flash.each do |name, msg| -%>
- <%= content_tag :div, msg, :id => "flash_#{name}" %>
- <%- end -%>
+ <%= render :partial => "base/flash",:object => flash unless @flash_inner %>
<%- if show_title? -%>
<h1><%=h yield(:title) %></h1>
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
+ </head>
+ <body>
+ <table>
+ <tr>
+ <td>
+ <h3>The Stock Factor</h3>
+ </td>
+ </tr>
+ <tr>
+ <td><%= yield %></td>
+ </tr>
+ <tr>
+ <td>
+ <a href="<%= "http://#{APP_CONFIG[:domain]}/subscribers/destroy/#{@subscriber.id}?signature=#{@signature}"%>">Unsubscribe from all emails</a> (One click and you are unsubscribed, no confirm step.)
+ </td>
+ </tr>
+ </table>
+ </body>
+</html>
@@ -0,0 +1,17 @@
+<%= form_for(@subscriber) do |f| %>
+ <% if @subscriber.errors.any? %>
+ <div id="error_explanation">
+ <h2><%= pluralize(@subscriber.errors.count, "error") %> prohibited this subscriber from being saved:</h2>
+
+ <ul>
+ <% @subscriber.errors.full_messages.each do |msg| %>
+ <li><%= msg %></li>
+ <% end %>
+ </ul>
+ </div>
+ <% end %>
+
+ <div class="actions">
+ <%= f.submit %>
+ </div>
+<% end %>
@@ -0,0 +1,6 @@
+<h1>Editing subscriber</h1>
+
+<%= render 'form' %>
+
+<%= link_to 'Show', @subscriber %> |
+<%= link_to 'Back', subscribers_path %>
@@ -0,0 +1,21 @@
+<h1>Listing subscribers</h1>
+
+<table>
+ <tr>
+ <th></th>
+ <th></th>
+ <th></th>
+ </tr>
+
+<% @subscribers.each do |subscriber| %>
+ <tr>
+ <td><%= link_to 'Show', subscriber %></td>
+ <td><%= link_to 'Edit', edit_subscriber_path(subscriber) %></td>
+ <td><%= link_to 'Destroy', subscriber, :confirm => 'Are you sure?', :method => :delete %></td>
+ </tr>
+<% end %>
+</table>
+
+<br />
+
+<%= link_to 'New Subscriber', new_subscriber_path %>
@@ -0,0 +1,5 @@
+<h1>New subscriber</h1>
+
+<%= render 'form' %>
+
+<%= link_to 'Back', subscribers_path %>
@@ -0,0 +1,5 @@
+<p id="notice"><%= notice %></p>
+
+
+<%= link_to 'Edit', edit_subscriber_path(@subscriber) %> |
+<%= link_to 'Back', subscribers_path %>
View
@@ -43,6 +43,9 @@ class Application < Rails::Application
# config.database_configuration_file= "/usr/local/pumpdump/conf/database.yml"
paths.config.database="/usr/local/pumpdump/conf/database.yml"
+ config.action_mailer.delivery_method = :ses
+
+
@@ -23,6 +23,8 @@
# Only use best-standards-support built into browsers
config.action_dispatch.best_standards_support = :builtin
+
+
puts "environment=development"
end
@@ -0,0 +1,3 @@
+ActionMailer::Base.add_delivery_method :ses, AWS::SES::Base,
+ :access_key_id => APP_CONFIG[:aws_id],
+ :secret_access_key => APP_CONFIG[:aws_secret]
View
@@ -1,4 +1,6 @@
Pumpdump::Application.routes.draw do
+ resources :subscribers
+
# The priority is based upon order of creation:
# first created -> highest priority.
@@ -0,0 +1,12 @@
+class AddEmailsContacts < ActiveRecord::Migration
+ def self.up
+ create_table :subscribers do |t|
+ t.timestamps
+ t.string(:address,:null=>false,:unique=>true)
+ end
+ end
+
+ def self.down
+ drop_table :subscribers
+ end
+end
@@ -0,0 +1,9 @@
+class AddIndexOnSubscriberAddress < ActiveRecord::Migration
+ def self.up
+ add_index(:subscribers,:address)
+ end
+
+ def self.down
+ remove_index(:subscribers,:address)
+ end
+end
View
@@ -10,7 +10,7 @@
#
# It's strongly recommended to check this file into your version control system.
-ActiveRecord::Schema.define(:version => 20101218192643) do
+ActiveRecord::Schema.define(:version => 20110226013757) do
create_table "bad_symbols", :force => true do |t|
t.string "symbol", :null => false
@@ -85,6 +85,14 @@
t.datetime "updated_at", :null => false
end
+ create_table "subscribers", :force => true do |t|
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.string "address", :null => false
+ end
+
+ add_index "subscribers", ["address"], :name => "index_subscribers_on_address"
+
create_table "tweets", :force => true do |t|
t.integer "source_id", :null => false
t.text "text", :null => false
View
@@ -118,10 +118,24 @@ def do_migrations
def top_changed(symbol)
# tweet it out
- response = HTTParty.post("http://easytweet.heroku.com/api/status",{:headers=>{"X-TWITTER-ID"=>APP_CONFIG[:easy_tweet_id].to_s,"X-TWITTER-TOKEN"=>APP_CONFIG[:easy_tweet_token].to_s},
- :body=>"The stock with the highest factor has changed to $#{symbol}. See it here http://thestockfactor.com"
- })
- Rails.logger.info("response from easy_tweet #{response.to_yaml}")
+ begin
+ response = HTTParty.post("http://easytweet.heroku.com/api/status", {:headers=>{"X-TWITTER-ID"=>APP_CONFIG[:easy_tweet_id].to_s, "X-TWITTER-TOKEN"=>APP_CONFIG[:easy_tweet_token].to_s},
+ :body=>"The stock with the highest factor has changed to $#{symbol}. See it here http://thestockfactor.com"
+ })
+ Rails.logger.info("response from easy_tweet #{response.to_yaml}")
+ rescue => e
+ Rails.logger.error(e)
+ end
+
+ Subscriber.all.each do |subscriber|
+ begin
+ Rails.logger.info("sending email to #{subscriber.to_yaml}")
+ AlertMailer.top_changed_email(subscriber, symbol).deliver()
+ rescue => e
+ Rails.logger.error(e)
+ end
+ end
+
end
View
@@ -98,6 +98,18 @@ namespace :update do
Rails.cache.write("top_symbol",nil)
end
+ task :set_top_changed => :environment do
+ Rails.cache.write("top_symbol","AAPL")
+ end
+
+ task :send_aws_email => :environment do
+ Subscriber.all.each do |subscriber|
+ Rails.logger.info("sending email to #{subscriber.to_yaml}")
+ AlertMailer.top_changed_email(subscriber, 'AAPL').deliver()
+ end
+
+ end
+
end
Oops, something went wrong.

0 comments on commit efa0fcc

Please sign in to comment.