Manage tag and community mod lists in Mailchimp (#2362)

* add moderation email list columns

* automate tag moderator mailing list

* reorder logic for tag mod list

* add community mod list

* remove trusted privileges when reverting a user to a regular member

* automatically make tag mods community mods

* fix merge conflicts

* add community view

* make methods less complex based on code climate sugggestion

* add specs

* refactor tag moderator module

* fix spec
This commit is contained in:
Jess Lee 2019-04-10 14:45:06 -04:00 committed by Ben Halpern
parent 1c285ba2c5
commit f637d9e02b
12 changed files with 244 additions and 28 deletions

View file

@ -109,6 +109,8 @@ variable :HONEYCOMB_API_KEY, :String, default: "Optional"
variable :MAILCHIMP_API_KEY, :String, default: "Optional-valid"
variable :MAILCHIMP_NEWSLETTER_ID, :String, default: "Optional"
variable :MAILCHIMP_SUSTAINING_MEMBERS_ID, :String, default: "Optional"
variable :MAILCHIMP_TAG_MODERATORS_ID, :String, default: "Optional"
variable :MAILCHIMP_COMMUNITY_MODERATORS_ID, :String, default: "Optional"
# Email digest frequency
variable :PERIODIC_EMAIL_DIGEST_MAX, :Integer, default: 0

View file

@ -22,8 +22,10 @@ class Internal::TagsController < Internal::ApplicationController
def update
@tag = Tag.find(params[:id])
add_moderator if params[:tag][:tag_moderator_id]
remove_moderator if params[:tag][:remove_moderator_id]
@add_user_id = params[:tag][:tag_moderator_id]
@remove_user_id = params[:tag][:remove_moderator_id]
add_moderator if @add_user_id
remove_moderator if @remove_user_id
@tag.update!(tag_params)
redirect_to "/internal/tags/#{params[:id]}"
end
@ -31,12 +33,14 @@ class Internal::TagsController < Internal::ApplicationController
private
def remove_moderator
User.find(params[:tag][:remove_moderator_id]).remove_role :tag_moderator, @tag
user = User.find(@remove_user_id)
user.update(email_tag_mod_newsletter: false)
AssignTagModerator.remove_tag_moderator(user, @tag)
end
def add_moderator
user_id = params[:tag][:tag_moderator_id]
AssignTagModerator.add_tag_moderators([user_id], [@tag.id])
User.find(@add_user_id).update(email_tag_mod_newsletter: true)
AssignTagModerator.add_tag_moderators([@add_user_id], [@tag.id])
end
def tag_params

View file

@ -1,11 +1,34 @@
module AssignTagModerator
def self.add_trusted_role(user)
user.add_role :trusted
user.update(email_community_mod_newsletter: true)
MailchimpBot.new(user).manage_community_moderator_list
end
def self.add_to_chat_channel(user)
ChatChannel.find_by(slug: "tag-moderators").add_users(user) if user.chat_channels.find_by(slug: "tag-moderators").blank?
end
def self.add_tag_mod_role(user, tag)
user.update(email_tag_mod_newsletter: true) if user.email_tag_mod_newsletter == false
user.add_role(:tag_moderator, tag)
MailchimpBot.new(user).manage_tag_moderator_list
end
def self.add_tag_moderators(user_ids, tag_ids)
user_ids.each_with_index do |user_id, index|
user = User.find(user_id)
tag = Tag.find(tag_ids[index])
user.add_role(:tag_moderator, tag)
ChatChannel.find_by(slug: "tag-moderators").add_users(user) if user.chat_channels.find_by(slug: "tag-moderators").blank?
add_tag_mod_role(user, tag)
add_trusted_role(user)
add_to_chat_channel(user)
NotifyMailer.tag_moderator_confirmation_email(user, tag.name).deliver unless tag.name == "go"
end
end
def self.remove_tag_moderator(user, tag)
user.remove_role(:tag_moderator, tag)
user.update(email_tag_mod_newsletter: false) if user.email_tag_mod_newsletter == true
MailchimpBot.new(user).manage_tag_moderator_list
end
end

View file

@ -11,6 +11,8 @@ class MailchimpBot
return true unless Rails.env.production? || Rails.env.test?
upsert_to_membership_newsletter
manage_community_moderator_list
manage_tag_moderator_list
upsert_to_newsletter
end
@ -45,6 +47,60 @@ class MailchimpBot
success
end
def manage_community_moderator_list
return false unless user.has_role?(:trusted)
success = false
status = user.email_community_mod_newsletter ? "subscribed" : "unsubscribed"
begin
gibbon.lists(ApplicationConfig["MAILCHIMP_COMMUNITY_MODERATORS_ID"]).members(target_md5_email).upsert(
body: {
email_address: user.email,
status: status,
merge_fields: {
NAME: user.name.to_s,
USERNAME: user.username.to_s,
TWITTER: user.twitter_username.to_s,
GITHUB: user.github_username.to_s,
IMAGE_URL: user.profile_image_url.to_s
}
},
)
success = true
rescue Gibbon::MailChimpError => e
report_error(e)
end
success
end
def manage_tag_moderator_list
return false unless user.tag_moderator?
success = false
tags = user.roles.where(name: "tag_moderator").map { |t| Tag.find(t.resource_id).name }
status = user.email_tag_mod_newsletter ? "subscribed" : "unsubscribed"
begin
gibbon.lists(ApplicationConfig["MAILCHIMP_TAG_MODERATORS_ID"]).members(target_md5_email).upsert(
body: {
email_address: user.email,
status: status,
merge_fields: {
NAME: user.name.to_s,
USERNAME: user.username.to_s,
TWITTER: user.twitter_username.to_s,
GITHUB: user.github_username.to_s,
IMAGE_URL: user.profile_image_url.to_s,
TAGS: tags.join(", ")
}
},
)
success = true
rescue Gibbon::MailChimpError => e
report_error(e)
end
success
end
def upsert_to_membership_newsletter
return false unless a_sustaining_member?
@ -80,6 +136,36 @@ class MailchimpBot
success
end
def unsub_sustaining_member
return unless user.tag_moderator?
gibbon.lists(ApplicationConfig["MAILCHIMP_TAG_MODERATORS_ID"]).members(target_md5_email).update(
body: {
status: "unsubscribed"
},
)
end
def unsub_community_mod
return unless user.has_role?(:trusted)
gibbon.lists(ApplicationConfig["MAILCHIMP_COMMUNITY_MODERATORS_ID"]).members(target_md5_email).update(
body: {
status: "unsubscribed"
},
)
end
def unsub_tag_mod
return unless a_sustaining_member?
gibbon.lists(ApplicationConfig["MAILCHIMP_SUSTAINING_MEMBERS_ID"]).members(target_md5_email).update(
body: {
status: "unsubscribed"
},
)
end
def unsubscribe_all_newsletters
success = false
begin
@ -88,13 +174,9 @@ class MailchimpBot
status: "unsubscribed"
},
)
if a_sustaining_member?
gibbon.lists(ApplicationConfig["MAILCHIMP_SUSTAINING_MEMBERS_ID"]).members(target_md5_email).update(
body: {
status: "unsubscribed"
},
)
end
unsub_tag_mod
unsub_sustaining_member
unsub_community_mod
success = true
rescue Gibbon::MailChimpError => e
report_error(e)

View file

@ -406,6 +406,10 @@ class User < ApplicationRecord
MailchimpBot.new(self).unsubscribe_all_newsletters
end
def tag_moderator?
roles.where(name: "tag_moderator").any?
end
private
def send_welcome_notification

View file

@ -69,6 +69,8 @@ class UserPolicy < ApplicationPolicy
email_digest_periodic
email_follower_notifications
email_membership_newsletter
email_tag_mod_newsletter
email_community_mod_newsletter
email_mention_notifications
email_connect_messages
email_newsletter

View file

@ -53,11 +53,25 @@ module Moderator
end
def remove_privileges
@user.remove_role :trusted
@user.remove_role :video_permission
@user.remove_role :tag_moderator
@user.remove_role :workshop_pass
@user.remove_role :pro
remove_mod_roles
remove_tag_moderator_role
end
def remove_mod_roles
@user.remove_role :trusted
@user.remove_role :tag_moderator
@user.update(email_tag_mod_newsletter: false)
MailchimpBot.new(user).manage_tag_moderator_list
@user.update(email_community_mod_newsletter: false)
MailchimpBot.new(user).manage_community_moderator_list
end
def remove_tag_moderator_role
@user.remove_role :tag_moderator
MailchimpBot.new(user).manage_tag_moderator_list
end
def create_note(reason, content)
@ -76,28 +90,47 @@ module Moderator
user.add_role :banned
remove_privileges
when "Warn"
user.add_role :warned
user.remove_role :banned
remove_privileges
warned
when "Comment Ban"
user.add_role :comment_banned
user.remove_role :banned
remove_privileges
comment_banned
when "Regular Member"
remove_negative_roles
user.remove_role :pro
regular_member
when "Trusted"
remove_negative_roles
user.remove_role :pro
user.add_role :trusted
add_trusted_role
when "Pro"
remove_negative_roles
user.add_role :trusted
add_trusted_role
user.add_role :pro
end
create_note(role, note)
end
def comment_banned
user.add_role :comment_banned
user.remove_role :banned
remove_privileges
end
def regular_member
remove_negative_roles
user.remove_role :pro
remove_mod_roles
end
def warned
user.add_role :warned
user.remove_role :banned
remove_privileges
end
def add_trusted_role
user.add_role :trusted
user.update(email_community_mod_newsletter: true)
MailchimpBot.new(user).manage_community_moderator_list
end
def remove_negative_roles
user.remove_role :banned if user.banned
user.remove_role :warned if user.warned

View file

@ -15,6 +15,18 @@
<%= f.label :email_membership_newsletter, "Send me sustaining membership newsletter emails" %>
</div>
<% end %>
<% if current_user.tag_moderator? %>
<div class="sub-field">
<%= f.check_box :email_tag_mod_newsletter %>
<%= f.label :email_tag_mod_newsletter, "Send me tag moderator newsletter emails" %>
</div>
<% end %>
<% if current_user.has_role?(:trusted) %>
<div class="sub-field">
<%= f.check_box :email_community_mod_newsletter %>
<%= f.label :email_community_mod_newsletter, "Send me community moderator newsletter emails" %>
</div>
<% end %>
<div class="sub-field">
<%= f.check_box :email_comment_notifications %>
<%= f.label :email_comment_notifications, "Send me an email when someone replies to me in a comment thread" %>

View file

@ -139,7 +139,6 @@ Rails.application.routes.draw do
resources :rating_votes, only: [:create]
resources :page_views, only: %i[create update]
resources :buffer_updates, only: [:create]
get "/notifications/:filter" => "notifications#index"
get "/notifications/:filter/:org_id" => "notifications#index"
patch "/onboarding_update" => "users#onboarding_update"

View file

@ -0,0 +1,6 @@
class AddMailchimpListsToUsers < ActiveRecord::Migration[5.2]
def change
add_column :users, :email_tag_mod_newsletter, :boolean, default: false
add_column :users, :email_community_mod_newsletter, :boolean, default: false
end
end

View file

@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2019_04_04_102732) do
ActiveRecord::Schema.define(version: 2019_04_05_190915) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@ -779,6 +779,7 @@ ActiveRecord::Schema.define(version: 2019_04_04_102732) do
t.string "email"
t.boolean "email_badge_notifications", default: true
t.boolean "email_comment_notifications", default: true
t.boolean "email_community_mod_newsletter", default: false
t.boolean "email_connect_messages", default: true
t.boolean "email_digest_periodic", default: true, null: false
t.boolean "email_follower_notifications", default: true
@ -786,6 +787,7 @@ ActiveRecord::Schema.define(version: 2019_04_04_102732) do
t.boolean "email_mention_notifications", default: true
t.boolean "email_newsletter", default: true
t.boolean "email_public", default: false
t.boolean "email_tag_mod_newsletter", default: false
t.boolean "email_unread_notifications", default: true
t.string "employer_name"
t.string "employer_url"

View file

@ -8,16 +8,27 @@ class FakeGibbonRequest < Gibbon::Request
def members(*args)
super
end
def tag_mods(*args)
super
end
def community_mods(*args)
super
end
end
RSpec.describe MailchimpBot do
let(:user) { create(:user, :ignore_after_callback) }
let(:article) { create(:article, user_id: user.id) }
let(:my_gibbon_client) { instance_double(FakeGibbonRequest) }
let(:tag) { create(:tag, name: "tag name", bg_color_hex: Faker::Color.hex_color, text_color_hex: Faker::Color.hex_color, supported: true) }
before do
allow(Gibbon::Request).to receive(:new) { my_gibbon_client }
allow(my_gibbon_client).to receive(:lists) { my_gibbon_client }
allow(my_gibbon_client).to receive(:tag_mods) { my_gibbon_client }
allow(my_gibbon_client).to receive(:community_mods) { my_gibbon_client }
allow(my_gibbon_client).to receive(:members) { my_gibbon_client }
allow(my_gibbon_client).to receive(:upsert).and_return(true)
end
@ -82,6 +93,42 @@ RSpec.describe MailchimpBot do
end
end
describe "manage community moderator list" do
it "returns false if user isn't a community moderator" do
expect(described_class.new(user).manage_community_moderator_list).to be(false)
end
it "sends proper information" do
user.update(email_community_mod_newsletter: true)
user.add_role :trusted
described_class.new(user).manage_community_moderator_list
expect(my_gibbon_client).to have_received(:upsert).
with(hash_including(
body: hash_including(
status: "subscribed",
),
))
end
end
describe "manage tag moderator list" do
it "returns false if user isn't a tag moderator" do
expect(described_class.new(user).manage_community_moderator_list).to be(false)
end
it "sends proper information" do
user.update(email_tag_mod_newsletter: true)
user.add_role(:tag_moderator, tag)
described_class.new(user).manage_tag_moderator_list
expect(my_gibbon_client).to have_received(:upsert).
with(hash_including(
body: hash_including(
status: "subscribed",
),
))
end
end
describe "#upsert_to_membership_newsletter" do
it "returns false if user isn't a sustaining member" do
expect(described_class.new(user).upsert_to_membership_newsletter).to be(false)