summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Hollingsworth <jhworth.developer@gmail.com>2014-02-08 21:08:49 -0600
committerJason Hollingsworth <jhworth.developer@gmail.com>2014-02-13 22:59:39 -0600
commit29cfd33d949d21d67f3892473c24d4f0a127dfe6 (patch)
treee9ed4a10e06f7eba224150a643cb87507fc2ddc7
parentd41e404e09c79394ff1938eee01b56345edc6ed9 (diff)
downloadgitlab-ce-29cfd33d949d21d67f3892473c24d4f0a127dfe6.tar.gz
Add email aliases for users
Emails are used to associate commits with users. The emails are not verified and don't have to be valid email addresses. They are assigned on a first come, first serve basis. Notifications are sent when an email is added.
-rw-r--r--app/controllers/profiles/emails_controller.rb26
-rw-r--r--app/helpers/commits_helper.rb15
-rw-r--r--app/mailers/emails/profile.rb6
-rw-r--r--app/models/email.rb33
-rw-r--r--app/models/user.rb13
-rw-r--r--app/observers/email_observer.rb5
-rw-r--r--app/services/git_push_service.rb4
-rw-r--r--app/services/notification_service.rb7
-rw-r--r--app/views/layouts/nav/_profile.html.haml4
-rw-r--r--app/views/notify/new_email_email.html.haml10
-rw-r--r--app/views/notify/new_email_email.text.erb7
-rw-r--r--app/views/profiles/emails/index.html.haml29
-rw-r--r--config/routes.rb1
-rw-r--r--db/migrate/20140209025651_create_emails.rb13
-rw-r--r--db/schema.rb84
-rw-r--r--features/profile/emails.feature25
-rw-r--r--features/project/commits/commits_user_lookup.feature14
-rw-r--r--features/steps/profile/profile_emails.rb48
-rw-r--r--features/steps/project/project_browse_commits_user_lookup.rb35
-rw-r--r--features/support/env.rb2
-rw-r--r--spec/factories.rb13
-rw-r--r--spec/mailers/notify_spec.rb22
-rw-r--r--spec/observers/email_observer_spec.rb17
-rw-r--r--spec/routing/routing_spec.rb17
-rw-r--r--spec/services/notification_service_spec.rb13
-rw-r--r--spec/support/valid_commit.rb1
-rw-r--r--spec/support/valid_commit_with_alt_email.rb6
27 files changed, 424 insertions, 46 deletions
diff --git a/app/controllers/profiles/emails_controller.rb b/app/controllers/profiles/emails_controller.rb
new file mode 100644
index 00000000000..9996b67a8a4
--- /dev/null
+++ b/app/controllers/profiles/emails_controller.rb
@@ -0,0 +1,26 @@
+class Profiles::EmailsController < ApplicationController
+ layout "profile"
+
+ def index
+ @primary = current_user.email
+ @emails = current_user.emails
+ end
+
+ def create
+ @email = current_user.emails.new(params[:email])
+
+ flash[:alert] = @email.errors.full_messages.first unless @email.save
+
+ redirect_to profile_emails_url
+ end
+
+ def destroy
+ @email = current_user.emails.find(params[:id])
+ @email.destroy
+
+ respond_to do |format|
+ format.html { redirect_to profile_emails_url }
+ format.js { render nothing: true }
+ end
+ end
+end
diff --git a/app/helpers/commits_helper.rb b/app/helpers/commits_helper.rb
index 663369e4584..5e5f3f77a21 100644
--- a/app/helpers/commits_helper.rb
+++ b/app/helpers/commits_helper.rb
@@ -122,17 +122,18 @@ module CommitsHelper
def commit_person_link(commit, options = {})
source_name = commit.send "#{options[:source]}_name".to_sym
source_email = commit.send "#{options[:source]}_email".to_sym
+
+ user = User.find_for_commit(source_email, source_name)
+ person_name = user.nil? ? source_name : user.name
+ person_email = user.nil? ? source_email : user.email
+
text = if options[:avatar]
- avatar = image_tag(avatar_icon(source_email, options[:size]), class: "avatar #{"s#{options[:size]}" if options[:size]}", width: options[:size], alt: "")
- %Q{#{avatar} <span class="commit-#{options[:source]}-name">#{source_name}</span>}
+ avatar = image_tag(avatar_icon(person_email, options[:size]), class: "avatar #{"s#{options[:size]}" if options[:size]}", width: options[:size], alt: "")
+ %Q{#{avatar} <span class="commit-#{options[:source]}-name">#{person_name}</span>}
else
- source_name
+ person_name
end
- # Prefer email match over name match
- user = User.where(email: source_email).first
- user ||= User.where(name: source_name).first
-
options = {
class: "commit-#{options[:source]}-link has_tooltip",
data: { :'original-title' => sanitize(source_email) }
diff --git a/app/mailers/emails/profile.rb b/app/mailers/emails/profile.rb
index bcd44f9476c..c91660a02b5 100644
--- a/app/mailers/emails/profile.rb
+++ b/app/mailers/emails/profile.rb
@@ -6,6 +6,12 @@ module Emails
mail(to: @user.email, subject: subject("Account was created for you"))
end
+ def new_email_email(email_id)
+ @email = Email.find(email_id)
+ @user = @email.user
+ mail(to: @user.email, subject: subject("Email was added to your account"))
+ end
+
def new_ssh_key_email(key_id)
@key = Key.find(key_id)
@user = @key.user
diff --git a/app/models/email.rb b/app/models/email.rb
new file mode 100644
index 00000000000..22e71e4f107
--- /dev/null
+++ b/app/models/email.rb
@@ -0,0 +1,33 @@
+# == Schema Information
+#
+# Table name: emails
+#
+# id :integer not null, primary key
+# user_id :integer not null
+# email :string not null
+# created_at :datetime not null
+class Email < ActiveRecord::Base
+ attr_accessible :email, :user_id
+
+ #
+ # Relations
+ #
+ belongs_to :user
+
+ #
+ # Validations
+ #
+ validates :user_id, presence: true
+ validates :email, presence: true, email: { strict_mode: true }, uniqueness: true
+ validate :unique_email, if: ->(email) { email.email_changed? }
+
+ before_validation :cleanup_email
+
+ def cleanup_email
+ self.email = self.email.downcase.strip
+ end
+
+ def unique_email
+ self.errors.add(:email, 'has already been taken') if User.exists?(email: self.email)
+ end
+end \ No newline at end of file
diff --git a/app/models/user.rb b/app/models/user.rb
index 10f21d23506..dd59f67ea3d 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -78,6 +78,7 @@ class User < ActiveRecord::Base
# Profile
has_many :keys, dependent: :destroy
+ has_many :emails, dependent: :destroy
# Groups
has_many :users_groups, dependent: :destroy
@@ -116,6 +117,7 @@ class User < ActiveRecord::Base
validates :notification_level, inclusion: { in: Notification.notification_levels }, presence: true
validate :namespace_uniq, if: ->(user) { user.username_changed? }
validate :avatar_type, if: ->(user) { user.avatar_changed? }
+ validate :unique_email, if: ->(user) { user.email_changed? }
validates :avatar, file_size: { maximum: 100.kilobytes.to_i }
before_validation :generate_password, on: :create
@@ -183,6 +185,13 @@ class User < ActiveRecord::Base
where(conditions).first
end
end
+
+ def find_for_commit(email, name)
+ # Prefer email match over name match
+ User.where(email: email).first ||
+ User.joins(:emails).where(emails: { email: email }).first ||
+ User.where(name: name).first
+ end
def filter filter_name
case filter_name
@@ -250,6 +259,10 @@ class User < ActiveRecord::Base
end
end
+ def unique_email
+ self.errors.add(:email, 'has already been taken') if Email.exists?(email: self.email)
+ end
+
# Groups user has access to
def authorized_groups
@authorized_groups ||= begin
diff --git a/app/observers/email_observer.rb b/app/observers/email_observer.rb
new file mode 100644
index 00000000000..026ad8b1d9a
--- /dev/null
+++ b/app/observers/email_observer.rb
@@ -0,0 +1,5 @@
+class EmailObserver < BaseObserver
+ def after_create(email)
+ notification.new_email(email)
+ end
+end
diff --git a/app/services/git_push_service.rb b/app/services/git_push_service.rb
index e54f88e42de..fcc03c3e4b8 100644
--- a/app/services/git_push_service.rb
+++ b/app/services/git_push_service.rb
@@ -188,8 +188,6 @@ class GitPushService
end
def commit_user commit
- User.where(email: commit.author_email).first ||
- User.where(name: commit.author_name).first ||
- user
+ User.find_for_commit(commit.author_email, commit.author_name) || user
end
end
diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb
index 7c02777e914..9d7bb9639ac 100644
--- a/app/services/notification_service.rb
+++ b/app/services/notification_service.rb
@@ -17,6 +17,13 @@ class NotificationService
end
end
+ # Always notify user about email added to profile
+ def new_email(email)
+ if email.user
+ mailer.new_email_email(email.id)
+ end
+ end
+
# When create an issue we should send next emails:
#
# * issue assignee if their notification level is not Disabled
diff --git a/app/views/layouts/nav/_profile.html.haml b/app/views/layouts/nav/_profile.html.haml
index d44cb975ea5..35d0d417502 100644
--- a/app/views/layouts/nav/_profile.html.haml
+++ b/app/views/layouts/nav/_profile.html.haml
@@ -4,6 +4,10 @@
%i.icon-home
= nav_link(controller: :accounts) do
= link_to "Account", profile_account_path
+ = nav_link(controller: :emails) do
+ = link_to profile_emails_path do
+ Emails
+ %span.count= current_user.emails.count + 1
- unless current_user.ldap_user?
= nav_link(controller: :passwords) do
= link_to "Password", edit_profile_password_path
diff --git a/app/views/notify/new_email_email.html.haml b/app/views/notify/new_email_email.html.haml
new file mode 100644
index 00000000000..4a0448a573c
--- /dev/null
+++ b/app/views/notify/new_email_email.html.haml
@@ -0,0 +1,10 @@
+%p
+ Hi #{@user.name}!
+%p
+ A new email was added to your account:
+%p
+ email:
+ %code= @email.email
+%p
+ If this email was added in error, you can remove it here:
+ = link_to "Emails", profile_emails_url
diff --git a/app/views/notify/new_email_email.text.erb b/app/views/notify/new_email_email.text.erb
new file mode 100644
index 00000000000..51cba99ad0d
--- /dev/null
+++ b/app/views/notify/new_email_email.text.erb
@@ -0,0 +1,7 @@
+Hi <%= @user.name %>!
+
+A new email was added to your account:
+
+email.................. <%= @email.email %>
+
+If this email was added in error, you can remove it here: <%= profile_emails_url %>
diff --git a/app/views/profiles/emails/index.html.haml b/app/views/profiles/emails/index.html.haml
new file mode 100644
index 00000000000..dc45ab2de79
--- /dev/null
+++ b/app/views/profiles/emails/index.html.haml
@@ -0,0 +1,29 @@
+%h3.page-title
+ My Email Addresses
+%p.light
+ Your
+ %b Primary Email
+ will be used for account notifications, avatar detection and web based operations, such as edits and merges. All email addresses will be used to identify your commits.
+
+.ui-box
+ .title
+ Emails (#{@emails.count + 1})
+ %ul.well-list#emails-table
+ %li
+ %strong= @primary
+ %span.label.label-success Primary Email
+ - @emails.each do |email|
+ %li
+ %strong= email.email
+ %span.cgray
+ added #{time_ago_with_tooltip(email.created_at)}
+ = link_to 'Remove', profile_email_path(email), data: { confirm: 'Are you sure?'}, method: :delete, class: 'btn btn-small btn-remove pull-right'
+
+%h3.page-title Add Email Address
+= form_for 'email', url: profile_emails_path, html: { class: 'form-horizontal' } do |f|
+ .form-group
+ = f.label :email, class: 'control-label'
+ .col-sm-10
+ = f.text_field :email, class: 'form-control'
+ .form-actions
+ = f.submit 'Add', class: 'btn btn-create' \ No newline at end of file
diff --git a/config/routes.rb b/config/routes.rb
index 8c66ad741f9..fdca1e62661 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -124,6 +124,7 @@ Gitlab::Application.routes.draw do
end
end
resources :keys
+ resources :emails, only: [:index, :create, :destroy]
resources :groups, only: [:index] do
member do
delete :leave
diff --git a/db/migrate/20140209025651_create_emails.rb b/db/migrate/20140209025651_create_emails.rb
new file mode 100644
index 00000000000..cb78c4af11b
--- /dev/null
+++ b/db/migrate/20140209025651_create_emails.rb
@@ -0,0 +1,13 @@
+class CreateEmails < ActiveRecord::Migration
+ def change
+ create_table :emails do |t|
+ t.integer :user_id, null: false
+ t.string :email, null: false
+
+ t.timestamps
+ end
+
+ add_index :emails, :user_id
+ add_index :emails, :email, unique: true
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index acbb793bbe8..65f79fb7e05 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20140127170938) do
+ActiveRecord::Schema.define(version: 20140209025651) do
create_table "broadcast_messages", force: true do |t|
t.text "message", null: false
@@ -33,6 +33,16 @@ ActiveRecord::Schema.define(version: 20140127170938) do
add_index "deploy_keys_projects", ["project_id"], name: "index_deploy_keys_projects_on_project_id", using: :btree
+ create_table "emails", force: true do |t|
+ t.integer "user_id", null: false
+ t.string "email", null: false
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ end
+
+ add_index "emails", ["email"], name: "index_emails_on_email", unique: true, using: :btree
+ add_index "emails", ["user_id"], name: "index_emails_on_user_id", using: :btree
+
create_table "events", force: true do |t|
t.string "target_type"
t.integer "target_id"
@@ -66,8 +76,8 @@ ActiveRecord::Schema.define(version: 20140127170938) do
t.integer "assignee_id"
t.integer "author_id"
t.integer "project_id"
- t.datetime "created_at"
- t.datetime "updated_at"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
t.integer "position", default: 0
t.string "branch_name"
t.text "description"
@@ -85,8 +95,8 @@ ActiveRecord::Schema.define(version: 20140127170938) do
create_table "keys", force: true do |t|
t.integer "user_id"
- t.datetime "created_at"
- t.datetime "updated_at"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
t.text "key"
t.string "title"
t.string "type"
@@ -111,8 +121,8 @@ ActiveRecord::Schema.define(version: 20140127170938) do
t.integer "author_id"
t.integer "assignee_id"
t.string "title"
- t.datetime "created_at"
- t.datetime "updated_at"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
t.integer "milestone_id"
t.string "state"
t.string "merge_status"
@@ -164,8 +174,8 @@ ActiveRecord::Schema.define(version: 20140127170938) do
t.text "note"
t.string "noteable_type"
t.integer "author_id"
- t.datetime "created_at"
- t.datetime "updated_at"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
t.integer "project_id"
t.string "attachment"
t.string "line_code"
@@ -187,8 +197,8 @@ ActiveRecord::Schema.define(version: 20140127170938) do
t.string "name"
t.string "path"
t.text "description"
- t.datetime "created_at"
- t.datetime "updated_at"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
t.integer "creator_id"
t.boolean "issues_enabled", default: true, null: false
t.boolean "wall_enabled", default: true, null: false
@@ -239,8 +249,8 @@ ActiveRecord::Schema.define(version: 20140127170938) do
t.text "content", limit: 2147483647
t.integer "author_id", null: false
t.integer "project_id"
- t.datetime "created_at"
- t.datetime "updated_at"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
t.string "file_name"
t.datetime "expires_at"
t.boolean "private", default: true, null: false
@@ -262,42 +272,45 @@ ActiveRecord::Schema.define(version: 20140127170938) do
t.datetime "created_at"
end
+ add_index "taggings", ["tag_id"], name: "index_taggings_on_tag_id", using: :btree
+ add_index "taggings", ["taggable_id", "taggable_type", "context"], name: "index_taggings_on_taggable_id_and_taggable_type_and_context", using: :btree
+
create_table "tags", force: true do |t|
t.string "name"
end
create_table "users", force: true do |t|
- t.string "email", default: "", null: false
- t.string "encrypted_password", limit: 128, default: "", null: false
+ t.string "email", default: "", null: false
+ t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
- t.integer "sign_in_count", default: 0
+ t.integer "sign_in_count", default: 0
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
- t.datetime "created_at"
- t.datetime "updated_at"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
t.string "name"
- t.boolean "admin", default: false, null: false
- t.integer "projects_limit", default: 10
- t.string "skype", default: "", null: false
- t.string "linkedin", default: "", null: false
- t.string "twitter", default: "", null: false
+ t.boolean "admin", default: false, null: false
+ t.integer "projects_limit", default: 10
+ t.string "skype", default: "", null: false
+ t.string "linkedin", default: "", null: false
+ t.string "twitter", default: "", null: false
t.string "authentication_token"
- t.integer "theme_id", default: 1, null: false
+ t.integer "theme_id", default: 1, null: false
t.string "bio"
- t.integer "failed_attempts", default: 0
+ t.integer "failed_attempts", default: 0
t.datetime "locked_at"
t.string "extern_uid"
t.string "provider"
t.string "username"
- t.boolean "can_create_group", default: true, null: false
- t.boolean "can_create_team", default: true, null: false
+ t.boolean "can_create_group", default: true, null: false
+ t.boolean "can_create_team", default: true, null: false
t.string "state"
- t.integer "color_scheme_id", default: 1, null: false
- t.integer "notification_level", default: 1, null: false
+ t.integer "color_scheme_id", default: 1, null: false
+ t.integer "notification_level", default: 1, null: false
t.datetime "password_expires_at"
t.integer "created_by_id"
t.string "avatar"
@@ -305,14 +318,15 @@ ActiveRecord::Schema.define(version: 20140127170938) do
t.datetime "confirmed_at"
t.datetime "confirmation_sent_at"
t.string "unconfirmed_email"
- t.boolean "hide_no_ssh_key", default: false
- t.string "website_url", default: "", null: false
+ t.boolean "hide_no_ssh_key", default: false
+ t.string "website_url", default: "", null: false
end
add_index "users", ["admin"], name: "index_users_on_admin", using: :btree
add_index "users", ["authentication_token"], name: "index_users_on_authentication_token", unique: true, using: :btree
add_index "users", ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true, using: :btree
add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree
+ add_index "users", ["extern_uid", "provider"], name: "index_users_on_extern_uid_and_provider", unique: true, using: :btree
add_index "users", ["name"], name: "index_users_on_name", using: :btree
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree
add_index "users", ["username"], name: "index_users_on_username", using: :btree
@@ -331,8 +345,8 @@ ActiveRecord::Schema.define(version: 20140127170938) do
create_table "users_projects", force: true do |t|
t.integer "user_id", null: false
t.integer "project_id", null: false
- t.datetime "created_at"
- t.datetime "updated_at"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
t.integer "project_access", default: 0, null: false
t.integer "notification_level", default: 3, null: false
end
@@ -344,8 +358,8 @@ ActiveRecord::Schema.define(version: 20140127170938) do
create_table "web_hooks", force: true do |t|
t.string "url"
t.integer "project_id"
- t.datetime "created_at"
- t.datetime "updated_at"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
t.string "type", default: "ProjectHook"
t.integer "service_id"
t.boolean "push_events", default: true, null: false
diff --git a/features/profile/emails.feature b/features/profile/emails.feature
new file mode 100644
index 00000000000..148fc766081
--- /dev/null
+++ b/features/profile/emails.feature
@@ -0,0 +1,25 @@
+Feature: Profile Emails
+ Background:
+ Given I sign in as a user
+ And I visit profile emails page
+
+ Scenario: I should see emails
+ Then I should see my emails
+
+ Scenario: Add new email
+ Given I submit new email "my@email.com"
+ Then I should see new email "my@email.com"
+ And I should see my emails
+
+ Scenario: Add duplicate email
+ Given I submit duplicate email @user.email
+ Then I should not have @user.email added
+ And I should see my emails
+
+ Scenario: Remove email
+ Given I submit new email "my@email.com"
+ Then I should see new email "my@email.com"
+ And I should see my emails
+ Then I click link "Remove" for "my@email.com"
+ Then I should not see email "my@email.com"
+ And I should see my emails
diff --git a/features/project/commits/commits_user_lookup.feature b/features/project/commits/commits_user_lookup.feature
new file mode 100644
index 00000000000..f3864c0ab38
--- /dev/null
+++ b/features/project/commits/commits_user_lookup.feature
@@ -0,0 +1,14 @@
+Feature: Project Browse Commits User Lookup
+ Background:
+ Given I sign in as a user
+ And I own a project
+ And I have the user that authored the commits
+ And I visit my project's commits page
+
+ Scenario: I browse commit from list
+ Given I click on commit link
+ Then I see commit info
+
+ Scenario: I browse another commit from list
+ Given I click on another commit link
+ Then I see other commit info \ No newline at end of file
diff --git a/features/steps/profile/profile_emails.rb b/features/steps/profile/profile_emails.rb
new file mode 100644
index 00000000000..99588c85991
--- /dev/null
+++ b/features/steps/profile/profile_emails.rb
@@ -0,0 +1,48 @@
+class ProfileEmails < Spinach::FeatureSteps
+ include SharedAuthentication
+
+ Then 'I visit profile emails page' do
+ visit profile_emails_path
+ end
+
+ Then 'I should see my emails' do
+ page.should have_content(@user.email)
+ @user.emails.each do |email|
+ page.should have_content(email.email)
+ end
+ end
+
+ And 'I submit new email "my@email.com"' do
+ fill_in "email_email", with: "my@email.com"
+ click_button "Add"
+ end
+
+ Then 'I should see new email "my@email.com"' do
+ email = @user.emails.find_by(email: "my@email.com")
+ email.should_not be_nil
+ page.should have_content("my@email.com")
+ end
+
+ Then 'I should not see email "my@email.com"' do
+ email = @user.emails.find_by(email: "my@email.com")
+ email.should be_nil
+ page.should_not have_content("my@email.com")
+ end
+
+ Then 'I click link "Remove" for "my@email.com"' do
+ # there should only be one remove button at this time
+ click_link "Remove"
+ # force these to reload as they have been cached
+ @user.emails.reload
+ end
+
+ And 'I submit duplicate email @user.email' do
+ fill_in "email_email", with: @user.email
+ click_button "Add"
+ end
+
+ Then 'I should not have @user.email added' do
+ email = @user.emails.find_by(email: @user.email)
+ email.should be_nil
+ end
+end
diff --git a/features/steps/project/project_browse_commits_user_lookup.rb b/features/steps/project/project_browse_commits_user_lookup.rb
new file mode 100644
index 00000000000..328be373553
--- /dev/null
+++ b/features/steps/project/project_browse_commits_user_lookup.rb
@@ -0,0 +1,35 @@
+class ProjectBrowseCommitsUserLookup < Spinach::FeatureSteps
+ include SharedAuthentication
+ include SharedProject
+ include SharedPaths
+
+ Given 'I have the user that authored the commits' do
+ @user = create(:user, email: 'dmitriy.zaporozhets@gmail.com')
+ create(:email, { user: @user, email: 'dzaporozhets@sphereconsultinginc.com' })
+ end
+
+ Given 'I click on commit link' do
+ visit project_commit_path(@project, ValidCommit::ID)
+ end
+
+ Given 'I click on another commit link' do
+ visit project_commit_path(@project, ValidCommitWithAltEmail::ID)
+ end
+
+ Then 'I see commit info' do
+ page.should have_content ValidCommit::MESSAGE
+ check_author_link(ValidCommit::AUTHOR_EMAIL)
+ end
+
+ Then 'I see other commit info' do
+ page.should have_content ValidCommitWithAltEmail::MESSAGE
+ check_author_link(ValidCommitWithAltEmail::AUTHOR_EMAIL)
+ end
+
+ def check_author_link(email)
+ author_link = find('.commit-author-link')
+ author_link['href'].should == user_path(@user)
+ author_link['data-original-title'].should == email
+ find('.commit-author-name').text.should == @user.name
+ end
+end
diff --git a/features/support/env.rb b/features/support/env.rb
index 0186002c559..7b11f5a7c6f 100644
--- a/features/support/env.rb
+++ b/features/support/env.rb
@@ -15,7 +15,7 @@ require 'spinach/capybara'
require 'sidekiq/testing/inline'
-%w(valid_commit big_commits select2_helper test_env).each do |f|
+%w(valid_commit valid_commit_with_alt_email big_commits select2_helper test_env).each do |f|
require Rails.root.join('spec', 'support', f)
end
diff --git a/spec/factories.rb b/spec/factories.rb
index e5d05a4c2ea..37436e53b95 100644
--- a/spec/factories.rb
+++ b/spec/factories.rb
@@ -219,6 +219,19 @@ FactoryGirl.define do
end
end
end
+
+ factory :email do
+ user
+ email do
+ Faker::Internet.email('alias')
+ end
+
+ factory :another_email do
+ email do
+ Faker::Internet.email('another.alias')
+ end
+ end
+ end
factory :milestone do
title
diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb
index d53dc17d977..88cae0bb756 100644
--- a/spec/mailers/notify_spec.rb
+++ b/spec/mailers/notify_spec.rb
@@ -90,6 +90,28 @@ describe Notify do
end
end
+ describe 'user added email' do
+ let(:email) { create(:email) }
+
+ subject { Notify.new_email_email(email.id) }
+
+ it 'is sent to the new user' do
+ should deliver_to email.user.email
+ end
+
+ it 'has the correct subject' do
+ should have_subject /^gitlab \| Email was added to your account$/i
+ end
+
+ it 'contains the new email address' do
+ should have_body_text /#{email.email}/
+ end
+
+ it 'includes a link to emails page' do
+ should have_body_text /#{profile_emails_path}/
+ end
+ end
+
context 'for a project' do
describe 'items that are assignable, the email' do
let(:assignee) { create(:user, email: 'assignee@example.com') }
diff --git a/spec/observers/email_observer_spec.rb b/spec/observers/email_observer_spec.rb
new file mode 100644
index 00000000000..599b9a6ffba
--- /dev/null
+++ b/spec/observers/email_observer_spec.rb
@@ -0,0 +1,17 @@
+require 'spec_helper'
+
+describe EmailObserver do
+ let(:email) { create(:email) }
+
+ before { subject.stub(notification: double('NotificationService').as_null_object) }
+
+ subject { EmailObserver.instance }
+
+ describe '#after_create' do
+ it 'trigger notification to send emails' do
+ subject.should_receive(:notification)
+
+ subject.after_create(email)
+ end
+ end
+end
diff --git a/spec/routing/routing_spec.rb b/spec/routing/routing_spec.rb
index 8929a48973d..9b67cd432bc 100644
--- a/spec/routing/routing_spec.rb
+++ b/spec/routing/routing_spec.rb
@@ -183,6 +183,23 @@ describe Profiles::KeysController, "routing" do
end
end
+# emails GET /emails(.:format) emails#index
+# POST /keys(.:format) emails#create
+# DELETE /keys/:id(.:format) keys#destroy
+describe Profiles::EmailsController, "routing" do
+ it "to #index" do
+ get("/profile/emails").should route_to('profiles/emails#index')
+ end
+
+ it "to #create" do
+ post("/profile/emails").should route_to('profiles/emails#create')
+ end
+
+ it "to #destroy" do
+ delete("/profile/emails/1").should route_to('profiles/emails#destroy', id: '1')
+ end
+end
+
# profile_avatar DELETE /profile/avatar(.:format) profiles/avatars#destroy
describe Profiles::AvatarsController, "routing" do
it "to #destroy" do
diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb
index 09a5debe1dc..e378be04255 100644
--- a/spec/services/notification_service_spec.rb
+++ b/spec/services/notification_service_spec.rb
@@ -16,6 +16,19 @@ describe NotificationService do
end
end
+ describe 'Email' do
+ describe :new_email do
+ let(:email) { create(:email) }
+
+ it { notification.new_email(email).should be_true }
+
+ it 'should send email to email owner' do
+ Notify.should_receive(:new_email_email).with(email.id)
+ notification.new_email(email)
+ end
+ end
+ end
+
describe 'Notes' do
context 'issue note' do
let(:issue) { create(:issue, assignee: create(:user)) }
diff --git a/spec/support/valid_commit.rb b/spec/support/valid_commit.rb
index 8094b679e99..98bc59b573f 100644
--- a/spec/support/valid_commit.rb
+++ b/spec/support/valid_commit.rb
@@ -2,6 +2,7 @@ module ValidCommit
ID = "8470d70da67355c9c009e4401746b1d5410af2e3"
MESSAGE = "notes controller refactored"
AUTHOR_FULL_NAME = "Dmitriy Zaporozhets"
+ AUTHOR_EMAIL = "dmitriy.zaporozhets@gmail.com"
FILES = [".foreman", ".gitignore", ".rails_footnotes", ".rspec", ".travis.yml", "CHANGELOG", "Gemfile", "Gemfile.lock", "LICENSE", "Procfile", "Procfile.production", "README.md", "Rakefile", "VERSION", "app", "config.ru", "config", "db", "doc", "lib", "log", "public", "resque.sh", "script", "spec", "vendor"]
FILES_COUNT = 26
diff --git a/spec/support/valid_commit_with_alt_email.rb b/spec/support/valid_commit_with_alt_email.rb
new file mode 100644
index 00000000000..d6e364c41f1
--- /dev/null
+++ b/spec/support/valid_commit_with_alt_email.rb
@@ -0,0 +1,6 @@
+module ValidCommitWithAltEmail
+ ID = "1e689bfba39525ead225eaf611948cfbe8ac34cf"
+ MESSAGE = "fixed notes logic"
+ AUTHOR_FULL_NAME = "Dmitriy Zaporozhets"
+ AUTHOR_EMAIL = "dzaporozhets@sphereconsultinginc.com"
+end \ No newline at end of file