Commit f5f0ed55 authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ce

parents 307a6ba5 f9319042
...@@ -45,8 +45,8 @@ v 7.11.0 (unreleased) ...@@ -45,8 +45,8 @@ v 7.11.0 (unreleased)
- Fix bug where avatar filenames were not actually deleted from the database during removal (Stan Hu) - Fix bug where avatar filenames were not actually deleted from the database during removal (Stan Hu)
- Fix bug where Slack service channel was not saved in admin template settings. (Stan Hu) - Fix bug where Slack service channel was not saved in admin template settings. (Stan Hu)
- Protect OmniAuth request phase against CSRF. - Protect OmniAuth request phase against CSRF.
- - Don't send notifications to mentioned users that don't have access to the project in question.
- - Add search issues/MR by number
- Move snippets UI to fluid layout - Move snippets UI to fluid layout
- Improve UI for sidebar. Increase separation between navigation and content - Improve UI for sidebar. Increase separation between navigation and content
- Improve new project command options (Ben Bodenmiller) - Improve new project command options (Ben Bodenmiller)
......
...@@ -140,8 +140,8 @@ $ -> ...@@ -140,8 +140,8 @@ $ ->
# Place the logo tooltip on the right when collapsed, bottom when expanded # Place the logo tooltip on the right when collapsed, bottom when expanded
$el.parents('header').hasClass('header-collapsed') and 'right' or 'bottom' $el.parents('header').hasClass('header-collapsed') and 'right' or 'bottom'
else else
# Otherwise use the data-placement attribute like normal # Otherwise use the data-placement attribute, or 'bottom' if undefined
$el.data('placement') $el.data('placement') or 'bottom'
}) })
# Form submitter # Form submitter
......
...@@ -129,7 +129,7 @@ ...@@ -129,7 +129,7 @@
} }
.option-descr { .option-descr {
margin-left: 24px; margin-left: 36px;
color: $gray; color: $gray;
} }
} }
......
...@@ -19,7 +19,15 @@ class Projects::IssuesController < Projects::ApplicationController ...@@ -19,7 +19,15 @@ class Projects::IssuesController < Projects::ApplicationController
def index def index
terms = params['issue_search'] terms = params['issue_search']
@issues = get_issues_collection @issues = get_issues_collection
@issues = @issues.full_search(terms) if terms.present?
if terms.present?
if terms =~ /\A#(\d+)\z/
@issues = @issues.where(iid: $1)
else
@issues = @issues.full_search(terms)
end
end
@issues = @issues.page(params[:page]).per(PER_PAGE) @issues = @issues.page(params[:page]).per(PER_PAGE)
respond_to do |format| respond_to do |format|
......
...@@ -19,7 +19,15 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -19,7 +19,15 @@ class Projects::MergeRequestsController < Projects::ApplicationController
def index def index
terms = params['issue_search'] terms = params['issue_search']
@merge_requests = get_merge_requests_collection @merge_requests = get_merge_requests_collection
@merge_requests = @merge_requests.full_search(terms) if terms.present?
if terms.present?
if terms =~ /\A[#!](\d+)\z/
@merge_requests = @merge_requests.where(iid: $1)
else
@merge_requests = @merge_requests.full_search(terms)
end
end
@merge_requests = @merge_requests.page(params[:page]).per(PER_PAGE) @merge_requests = @merge_requests.page(params[:page]).per(PER_PAGE)
respond_to do |format| respond_to do |format|
......
...@@ -35,8 +35,8 @@ module Participable ...@@ -35,8 +35,8 @@ module Participable
end end
end end
def participants(current_user = self.author) def participants(current_user = self.author, project = self.project)
self.class.participant_attrs.flat_map do |attr| participants = self.class.participant_attrs.flat_map do |attr|
meth = method(attr) meth = method(attr)
value = value =
...@@ -46,20 +46,28 @@ module Participable ...@@ -46,20 +46,28 @@ module Participable
meth.call meth.call
end end
participants_for(value, current_user) participants_for(value, current_user, project)
end.compact.uniq end.compact.uniq
if project
participants.select! do |user|
user.can?(:read_project, project)
end
end
participants
end end
private private
def participants_for(value, current_user = nil) def participants_for(value, current_user = nil, project = nil)
case value case value
when User when User
[value] [value]
when Enumerable, ActiveRecord::Relation when Enumerable, ActiveRecord::Relation
value.flat_map { |v| participants_for(v, current_user) } value.flat_map { |v| participants_for(v, current_user, project) }
when Participable when Participable
value.participants(current_user) value.participants(current_user, project)
end end
end end
end end
...@@ -91,10 +91,14 @@ class NotificationService ...@@ -91,10 +91,14 @@ class NotificationService
# * project team members with notification level higher then Participating # * project team members with notification level higher then Participating
# #
def merge_mr(merge_request, current_user) def merge_mr(merge_request, current_user)
recipients = reject_muted_users([merge_request.author, merge_request.assignee], merge_request.target_project) recipients = [merge_request.author, merge_request.assignee]
recipients = add_project_watchers(recipients, merge_request.target_project)
recipients = reject_muted_users(recipients, merge_request.target_project)
recipients = add_subscribed_users(recipients, merge_request) recipients = add_subscribed_users(recipients, merge_request)
recipients = reject_unsubscribed_users(recipients, merge_request) recipients = reject_unsubscribed_users(recipients, merge_request)
recipients = recipients.concat(project_watchers(merge_request.target_project)).uniq
recipients.delete(current_user) recipients.delete(current_user)
recipients.each do |recipient| recipients.each do |recipient|
...@@ -137,20 +141,17 @@ class NotificationService ...@@ -137,20 +141,17 @@ class NotificationService
recipients = recipients.concat(participants) recipients = recipients.concat(participants)
# Merge project watchers # Merge project watchers
recipients = recipients.concat(project_watchers(note.project)).compact.uniq recipients = add_project_watchers(recipients, note.project)
# Reject users with Mention notification level, except those mentioned in _this_ note. # Reject users with Mention notification level, except those mentioned in _this_ note.
recipients = reject_mention_users(recipients - note.mentioned_users, note.project) recipients = reject_mention_users(recipients - note.mentioned_users, note.project)
recipients = recipients + note.mentioned_users recipients = recipients + note.mentioned_users
# Reject mutes users
recipients = reject_muted_users(recipients, note.project) recipients = reject_muted_users(recipients, note.project)
recipients = add_subscribed_users(recipients, note.noteable) recipients = add_subscribed_users(recipients, note.noteable)
recipients = reject_unsubscribed_users(recipients, note.noteable) recipients = reject_unsubscribed_users(recipients, note.noteable)
# Reject author
recipients.delete(note.author) recipients.delete(note.author)
# build notify method like 'note_commit_email' # build notify method like 'note_commit_email'
...@@ -287,6 +288,10 @@ class NotificationService ...@@ -287,6 +288,10 @@ class NotificationService
users users
end end
def add_project_watchers(recipients, project)
recipients.concat(project_watchers(project)).compact.uniq
end
# Remove users with disabled notifications from array # Remove users with disabled notifications from array
# Also remove duplications and nil recipients # Also remove duplications and nil recipients
def reject_muted_users(users, project = nil) def reject_muted_users(users, project = nil)
...@@ -403,11 +408,13 @@ class NotificationService ...@@ -403,11 +408,13 @@ class NotificationService
[target.author, target.assignee] [target.author, target.assignee]
end end
recipients = reject_muted_users(recipients, project) recipients = add_project_watchers(recipients, project)
recipients = reject_mention_users(recipients, project) recipients = reject_mention_users(recipients, project)
recipients = reject_muted_users(recipients, project)
recipients = add_subscribed_users(recipients, target) recipients = add_subscribed_users(recipients, target)
recipients = recipients.concat(project_watchers(project)).uniq
recipients = reject_unsubscribed_users(recipients, target) recipients = reject_unsubscribed_users(recipients, target)
recipients recipients
end end
......
- Gitlab::VisibilityLevel.values.each do |level| - Gitlab::VisibilityLevel.values.each do |level|
.radio .radio
- restricted = restricted_visibility_levels.include?(level) - restricted = restricted_visibility_levels.include?(level)
= label model_method, level do = form.label "#{model_method}_#{level}" do
= form.radio_button model_method, level, checked: (selected_level == level), disabled: restricted = form.radio_button model_method, level, checked: (selected_level == level), disabled: restricted
= visibility_level_icon(level) = visibility_level_icon(level)
.option-title .option-title
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
.col-sm-10= f.text_field :title, placeholder: "Example Snippet", class: 'form-control', required: true .col-sm-10= f.text_field :title, placeholder: "Example Snippet", class: 'form-control', required: true
= render 'shared/visibility_level', f: f, visibility_level: visibility_level, can_change_visibility_level: true, form_model: @snippet = render 'shared/visibility_level', f: f, visibility_level: visibility_level, can_change_visibility_level: true, form_model: @snippet
.form-group .form-group
.file-editor .file-editor
= f.label :file_name, "File", class: 'control-label' = f.label :file_name, "File", class: 'control-label'
......
class AddInviteDataToMember < ActiveRecord::Migration class AddInviteDataToMember < ActiveRecord::Migration
def change def up
add_column :members, :created_by_id, :integer add_column :members, :created_by_id, :integer
add_column :members, :invite_email, :string add_column :members, :invite_email, :string
add_column :members, :invite_token, :string add_column :members, :invite_token, :string
...@@ -9,4 +9,15 @@ class AddInviteDataToMember < ActiveRecord::Migration ...@@ -9,4 +9,15 @@ class AddInviteDataToMember < ActiveRecord::Migration
add_index :members, :invite_token, unique: true add_index :members, :invite_token, unique: true
end end
def down
remove_index :members, :invite_token
change_column :members, :user_id, :integer, null: false
remove_column :members, :invite_accepted_at
remove_column :members, :invite_token
remove_column :members, :invite_email
remove_column :members, :created_by_id
end
end end
class RemoveImportDataFromProject < ActiveRecord::Migration class RemoveImportDataFromProject < ActiveRecord::Migration
def change def up
remove_column :projects, :import_data remove_column :projects, :import_data
end end
def down
add_column :projects, :import_data, :text
end
end end
class AddDefaultSnippetVisibilityToAppSettings < ActiveRecord::Migration class AddDefaultSnippetVisibilityToAppSettings < ActiveRecord::Migration
def change def up
add_column :application_settings, :default_snippet_visibility, :integer add_column :application_settings, :default_snippet_visibility, :integer
visibility = Settings.gitlab.default_projects_features['visibility_level'] visibility = Settings.gitlab.default_projects_features['visibility_level']
execute("update application_settings set default_snippet_visibility = #{visibility}") execute("update application_settings set default_snippet_visibility = #{visibility}")
end end
def down
remove_column :application_settings, :default_snippet_visibility
end
end end
...@@ -28,6 +28,7 @@ EXPOSE 80 22 ...@@ -28,6 +28,7 @@ EXPOSE 80 22
# Copy assets # Copy assets
COPY assets/wrapper /usr/local/bin/ COPY assets/wrapper /usr/local/bin/
COPY assets/gitlab.rb /etc/gitlab/
# Wrapper to handle signal, trigger runit and reconfigure GitLab # Wrapper to handle signal, trigger runit and reconfigure GitLab
CMD ["/usr/local/bin/wrapper"] CMD ["/usr/local/bin/wrapper"]
# External URL should be your Docker instance.
# By default, GitLab will use the Docker container hostname.
# Always use port 80 here to force the internal nginx to bind port 80,
# even if you intend to use another port in Docker.
# external_url "http://192.168.59.103/"
# Prevent Postgres from trying to allocate 25% of total memory
postgresql['shared_buffers'] = '1MB'
# Configure GitLab to redirect PostgreSQL logs to the data volume
postgresql['log_directory'] = '/var/log/gitlab/postgresql'
# Some configuration of GitLab
# You can find more at https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/README.md#configuration
gitlab_rails['gitlab_email_from'] = 'gitlab@example.com'
gitlab_rails['gitlab_support_email'] = 'support@example.com'
gitlab_rails['time_zone'] = 'Europe/Paris'
# SMTP settings
# You must use an external server, the Docker container does not install an SMTP server
gitlab_rails['smtp_enable'] = true
gitlab_rails['smtp_address'] = "smtp.example.com"
gitlab_rails['smtp_port'] = 587
gitlab_rails['smtp_user_name'] = "user"
gitlab_rails['smtp_password'] = "password"
gitlab_rails['smtp_domain'] = "example.com"
gitlab_rails['smtp_authentication'] = "plain"
gitlab_rails['smtp_enable_starttls_auto'] = true
# Enable LDAP authentication
# gitlab_rails['ldap_enabled'] = true
# gitlab_rails['ldap_host'] = 'ldap.example.com'
# gitlab_rails['ldap_port'] = 389
# gitlab_rails['ldap_method'] = 'plain' # 'ssl' or 'plain'
# gitlab_rails['ldap_allow_username_or_email_login'] = false
# gitlab_rails['ldap_uid'] = 'uid'
# gitlab_rails['ldap_base'] = 'ou=users,dc=example,dc=com'
...@@ -51,11 +51,23 @@ module Gitlab ...@@ -51,11 +51,23 @@ module Gitlab
end end
def issues def issues
Issue.where(project_id: limit_project_ids).full_search(query).order('updated_at DESC') issues = Issue.where(project_id: limit_project_ids)
if query =~ /#(\d+)\z/
issues = issues.where(iid: $1)
else
issues = issues.full_search(query)
end
issues.order('updated_at DESC')
end end
def merge_requests def merge_requests
MergeRequest.in_projects(limit_project_ids).full_search(query).order('updated_at DESC') merge_requests = MergeRequest.in_projects(limit_project_ids)
if query =~ /[#!](\d+)\z/
merge_requests = merge_requests.where(iid: $1)
else
merge_requests = merge_requests.full_search(query)
end
merge_requests.order('updated_at DESC')
end end
def default_scope def default_scope
......
require 'spec_helper' require 'spec_helper'
describe Issues::CloseService do describe Issues::CloseService do
let(:project) { create(:empty_project) }
let(:user) { create(:user) } let(:user) { create(:user) }
let(:user2) { create(:user) } let(:user2) { create(:user) }
let(:issue) { create(:issue, assignee: user2) } let(:issue) { create(:issue, assignee: user2) }
let(:project) { issue.project }
before do before do
project.team << [user, :master] project.team << [user, :master]
......
require 'spec_helper' require 'spec_helper'
describe Issues::UpdateService do describe Issues::UpdateService do
let(:project) { create(:empty_project) }
let(:user) { create(:user) } let(:user) { create(:user) }
let(:user2) { create(:user) } let(:user2) { create(:user) }
let(:issue) { create(:issue) } let(:issue) { create(:issue) }
let(:label) { create(:label) } let(:label) { create(:label) }
let(:project) { issue.project }
before do before do
project.team << [user, :master] project.team << [user, :master]
......
...@@ -31,7 +31,8 @@ describe NotificationService do ...@@ -31,7 +31,8 @@ describe NotificationService do
describe 'Notes' do describe 'Notes' do
context 'issue note' do context 'issue note' do
let(:issue) { create(:issue, assignee: create(:user)) } let(:project) { create(:empty_project, :public) }
let(:issue) { create(:issue, project: project, assignee: create(:user)) }
let(:mentioned_issue) { create(:issue, assignee: issue.assignee) } let(:mentioned_issue) { create(:issue, assignee: issue.assignee) }
let(:note) { create(:note_on_issue, noteable: issue, project_id: issue.project_id, note: '@mention referenced') } let(:note) { create(:note_on_issue, noteable: issue, project_id: issue.project_id, note: '@mention referenced') }
...@@ -101,7 +102,8 @@ describe NotificationService do ...@@ -101,7 +102,8 @@ describe NotificationService do
end end
context 'issue note mention' do context 'issue note mention' do
let(:issue) { create(:issue, assignee: create(:user)) } let(:project) { create(:empty_project, :public) }
let(:issue) { create(:issue, project: project, assignee: create(:user)) }
let(:mentioned_issue) { create(:issue, assignee: issue.assignee) } let(:mentioned_issue) { create(:issue, assignee: issue.assignee) }
let(:note) { create(:note_on_issue, noteable: issue, project_id: issue.project_id, note: '@all mentioned') } let(:note) { create(:note_on_issue, noteable: issue, project_id: issue.project_id, note: '@all mentioned') }
...@@ -145,7 +147,8 @@ describe NotificationService do ...@@ -145,7 +147,8 @@ describe NotificationService do
end end
context 'commit note' do context 'commit note' do
let(:note) { create(:note_on_commit) } let(:project) { create(:project, :public) }
let(:note) { create(:note_on_commit, project: project) }
before do before do
build_team(note.project) build_team(note.project)
...@@ -192,7 +195,8 @@ describe NotificationService do ...@@ -192,7 +195,8 @@ describe NotificationService do
end end
describe 'Issues' do describe 'Issues' do
let(:issue) { create :issue, assignee: create(:user), description: 'cc @participant' } let(:project) { create(:empty_project, :public) }
let(:issue) { create :issue, project: project, assignee: create(:user), description: 'cc @participant' }
before do before do
build_team(issue.project) build_team(issue.project)
...@@ -295,7 +299,8 @@ describe NotificationService do ...@@ -295,7 +299,8 @@ describe NotificationService do
end end
describe 'Merge Requests' do describe 'Merge Requests' do
let(:merge_request) { create :merge_request, assignee: create(:user) } let(:project) { create(:project, :public) }
let(:merge_request) { create :merge_request, source_project: project, assignee: create(:user) }
before do before do
build_team(merge_request.target_project) build_team(merge_request.target_project)
......
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