Commit 0b413349 authored by Vasilii Iakliushin's avatar Vasilii Iakliushin

Merge branch '335462-update-blob-permissions' into 'master'

Add canCurrentUserPushToBranch permission

See merge request gitlab-org/gitlab!75017
parents dadc7810 c38e4ccd
......@@ -53,6 +53,10 @@ export default {
type: Boolean,
required: true,
},
canPushToBranch: {
type: Boolean,
required: true,
},
emptyRepo: {
type: Boolean,
required: true,
......@@ -126,6 +130,7 @@ export default {
:target-branch="targetBranch || ref"
:original-branch="originalBranch || ref"
:can-push-code="canPushCode"
:can-push-to-branch="canPushToBranch"
:empty-repo="emptyRepo"
/>
</div>
......
......@@ -106,6 +106,7 @@ export default {
ideForkAndEditPath: '',
storedExternally: false,
canModifyBlob: false,
canCurrentUserPushToBranch: false,
rawPath: '',
externalStorageUrl: '',
replacePath: '',
......@@ -266,6 +267,7 @@ export default {
:replace-path="blobInfo.replacePath"
:delete-path="blobInfo.webPath"
:can-push-code="project.userPermissions.pushCode"
:can-push-to-branch="blobInfo.canCurrentUserPushToBranch"
:empty-repo="project.repository.empty"
:project-path="projectPath"
:is-locked="isLocked"
......
......@@ -71,6 +71,10 @@ export default {
type: Boolean,
required: true,
},
canPushToBranch: {
type: Boolean,
required: true,
},
emptyRepo: {
type: Boolean,
required: true,
......@@ -176,9 +180,12 @@ export default {
</template>
<template v-else>
<input type="hidden" name="original_branch" :value="originalBranch" />
<!-- Once "push to branch" permission is made available, will need to add to conditional
Follow-up issue: https://gitlab.com/gitlab-org/gitlab/-/issues/335462 -->
<input v-if="createNewMr" type="hidden" name="create_merge_request" value="1" />
<input
v-if="createNewMr || !canPushToBranch"
type="hidden"
name="create_merge_request"
value="1"
/>
<gl-form-group
:label="$options.i18n.COMMIT_LABEL"
label-for="commit_message"
......
......@@ -28,6 +28,7 @@ query getBlobInfo($projectPath: ID!, $filePath: String!, $ref: String!) {
forkAndEditPath
ideForkAndEditPath
canModifyBlob
canCurrentUserPushToBranch
storedExternally
rawPath
replacePath
......
......@@ -91,6 +91,9 @@ module Types
calls_gitaly: true,
description: 'Whether the current user can modify the blob.'
field :can_current_user_push_to_branch, GraphQL::Types::Boolean, null: true, method: :can_current_user_push_to_branch?,
description: 'Whether the current user can push to the branch.'
def raw_text_blob
object.data unless object.binary?
end
......
......@@ -78,6 +78,12 @@ class BlobPresenter < Gitlab::View::Presenter::Delegated
super(blob, project, blob.commit_id)
end
def can_current_user_push_to_branch?
return false unless current_user && project.repository.branch_exists?(blob.commit_id)
user_access(project).can_push_to_branch?(blob.commit_id)
end
def ide_edit_path
super(project, blob.commit_id, blob.path)
end
......
......@@ -14072,6 +14072,7 @@ Returns [`Tree`](#tree).
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="repositoryblobcancurrentuserpushtobranch"></a>`canCurrentUserPushToBranch` | [`Boolean`](#boolean) | Whether the current user can push to the branch. |
| <a id="repositoryblobcanmodifyblob"></a>`canModifyBlob` | [`Boolean`](#boolean) | Whether the current user can modify the blob. |
| <a id="repositoryblobeditblobpath"></a>`editBlobPath` | [`String`](#string) | Web path to edit the blob in the old-style editor. |
| <a id="repositoryblobexternalstorageurl"></a>`externalStorageUrl` | [`String`](#string) | Web path to download the raw blob via external storage, if enabled. |
......@@ -6,6 +6,7 @@ const DEFAULT_PROPS = {
name: 'some name',
path: 'some/path',
canPushCode: true,
canPushToBranch: true,
replacePath: 'some/replace/path',
deletePath: 'some/delete/path',
emptyRepo: false,
......
......@@ -9,6 +9,7 @@ const DEFAULT_PROPS = {
name: 'some name',
path: 'some/path',
canPushCode: true,
canPushToBranch: true,
replacePath: 'some/replace/path',
deletePath: 'some/delete/path',
emptyRepo: false,
......
......@@ -13,6 +13,7 @@ const initialProps = {
targetBranch: 'some-target-branch',
originalBranch: 'main',
canPushCode: true,
canPushToBranch: true,
emptyRepo: false,
};
......@@ -103,22 +104,25 @@ describe('DeleteBlobModal', () => {
);
it.each`
input | value | emptyRepo | canPushCode | exist
${'authenticity_token'} | ${'mock-csrf-token'} | ${false} | ${true} | ${true}
${'authenticity_token'} | ${'mock-csrf-token'} | ${true} | ${false} | ${true}
${'_method'} | ${'delete'} | ${false} | ${true} | ${true}
${'_method'} | ${'delete'} | ${true} | ${false} | ${true}
${'original_branch'} | ${initialProps.originalBranch} | ${false} | ${true} | ${true}
${'original_branch'} | ${undefined} | ${true} | ${true} | ${false}
${'create_merge_request'} | ${'1'} | ${false} | ${false} | ${true}
${'create_merge_request'} | ${'1'} | ${false} | ${true} | ${true}
${'create_merge_request'} | ${undefined} | ${true} | ${false} | ${false}
input | value | emptyRepo | canPushCode | canPushToBranch | exist
${'authenticity_token'} | ${'mock-csrf-token'} | ${false} | ${true} | ${true} | ${true}
${'authenticity_token'} | ${'mock-csrf-token'} | ${true} | ${false} | ${true} | ${true}
${'_method'} | ${'delete'} | ${false} | ${true} | ${true} | ${true}
${'_method'} | ${'delete'} | ${true} | ${false} | ${true} | ${true}
${'original_branch'} | ${initialProps.originalBranch} | ${false} | ${true} | ${true} | ${true}
${'original_branch'} | ${undefined} | ${true} | ${true} | ${true} | ${false}
${'create_merge_request'} | ${'1'} | ${false} | ${false} | ${true} | ${true}
${'create_merge_request'} | ${'1'} | ${false} | ${true} | ${true} | ${true}
${'create_merge_request'} | ${'1'} | ${false} | ${false} | ${false} | ${true}
${'create_merge_request'} | ${'1'} | ${false} | ${false} | ${true} | ${true}
${'create_merge_request'} | ${undefined} | ${true} | ${false} | ${true} | ${false}
`(
'passes $input as a hidden input with the correct value',
({ input, value, emptyRepo, canPushCode, exist }) => {
({ input, value, emptyRepo, canPushCode, canPushToBranch, exist }) => {
createComponent({
emptyRepo,
canPushCode,
canPushToBranch,
});
const inputMethod = findForm().find(`input[name="${input}"]`);
......
......@@ -11,6 +11,7 @@ export const simpleViewerMock = {
forkAndEditPath: 'some_file.js/fork/edit',
ideForkAndEditPath: 'some_file.js/fork/ide',
canModifyBlob: true,
canCurrentUserPushToBranch: true,
storedExternally: false,
rawPath: 'some_file.js',
replacePath: 'some_file.js/replace',
......
......@@ -28,6 +28,7 @@ RSpec.describe Types::Repository::BlobType do
:rich_viewer,
:plain_data,
:can_modify_blob,
:can_current_user_push_to_branch,
:ide_edit_path,
:external_storage_url,
:fork_and_edit_path,
......
......@@ -31,6 +31,28 @@ RSpec.describe BlobPresenter do
it { expect(presenter.replace_path).to eq("/#{project.full_path}/-/create/#{blob.commit_id}/#{blob.path}") }
end
describe '#can_current_user_push_to_branch' do
let(:branch_exists) { true }
before do
allow(project.repository).to receive(:branch_exists?).with(blob.commit_id).and_return(branch_exists)
end
it { expect(presenter.can_current_user_push_to_branch?).to eq(true) }
context 'current_user is nil' do
let(:user) { nil }
it { expect(presenter.can_current_user_push_to_branch?).to eq(false) }
end
context 'branch does not exist' do
let(:branch_exists) { false }
it { expect(presenter.can_current_user_push_to_branch?).to eq(false) }
end
end
describe '#pipeline_editor_path' do
context 'when blob is .gitlab-ci.yml' do
before do
......
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