Commit dcfdb398 authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Merge branch 'feature-admin-emails' into 'master'

Feature admin emails

solves issue #126

One point remains. There is no clickable link to open the email page. Where should this link be communicated?!

# User Overview
![](https://dev.gitlab.org/uploads/gitlab/gitlab-ee/638fd79165/Screen_Shot_2014-08-12_at_17.30.53.png)

# Composing an email
![](https://dev.gitlab.org/uploads/gitlab/gitlab-ee/c07f753aec/Screen_Shot_2014-08-11_at_16.28.57.png)

# Unsubscribe
![](https://dev.gitlab.org/uploads/gitlab/gitlab-ee/db15c9f8b0/Screen_Shot_2014-08-12_at_17.32.27.png)

See merge request !140
parents 361432af 94d69fe2
class Admin::EmailsController < Admin::ApplicationController
def show
end
def create
AdminEmailsWorker.perform_async(params[:recipients], params[:subject], params[:body])
redirect_to admin_email_path, notice: 'Email sent'
end
end
class UnsubscribesController < ApplicationController
skip_before_filter :authenticate_user!,
:reject_blocked, :set_current_user_for_observers,
:add_abilities
layout 'public_users'
def show
@user = get_user
end
def create
@user = get_user
@user.admin_unsubscribe! if @user
redirect_to new_user_session_path, notice: 'You have been unsubscribed'
end
protected
def get_user
@email = CGI.unescape(params[:email])
User.where(email: @email).first
end
end
module AdminEmailHelper
def admin_email_grouped_recipient_options
options_for_select([['All GitLab users', 'all']]) +
grouped_options_for_select(
'Groups' => Group.pluck(:name, :id).map{ |name, id| [name, "group-#{id}"] },
'Projects' => grouped_project_list
)
end
protected
def grouped_project_list
Group.includes(:projects).flat_map do |group|
group.human_name
group.projects.map do |project|
["#{group.human_name} / #{project.name}", "project-#{project.id}"]
end
end
end
end
\ No newline at end of file
module Emails
module AdminNotification
def send_admin_notification(user_id, subject, body)
email = recipient(user_id)
@unsubscribe_url = unsubscribe_url(email: CGI.escape(email))
@body = body
mail to: email, subject: subject
end
end
end
\ No newline at end of file
class Notify < ActionMailer::Base
include ActionDispatch::Routing::PolymorphicRoutes
include Emails::AdminNotification
include Emails::Issues
include Emails::MergeRequests
include Emails::Notes
......
......@@ -175,6 +175,7 @@ class User < ActiveRecord::Base
scope :not_in_project, ->(project) { project.users.present? ? where("id not in (:ids)", ids: project.users.map(&:id) ) : all }
scope :without_projects, -> { where('id NOT IN (SELECT DISTINCT(user_id) FROM users_projects)') }
scope :ldap, -> { where(provider: 'ldap') }
scope :subscribed_for_admin_email, -> { where(admin_email_unsubscribed_at: nil) }
scope :potential_team_members, ->(team) { team.members.any? ? active.not_in_team(team) : active }
......@@ -509,4 +510,8 @@ class User < ActiveRecord::Base
def system_hook_service
SystemHooksService.new
end
def admin_unsubscribe!
update_column :admin_email_unsubscribed_at, Time.now
end
end
%h3.page-title
Send email notication
%p.light
You can notify the app / group or a project by sending them an email notification
= form_tag admin_email_path, class: 'form-horizontal', id: 'new-admin-email' do
.form-group
%label.control-label{for: :subject} Subject
.col-sm-10
= text_field_tag :subject, '', class: 'form-control', required: true
.form-group
%label.control-label{for: :body} Body
.col-sm-10
= text_area_tag :body, '', class: 'form-control', rows: 15, required: true
.form-group
%label.control-label{for: :recipients} Recipient group
.col-sm-10
= select_tag :recipients, admin_email_grouped_recipient_options, class: :select2, required: true
.form-actions
= submit_tag 'Send message', class: 'btn btn-create'
......@@ -32,6 +32,7 @@
.panel-heading
Users (#{@users.total_count})
.panel-head-actions
= link_to 'Send email to users', admin_email_path, class: 'btn btn-info'
= link_to 'New User', new_admin_user_path, class: "btn btn-new"
%ul.well-list
- @users.each do |user|
......
= simple_format @body
\----
%p
Don't want to receive updates from GitLab administrators?
= link_to 'Unsubscribe', @unsubscribe_url
\ No newline at end of file
= h @body
\-----
Don't want to receive updates from GitLab administrators?
== Unsubscribe here: #{@unsubscribe_url}
\ No newline at end of file
%h3.page-title Unsubscribe from Admin notifications
%hr
= form_tag unsubscribe_path(@email) do
%p
Yes, I want to unsubscribe
%strong= @email
from any further admin emails.
.form-actions
= submit_tag 'Unsubscribe', class: 'btn btn-create'
class AdminEmailsWorker
include Sidekiq::Worker
def perform(recipient_id, subject, body)
recipient_list(recipient_id).pluck(:id).each do |user_id|
Notify.send_admin_notification(user_id, subject, body).deliver
end
end
private
def recipient_list(recipient_id)
case recipient_id
when 'all'
User.subscribed_for_admin_email
when /group-(\d+)\z/
Group.find($1).users.subscribed_for_admin_email
when /project-(\d+)\z/
Project.find($1).team.users.subscribed_for_admin_email
end
end
end
\ No newline at end of file
......@@ -86,6 +86,7 @@ Gitlab::Application.routes.draw do
resources :broadcast_messages, only: [:index, :create, :destroy]
resource :logs, only: [:show]
resource :background_jobs, controller: 'background_jobs', only: [:show]
resource :email, only: [:show, :create]
resources :projects, constraints: { id: /[a-zA-Z.\/0-9_\-]+/ }, only: [:index, :show] do
member do
......@@ -173,6 +174,8 @@ Gitlab::Application.routes.draw do
end
end
get 'unsubscribes/:email', to: 'unsubscribes#show', as: :unsubscribe
post 'unsubscribes/:email', to: 'unsubscribes#create'
resources :projects, constraints: { id: /[^\/]+/ }, only: [:new, :create]
devise_for :users, controllers: { omniauth_callbacks: :omniauth_callbacks, registrations: :registrations , passwords: :passwords, sessions: :sessions }
......
class AddUnsubscribedAtFieldToUsers < ActiveRecord::Migration
def change
add_column :users, :admin_email_unsubscribed_at, :datetime
end
end
@admin
Feature: Admin email
Background:
Given I sign in as an admin
And there are groups with projects
Scenario: Create a new email notification
Given I visit admin email page
When I submit form with email notification info
Then I should see a notification email is begin sent
And admin emails are being sent
class Spinach::Features::AdminEmail < Spinach::FeatureSteps
include SharedAuthentication
include SharedPaths
include SharedAdmin
step 'I submit form with email notification info' do
ActionMailer::Base.deliveries = []
@email_text = "Your project has been moved."
@selected_group = Group.last
# ensure there are ppl to be emailed
2.times do
@selected_group.add_user(create(:user), Gitlab::Access::DEVELOPER)
end
within('form#new-admin-email') do
fill_in :subject, with: 'my subject'
fill_in :body, with: @email_text
select @selected_group.name, from: :recipients
find('.btn-create').click
end
end
step 'I should see a notification email is begin sent' do
expect(find('.flash-notice')).to have_content 'Email sent'
end
step 'admin emails are being sent' do
expect(ActionMailer::Base.deliveries.count).to eql @selected_group.users.count
mail = ActionMailer::Base.deliveries.last
expect(mail.text_part.body.decoded).to include @email_text
end
end
\ No newline at end of file
......@@ -8,5 +8,12 @@ module SharedAdmin
And 'system has users' do
2.times { create(:user) }
end
And 'there are groups with projects' do
2.times do
group = create :group
create :project, group: group
end
end
end
......@@ -169,6 +169,9 @@ module SharedPaths
visit admin_teams_path
end
step 'I visit admin email page' do
visit admin_email_path
end
# ----------------------------------------
# Generic Project
# ----------------------------------------
......
require 'spec_helper'
describe UnsubscribesController do
let!(:user) { create :user, email: 'me@example.com' }
describe "show" do
it "responds with success" do
get :show, email: CGI.escape('me@example.com')
assert_response :success
end
it "behaves the same if email address isn't known in the system" do
get :show, email: CGI.escape('i@dont_exists.com')
assert_response :success
end
end
describe "create" do
it "unsubscribes the connected user" do
post :create, email: CGI.escape('me@example.com')
assert user.reload.admin_email_unsubscribed_at
end
# Don't tell if the email does not exists
it "behaves the same if email address isn't known in the system" do
post :create, email: CGI.escape('i@dont_exists.com')
assert_response :redirect
end
end
end
......@@ -119,3 +119,12 @@ describe Admin::DashboardController, "routing" do
end
end
describe Admin::EmailsController, "routing" do
it "to #show" do
get("/admin/email").should route_to('admin/emails#show')
end
it "to #create" do
post("/admin/email").should route_to('admin/emails#create')
end
end
require 'spec_helper'
describe AdminEmailsWorker do
context "recipients" do
let(:recipient_id) { "group-#{group.id}" }
let(:group) { create :group }
before do
2.times do
group.add_user(create(:user), Gitlab::Access::DEVELOPER)
end
unsubscribed_user = create(:user, admin_email_unsubscribed_at: 5.days.ago)
group.add_user(unsubscribed_user, Gitlab::Access::DEVELOPER)
ActionMailer::Base.deliveries = []
end
it "sends email to subscribed users" do
AdminEmailsWorker.new.perform(recipient_id, 'subject', 'body')
expect(ActionMailer::Base.deliveries.count).to eql 2
end
end
end
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment