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

Adds external author to note type

Allows to fetch the external author of a note
if present.

Changelog: added
parent 46454a6c
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