Merge "Introduce gr-project-access"

This commit is contained in:
Wyatt Allen
2017-08-29 20:27:24 +00:00
committed by Gerrit Code Review
9 changed files with 315 additions and 0 deletions

View File

@@ -33,6 +33,7 @@ limitations under the License.
<link rel="import" href="../gr-group-members/gr-group-members.html">
<link rel="import" href="../gr-plugin-list/gr-plugin-list.html">
<link rel="import" href="../gr-project/gr-project.html">
<link rel="import" href="../gr-project-access/gr-project-access.html">
<link rel="import" href="../gr-project-commands/gr-project-commands.html">
<link rel="import" href="../gr-project-detail-list/gr-project-detail-list.html">
@@ -127,6 +128,11 @@ limitations under the License.
project="[[params.project]]"></gr-project-commands>
</main>
</template>
<template is="dom-if" if="[[_showProjectAccess]]" restamp="true">
<main class="table">
<gr-project-access project="[[params.project]]"></gr-project-access>
</main>
</template>
<template is="dom-if" if="[[params.placeholder]]" restamp="true">
<gr-placeholder title="Admin" path="[[path]]"></gr-placeholder>
</template>

View File

@@ -69,6 +69,7 @@
_showProjectList: Boolean,
_showProjectDetailList: Boolean,
_showPluginList: Boolean,
_showProjectAccess: Boolean,
},
behaviors: [
@@ -110,6 +111,13 @@
view: 'gr-project',
url: `/admin/projects/${this.encodeURL(this._projectName, true)}`,
children: [{
name: 'Access',
detailType: 'access',
view: 'gr-project-access',
url: `/admin/projects/` +
`${this.encodeURL(this._projectName, true)},access`,
},
{
name: 'Commands',
detailType: 'commands',
view: 'gr-project-commands',
@@ -187,6 +195,7 @@
this.set('_showProjectDetailList',
params.adminView === 'gr-project-detail-list');
this.set('_showPluginList', params.adminView === 'gr-plugin-list');
this.set('_showProjectAccess', params.adminView === 'gr-project-access');
if (params.project !== this._projectName) {
this._projectName = params.project || '';
// Reloads the admin menu.

View File

@@ -0,0 +1,55 @@
<!--
Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<link rel="import" href="../../../bower_components/polymer/polymer.html">
<link rel="import" href="../../../behaviors/gr-access-behavior/gr-access-behavior.html">
<link rel="import" href="../../../behaviors/base-url-behavior/base-url-behavior.html">
<link rel="import" href="../../../behaviors/gr-url-encoding-behavior.html">
<link rel="import" href="../../../styles/gr-menu-page-styles.html">
<link rel="import" href="../../../styles/shared-styles.html">
<link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html">
<link rel="import" href="../gr-access-section/gr-access-section.html">
<script src="../../../scripts/util.js"></script>
<dom-module id="gr-project-access">
<template>
<style include="shared-styles"></style>
<style include="gr-menu-page-styles"></style>
<main>
<template
is="dom-repeat"
items="{{_sections}}"
as="section">
<gr-access-section
capabilities="[[_capabilities]]"
section="{{section}}"
labels="[[_labels]]"
editing="[[_editing]]"></gr-access-section>
</template>
<template is="dom-if" if="[[_inheritsFrom]]">
<h3 id="inheritsFrom">Rights Inherit From
<a href$="[[_computeParentHref(_inheritsFrom.name)]]" rel="noopener">
[[_inheritsFrom.name]]</a>
</h3>
</template>
</main>
<gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
</template>
<script src="gr-project-access.js"></script>
</dom-module>

View File

@@ -0,0 +1,80 @@
// Copyright (C) 2017 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
(function() {
'use strict';
Polymer({
is: 'gr-project-access',
properties: {
project: {
type: String,
observer: '_projectChanged',
},
_capabilities: Object,
/** @type {?} */
_inheritsFrom: Object,
_labels: Object,
_local: Object,
_editing: {
type: Boolean,
value: false,
},
_sections: Array,
},
behaviors: [
Gerrit.AccessBehavior,
Gerrit.BaseUrlBehavior,
Gerrit.URLEncodingBehavior,
],
_projectChanged(project) {
const promises = [];
if (!this._sections) {
this._sections = [];
}
promises.push(this.$.restAPI.getProjectAccessRights(project).then(res => {
this._inheritsFrom = res.inherits_from;
this._local = res.local;
return this.toSortedArray(this._local);
}));
promises.push(this.$.restAPI.getCapabilities().then(res => {
return res;
}));
promises.push(this.$.restAPI.getProject(project).then(res => {
return res.labels;
}));
return Promise.all(promises).then(value => {
this._capabilities = value[1];
this._labels = value[2];
// Use splice instead of setting _sections directly so that dom-repeat
// renders new sections properly. Otherwise, gr-access-section is not
// aware that the section has updated.
this.splice(...['_sections', 0, this._sections.length]
.concat(value[0]));
});
},
_computeParentHref(projectName) {
return this.getBaseUrl() +
`/admin/projects/${this.encodeURL(projectName, true)},access`;
},
});
})();

View File

@@ -0,0 +1,118 @@
<!DOCTYPE html>
<!--
Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
<title>gr-project-access</title>
<script src="../../../bower_components/page/page.js"></script>
<script src="../../../bower_components/webcomponentsjs/webcomponents-lite.min.js"></script>
<script src="../../../bower_components/web-component-tester/browser.js"></script>
<link rel="import" href="../../../test/common-test-setup.html"/>
<link rel="import" href="gr-project-access.html">
<script>void(0);</script>
<test-fixture id="basic">
<template>
<gr-project-access></gr-project-access>
</template>
</test-fixture>
<script>
suite('gr-project-access tests', () => {
let element;
let sandbox;
setup(() => {
sandbox = sinon.sandbox.create();
element = fixture('basic');
});
teardown(() => {
sandbox.restore();
});
test('_projectChanged called when project name changes', () => {
sandbox.stub(element, '_projectChanged');
element.project = 'New Project';
assert.isTrue(element._projectChanged.called);
});
test('_projectChanged', done => {
const capabilitiesRes = {
accessDatabase: {
id: 'accessDatabase',
name: 'Access Database',
},
};
const accessRes = {
local: {
GLOBAL_CAPABILITIES: {
permissions: {
accessDatabase: {
rules: {
123: {},
},
},
},
},
},
};
const projectRes = {
labels: {
'Code-Review': {},
},
};
const accessStub = sandbox.stub(element.$.restAPI,
'getProjectAccessRights') .returns(Promise.resolve(accessRes));
const capabilitiesStub = sandbox.stub(element.$.restAPI,
'getCapabilities').returns(Promise.resolve(capabilitiesRes));
const projectStub = sandbox.stub(element.$.restAPI, 'getProject').returns(
Promise.resolve(projectRes));
element._projectChanged('New Project').then(() => {
assert.isTrue(accessStub.called);
assert.isTrue(capabilitiesStub.called);
assert.isTrue(projectStub.called);
assert.isNotOk(element._inheritsFrom);
assert.deepEqual(element._local, accessRes.local);
assert.deepEqual(element._sections,
element.toSortedArray(accessRes.local));
assert.deepEqual(element._labels, projectRes.labels);
done();
});
});
test('_computeParentHref', () => {
const projectName = 'test-project';
assert.equal(element._computeParentHref(projectName),
'/admin/projects/test-project,access');
});
test('inherit section', () => {
sandbox.stub(element, '_computeParentHref');
assert.isNotOk(Polymer.dom(element.root).querySelector('#inheritsFrom'));
assert.isFalse(element._computeParentHref.called);
element._inheritsFrom = {
name: 'another-project',
};
flushAsynchronousOperations();
assert.isOk(Polymer.dom(element.root).querySelector('#inheritsFrom'));
assert.isTrue(element._computeParentHref.called);
});
});
</script>

View File

@@ -45,6 +45,9 @@
// Matches /admin/projects/<project>,commands.
PROJECT_COMMANDS: /^\/admin\/projects\/(.+),commands$/,
// Matches /admin/projects/<project>,access.
PROJECT_ACCESS: /^\/admin\/projects\/(.+),access$/,
// Matches /admin/projects[,<offset>][/].
PROJECT_LIST_OFFSET: /^\/admin\/projects(,(\d+))?(\/)?$/,
PROJECT_LIST_FILTER: '/admin/projects/q/filter::filter',
@@ -402,6 +405,9 @@
this._mapRoute(RoutePattern.PROJECT_COMMANDS,
'_handleProjectCommandsRoute', true);
this._mapRoute(RoutePattern.PROJECT_ACCESS,
'_handleProjectAccessRoute', true);
this._mapRoute(RoutePattern.BRANCH_LIST_OFFSET,
'_handleBranchListOffsetRoute');
@@ -598,6 +604,15 @@
});
},
_handleProjectAccessRoute(data) {
this._setParams({
view: Gerrit.Nav.View.ADMIN,
adminView: 'gr-project-access',
detailType: 'access',
project: data.params[0],
});
},
_handleBranchListOffsetRoute(data) {
this._setParams({
view: Gerrit.Nav.View.ADMIN,

View File

@@ -102,6 +102,7 @@ limitations under the License.
'_handlePluginListFilterRoute',
'_handlePluginListOffsetRoute',
'_handlePluginListRoute',
'_handleProjectAccessRoute',
'_handleProjectCommandsRoute',
'_handleSettingsLegacyRoute',
'_handleSettingsRoute',
@@ -655,6 +656,16 @@ limitations under the License.
});
});
test('_handleProjectAccessRoute', () => {
const data = {params: {0: 4321}};
assertDataToParams(data, '_handleProjectAccessRoute', {
view: Gerrit.Nav.View.ADMIN,
adminView: 'gr-project-access',
detailType: 'access',
project: 4321,
});
});
suite('branch list routes', () => {
test('_handleBranchListOffsetRoute', () => {
const data = {params: {0: 4321}};

View File

@@ -201,6 +201,11 @@
return this._fetchSharedCacheURL('/config/server/info');
},
getProject(project) {
return this._fetchSharedCacheURL(
'/projects/' + encodeURIComponent(project));
},
getProjectConfig(project) {
return this._fetchSharedCacheURL(
'/projects/' + encodeURIComponent(project) + '/config');
@@ -1016,6 +1021,17 @@
);
},
getProjectAccessRights(projectName) {
return this._fetchSharedCacheURL(
`/projects/${encodeURIComponent(projectName)}/access`);
},
setProjectAccessRights(projectName, projectInfo) {
return this.send(
'POST', `/projects/${encodeURIComponent(projectName)}/access`,
projectInfo);
},
/**
* @param {string} inputVal
* @param {number} opt_n
@@ -1679,6 +1695,10 @@
});
},
getCapabilities(token) {
return this.fetchJSON('/config/server/capabilities');
},
setAssignee(changeNum, assignee) {
const p = {assignee};
return this.getChangeURLAndSend(changeNum, 'PUT', null, '/assignee', p);

View File

@@ -45,6 +45,7 @@ limitations under the License.
'admin/gr-permission/gr-permission_test.html',
'admin/gr-plugin-list/gr-plugin-list_test.html',
'admin/gr-project/gr-project_test.html',
'admin/gr-project-access/gr-project-access_test.html',
'admin/gr-project-commands/gr-project-commands_test.html',
'admin/gr-project-detail-list/gr-project-detail-list_test.html',
'admin/gr-rule-editor/gr-rule-editor_test.html',