Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an unsubscribe link to invitation emails #3136

Merged
merged 2 commits into from Nov 10, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
17 changes: 14 additions & 3 deletions app/controllers/invitations_controller.rb
@@ -1,10 +1,10 @@
class InvitationsController < ApplicationController

before_action do |controller|
before_action except: :unsubscribe do |controller|
controller.ensure_logged_in t("layouts.notifications.you_must_log_in_to_invite_new_users")
end

before_action :users_can_invite_new_users
before_action :users_can_invite_new_users, except: :unsubscribe

def new
@selected_tribe_navi_tab = "members"
Expand All @@ -26,7 +26,8 @@ def create
:message
)

invitation_emails = invitation_params[:email].split(",").map(&:strip)
raw_invitation_emails = invitation_params[:email].split(",").map(&:strip)
invitation_emails = Invitation::Unsubscribe.remove_unsubscribed_emails(@current_community, raw_invitation_emails)

unless validate_daily_limit(@current_user.id, invitation_emails.size, @current_community)
return redirect_to new_invitation_path, flash: { error: t("layouts.notifications.invitation_limit_reached")}
Expand Down Expand Up @@ -66,6 +67,16 @@ def create
redirect_to new_invitation_path
end

def unsubscribe
invitation_unsubscribe = Invitation::Unsubscribe.unsubscribe(params[:code])
if invitation_unsubscribe.persisted?
flash[:notice] = t("layouts.notifications.invitation_successfully_unsubscribed")
else
flash[:error] = t("layouts.notifications.invitation_cannot_unsubscribe")
end
redirect_to landing_page_path
end

private

def users_can_invite_new_users
Expand Down
4 changes: 3 additions & 1 deletion app/mailers/person_mailer.rb
Expand Up @@ -197,8 +197,10 @@ def invitation_to_kassi(invitation)
@invitation_code_required = invitation.community.join_with_invite_only
set_up_layout_variables(nil, invitation.community)
@url_params[:locale] = mail_locale
@url_params[:code] = invitation.code
@invitation_community = invitation.community.full_name_with_separator(invitation.inviter.locale)
with_locale(mail_locale, invitation.community.locales.map(&:to_sym), invitation.community.id) do
subject = t("emails.invitation_to_kassi.you_have_been_invited_to_kassi", :inviter => PersonViewUtils.person_display_name(invitation.inviter, invitation.community), :community => invitation.community.full_name_with_separator(invitation.inviter.locale))
subject = t("emails.invitation_to_kassi.you_have_been_invited_to_kassi", :inviter => PersonViewUtils.person_display_name(invitation.inviter, invitation.community), :community => @invitation_community)
premailer_mail(:to => invitation.email,
:from => community_specific_sender(invitation.community),
:subject => subject,
Expand Down
37 changes: 37 additions & 0 deletions app/models/invitation/unsubscribe.rb
@@ -0,0 +1,37 @@
# == Schema Information
#
# Table name: invitation_unsubscribes
#
# id :integer not null, primary key
# community_id :integer
# email :string(255)
# created_at :datetime not null
# updated_at :datetime not null
#
# Indexes
#
# index_invitation_unsubscribes_on_community_id (community_id)
# index_invitation_unsubscribes_on_email (email)
#

class Invitation::Unsubscribe < ApplicationRecord
belongs_to :community

validates :community, :email, presence: true

scope :by_community_and_email, ->(community, email) { where(community: community, email: email) }

class << self
def unsubscribe(code)
invitation = Invitation.find_by(code: code.upcase)
if invitation
where(community: invitation.community,
email: invitation.email.downcase).first_or_create
end
end

def remove_unsubscribed_emails(community, invitation_emails)
invitation_emails.reject{ |email| by_community_and_email(community, email).any? }
end
end
end
11 changes: 11 additions & 0 deletions app/views/layouts/email.html.haml
Expand Up @@ -34,7 +34,18 @@
%tr
%td{:align => "left", :style => "padding-top: 10px; padding-bottom: 30px;border-top:1px dotted grey;"}
%font{:size => 3, :color => "gray", :face => "font-family:Helvetica Neue, Arial, Helvetica, Arial, sans-serif;", :style => "font-size:12px;"}
- if @community
= t("emails.common.unsubscribe_from_these_emails_info", service_name: @community.full_name(I18n.locale))
= t("emails.welcome_email.welcome_email_footer_text", :settings_link => link_to(t("emails.welcome_email.settings_link_text"), notifications_person_settings_url(@recipient, @url_params))).html_safe
- if @email_type
= t("emails.common.or")
= link_to(t("emails.common.unsubscribe_from_these_emails"), unsubscribe_person_settings_url(@recipient, @url_params.merge({email_type: @email_type, auth: @unsubscribe_token}))) + "."

- if @invitation
%tr
%td{:align => "left", :style => "padding-top: 10px; padding-bottom: 30px;border-top:1px dotted grey;"}
%font{:size => 3, :color => "gray", :face => "font-family:Helvetica Neue, Arial, Helvetica, Arial, sans-serif;", :style => "font-size:12px;"}
= t("emails.common.unsubscribe_from_invitation_emails_info", service_name: @invitation_community)
= link_to(t("emails.common.unsubscribe_from_invitation_emails", service_name: @invitation_community),
unsubscribe_invitations_url(@url_params)) + "."

5 changes: 5 additions & 0 deletions config/locales/en.yml
Expand Up @@ -946,7 +946,10 @@ en:
message_not_displaying_correctly: "Is this email not displaying correctly?"
view_it_in_your_browser: "View it in your browser"
or: or
unsubscribe_from_these_emails_info: "You have received this email because you are a member of %{service_name}."
unsubscribe_from_these_emails: "unsubscribe from these emails"
unsubscribe_from_invitation_emails_info: "You have received this email because a member of %{service_name} has invited you to join them."
unsubscribe_from_invitation_emails: "Unsubscribe from invitation emails to join %{service_name}"
conversation_status_changed:
has_accepted_your_offer: "%{accepter} has accepted your offer %{listing}."
has_accepted_your_request: "%{accepter} has accepted your request %{listing}."
Expand Down Expand Up @@ -1412,8 +1415,10 @@ en:
feedback_sent_to: "Feedback sent to %{target_person}."
feedback_skipped: "Feedback skipped"
invitation_cannot_be_sent: "Invitation could not be sent"
invitation_cannot_unsubscribe: "Cannot unsubscribe from invitation emails"
invitation_limit_reached: "You were trying to send too many invitations. Daily limit reached."
invitation_sent: "Invitation sent successfully"
invitation_successfully_unsubscribed: "Successfully unsubscribed from invitation emails"
inviting_new_users_is_not_allowed_in_this_community: "Inviting new users is not allowed."
login_again: "Please log in again."
login_failed: "Login failed. Please enter the correct credentials."
Expand Down
6 changes: 5 additions & 1 deletion config/routes.rb
Expand Up @@ -317,7 +317,11 @@
resource :plan, only: [:show]
end

resources :invitations
resources :invitations, only: [:new, :create ] do
collection do
get :unsubscribe
end
end
resources :user_feedbacks, :controller => :feedbacks
resources :homepage do
collection do
Expand Down
12 changes: 12 additions & 0 deletions db/migrate/20171107063241_create_invitation_unsubscribes.rb
@@ -0,0 +1,12 @@
class CreateInvitationUnsubscribes < ActiveRecord::Migration[5.1]
def change
create_table :invitation_unsubscribes do |t|
t.integer :community_id
t.string :email

t.timestamps
end
add_index :invitation_unsubscribes, :community_id
add_index :invitation_unsubscribes, :email
end
end
17 changes: 16 additions & 1 deletion db/structure.sql
Expand Up @@ -547,6 +547,20 @@ CREATE TABLE `follower_relationships` (
KEY `index_follower_relationships_on_person_id` (`person_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `invitation_unsubscribes`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `invitation_unsubscribes` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`community_id` int(11) DEFAULT NULL,
`email` varchar(255) DEFAULT NULL,
`created_at` datetime NOT NULL,
`updated_at` datetime NOT NULL,
PRIMARY KEY (`id`),
KEY `index_invitation_unsubscribes_on_community_id` (`community_id`),
KEY `index_invitation_unsubscribes_on_email` (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `invitations`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
Expand Down Expand Up @@ -2195,6 +2209,7 @@ INSERT INTO `schema_migrations` (version) VALUES
('20170728065012'),
('20170801125553'),
('20170814125622'),
('20170817035830');
('20170817035830'),
('20171107063241');


7 changes: 7 additions & 0 deletions features/invitations/visitor_unsubscribe.feature
@@ -0,0 +1,7 @@
Feature: Visitor unsubscribe from invitaion to join community

Scenario: Visitor click on link to unsubscribe
Given community "test" admin sent invitation to "elaine@example.com" code "ABC"
When I go to the unsubscribe link with code "ABC" from invitation email to join community
Then I should see "Successfully unsubscribed from invitation emails"

4 changes: 4 additions & 0 deletions features/step_definitions/invitation_steps.rb
@@ -0,0 +1,4 @@
Given(/^community "(.*?)" admin sent invitation to "(.*?)" code "(.*?)"$/) do |community, email, code|
community = Community.where(ident: community).first
FactoryGirl.create(:invitation, community: community, code: code, email: email)
end
2 changes: 2 additions & 0 deletions features/support/paths.rb
Expand Up @@ -94,6 +94,8 @@ def path_to(page_name)
admin_listing_shapes_path
when /the edit "(.*)" order type admin page/
edit_admin_listing_shape_path(id: $1)
when /the unsubscribe link with code "(.*)" from invitation email to join community/
unsubscribe_invitations_path(code: $1)
else
begin
page_name =~ /the (.*) page/
Expand Down
5 changes: 5 additions & 0 deletions spec/factories.rb
Expand Up @@ -412,4 +412,9 @@ def build_association(association, opts = {})
sort_priority 0
end

factory :invitation_unsubscribe, class: 'Invitation::Unsubscribe' do
build_association(:community)
email 'sherry@example.com'
end

end
47 changes: 47 additions & 0 deletions spec/models/invitation/unsubscribe_spec.rb
@@ -0,0 +1,47 @@
# == Schema Information
#
# Table name: invitation_unsubscribes
#
# id :integer not null, primary key
# community_id :integer
# email :string(255)
# created_at :datetime not null
# updated_at :datetime not null
#
# Indexes
#
# index_invitation_unsubscribes_on_community_id (community_id)
# index_invitation_unsubscribes_on_email (email)
#

require 'spec_helper'

RSpec.describe Invitation::Unsubscribe, type: :model do
let(:invitation) { FactoryGirl.create(:invitation, code: 'ABC', email: 'cindy@example.com') }
let(:invitation_unsubscribe) { FactoryGirl.create(:invitation_unsubscribe) }
let(:community) { FactoryGirl.create(:community) }

context '#unsubscribe' do
it 'creates unsubscribe record' do
expect(Invitation::Unsubscribe.count).to eq 0
Invitation::Unsubscribe.unsubscribe(invitation.code)
expect(Invitation::Unsubscribe.count).to eq 1
end
end

context '#remove_unsubscribed_emails' do
it 'works' do
invitation_unsubscribe
invitation_emails = ['sherry@example.com', 'thelma@example.com']
result = Invitation::Unsubscribe.remove_unsubscribed_emails(invitation_unsubscribe.community, invitation_emails)
expect(result).to eq ['thelma@example.com']
end

it 'does not remove email related to another community' do
invitation_unsubscribe
invitation_emails = ['sherry@example.com', 'thelma@example.com']
result = Invitation::Unsubscribe.remove_unsubscribed_emails(community, invitation_emails)
expect(result).to eq ['sherry@example.com', 'thelma@example.com']
end
end
end
25 changes: 25 additions & 0 deletions spec/models/listing_shape_spec.rb
@@ -1,3 +1,28 @@
# == Schema Information
#
# Table name: listing_shapes
#
# id :integer not null, primary key
# community_id :integer not null
# transaction_process_id :integer not null
# price_enabled :boolean not null
# shipping_enabled :boolean not null
# availability :string(32) default("none")
# name :string(255) not null
# name_tr_key :string(255) not null
# action_button_tr_key :string(255) not null
# sort_priority :integer default(0), not null
# created_at :datetime not null
# updated_at :datetime not null
# deleted :boolean default(FALSE)
#
# Indexes
#
# index_listing_shapes_on_community_id (community_id)
# index_listing_shapes_on_name (name)
# multicol_index (community_id,deleted,sort_priority)
#

require 'spec_helper'

describe ListingShape, type: :model do
Expand Down