| // Copyright (C) 2008 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. |
| |
| package com.google.gerrit.client.admin; |
| |
| import com.google.gerrit.client.Gerrit; |
| import com.google.gerrit.client.rpc.GerritCallback; |
| import com.google.gerrit.client.ui.AccountGroupSuggestOracle; |
| import com.google.gerrit.client.ui.FancyFlexTable; |
| import com.google.gerrit.client.ui.SmallHeading; |
| import com.google.gerrit.common.data.ApprovalType; |
| import com.google.gerrit.common.data.GerritConfig; |
| import com.google.gerrit.common.data.ProjectDetail; |
| import com.google.gerrit.reviewdb.AccountGroup; |
| import com.google.gerrit.reviewdb.ApprovalCategory; |
| import com.google.gerrit.reviewdb.ApprovalCategoryValue; |
| import com.google.gerrit.reviewdb.Project; |
| import com.google.gerrit.reviewdb.RefRight; |
| import com.google.gwt.event.dom.client.BlurEvent; |
| import com.google.gwt.event.dom.client.BlurHandler; |
| import com.google.gwt.event.dom.client.ChangeEvent; |
| import com.google.gwt.event.dom.client.ChangeHandler; |
| import com.google.gwt.event.dom.client.ClickEvent; |
| import com.google.gwt.event.dom.client.ClickHandler; |
| import com.google.gwt.event.dom.client.FocusEvent; |
| import com.google.gwt.event.dom.client.FocusHandler; |
| import com.google.gwt.event.dom.client.KeyCodes; |
| import com.google.gwt.event.dom.client.KeyPressEvent; |
| import com.google.gwt.event.dom.client.KeyPressHandler; |
| import com.google.gwt.user.client.ui.Button; |
| import com.google.gwt.user.client.ui.CheckBox; |
| import com.google.gwt.user.client.ui.Composite; |
| import com.google.gwt.user.client.ui.FlowPanel; |
| import com.google.gwt.user.client.ui.Grid; |
| import com.google.gwt.user.client.ui.ListBox; |
| import com.google.gwt.user.client.ui.Panel; |
| import com.google.gwt.user.client.ui.SuggestBox; |
| import com.google.gwt.user.client.ui.FlexTable.FlexCellFormatter; |
| import com.google.gwtexpui.globalkey.client.NpTextBox; |
| import com.google.gwtexpui.safehtml.client.SafeHtml; |
| import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder; |
| import com.google.gwtjsonrpc.client.VoidResult; |
| |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Map; |
| |
| public class ProjectRightsPanel extends Composite { |
| private Project.NameKey projectName; |
| |
| private RightsTable rights; |
| private Button delRight; |
| private Button addRight; |
| private ListBox catBox; |
| private ListBox rangeMinBox; |
| private ListBox rangeMaxBox; |
| private NpTextBox nameTxtBox; |
| private SuggestBox nameTxt; |
| private NpTextBox referenceTxt; |
| |
| public ProjectRightsPanel(final Project.NameKey toShow) { |
| projectName = toShow; |
| |
| final FlowPanel body = new FlowPanel(); |
| initRights(body); |
| initWidget(body); |
| } |
| |
| @Override |
| protected void onLoad() { |
| enableForm(false); |
| super.onLoad(); |
| |
| Util.PROJECT_SVC.projectDetail(projectName, |
| new GerritCallback<ProjectDetail>() { |
| public void onSuccess(final ProjectDetail result) { |
| enableForm(true); |
| display(result); |
| } |
| }); |
| } |
| |
| private void enableForm(final boolean on) { |
| delRight.setEnabled(on); |
| |
| final boolean canAdd = on && catBox.getItemCount() > 0; |
| addRight.setEnabled(canAdd); |
| nameTxtBox.setEnabled(canAdd); |
| referenceTxt.setEnabled(canAdd); |
| catBox.setEnabled(canAdd); |
| rangeMinBox.setEnabled(canAdd); |
| rangeMaxBox.setEnabled(canAdd); |
| } |
| |
| private void initRights(final Panel body) { |
| final FlowPanel addPanel = new FlowPanel(); |
| addPanel.setStyleName(Gerrit.RESOURCES.css().addSshKeyPanel()); |
| |
| final Grid addGrid = new Grid(5, 2); |
| |
| catBox = new ListBox(); |
| rangeMinBox = new ListBox(); |
| rangeMaxBox = new ListBox(); |
| |
| catBox.addChangeHandler(new ChangeHandler() { |
| @Override |
| public void onChange(final ChangeEvent event) { |
| updateCategorySelection(); |
| } |
| }); |
| for (final ApprovalType at : Gerrit.getConfig().getApprovalTypes() |
| .getApprovalTypes()) { |
| final ApprovalCategory c = at.getCategory(); |
| catBox.addItem(c.getName(), c.getId().get()); |
| } |
| for (final ApprovalType at : Gerrit.getConfig().getApprovalTypes() |
| .getActionTypes()) { |
| final ApprovalCategory c = at.getCategory(); |
| if (Gerrit.getConfig().getWildProject().equals(projectName) |
| && ApprovalCategory.OWN.equals(c.getId())) { |
| // Giving out control of the WILD_PROJECT to other groups beyond |
| // Administrators is dangerous. Having control over WILD_PROJECT |
| // is about the same as having Administrator access as users are |
| // able to affect grants in all projects on the system. |
| // |
| continue; |
| } |
| catBox.addItem(c.getName(), c.getId().get()); |
| } |
| |
| addGrid.setText(0, 0, Util.C.columnApprovalCategory() + ":"); |
| addGrid.setWidget(0, 1, catBox); |
| |
| nameTxtBox = new NpTextBox(); |
| nameTxt = new SuggestBox(new AccountGroupSuggestOracle(), nameTxtBox); |
| nameTxtBox.setVisibleLength(50); |
| nameTxtBox.setText(Util.C.defaultAccountGroupName()); |
| nameTxtBox.addStyleName(Gerrit.RESOURCES.css().inputFieldTypeHint()); |
| nameTxtBox.addFocusHandler(new FocusHandler() { |
| @Override |
| public void onFocus(FocusEvent event) { |
| if (Util.C.defaultAccountGroupName().equals(nameTxtBox.getText())) { |
| nameTxtBox.setText(""); |
| nameTxtBox.removeStyleName(Gerrit.RESOURCES.css() |
| .inputFieldTypeHint()); |
| } |
| } |
| }); |
| nameTxtBox.addBlurHandler(new BlurHandler() { |
| @Override |
| public void onBlur(BlurEvent event) { |
| if ("".equals(nameTxtBox.getText())) { |
| nameTxtBox.setText(Util.C.defaultAccountGroupName()); |
| nameTxtBox.addStyleName(Gerrit.RESOURCES.css().inputFieldTypeHint()); |
| } |
| } |
| }); |
| addGrid.setText(1, 0, Util.C.columnGroupName() + ":"); |
| addGrid.setWidget(1, 1, nameTxt); |
| |
| referenceTxt = new NpTextBox(); |
| referenceTxt.setVisibleLength(50); |
| referenceTxt.setText(""); |
| referenceTxt.addKeyPressHandler(new KeyPressHandler() { |
| @Override |
| public void onKeyPress(KeyPressEvent event) { |
| if (event.getCharCode() == KeyCodes.KEY_ENTER) { |
| doAddNewRight(); |
| } |
| } |
| }); |
| |
| addGrid.setText(2, 0, Util.C.columnRefName() + ":"); |
| addGrid.setWidget(2, 1, referenceTxt); |
| |
| addGrid.setText(3, 0, Util.C.columnRightRange() + ":"); |
| addGrid.setWidget(3, 1, rangeMinBox); |
| |
| addGrid.setText(4, 0, ""); |
| addGrid.setWidget(4, 1, rangeMaxBox); |
| |
| addRight = new Button(Util.C.buttonAddProjectRight()); |
| addRight.addClickHandler(new ClickHandler() { |
| @Override |
| public void onClick(final ClickEvent event) { |
| doAddNewRight(); |
| } |
| }); |
| addPanel.add(addGrid); |
| addPanel.add(addRight); |
| |
| rights = new RightsTable(); |
| |
| delRight = new Button(Util.C.buttonDeleteGroupMembers()); |
| delRight.addClickHandler(new ClickHandler() { |
| @Override |
| public void onClick(final ClickEvent event) { |
| rights.deleteChecked(); |
| } |
| }); |
| |
| body.add(new SmallHeading(Util.C.headingAccessRights())); |
| body.add(rights); |
| body.add(delRight); |
| body.add(addPanel); |
| |
| if (catBox.getItemCount() > 0) { |
| catBox.setSelectedIndex(0); |
| updateCategorySelection(); |
| } |
| } |
| |
| void display(final ProjectDetail result) { |
| rights.display(result.groups, result.rights); |
| } |
| |
| private void doAddNewRight() { |
| int idx = catBox.getSelectedIndex(); |
| final ApprovalType at; |
| ApprovalCategoryValue min, max; |
| if (idx < 0) { |
| return; |
| } |
| at = |
| Gerrit.getConfig().getApprovalTypes().getApprovalType( |
| new ApprovalCategory.Id(catBox.getValue(idx))); |
| if (at == null) { |
| return; |
| } |
| |
| idx = rangeMinBox.getSelectedIndex(); |
| if (idx < 0) { |
| return; |
| } |
| min = at.getValue(Short.parseShort(rangeMinBox.getValue(idx))); |
| if (min == null) { |
| return; |
| } |
| |
| idx = rangeMaxBox.getSelectedIndex(); |
| if (idx < 0) { |
| return; |
| } |
| max = at.getValue(Short.parseShort(rangeMaxBox.getValue(idx))); |
| if (max == null) { |
| return; |
| } |
| |
| final String groupName = nameTxt.getText(); |
| if ("".equals(groupName) |
| || Util.C.defaultAccountGroupName().equals(groupName)) { |
| return; |
| } |
| |
| final String refPattern = referenceTxt.getText(); |
| |
| if (min.getValue() > max.getValue()) { |
| // If the user selects it backwards in the web UI, help them out |
| // by reversing the order to what we would expect. |
| // |
| final ApprovalCategoryValue newMin = max; |
| final ApprovalCategoryValue newMax = min; |
| min = newMin; |
| max = newMax; |
| } |
| |
| addRight.setEnabled(false); |
| Util.PROJECT_SVC.addRight(projectName, at.getCategory().getId(), groupName, |
| refPattern, min.getValue(), max.getValue(), |
| new GerritCallback<ProjectDetail>() { |
| public void onSuccess(final ProjectDetail result) { |
| addRight.setEnabled(true); |
| nameTxt.setText(""); |
| referenceTxt.setText(""); |
| display(result); |
| } |
| |
| @Override |
| public void onFailure(final Throwable caught) { |
| addRight.setEnabled(true); |
| super.onFailure(caught); |
| } |
| }); |
| } |
| |
| private void updateCategorySelection() { |
| final int idx = catBox.getSelectedIndex(); |
| final ApprovalType at; |
| if (idx >= 0) { |
| at = |
| Gerrit.getConfig().getApprovalTypes().getApprovalType( |
| new ApprovalCategory.Id(catBox.getValue(idx))); |
| } else { |
| at = null; |
| } |
| |
| if (at == null || at.getValues().isEmpty()) { |
| rangeMinBox.setEnabled(false); |
| rangeMaxBox.setEnabled(false); |
| referenceTxt.setEnabled(false); |
| addRight.setEnabled(false); |
| return; |
| } |
| |
| // TODO Support per-branch READ access. |
| if (ApprovalCategory.READ.equals(at.getCategory().getId())) { |
| referenceTxt.setText(""); |
| referenceTxt.setEnabled(false); |
| } else { |
| referenceTxt.setEnabled(true); |
| } |
| |
| int curIndex = 0, minIndex = -1, maxIndex = -1; |
| rangeMinBox.clear(); |
| rangeMaxBox.clear(); |
| for (final ApprovalCategoryValue v : at.getValues()) { |
| final String vStr = String.valueOf(v.getValue()); |
| String nStr = vStr + ": " + v.getName(); |
| if (v.getValue() > 0) { |
| nStr = "+" + nStr; |
| } |
| |
| rangeMinBox.addItem(nStr, vStr); |
| rangeMaxBox.addItem(nStr, vStr); |
| |
| if (v.getValue() < 0) { |
| minIndex = curIndex; |
| } |
| if (maxIndex < 0 && v.getValue() > 0) { |
| maxIndex = curIndex; |
| } |
| |
| curIndex++; |
| } |
| if (ApprovalCategory.READ.equals(at.getCategory().getId())) { |
| // Special case; for READ the most logical range is just |
| // +1 READ, so assume that as the default for both. |
| minIndex = maxIndex; |
| } |
| rangeMinBox.setSelectedIndex(minIndex >= 0 ? minIndex : 0); |
| rangeMaxBox.setSelectedIndex(maxIndex >= 0 ? maxIndex : curIndex - 1); |
| |
| addRight.setEnabled(true); |
| } |
| |
| private class RightsTable extends FancyFlexTable<RefRight> { |
| RightsTable() { |
| table.setWidth(""); |
| table.setText(0, 2, Util.C.columnApprovalCategory()); |
| table.setText(0, 3, Util.C.columnGroupName()); |
| table.setText(0, 4, Util.C.columnRefName()); |
| table.setText(0, 5, Util.C.columnRightRange()); |
| |
| final FlexCellFormatter fmt = table.getFlexCellFormatter(); |
| fmt.addStyleName(0, 1, Gerrit.RESOURCES.css().iconHeader()); |
| fmt.addStyleName(0, 2, Gerrit.RESOURCES.css().dataHeader()); |
| fmt.addStyleName(0, 3, Gerrit.RESOURCES.css().dataHeader()); |
| fmt.addStyleName(0, 4, Gerrit.RESOURCES.css().dataHeader()); |
| fmt.addStyleName(0, 5, Gerrit.RESOURCES.css().dataHeader()); |
| } |
| |
| void deleteChecked() { |
| final HashSet<RefRight.Key> refRightIds = new HashSet<RefRight.Key>(); |
| for (int row = 1; row < table.getRowCount(); row++) { |
| RefRight r = getRowItem(row); |
| if (r != null && table.getWidget(row, 1) instanceof CheckBox |
| && ((CheckBox) table.getWidget(row, 1)).getValue()) { |
| refRightIds.add(r.getKey()); |
| } |
| } |
| |
| GerritCallback<VoidResult> updateTable = |
| new GerritCallback<VoidResult>() { |
| @Override |
| public void onSuccess(final VoidResult result) { |
| for (int row = 1; row < table.getRowCount();) { |
| RefRight r = getRowItem(row); |
| if (r != null && refRightIds.contains(r.getKey())) { |
| table.removeRow(row); |
| } else { |
| row++; |
| } |
| } |
| } |
| }; |
| if (!refRightIds.isEmpty()) { |
| Util.PROJECT_SVC.deleteRight(projectName, refRightIds, updateTable); |
| } |
| } |
| |
| void display(final Map<AccountGroup.Id, AccountGroup> groups, |
| final List<RefRight> refRights) { |
| while (1 < table.getRowCount()) |
| table.removeRow(table.getRowCount() - 1); |
| |
| for (final RefRight r : refRights) { |
| final int row = table.getRowCount(); |
| table.insertRow(row); |
| applyDataRowStyle(row); |
| populate(row, groups, r); |
| } |
| } |
| |
| void populate(final int row, |
| final Map<AccountGroup.Id, AccountGroup> groups, final RefRight r) { |
| final GerritConfig config = Gerrit.getConfig(); |
| final ApprovalType ar = |
| config.getApprovalTypes().getApprovalType(r.getApprovalCategoryId()); |
| final AccountGroup group = groups.get(r.getAccountGroupId()); |
| |
| if (!projectName.equals(Gerrit.getConfig().getWildProject()) |
| && Gerrit.getConfig().getWildProject().equals(r.getProjectNameKey())) { |
| table.setText(row, 1, ""); |
| } else { |
| table.setWidget(row, 1, new CheckBox()); |
| } |
| |
| if (ar != null) { |
| table.setText(row, 2, ar.getCategory().getName()); |
| } else { |
| table.setText(row, 2, r.getApprovalCategoryId().get()); |
| } |
| |
| if (group != null) { |
| table.setText(row, 3, group.getName()); |
| } else { |
| table.setText(row, 3, Util.M.deletedGroup(r.getAccountGroupId().get())); |
| } |
| |
| table.setText(row, 4, r.getRefPattern()); |
| |
| { |
| final SafeHtmlBuilder m = new SafeHtmlBuilder(); |
| final ApprovalCategoryValue min, max; |
| min = ar != null ? ar.getValue(r.getMinValue()) : null; |
| max = ar != null ? ar.getValue(r.getMaxValue()) : null; |
| |
| formatValue(m, r.getMinValue(), min); |
| if (r.getMinValue() != r.getMaxValue()) { |
| m.br(); |
| formatValue(m, r.getMaxValue(), max); |
| } |
| SafeHtml.set(table, row, 5, m); |
| } |
| |
| final FlexCellFormatter fmt = table.getFlexCellFormatter(); |
| fmt.addStyleName(row, 1, Gerrit.RESOURCES.css().iconCell()); |
| fmt.addStyleName(row, 2, Gerrit.RESOURCES.css().dataCell()); |
| fmt.addStyleName(row, 3, Gerrit.RESOURCES.css().dataCell()); |
| fmt.addStyleName(row, 4, Gerrit.RESOURCES.css().dataCell()); |
| fmt.addStyleName(row, 5, Gerrit.RESOURCES.css().dataCell()); |
| fmt.addStyleName(row, 5, Gerrit.RESOURCES.css() |
| .projectAdminApprovalCategoryRangeLine()); |
| |
| setRowItem(row, r); |
| } |
| |
| private void formatValue(final SafeHtmlBuilder m, final short v, |
| final ApprovalCategoryValue e) { |
| m.openSpan(); |
| m |
| .setStyleName(Gerrit.RESOURCES.css() |
| .projectAdminApprovalCategoryValue()); |
| if (v == 0) { |
| m.append(' '); |
| } else if (v > 0) { |
| m.append('+'); |
| } |
| m.append(v); |
| m.closeSpan(); |
| if (e != null) { |
| m.append(": "); |
| m.append(e.getName()); |
| } |
| } |
| } |
| } |