Commit 011e561b authored by tiagonbotelho's avatar tiagonbotelho

implements reset incoming email token on issues modal and account page,

reactivates all tests and writes more tests for it
parent 9d514213
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
Issuable.initSearch(); Issuable.initSearch();
Issuable.initChecks(); Issuable.initChecks();
Issuable.initResetFilters(); Issuable.initResetFilters();
Issuable.resetIncomingEmailToken();
return Issuable.initLabelFilterRemove(); return Issuable.initLabelFilterRemove();
}, },
initTemplates: function() { initTemplates: function() {
...@@ -154,6 +155,27 @@ ...@@ -154,6 +155,27 @@
this.issuableBulkActions.willUpdateLabels = false; this.issuableBulkActions.willUpdateLabels = false;
} }
return true; return true;
},
resetIncomingEmailToken: function() {
$('.incoming-email-token-reset').on('click', function(e) {
e.preventDefault();
$.ajax({
type: 'PUT',
url: $('.incoming-email-token-reset').attr('href'),
dataType: 'json',
success: function(response) {
$('#issue_email').val(response.new_issue_address).focus();
},
beforeSend: function() {
$('.incoming-email-token-reset').text('resetting...');
},
complete: function() {
$('.incoming-email-token-reset').text('reset it');
}
});
});
} }
}; };
......
...@@ -23,6 +23,10 @@ ...@@ -23,6 +23,10 @@
color: $md-link-color; color: $md-link-color;
} }
.private-tokens-reset div.reset-action:not(:first-child) {
padding-top: 15px;
}
.oauth-buttons { .oauth-buttons {
.btn-group { .btn-group {
margin-right: 10px; margin-right: 10px;
......
...@@ -26,7 +26,7 @@ class ProfilesController < Profiles::ApplicationController ...@@ -26,7 +26,7 @@ class ProfilesController < Profiles::ApplicationController
def reset_private_token def reset_private_token
if current_user.reset_authentication_token! if current_user.reset_authentication_token!
flash[:notice] = "Private token was successfully updated" flash[:notice] = "Private token was successfully reset"
end end
redirect_to profile_account_path redirect_to profile_account_path
...@@ -34,7 +34,7 @@ class ProfilesController < Profiles::ApplicationController ...@@ -34,7 +34,7 @@ class ProfilesController < Profiles::ApplicationController
def reset_incoming_email_token def reset_incoming_email_token
if current_user.reset_incoming_email_token! if current_user.reset_incoming_email_token!
flash[:notice] = "Incoming email token was successfully updated" flash[:notice] = "Incoming email token was successfully reset"
end end
redirect_to profile_account_path redirect_to profile_account_path
......
...@@ -160,6 +160,13 @@ class ProjectsController < Projects::ApplicationController ...@@ -160,6 +160,13 @@ class ProjectsController < Projects::ApplicationController
end end
end end
def new_issue_address
return render_404 unless Gitlab::IncomingEmail.supports_issue_creation?
current_user.reset_incoming_email_token!
render json: { new_issue_address: @project.new_issue_address(current_user) }
end
def archive def archive
return access_denied! unless can?(current_user, :archive_project, @project) return access_denied! unless can?(current_user, :archive_project, @project)
......
module AccountsHelper
def incoming_email_token_enabled?
current_user.incoming_email_token && Gitlab::IncomingEmail.supports_issue_creation?
end
end
...@@ -624,7 +624,7 @@ class Project < ActiveRecord::Base ...@@ -624,7 +624,7 @@ class Project < ActiveRecord::Base
end end
def new_issue_address(author) def new_issue_address(author)
return unless Gitlab::IncomingEmail.enabled? && author return unless Gitlab::IncomingEmail.supports_issue_creation? && author
author.ensure_incoming_email_token! author.ensure_incoming_email_token!
......
...@@ -951,7 +951,7 @@ class User < ActiveRecord::Base ...@@ -951,7 +951,7 @@ class User < ActiveRecord::Base
def generate_token(token_field) def generate_token(token_field)
if token_field == :incoming_email_token if token_field == :incoming_email_token
# Needs to be all lowercase and alphanumeric because it's gonna be used in an email address. # Needs to be all lowercase and alphanumeric because it's gonna be used in an email address.
SecureRandom.hex SecureRandom.hex.to_i(16).to_s(36)
else else
super super
end end
......
...@@ -8,28 +8,35 @@ ...@@ -8,28 +8,35 @@
.row.prepend-top-default .row.prepend-top-default
.col-lg-3.profile-settings-sidebar .col-lg-3.profile-settings-sidebar
%h4.prepend-top-0 %h4.prepend-top-0
Private Tokens = incoming_email_token_enabled? ? "Private Tokens" : "Private Token"
%p %p
Your private token is used to access the API and Atom feeds without Keep
username/password authentication. = incoming_email_token_enabled? ? "these tokens" : "this token"
%p secret, anyone with access to them can interact with GitLab as if they were you.
Your incoming email token is used to create new issues by email, and is .col-lg-9.private-tokens-reset
included in your project-specific email addresses. .reset-action
.col-lg-9 %p.cgray
%p.cgray - if current_user.private_token
- if current_user.private_token = label_tag "private-token", "Private token", class: "label-light"
= label_tag "token", "Private token", class: "label-light" = text_field_tag "private-token", current_user.private_token, class: "form-control", readonly: true, onclick: "this.select()"
= text_field_tag "token", current_user.private_token, class: "form-control" - else
- else %span You don't have one yet. Click generate to fix it.
%span You don`t have one yet. Click generate to fix it. %p.help-block
%p.help-block Your private token is used to access the API and Atom feeds without username/password authentication.
Keep this token secret, anyone with access to it can interact with the GitLab API as if they were you. .prepend-top-default
.prepend-top-default - if current_user.private_token
- if current_user.private_token = link_to 'Reset private token', reset_private_token_profile_path, method: :put, data: { confirm: "Are you sure?" }, class: "btn btn-default private-token"
= link_to 'Reset private token', reset_private_token_profile_path, method: :put, data: { confirm: "Are you sure?" }, class: "btn btn-default" - else
- else = f.submit 'Generate', class: "btn btn-default"
= f.submit 'Generate', class: "btn btn-default" - if incoming_email_token_enabled?
= link_to 'Reset incoming email token', reset_incoming_email_token_profile_path, method: :put, data: { confirm: "Are you sure?" }, class: "btn btn-default" .reset-action
%p.cgray
= label_tag "incoming-email-token", "Incoming Email Token", class: 'label-light'
= text_field_tag "incoming-email-token", current_user.incoming_email_token, class: "form-control", readonly: true, onclick: "this.select()"
%p.help-block
Your incoming email token is used to create new issues by email, and is included in your project-specific email addresses.
.prepend-top-default
= link_to 'Reset incoming email token', reset_incoming_email_token_profile_path, method: :put, data: { confirm: "Are you sure?" }, class: "btn btn-default incoming-email-token"
%hr %hr
.row.prepend-top-default .row.prepend-top-default
......
...@@ -12,16 +12,23 @@ ...@@ -12,16 +12,23 @@
Create new issue by email Create new issue by email
.modal-body .modal-body
%p %p
Write an email to the below email address. (This is a private email address, so keep it secret.) You can create a new issue inside this project by sending an email to the following email address:
.email-modal-input-group.input-group .email-modal-input-group.input-group
= text_field_tag :issue_email, email, class: "monospace js-select-on-focus form-control", readonly: true = text_field_tag :issue_email, email, class: "monospace js-select-on-focus form-control", readonly: true
.input-group-btn .input-group-btn
= clipboard_button(clipboard_target: '#issue_email') = clipboard_button(clipboard_target: '#issue_email')
%p %p
Send an email to this address to create an issue. The subject will be used as the title of the new issue, and the message will be the description.
%p
Use the subject line as the title of your issue. = link_to 'Slash commands', help_page_path('user/project/slash_commands'), target: '_blank', tabindex: -1
and styling with
= link_to 'Markdown', help_page_path('user/markdown'), target: '_blank', tabindex: -1
are supported.
%p %p
Use the message as the body of your issue (feel free to include some nice This is a private email address, generated just for you.
= succeed ")." do
= link_to "Markdown", help_page_path('markdown', 'markdown') Anyone who gets ahold of it can create issues as if they were you.
You should
= link_to 'reset it', new_issue_address_namespace_project_path(@project.namespace, @project), class: 'incoming-email-token-reset'
if that ever happens.
---
title: Use separate email-token for incoming email and revert back the inactive feature
merge_request: 5914
author:
...@@ -18,6 +18,7 @@ resources :namespaces, path: '/', constraints: { id: /[a-zA-Z.0-9_\-]+/ }, only: ...@@ -18,6 +18,7 @@ resources :namespaces, path: '/', constraints: { id: /[a-zA-Z.0-9_\-]+/ }, only:
get :autocomplete_sources get :autocomplete_sources
get :activity get :activity
get :refs get :refs
put :new_issue_address
end end
scope module: :projects do scope module: :projects do
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20160819232256) do ActiveRecord::Schema.define(version: 20161103171205) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
...@@ -1176,7 +1176,7 @@ ActiveRecord::Schema.define(version: 20160819232256) do ...@@ -1176,7 +1176,7 @@ ActiveRecord::Schema.define(version: 20160819232256) do
t.boolean "ldap_email", default: false, null: false t.boolean "ldap_email", default: false, null: false
t.boolean "external", default: false t.boolean "external", default: false
t.string "organization" t.string "organization"
t.string "incoming_email_token" t.string "incoming_email_token"
end end
add_index "users", ["admin"], name: "index_users_on_admin", using: :btree add_index "users", ["admin"], name: "index_users_on_admin", using: :btree
......
...@@ -59,11 +59,6 @@ Feature: Profile ...@@ -59,11 +59,6 @@ Feature: Profile
When I unsuccessfully change my password When I unsuccessfully change my password
Then I should see a password error message Then I should see a password error message
Scenario: I reset my token
Given I visit profile account page
Then I reset my token
And I should see new token
Scenario: I visit history tab Scenario: I visit history tab
Given I have activity Given I have activity
When I visit Audit Log page When I visit Audit Log page
......
...@@ -104,18 +104,6 @@ class Spinach::Features::Profile < Spinach::FeatureSteps ...@@ -104,18 +104,6 @@ class Spinach::Features::Profile < Spinach::FeatureSteps
end end
end end
step 'I reset my token' do
page.within '.private-token' do
@old_token = @user.private_token
click_button "Reset private token"
end
end
step 'I should see new token' do
expect(find("#token").value).not_to eq @old_token
expect(find("#token").value).to eq @user.reload.private_token
end
step 'I have activity' do step 'I have activity' do
create(:closed_issue_event, author: current_user) create(:closed_issue_event, author: current_user)
end end
......
...@@ -4,8 +4,7 @@ require 'gitlab/email/handler/create_issue_handler' ...@@ -4,8 +4,7 @@ require 'gitlab/email/handler/create_issue_handler'
module Gitlab module Gitlab
module Email module Email
module Handler module Handler
# The `CreateIssueHandler` feature is disabled for the time being. HANDLERS = [CreateNoteHandler, CreateIssueHandler]
HANDLERS = [CreateNoteHandler]
def self.for(mail, mail_key) def self.for(mail, mail_key)
HANDLERS.find do |klass| HANDLERS.find do |klass|
......
module Gitlab module Gitlab
module IncomingEmail module IncomingEmail
WILDCARD_PLACEHOLDER = '%{key}'.freeze
class << self class << self
FALLBACK_MESSAGE_ID_REGEX = /\Areply\-(.+)@#{Gitlab.config.gitlab.host}\Z/.freeze FALLBACK_MESSAGE_ID_REGEX = /\Areply\-(.+)@#{Gitlab.config.gitlab.host}\Z/.freeze
...@@ -7,8 +9,16 @@ module Gitlab ...@@ -7,8 +9,16 @@ module Gitlab
config.enabled && config.address config.enabled && config.address
end end
def supports_wildcard?
config.address && config.address.include?(WILDCARD_PLACEHOLDER)
end
def supports_issue_creation?
enabled? && supports_wildcard?
end
def reply_address(key) def reply_address(key)
config.address.gsub('%{key}', key) config.address.gsub(WILDCARD_PLACEHOLDER, key)
end end
def key_from_address(address) def key_from_address(address)
......
...@@ -264,6 +264,33 @@ describe ProjectsController do ...@@ -264,6 +264,33 @@ describe ProjectsController do
end end
end end
describe 'PUT #new_issue_address' do
subject do
put :new_issue_address,
namespace_id: project.namespace.to_param,
id: project.to_param
user.reload
end
before do
sign_in(user)
project.team << [user, :developer]
allow(Gitlab.config.incoming_email).to receive(:enabled).and_return(true)
end
it 'has http status 200' do
expect(response).to have_http_status(200)
end
it 'changes the user incoming email token' do
expect { subject }.to change { user.incoming_email_token }
end
it 'changes projects new issue address' do
expect { subject }.to change { project.new_issue_address(user) }
end
end
describe "POST #toggle_star" do describe "POST #toggle_star" do
it "toggles star if user is signed in" do it "toggles star if user is signed in" do
sign_in(user) sign_in(user)
......
...@@ -3,6 +3,7 @@ require 'spec_helper' ...@@ -3,6 +3,7 @@ require 'spec_helper'
describe 'Issues', feature: true do describe 'Issues', feature: true do
include IssueHelpers include IssueHelpers
include SortingHelper include SortingHelper
include WaitForAjax
let(:project) { create(:project) } let(:project) { create(:project) }
...@@ -368,6 +369,26 @@ describe 'Issues', feature: true do ...@@ -368,6 +369,26 @@ describe 'Issues', feature: true do
end end
end end
describe 'when I want to reset my incoming email token' do
let(:project1) { create(:project, namespace: @user.namespace) }
before do
allow(Gitlab.config.incoming_email).to receive(:enabled).and_return(true)
project1.team << [@user, :master]
visit namespace_project_issues_path(@user.namespace, project1)
end
it 'changes incoming email address token', js: true do
find('.issue-email-modal-btn').click
previous_token = find('input#issue_email').value
find('.incoming-email-token-reset').click
wait_for_ajax
expect(find('input#issue_email').value).not_to eq(previous_token)
end
end
describe 'update labels from issue#show', js: true do describe 'update labels from issue#show', js: true do
let(:issue) { create(:issue, project: project, author: @user, assignee: @user) } let(:issue) { create(:issue, project: project, author: @user, assignee: @user) }
let!(:label) { create(:label, project: project) } let!(:label) { create(:label, project: project) }
...@@ -553,7 +574,7 @@ describe 'Issues', feature: true do ...@@ -553,7 +574,7 @@ describe 'Issues', feature: true do
end end
end end
xdescribe 'new issue by email' do describe 'new issue by email' do
shared_examples 'show the email in the modal' do shared_examples 'show the email in the modal' do
before do before do
stub_incoming_email_setting(enabled: true, address: "p+%{key}@gl.ab") stub_incoming_email_setting(enabled: true, address: "p+%{key}@gl.ab")
......
...@@ -32,4 +32,33 @@ describe 'Profile account page', feature: true do ...@@ -32,4 +32,33 @@ describe 'Profile account page', feature: true do
expect(current_path).to eq(profile_account_path) expect(current_path).to eq(profile_account_path)
end end
end end
describe 'when I reset private token' do
before do
visit profile_account_path
end
it 'resets private token' do
previous_token = find("#private-token").value
click_link('Reset private token')
expect(find('#private-token').value).not_to eq(previous_token)
end
end
describe 'when I reset incoming email token' do
before do
allow(Gitlab.config.incoming_email).to receive(:enabled).and_return(true)
visit profile_account_path
end
it 'resets incoming email token' do
previous_token = find('#incoming-email-token').value
click_link('Reset incoming email token')
expect(find('#incoming-email-token').value).not_to eq(previous_token)
end
end
end end
require 'spec_helper' require 'spec_helper'
require_relative '../email_shared_blocks' require_relative '../email_shared_blocks'
xdescribe Gitlab::Email::Handler::CreateIssueHandler, lib: true do describe Gitlab::Email::Handler::CreateIssueHandler, lib: true do
include_context :email_shared_context include_context :email_shared_context
it_behaves_like :email_shared_examples it_behaves_like :email_shared_examples
......
...@@ -295,7 +295,7 @@ describe Project, models: true do ...@@ -295,7 +295,7 @@ describe Project, models: true do
end end
end end
xdescribe "#new_issue_address" do describe "#new_issue_address" do
let(:project) { create(:empty_project, path: "somewhere") } let(:project) { create(:empty_project, path: "somewhere") }
let(:user) { create(:user) } let(:user) { create(:user) }
...@@ -305,8 +305,7 @@ describe Project, models: true do ...@@ -305,8 +305,7 @@ describe Project, models: true do
end end
it 'returns the address to create a new issue' do it 'returns the address to create a new issue' do
token = user.authentication_token address = "p+#{project.path_with_namespace}+#{user.incoming_email_token}@gl.ab"
address = "p+#{project.namespace.path}/#{project.path}+#{token}@gl.ab"
expect(project.new_issue_address(user)).to eq(address) expect(project.new_issue_address(user)).to eq(address)
end end
......
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