Skip to content
Snippets Groups Projects
Unverified Commit f5ea458e authored by Marc Saleiko's avatar Marc Saleiko Committed by GitLab
Browse files

Merge branch 'ms/work-items/add-notes-metadata-type' into 'master'

parents 8eedb8a9 0bf5c971
No related branches found
No related tags found
No related merge requests found
Loading
Loading
@@ -29,7 +29,7 @@ def resolve_with_lookahead(**args)
private
 
def unconditional_includes
[:author, :project]
[:author, :project, :note_metadata]
end
 
def preloads
Loading
Loading
Loading
Loading
@@ -33,8 +33,7 @@ class NoteType < BaseObject
field :system, GraphQL::Types::Boolean,
null: false,
description: 'Indicates whether the note was created by the system or by a user.'
field :system_note_icon_name,
GraphQL::Types::String,
field :system_note_icon_name, GraphQL::Types::String,
null: true,
description: 'Name of the icon corresponding to a system note.'
 
Loading
Loading
@@ -64,6 +63,10 @@ class NoteType < BaseObject
null: true,
description: 'Metadata for the given note if it is a system note.'
 
field :external_author, GraphQL::Types::String,
null: true,
description: 'Email address of non-GitLab user adding the note. For guests, the email address is obfuscated.'
def system_note_icon_name
SystemNoteHelper.system_note_icon_name(object) if object.system?
end
Loading
Loading
Loading
Loading
@@ -17,6 +17,16 @@ def note_html
obfuscate_participants_emails_in_system_note(text)
end
 
def external_author
return unless object.note_metadata&.external_author
if can?(current_user, :read_external_emails, object)
object.note_metadata.external_author
else
Gitlab::Utils::Email.obfuscated_email(object.note_metadata.external_author, deform: true)
end
end
private
 
def obfuscate_participants_emails_in_system_note(text)
Loading
Loading
Loading
Loading
@@ -12,7 +12,9 @@ class NoteEntity < API::Entities::Note
 
expose :type
 
expose :external_author
expose :external_author do |note|
note_presenter(note).external_author
end
 
expose :author, using: NoteUserEntity
 
Loading
Loading
@@ -115,16 +117,6 @@ def with_base_discussion?
options.fetch(:with_base_discussion, true)
end
 
def external_author
return unless object.note_metadata&.external_author
if can?(current_user, :read_external_emails, object.project)
object.note_metadata.external_author
else
Gitlab::Utils::Email.obfuscated_email(object.note_metadata.external_author, deform: true)
end
end
def note_presenter(note)
NotePresenter.new(note, current_user: current_user) # rubocop: disable CodeReuse/Presenter -- Directly instantiate NotePresenter because we don't have presenters for all subclasses of Note
end
Loading
Loading
Loading
Loading
@@ -28820,6 +28820,7 @@ Describes where code is deployed for a project organized by folder.
| <a id="notebodyhtml"></a>`bodyHtml` | [`String`](#string) | GitLab Flavored Markdown rendering of the content of the note. |
| <a id="notecreatedat"></a>`createdAt` | [`Time!`](#time) | Timestamp of the note creation. |
| <a id="notediscussion"></a>`discussion` | [`Discussion`](#discussion) | Discussion the note is a part of. |
| <a id="noteexternalauthor"></a>`externalAuthor` | [`String`](#string) | Email address of non-GitLab user adding the note. For guests, the email address is obfuscated. |
| <a id="noteid"></a>`id` | [`NoteID!`](#noteid) | ID of the note. |
| <a id="noteimported"></a>`imported` | [`Boolean`](#boolean) | Indicates whether the note was imported. |
| <a id="noteinternal"></a>`internal` | [`Boolean`](#boolean) | Indicates if the note is internal. |
Loading
Loading
@@ -11,9 +11,11 @@
 
let_it_be(:note_text) { 'note body content' }
let_it_be(:note) { create(:note, note: note_text, project: project) }
let_it_be(:email) { 'user@example.com' }
# rubocop:enable RSpec/FactoryBot/AvoidCreate
 
let(:batch_loader) { instance_double(Gitlab::Graphql::Loaders::BatchModelLoader) }
let(:obfuscated_email) { 'us*****@e*****.c**' }
 
it 'exposes the expected fields' do
expected_fields = %i[
Loading
Loading
@@ -26,6 +28,7 @@
internal
created_at
discussion
external_author
id
position
project
Loading
Loading
@@ -52,7 +55,6 @@
specify { expect(described_class).to require_graphql_authorizations(:read_note) }
 
context 'when system note with issue_email_participants action', feature_category: :service_desk do
let_it_be(:email) { 'user@example.com' }
let_it_be(:note_text) { "added #{email}" }
# Create project and issue separately because we need to public project.
# rubocop:disable RSpec/FactoryBot/AvoidCreate -- Notes::RenderService updates #note and #cached_markdown_version
Loading
Loading
@@ -64,8 +66,6 @@
let_it_be(:system_note_metadata) { create(:system_note_metadata, note: note, action: :issue_email_participants) }
# rubocop:enable RSpec/FactoryBot/AvoidCreate
 
let(:obfuscated_email) { 'us*****@e*****.c**' }
describe '#body' do
subject { resolve_field(:body, note, current_user: user) }
 
Loading
Loading
@@ -79,6 +79,19 @@
end
end
 
context 'when note is from external author', feature_category: :service_desk do
let(:note_text) { 'Note body from external participant' }
let!(:note) { build(:note, note: note_text, project: project, author: Users::Internal.support_bot) }
let!(:note_metadata) { build(:note_metadata, note: note, email_participant: email) }
describe '#external_author' do
subject { resolve_field(:external_author, note, current_user: user) }
it_behaves_like 'a note content field with obfuscated email address'
end
end
describe '#body_first_line_html' do
let(:note_text) { 'note body content' }
let(:note) { build(:note, note: note_text, project: project) }
Loading
Loading
Loading
Loading
@@ -36,4 +36,14 @@
is_expected.to include(obfuscated_email)
end
end
describe '#external_author' do
let!(:note_text) { "note body" }
let!(:note) { build(:note, :system, author: Users::Internal.support_bot, note: note_text) }
let!(:note_metadata) { build(:note_metadata, note: note, email_participant: email) }
subject { presenter.external_author }
it_behaves_like 'a note content field with obfuscated email address'
end
end
Loading
Loading
@@ -18,46 +18,8 @@
 
it_behaves_like 'note entity'
 
shared_examples 'external author' do
context 'when anonymous' do
let(:user) { nil }
it { is_expected.to eq(obfuscated_email) }
end
context 'with signed in user' do
before do
stub_member_access_level(note.project, access_level => user) if access_level
end
context 'when user has no role in project' do
let(:access_level) { nil }
it { is_expected.to eq(obfuscated_email) }
end
context 'when user has guest role in project' do
let(:access_level) { :guest }
it { is_expected.to eq(obfuscated_email) }
end
context 'when user has reporter role in project' do
let(:access_level) { :reporter }
it { is_expected.to eq(email) }
end
context 'when user has developer role in project' do
let(:access_level) { :developer }
it { is_expected.to eq(email) }
end
end
end
describe 'with email participant', feature_category: :service_desk do
let_it_be(:note_metadata) { create(:note_metadata, note: note) } # rubocop:disable RSpec/FactoryBot/AvoidCreate -- Persisted records required
let!(:note_metadata) { build(:note_metadata, note: note) }
 
subject { entity.as_json[:external_author] }
 
Loading
Loading
@@ -65,7 +27,7 @@
let(:obfuscated_email) { 'em*****@e*****.c**' }
let(:email) { 'email@example.com' }
 
it_behaves_like 'external author'
it_behaves_like 'a note content field with obfuscated email address'
end
end
 
Loading
Loading
Loading
Loading
@@ -66,6 +66,9 @@
create(:award_emoji, awardable: note, name: 'star', user: user)
another_user = create(:user, developer_of: note.resource_parent)
create(:note, project: note.project, noteable: noteable, author: another_user)
note_from_external_participant = create(:note,
project: note.project, noteable: noteable, author: Users::Internal.support_bot)
create(:note_metadata, note: note_from_external_participant)
 
post_graphql(query, current_user: user)
 
Loading
Loading
@@ -78,6 +81,9 @@
another_user = create(:user, developer_of: note.resource_parent)
note_with_different_user = create(:note, project: note.project, noteable: noteable, author: another_user)
create(:award_emoji, awardable: note_with_different_user, name: 'star', user: user)
another_note_from_external_participant = create(:note,
project: note.project, noteable: noteable, author: Users::Internal.support_bot)
create(:note_metadata, note: another_note_from_external_participant)
 
expect { post_graphql(query, current_user: user) }.not_to exceed_query_limit(control)
expect_graphql_errors_to_be_empty
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment