Merged in bugfix/disable_repository_config (pull request #218)

Bugfix: Disable repository config without permission
This commit is contained in:
Sebastian Sdorra
2019-03-14 10:48:06 +00:00
7 changed files with 48 additions and 23 deletions

View File

@@ -8,6 +8,7 @@ import sonia.scm.repository.GitRepositoryConfig;
import sonia.scm.repository.NamespaceAndName; import sonia.scm.repository.NamespaceAndName;
import sonia.scm.repository.Repository; import sonia.scm.repository.Repository;
import sonia.scm.repository.RepositoryManager; import sonia.scm.repository.RepositoryManager;
import sonia.scm.repository.RepositoryPermissions;
import sonia.scm.store.ConfigurationStore; import sonia.scm.store.ConfigurationStore;
import sonia.scm.web.GitVndMediaType; import sonia.scm.web.GitVndMediaType;
@@ -50,6 +51,7 @@ public class GitRepositoryConfigResource {
}) })
public Response getRepositoryConfig(@PathParam("namespace") String namespace, @PathParam("name") String name) { public Response getRepositoryConfig(@PathParam("namespace") String namespace, @PathParam("name") String name) {
Repository repository = getRepository(namespace, name); Repository repository = getRepository(namespace, name);
RepositoryPermissions.read(repository).check();
ConfigurationStore<GitRepositoryConfig> repositoryConfigStore = getStore(repository); ConfigurationStore<GitRepositoryConfig> repositoryConfigStore = getStore(repository);
GitRepositoryConfig config = repositoryConfigStore.get(); GitRepositoryConfig config = repositoryConfigStore.get();
GitRepositoryConfigDto dto = repositoryConfigMapper.map(config, repository); GitRepositoryConfigDto dto = repositoryConfigMapper.map(config, repository);
@@ -68,6 +70,7 @@ public class GitRepositoryConfigResource {
}) })
public Response setRepositoryConfig(@PathParam("namespace") String namespace, @PathParam("name") String name, GitRepositoryConfigDto dto) { public Response setRepositoryConfig(@PathParam("namespace") String namespace, @PathParam("name") String name, GitRepositoryConfigDto dto) {
Repository repository = getRepository(namespace, name); Repository repository = getRepository(namespace, name);
RepositoryPermissions.modify(repository).check();
ConfigurationStore<GitRepositoryConfig> repositoryConfigStore = getStore(repository); ConfigurationStore<GitRepositoryConfig> repositoryConfigStore = getStore(repository);
GitRepositoryConfig config = repositoryConfigMapper.map(dto); GitRepositoryConfig config = repositoryConfigMapper.map(dto);
repositoryConfigStore.set(config); repositoryConfigStore.set(config);

View File

@@ -18,7 +18,8 @@ type State = {
error?: Error, error?: Error,
branches: Branch[], branches: Branch[],
selectedBranchName?: string, selectedBranchName?: string,
defaultBranchChanged: boolean defaultBranchChanged: boolean,
disabled: boolean
}; };
const GIT_CONFIG_CONTENT_TYPE = "application/vnd.scmm-gitConfig+json"; const GIT_CONFIG_CONTENT_TYPE = "application/vnd.scmm-gitConfig+json";
@@ -33,7 +34,8 @@ class RepositoryConfig extends React.Component<Props, State> {
loadingDefaultBranch: true, loadingDefaultBranch: true,
submitPending: false, submitPending: false,
branches: [], branches: [],
defaultBranchChanged: false defaultBranchChanged: false,
disabled: true
}; };
} }
@@ -53,11 +55,11 @@ class RepositoryConfig extends React.Component<Props, State> {
apiClient apiClient
.get(repository._links.configuration.href) .get(repository._links.configuration.href)
.then(response => response.json()) .then(response => response.json())
.then(payload => payload.defaultBranch) .then(payload =>
.then(selectedBranchName =>
this.setState({ this.setState({
...this.state, ...this.state,
selectedBranchName, selectedBranchName: payload.defaultBranch,
disabled: !payload._links.update,
loadingDefaultBranch: false loadingDefaultBranch: false
}) })
) )
@@ -98,7 +100,7 @@ class RepositoryConfig extends React.Component<Props, State> {
render() { render() {
const { t } = this.props; const { t } = this.props;
const { loadingBranches, loadingDefaultBranch, submitPending, error } = this.state; const { loadingBranches, loadingDefaultBranch, submitPending, error, disabled } = this.state;
if (error) { if (error) {
return ( return (
@@ -110,6 +112,12 @@ class RepositoryConfig extends React.Component<Props, State> {
); );
} }
const submitButton = disabled? null: <SubmitButton
label={t("scm-git-plugin.repo-config.submit")}
loading={submitPending}
disabled={!this.state.selectedBranchName}
/>;
if (!(loadingBranches || loadingDefaultBranch)) { if (!(loadingBranches || loadingDefaultBranch)) {
return ( return (
<> <>
@@ -121,12 +129,9 @@ class RepositoryConfig extends React.Component<Props, State> {
branches={this.state.branches} branches={this.state.branches}
selected={this.branchSelected} selected={this.branchSelected}
selectedBranch={this.state.selectedBranchName} selectedBranch={this.state.selectedBranchName}
disabled={disabled}
/> />
<SubmitButton { submitButton }
label={t("scm-git-plugin.repo-config.submit")}
loading={submitPending}
disabled={!this.state.selectedBranchName}
/>
</form> </form>
<hr /> <hr />
</> </>

View File

@@ -159,7 +159,7 @@ public class GitConfigResourceTest {
} }
@Test @Test
@SubjectAware(username = "writeOnly") @SubjectAware(username = "readWrite")
public void shouldReadDefaultRepositoryConfig() throws URISyntaxException, UnsupportedEncodingException { public void shouldReadDefaultRepositoryConfig() throws URISyntaxException, UnsupportedEncodingException {
when(repositoryManager.get(new NamespaceAndName("space", "X"))).thenReturn(new Repository("id", "git", "space", "X")); when(repositoryManager.get(new NamespaceAndName("space", "X"))).thenReturn(new Repository("id", "git", "space", "X"));
@@ -193,7 +193,7 @@ public class GitConfigResourceTest {
} }
@Test @Test
@SubjectAware(username = "writeOnly") @SubjectAware(username = "readOnly")
public void shouldReadStoredRepositoryConfig() throws URISyntaxException, UnsupportedEncodingException { public void shouldReadStoredRepositoryConfig() throws URISyntaxException, UnsupportedEncodingException {
when(repositoryManager.get(new NamespaceAndName("space", "X"))).thenReturn(new Repository("id", "git", "space", "X")); when(repositoryManager.get(new NamespaceAndName("space", "X"))).thenReturn(new Repository("id", "git", "space", "X"));
GitRepositoryConfig gitRepositoryConfig = new GitRepositoryConfig(); GitRepositoryConfig gitRepositoryConfig = new GitRepositoryConfig();

View File

@@ -7,7 +7,7 @@ admin = secret, admin
[roles] [roles]
reader = configuration:read:git reader = configuration:read:git
writer = configuration:write:git writer = configuration:write:git
readerWriter = configuration:*:git readerWriter = configuration:*:git,repository:*:id
admin = * admin = *
repoRead = repository:read:* repoRead = repository:read:*
repoWrite = repository:modify:* repoWrite = repository:modify:*

View File

@@ -26,6 +26,7 @@ type Props = {
selected: (branch?: Branch) => void, selected: (branch?: Branch) => void,
selectedBranch?: string, selectedBranch?: string,
label: string, label: string,
disabled?: boolean,
// context props // context props
classes: Object classes: Object
@@ -47,7 +48,7 @@ class BranchSelector extends React.Component<Props, State> {
} }
render() { render() {
const { branches, classes, label } = this.props; const { branches, classes, label, disabled } = this.props;
if (branches) { if (branches) {
return ( return (
@@ -79,6 +80,7 @@ class BranchSelector extends React.Component<Props, State> {
className="is-fullwidth" className="is-fullwidth"
options={branches.map(b => b.name)} options={branches.map(b => b.name)}
optionSelected={this.branchSelected} optionSelected={this.branchSelected}
disabled={!!disabled}
preselectedOption={ preselectedOption={
this.state.selectedBranch this.state.selectedBranch
? this.state.selectedBranch.name ? this.state.selectedBranch.name

View File

@@ -14,7 +14,8 @@ type Props = {
value?: string, value?: string,
autofocus?: boolean, autofocus?: boolean,
onChange: (value: string, name?: string) => void, onChange: (value: string, name?: string) => void,
helpText?: string helpText?: string,
disabled?: boolean
}; };
class Textarea extends React.Component<Props> { class Textarea extends React.Component<Props> {
@@ -31,7 +32,7 @@ class Textarea extends React.Component<Props> {
}; };
render() { render() {
const { placeholder, value, label, helpText } = this.props; const { placeholder, value, label, helpText, disabled } = this.props;
return ( return (
<div className="field"> <div className="field">
@@ -45,6 +46,7 @@ class Textarea extends React.Component<Props> {
placeholder={placeholder} placeholder={placeholder}
onChange={this.handleInput} onChange={this.handleInput}
value={value} value={value}
disabled={!!disabled}
/> />
</div> </div>
</div> </div>

View File

@@ -71,7 +71,8 @@ class RepositoryForm extends React.Component<Props, State> {
this.state.nameValidationError || this.state.nameValidationError ||
this.state.contactValidationError || this.state.contactValidationError ||
this.isFalsy(repository.name) || this.isFalsy(repository.name) ||
(namespaceStrategy === CUSTOM_NAMESPACE_STRATEGY && this.isFalsy(repository.namespace)) (namespaceStrategy === CUSTOM_NAMESPACE_STRATEGY &&
this.isFalsy(repository.namespace))
); );
}; };
@@ -86,10 +87,24 @@ class RepositoryForm extends React.Component<Props, State> {
return !this.props.repository; return !this.props.repository;
}; };
isModifiable = () => {
return !!this.props.repository && !!this.props.repository._links.update;
};
render() { render() {
const { loading, t } = this.props; const { loading, t } = this.props;
const repository = this.state.repository; const repository = this.state.repository;
const disabled = !this.isModifiable() && !this.isCreateMode();
const submitButton = disabled ? null : (
<SubmitButton
disabled={!this.isValid()}
loading={loading}
label={t("repositoryForm.submit")}
/>
);
let subtitle = null; let subtitle = null;
if (this.props.repository) { if (this.props.repository) {
// edit existing repo // edit existing repo
@@ -108,6 +123,7 @@ class RepositoryForm extends React.Component<Props, State> {
validationError={this.state.contactValidationError} validationError={this.state.contactValidationError}
errorMessage={t("validation.contact-invalid")} errorMessage={t("validation.contact-invalid")}
helpText={t("help.contactHelpText")} helpText={t("help.contactHelpText")}
disabled={disabled}
/> />
<Textarea <Textarea
@@ -115,12 +131,9 @@ class RepositoryForm extends React.Component<Props, State> {
onChange={this.handleDescriptionChange} onChange={this.handleDescriptionChange}
value={repository ? repository.description : ""} value={repository ? repository.description : ""}
helpText={t("help.descriptionHelpText")} helpText={t("help.descriptionHelpText")}
disabled={disabled}
/> />
<SubmitButton {submitButton}
disabled={!this.isValid()}
loading={loading}
label={t("repositoryForm.submit")}
/>
</form> </form>
</> </>
); );