summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/controllers/projects/issues_controller.rb8
-rw-r--r--app/controllers/projects_controller.rb2
-rw-r--r--app/finders/issues_finder.rb6
-rw-r--r--app/helpers/application_helper.rb2
-rw-r--r--app/helpers/events_helper.rb2
-rw-r--r--app/helpers/issues_helper.rb4
-rw-r--r--app/helpers/milestones_helper.rb2
-rw-r--r--app/models/ability.rb17
-rw-r--r--app/models/concerns/milestoneish.rb20
-rw-r--r--app/models/event.rb6
-rw-r--r--app/models/issue.rb7
-rw-r--r--app/models/milestone.rb4
-rw-r--r--app/services/projects/autocomplete_service.rb6
-rw-r--r--app/services/search/global_service.rb2
-rw-r--r--app/services/search/project_service.rb3
-rw-r--r--app/views/events/_event.html.haml2
-rw-r--r--app/views/layouts/nav/_project.html.haml2
-rw-r--r--app/views/projects/diffs/_file.html.haml22
-rw-r--r--app/views/projects/issues/_issue.html.haml1
-rw-r--r--app/views/projects/issues/show.html.haml1
-rw-r--r--app/views/projects/milestones/show.html.haml2
-rw-r--r--app/views/search/results/_issue.html.haml1
-rw-r--r--app/views/shared/issuable/_form.html.haml9
-rw-r--r--app/views/shared/milestones/_issuable.html.haml2
-rw-r--r--app/views/shared/milestones/_milestone.html.haml4
-rw-r--r--app/views/shared/milestones/_summary.html.haml8
-rw-r--r--app/views/shared/milestones/_tabs.html.haml4
-rw-r--r--app/views/shared/milestones/_top.html.haml4
28 files changed, 105 insertions, 48 deletions
diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb
index aa7a178dcf4..6603f28a082 100644
--- a/app/controllers/projects/issues_controller.rb
+++ b/app/controllers/projects/issues_controller.rb
@@ -5,7 +5,7 @@ class Projects::IssuesController < Projects::ApplicationController
before_action :issue, only: [:edit, :update, :show]
# Allow read any issue
- before_action :authorize_read_issue!
+ before_action :authorize_read_issue!, only: [:show]
# Allow write(create) issue
before_action :authorize_create_issue!, only: [:new, :create]
@@ -128,6 +128,10 @@ class Projects::IssuesController < Projects::ApplicationController
end
alias_method :subscribable_resource, :issue
+ def authorize_read_issue!
+ return render_404 unless can?(current_user, :read_issue, @issue)
+ end
+
def authorize_update_issue!
return render_404 unless can?(current_user, :update_issue, @issue)
end
@@ -158,7 +162,7 @@ class Projects::IssuesController < Projects::ApplicationController
def issue_params
params.require(:issue).permit(
- :title, :assignee_id, :position, :description,
+ :title, :assignee_id, :position, :description, :confidential,
:milestone_id, :state_event, :task_num, label_ids: []
)
end
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index 36f37221c58..c9930480770 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -134,7 +134,7 @@ class ProjectsController < ApplicationController
def autocomplete_sources
note_type = params['type']
note_id = params['type_id']
- autocomplete = ::Projects::AutocompleteService.new(@project)
+ autocomplete = ::Projects::AutocompleteService.new(@project, current_user)
participants = ::Projects::ParticipantsService.new(@project, current_user).execute(note_type, note_id)
@suggestions = {
diff --git a/app/finders/issues_finder.rb b/app/finders/issues_finder.rb
index 20a2b0ce8f0..c2befa5a5b3 100644
--- a/app/finders/issues_finder.rb
+++ b/app/finders/issues_finder.rb
@@ -19,4 +19,10 @@ class IssuesFinder < IssuableFinder
def klass
Issue
end
+
+ private
+
+ def init_collection
+ Issue.visible_to_user(current_user)
+ end
end
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 883c2871746..e6ceb213532 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -301,7 +301,7 @@ module ApplicationHelper
if project.nil?
nil
elsif current_controller?(:issues)
- project.issues.send(entity).count
+ project.issues.visible_to_user(current_user).send(entity).count
elsif current_controller?(:merge_requests)
project.merge_requests.send(entity).count
end
diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb
index 37a888d9c60..a67a6b208e2 100644
--- a/app/helpers/events_helper.rb
+++ b/app/helpers/events_helper.rb
@@ -194,7 +194,7 @@ module EventsHelper
end
def event_to_atom(xml, event)
- if event.proper?
+ if event.proper?(current_user)
xml.entry do
event_link = event_feed_url(event)
event_title = event_feed_title(event)
diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb
index ae4ebc0854a..e00d3204027 100644
--- a/app/helpers/issues_helper.rb
+++ b/app/helpers/issues_helper.rb
@@ -98,6 +98,10 @@ module IssuesHelper
end.sort.to_sentence(last_word_connector: ', or ')
end
+ def confidential_icon(issue)
+ icon('eye-slash') if issue.confidential?
+ end
+
def emoji_icon(name, unicode = nil, aliases = [])
unicode ||= Emoji.emoji_filename(name) rescue ""
diff --git a/app/helpers/milestones_helper.rb b/app/helpers/milestones_helper.rb
index e8ac8788d9d..92ed0891e92 100644
--- a/app/helpers/milestones_helper.rb
+++ b/app/helpers/milestones_helper.rb
@@ -38,7 +38,7 @@ module MilestonesHelper
def milestone_progress_bar(milestone)
options = {
class: 'progress-bar progress-bar-success',
- style: "width: #{milestone.percent_complete}%;"
+ style: "width: #{milestone.percent_complete(current_user)}%;"
}
content_tag :div, class: 'progress' do
diff --git a/app/models/ability.rb b/app/models/ability.rb
index ccac08b7d3f..e22da4806e6 100644
--- a/app/models/ability.rb
+++ b/app/models/ability.rb
@@ -49,7 +49,6 @@ class Ability
rules = [
:read_project,
:read_wiki,
- :read_issue,
:read_label,
:read_milestone,
:read_project_snippet,
@@ -63,6 +62,9 @@ class Ability
# Allow to read builds by anonymous user if guests are allowed
rules << :read_build if project.public_builds?
+ # Allow to read issues by anonymous user if issue is not confidential
+ rules << :read_issue unless subject.is_a?(Issue) && subject.confidential?
+
rules - project_disabled_features_rules(project)
else
[]
@@ -321,6 +323,7 @@ class Ability
end
rules += project_abilities(user, subject.project)
+ rules = filter_confidential_issues_abilities(user, subject, rules) if subject.is_a?(Issue)
rules
end
end
@@ -439,5 +442,17 @@ class Ability
:"admin_#{name}"
]
end
+
+ def filter_confidential_issues_abilities(user, issue, rules)
+ return rules if user.admin? || !issue.confidential?
+
+ unless issue.author == user || issue.assignee == user || issue.project.team.member?(user.id)
+ rules.delete(:admin_issue)
+ rules.delete(:read_issue)
+ rules.delete(:update_issue)
+ end
+
+ rules
+ end
end
end
diff --git a/app/models/concerns/milestoneish.rb b/app/models/concerns/milestoneish.rb
index d67df7c1d9c..5b8e3f654ea 100644
--- a/app/models/concerns/milestoneish.rb
+++ b/app/models/concerns/milestoneish.rb
@@ -1,18 +1,18 @@
module Milestoneish
- def closed_items_count
- issues.closed.size + merge_requests.closed_and_merged.size
+ def closed_items_count(user = nil)
+ issues_visible_to_user(user).closed.size + merge_requests.closed_and_merged.size
end
- def total_items_count
- issues.size + merge_requests.size
+ def total_items_count(user = nil)
+ issues_visible_to_user(user).size + merge_requests.size
end
- def complete?
- total_items_count == closed_items_count
+ def complete?(user = nil)
+ total_items_count(user) == closed_items_count(user)
end
- def percent_complete
- ((closed_items_count * 100) / total_items_count).abs
+ def percent_complete(user = nil)
+ ((closed_items_count(user) * 100) / total_items_count(user)).abs
rescue ZeroDivisionError
0
end
@@ -22,4 +22,8 @@ module Milestoneish
(due_date - Date.today).to_i
end
+
+ def issues_visible_to_user(user = nil)
+ issues.visible_to_user(user)
+ end
end
diff --git a/app/models/event.rb b/app/models/event.rb
index 9a0bbf50f8b..a5cfeaf388e 100644
--- a/app/models/event.rb
+++ b/app/models/event.rb
@@ -73,15 +73,17 @@ class Event < ActiveRecord::Base
end
end
- def proper?
+ def proper?(user = nil)
if push?
true
elsif membership_changed?
true
elsif created_project?
true
+ elsif issue?
+ Ability.abilities.allowed?(user, :read_issue, issue)
else
- ((issue? || merge_request? || note?) && target) || milestone?
+ ((merge_request? || note?) && target) || milestone?
end
end
diff --git a/app/models/issue.rb b/app/models/issue.rb
index 2447f860c5a..053387cffd7 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -58,6 +58,13 @@ class Issue < ActiveRecord::Base
attributes
end
+ def self.visible_to_user(user)
+ return where(confidential: false) if user.blank?
+ return all if user.admin?
+
+ where('issues.confidential = false OR (issues.confidential = true AND (issues.author_id = :user_id OR issues.assignee_id = :user_id OR issues.project_id IN(:project_ids)))', user_id: user.id, project_ids: user.authorized_projects.select(:id))
+ end
+
def self.reference_prefix
'#'
end
diff --git a/app/models/milestone.rb b/app/models/milestone.rb
index 374590ba0c5..de7183bf6b4 100644
--- a/app/models/milestone.rb
+++ b/app/models/milestone.rb
@@ -121,8 +121,8 @@ class Milestone < ActiveRecord::Base
active? && issues.opened.count.zero?
end
- def is_empty?
- total_items_count.zero?
+ def is_empty?(user = nil)
+ total_items_count(user).zero?
end
def author_id
diff --git a/app/services/projects/autocomplete_service.rb b/app/services/projects/autocomplete_service.rb
index 7408e09ed1e..ba50305dbd5 100644
--- a/app/services/projects/autocomplete_service.rb
+++ b/app/services/projects/autocomplete_service.rb
@@ -1,11 +1,7 @@
module Projects
class AutocompleteService < BaseService
- def initialize(project)
- @project = project
- end
-
def issues
- @project.issues.opened.select([:iid, :title])
+ @project.issues.visible_to_user(current_user).opened.select([:iid, :title])
end
def merge_requests
diff --git a/app/services/search/global_service.rb b/app/services/search/global_service.rb
index e1e94c5cc38..aa9837038a6 100644
--- a/app/services/search/global_service.rb
+++ b/app/services/search/global_service.rb
@@ -11,7 +11,7 @@ module Search
projects = ProjectsFinder.new.execute(current_user)
projects = projects.in_namespace(group.id) if group
- Gitlab::SearchResults.new(projects, params[:search])
+ Gitlab::SearchResults.new(current_user, projects, params[:search])
end
end
end
diff --git a/app/services/search/project_service.rb b/app/services/search/project_service.rb
index c08881dce4b..4b500914cfb 100644
--- a/app/services/search/project_service.rb
+++ b/app/services/search/project_service.rb
@@ -7,7 +7,8 @@ module Search
end
def execute
- Gitlab::ProjectSearchResults.new(project,
+ Gitlab::ProjectSearchResults.new(current_user,
+ project,
params[:search],
params[:repository_ref])
end
diff --git a/app/views/events/_event.html.haml b/app/views/events/_event.html.haml
index 36fb2d51629..2d9d9dd6342 100644
--- a/app/views/events/_event.html.haml
+++ b/app/views/events/_event.html.haml
@@ -1,4 +1,4 @@
-- if event.proper?
+- if event.proper?(current_user)
.event-item{class: "#{event.body? ? "event-block" : "event-inline" }"}
.event-item-timestamp
#{time_ago_with_tooltip(event.created_at)}
diff --git a/app/views/layouts/nav/_project.html.haml b/app/views/layouts/nav/_project.html.haml
index 0ae83ee01eb..86b46e8c75e 100644
--- a/app/views/layouts/nav/_project.html.haml
+++ b/app/views/layouts/nav/_project.html.haml
@@ -67,7 +67,7 @@
%span
Issues
- if @project.default_issues_tracker?
- %span.count.issue_counter= number_with_delimiter(@project.issues.opened.count)
+ %span.count.issue_counter= number_with_delimiter(@project.issues.visible_to_user(current_user).opened.count)
- if project_nav_tab? :merge_requests
= nav_link(controller: :merge_requests) do
diff --git a/app/views/projects/diffs/_file.html.haml b/app/views/projects/diffs/_file.html.haml
index 3ac058a3bf8..dc34032b1b8 100644
--- a/app/views/projects/diffs/_file.html.haml
+++ b/app/views/projects/diffs/_file.html.haml
@@ -42,13 +42,17 @@
.diff-content.diff-wrap-lines
-# Skipp all non non-supported blobs
- return unless blob.respond_to?('text?')
- - if blob_text_viewable?(blob)
- - if diff_view == 'parallel'
- = render "projects/diffs/parallel_view", diff_file: diff_file, project: project, blob: blob, index: i
- - else
- = render "projects/diffs/text_file", diff_file: diff_file, index: i
- - elsif blob.image?
- - old_file = project.repository.prev_blob_for_diff(diff_commit, diff_file)
- = render "projects/diffs/image", diff_file: diff_file, old_file: old_file, file: blob, index: i
+ - if diff_file.too_large?
+ .nothing-here-block
+ This diff could not be displayed because it is too large.
- else
- .nothing-here-block No preview for this file type
+ - if blob_text_viewable?(blob)
+ - if diff_view == 'parallel'
+ = render "projects/diffs/parallel_view", diff_file: diff_file, project: project, blob: blob, index: i
+ - else
+ = render "projects/diffs/text_file", diff_file: diff_file, index: i
+ - elsif blob.image?
+ - old_file = project.repository.prev_blob_for_diff(diff_commit, diff_file)
+ = render "projects/diffs/image", diff_file: diff_file, old_file: old_file, file: blob, index: i
+ - else
+ .nothing-here-block No preview for this file type
diff --git a/app/views/projects/issues/_issue.html.haml b/app/views/projects/issues/_issue.html.haml
index a44f34c2a68..00e1a3d8069 100644
--- a/app/views/projects/issues/_issue.html.haml
+++ b/app/views/projects/issues/_issue.html.haml
@@ -5,6 +5,7 @@
.issue-title
%span.issue-title-text
+ = confidential_icon(issue)
= link_to_gfm issue.title, issue_path(issue), class: "title"
%ul.controls.light
- if issue.closed?
diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml
index c3ee5c80e5f..ce5b84ee712 100644
--- a/app/views/projects/issues/show.html.haml
+++ b/app/views/projects/issues/show.html.haml
@@ -22,6 +22,7 @@
= icon('angle-double-left')
.issue-meta
+ = confidential_icon(@issue)
%strong.identifier
Issue ##{@issue.iid}
%span.creator
diff --git a/app/views/projects/milestones/show.html.haml b/app/views/projects/milestones/show.html.haml
index b4597043a27..be63875ab34 100644
--- a/app/views/projects/milestones/show.html.haml
+++ b/app/views/projects/milestones/show.html.haml
@@ -42,7 +42,7 @@
= preserve do
= markdown @milestone.description
-- if @milestone.complete? && @milestone.active?
+- if @milestone.complete?(current_user) && @milestone.active?
.alert.alert-success.prepend-top-default
%span All issues for this milestone are closed. You may close milestone now.
diff --git a/app/views/search/results/_issue.html.haml b/app/views/search/results/_issue.html.haml
index 45d700781f3..710f5613c81 100644
--- a/app/views/search/results/_issue.html.haml
+++ b/app/views/search/results/_issue.html.haml
@@ -1,5 +1,6 @@
.search-result-row
%h4
+ = confidential_icon(issue)
= link_to [issue.project.namespace.becomes(Namespace), issue.project, issue] do
%span.term.str-truncated= issue.title
.pull-right ##{issue.iid}
diff --git a/app/views/shared/issuable/_form.html.haml b/app/views/shared/issuable/_form.html.haml
index d5a4aad05d9..9ef729e960c 100644
--- a/app/views/shared/issuable/_form.html.haml
+++ b/app/views/shared/issuable/_form.html.haml
@@ -29,6 +29,15 @@
= render 'projects/notes/hints'
.clearfix
.error-alert
+
+- if issuable.is_a?(Issue) && !issuable.project.private?
+ .form-group
+ .col-sm-offset-2.col-sm-10
+ .checkbox
+ = f.label :confidential do
+ = f.check_box :confidential
+ This issue is confidential and should only be visible to team members
+
- if can?(current_user, :"admin_#{issuable.to_ability_name}", issuable.project)
%hr
.form-group
diff --git a/app/views/shared/milestones/_issuable.html.haml b/app/views/shared/milestones/_issuable.html.haml
index f7c6fc14adf..85888096722 100644
--- a/app/views/shared/milestones/_issuable.html.haml
+++ b/app/views/shared/milestones/_issuable.html.haml
@@ -10,6 +10,8 @@
%strong #{project.name} &middot;
- elsif show_full_project_name
%strong #{project.name_with_namespace} &middot;
+ - if issuable.is_a?(Issue)
+ = confidential_icon(issuable)
= link_to_gfm issuable.title, [project.namespace.becomes(Namespace), project, issuable], title: issuable.title
%div{class: 'issuable-detail'}
= link_to [project.namespace.becomes(Namespace), project, issuable] do
diff --git a/app/views/shared/milestones/_milestone.html.haml b/app/views/shared/milestones/_milestone.html.haml
index f01138af3f0..6b25745c554 100644
--- a/app/views/shared/milestones/_milestone.html.haml
+++ b/app/views/shared/milestones/_milestone.html.haml
@@ -6,10 +6,10 @@
.col-sm-6
%strong= link_to_gfm truncate(milestone.title, length: 100), milestone_path
.col-sm-6
- .pull-right.light #{milestone.percent_complete}% complete
+ .pull-right.light #{milestone.percent_complete(current_user)}% complete
.row
.col-sm-6
- = link_to pluralize(milestone.issues.size, 'Issue'), issues_path
+ = link_to pluralize(milestone.issues_visible_to_user(current_user).size, 'Issue'), issues_path
&middot;
= link_to pluralize(milestone.merge_requests.size, 'Merge Request'), merge_requests_path
.col-sm-6= milestone_progress_bar(milestone)
diff --git a/app/views/shared/milestones/_summary.html.haml b/app/views/shared/milestones/_summary.html.haml
index 59d4ae29f79..385c6596606 100644
--- a/app/views/shared/milestones/_summary.html.haml
+++ b/app/views/shared/milestones/_summary.html.haml
@@ -3,15 +3,15 @@
.context.prepend-top-default
.milestone-summary
%h4 Progress
- %strong= milestone.issues.size
+ %strong= milestone.issues_visible_to_user(current_user).size
issues:
%span.milestone-stat
- %strong= milestone.issues.opened.size
+ %strong= milestone.issues_visible_to_user(current_user).opened.size
open and
- %strong= milestone.issues.closed.size
+ %strong= milestone.issues_visible_to_user(current_user).closed.size
closed
%span.milestone-stat
- %strong== #{milestone.percent_complete}%
+ %strong== #{milestone.percent_complete(current_user)}%
complete
%span.milestone-stat
diff --git a/app/views/shared/milestones/_tabs.html.haml b/app/views/shared/milestones/_tabs.html.haml
index 57d7ee85a3b..2b6ce2d7e7a 100644
--- a/app/views/shared/milestones/_tabs.html.haml
+++ b/app/views/shared/milestones/_tabs.html.haml
@@ -2,7 +2,7 @@
%li.active
= link_to '#tab-issues', 'data-toggle' => 'tab', 'data-show' => '.tab-issues-buttons' do
Issues
- %span.badge= milestone.issues.size
+ %span.badge= milestone.issues_visible_to_user(current_user).size
%li
= link_to '#tab-merge-requests', 'data-toggle' => 'tab', 'data-show' => '.tab-merge-requests-buttons' do
Merge Requests
@@ -21,7 +21,7 @@
.tab-content.milestone-content
.tab-pane.active#tab-issues
- = render 'shared/milestones/issues_tab', issues: milestone.issues, show_project_name: show_project_name, show_full_project_name: show_full_project_name
+ = render 'shared/milestones/issues_tab', issues: milestone.issues_visible_to_user(current_user), show_project_name: show_project_name, show_full_project_name: show_full_project_name
.tab-pane#tab-merge-requests
= render 'shared/milestones/merge_requests_tab', merge_requests: milestone.merge_requests, show_project_name: show_project_name, show_full_project_name: show_full_project_name
.tab-pane#tab-participants
diff --git a/app/views/shared/milestones/_top.html.haml b/app/views/shared/milestones/_top.html.haml
index 4cf1d948b5b..cab8743a077 100644
--- a/app/views/shared/milestones/_top.html.haml
+++ b/app/views/shared/milestones/_top.html.haml
@@ -28,7 +28,7 @@
%h2.title
= markdown escape_once(milestone.title), pipeline: :single_line
-- if milestone.complete? && milestone.active?
+- if milestone.complete?(current_user) && milestone.active?
.alert.alert-success.prepend-top-default
- close_msg = group ? 'You may close the milestone now.' : 'Navigate to the project to close the milestone.'
%span All issues for this milestone are closed. #{close_msg}
@@ -47,7 +47,7 @@
- project_name = group ? ms.project.name : ms.project.name_with_namespace
= link_to project_name, namespace_project_milestone_path(ms.project.namespace, ms.project, ms)
%td
- = ms.issues.opened.count
+ = ms.issues_visible_to_user(current_user).opened.count
%td
- if ms.closed?
Closed