From 66f433176a0d3f0829794110ae75b6403c3f1cc4 Mon Sep 17 00:00:00 2001
From: joshua stein
Date: Fri, 18 Oct 2013 15:49:20 -0500
Subject: [PATCH] add an invitiation request queue
the user tree is pretty big to look through now, so let users submit
a request for an invitation, which logged-in users can browse and
instantly send invites to
---
app/controllers/invitations_controller.rb | 65 ++++++++++++++++++-
app/mailers/invitation_request_mailer.rb | 14 ++++
app/models/invitation_request.rb | 25 +++++++
.../invitation_request.text.erb | 15 +++++
app/views/invitations/build.html.erb | 39 +++++++++++
app/views/invitations/index.html.erb | 40 ++++++++++++
app/views/login/index.html.erb | 7 +-
config/routes.rb | 9 ++-
.../20131018201413_add_invitation_requests.rb | 17 +++++
db/schema.rb | 13 +++-
10 files changed, 238 insertions(+), 6 deletions(-)
create mode 100644 app/mailers/invitation_request_mailer.rb
create mode 100644 app/models/invitation_request.rb
create mode 100644 app/views/invitation_request_mailer/invitation_request.text.erb
create mode 100644 app/views/invitations/build.html.erb
create mode 100644 app/views/invitations/index.html.erb
create mode 100644 db/migrate/20131018201413_add_invitation_requests.rb
diff --git a/app/controllers/invitations_controller.rb b/app/controllers/invitations_controller.rb
index cf415b6..e3f2b08 100644
--- a/app/controllers/invitations_controller.rb
+++ b/app/controllers/invitations_controller.rb
@@ -1,5 +1,27 @@
class InvitationsController < ApplicationController
- before_filter :require_logged_in_user
+ before_filter :require_logged_in_user,
+ :except => [ :build, :create_by_request, :confirm_email ]
+
+ def build
+ end
+
+ def index
+ @invitation_requests = InvitationRequest.where(:is_verified => true)
+ end
+
+ def confirm_email
+ if !(ir = InvitationRequest.find_by_code(params[:code].to_s))
+ flash[:error] = "Invalid or expired invitation request"
+ return redirect_to "/invitations/request"
+ end
+
+ ir.is_verified = true
+ ir.save!
+
+ flash[:success] = "Your invitiation request has been validated and " <<
+ "will now be shown to other logged-in users."
+ return redirect_to "/invitations/request"
+ end
def create
i = Invitation.new
@@ -26,4 +48,45 @@ class InvitationsController < ApplicationController
return redirect_to "/settings"
end
end
+
+ def create_by_request
+ ir = InvitationRequest.new
+ ir.name = params[:name]
+ ir.email = params[:email]
+ ir.memo = params[:memo]
+
+ ir.ip_address = request.remote_ip
+
+ if ir.save
+ flash[:success] = "You have been e-mailed a confirmation to " <<
+ params[:email].to_s << "."
+ return redirect_to "/invitations/request"
+ else
+ render :action => :build
+ end
+ end
+
+ def send_for_request
+ if !(ir = InvitationRequest.find_by_code(params[:code].to_s))
+ flash[:error] = "Invalid or expired invitation request"
+ return redirect_to "/invitations"
+ end
+
+ if ir.save
+ i = Invitation.new
+ i.user_id = @user.id
+ i.email = ir.email
+
+ if i.save
+ i.send_email
+ ir.destroy
+ flash[:success] = "Successfully e-mailed invitation to " <<
+ ir.name.to_s << "."
+ end
+
+ return redirect_to "/invitations"
+ else
+ render :action => :build
+ end
+ end
end
diff --git a/app/mailers/invitation_request_mailer.rb b/app/mailers/invitation_request_mailer.rb
new file mode 100644
index 0000000..9c6d02a
--- /dev/null
+++ b/app/mailers/invitation_request_mailer.rb
@@ -0,0 +1,14 @@
+class InvitationRequestMailer < ActionMailer::Base
+ default :from => "#{Rails.application.name} " <<
+ ""
+
+ def invitation_request(invitation_request)
+ @invitation_request = invitation_request
+
+ mail(
+ :to => invitation_request.email,
+ subject: "[#{Rails.application.name}] Confirm your invitation " <<
+ "request to " << Rails.application.name
+ )
+ end
+end
diff --git a/app/models/invitation_request.rb b/app/models/invitation_request.rb
new file mode 100644
index 0000000..20c37b1
--- /dev/null
+++ b/app/models/invitation_request.rb
@@ -0,0 +1,25 @@
+class InvitationRequest < ActiveRecord::Base
+ attr_accessible nil
+
+ validates :name, :presence => true
+ validates :email, :format => { :with => /\A[^@ ]+@[^@ ]+\.[^@ ]+\Z/ }
+
+ before_validation :create_code
+ after_create :send_email
+
+ def create_code
+ (1...10).each do |tries|
+ if tries == 10
+ raise "too many hash collisions"
+ end
+
+ if !InvitationRequest.find_by_code(self.code = Utils.random_str(15))
+ break
+ end
+ end
+ end
+
+ def send_email
+ InvitationRequestMailer.invitation_request(self).deliver
+ end
+end
diff --git a/app/views/invitation_request_mailer/invitation_request.text.erb b/app/views/invitation_request_mailer/invitation_request.text.erb
new file mode 100644
index 0000000..345cf89
--- /dev/null
+++ b/app/views/invitation_request_mailer/invitation_request.text.erb
@@ -0,0 +1,15 @@
+Hello <%= @invitation_request.email %>,
+
+Someone at <%= @invitation_request.ip_address %> has submitted an invitiation request to
+<%= Rails.application.name %>.
+
+ Name: <%= @invitation_request.name %>
+ E-mail: <%= @invitation_request.email %> (won't be displayed to other users)
+ Memo: <%= @invitation_request.memo %>
+
+If this is you, visit the URL below to confirm your request and
+display it to other logged-in users.
+
+ <%= root_url %>invitations/confirm/<%= @invitation_request.code %>
+
+If this is not you, you can delete this message.
diff --git a/app/views/invitations/build.html.erb b/app/views/invitations/build.html.erb
new file mode 100644
index 0000000..0e16a31
--- /dev/null
+++ b/app/views/invitations/build.html.erb
@@ -0,0 +1,39 @@
+
+
+ Request an Invitation
+
+
+
+ If you don't know (or can't find) an existing user from
+ which to request an invitiation, you can make a public request for one. This
+ will display your name and memo to all other logged-in users who can then
+ send you an invitation if they recognize you.
+
+
+ Your e-mail address must be valid and confirmed by visiting a URL e-mailed to
+ you before your request will be displayed. Your e-mail address will not be
+ shown to any other users.
+
+
+ <%= form_tag create_invitation_by_request_url do %>
+
diff --git a/app/views/invitations/index.html.erb b/app/views/invitations/index.html.erb
new file mode 100644
index 0000000..f116abb
--- /dev/null
+++ b/app/views/invitations/index.html.erb
@@ -0,0 +1,40 @@
+
+
+ Requested Invitations
+
+
+
+ These persons have requested invitations and confirmed their e-mail
+ addresses. If you recognize anyone, feel free to send them an invitation and
+ remove their request. Spam will be cleared out by a moderator.
+
+
+
+
+
Date/Time
+
Name
+
Memo
+
+
+ <% bit = 0 %>
+ <% @invitation_requests.each do |ir| %>
+
<%= form_tag send_invitation_for_request_url, :confirm => "Are " <<
+ "you sure you want to invite this person and remove this request?" do %>
+ <%= hidden_field_tag "code", ir.code %>
+ <%= submit_tag "Send Invitiation" %>
+ <% end %>
+
+ <% bit = (bit == 1 ? 0 : 1) %>
+ <% end %>
+ <% if @invitation_requests.count == 0 %>
+
- Not a user yet? Signup is currently by invitation only to combat spam and
- increase accountability. If you know a current user of
- the site, ask them for an invitation.
+ Not a user yet? Signup is by invitation only to combat spam and increase
+ accountability. If you know a current user of the site,
+ ask them for an invitation or request one
+ publicly.
<% end %>
diff --git a/config/routes.rb b/config/routes.rb
index e893dc8..3339e1f 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -1,7 +1,7 @@
Lobsters::Application.routes.draw do
root :to => "home#index",
:protocol => (Rails.env == "production" ? "https://" : "http://")
-
+
get "/rss" => "home#index", :format => "rss"
get "/hottest.json" => "home#index", :format => "json"
@@ -77,6 +77,13 @@ Lobsters::Application.routes.draw do
post "/filters" => "filters#update"
post "/invitations" => "invitations#create"
+ get "/invitations" => "invitations#index"
+ get "/invitations/request" => "invitations#build"
+ post "/invitations/create_by_request" => "invitations#create_by_request",
+ :as => "create_invitation_by_request"
+ get "/invitations/confirm/:code" => "invitations#confirm_email"
+ post "/invitations/send_for_request" => "invitations#send_for_request",
+ :as => "send_invitation_for_request"
get "/invitations/:invitation_code" => "signup#invited"
get "/moderations" => "moderations#index"
diff --git a/db/migrate/20131018201413_add_invitation_requests.rb b/db/migrate/20131018201413_add_invitation_requests.rb
new file mode 100644
index 0000000..20c99be
--- /dev/null
+++ b/db/migrate/20131018201413_add_invitation_requests.rb
@@ -0,0 +1,17 @@
+class AddInvitationRequests < ActiveRecord::Migration
+ def up
+ create_table :invitation_requests do |t|
+ t.string :code
+ t.boolean :is_verified, :default => false
+ t.string :email
+ t.string :name
+ t.text :memo
+ t.string :ip_address
+ t.timestamps
+ end
+ end
+
+ def down
+ drop_table :invitation_requests
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 5a00104..a61d8bd 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
#
# It's strongly recommended to check this file into your version control system.
-ActiveRecord::Schema.define(:version => 20130622021035) do
+ActiveRecord::Schema.define(:version => 20131018201413) do
create_table "comments", :force => true do |t|
t.datetime "created_at", :null => false
@@ -35,6 +35,17 @@ ActiveRecord::Schema.define(:version => 20130622021035) do
add_index "comments", ["story_id", "short_id"], :name => "story_id_short_id"
add_index "comments", ["thread_id"], :name => "thread_id"
+ create_table "invitation_requests", :force => true do |t|
+ t.string "code"
+ t.boolean "is_verified", :default => false
+ t.string "email"
+ t.string "name"
+ t.text "memo"
+ t.string "ip_address"
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
+ end
+
create_table "invitations", :force => true do |t|
t.integer "user_id"
t.string "email"