Allow groups to be renamed if the user is an owner
Signed-off-by: Shawn O. Pearce <sop@google.com>
This commit is contained in:
@@ -27,6 +27,7 @@ public interface GerritConstants extends Constants {
|
||||
|
||||
String notFoundTitle();
|
||||
String notFoundBody();
|
||||
String nameAlreadyUsedBody();
|
||||
|
||||
String menuAll();
|
||||
String menuAllUnclaimedChanges();
|
||||
|
@@ -8,6 +8,7 @@ errorDialogClose = Close
|
||||
|
||||
notFoundTitle = Not Found
|
||||
notFoundBody = The page you requested was not found.
|
||||
nameAlreadyUsedBody = The name is already in use.
|
||||
|
||||
menuAll = All
|
||||
menuAllUnclaimedChanges = Unclaimed Changes
|
||||
|
@@ -48,8 +48,12 @@ public class AccountGroupScreen extends Screen {
|
||||
private AccountInfoCache accounts = AccountInfoCache.empty();
|
||||
private MemberTable members;
|
||||
|
||||
private TextBox groupNameTxt;
|
||||
private Button saveName;
|
||||
|
||||
private TextArea descTxt;
|
||||
private Button saveDesc;
|
||||
|
||||
private Button addMember;
|
||||
private TextBox nameTxtBox;
|
||||
private SuggestBox nameTxt;
|
||||
@@ -66,6 +70,7 @@ public class AccountGroupScreen extends Screen {
|
||||
}
|
||||
|
||||
enableForm(false);
|
||||
saveName.setEnabled(false);
|
||||
saveDesc.setEnabled(false);
|
||||
super.onLoad();
|
||||
|
||||
@@ -73,6 +78,7 @@ public class AccountGroupScreen extends Screen {
|
||||
new GerritCallback<AccountGroupDetail>() {
|
||||
public void onSuccess(final AccountGroupDetail result) {
|
||||
enableForm(true);
|
||||
saveName.setEnabled(false);
|
||||
saveDesc.setEnabled(false);
|
||||
display(result);
|
||||
}
|
||||
@@ -80,6 +86,7 @@ public class AccountGroupScreen extends Screen {
|
||||
}
|
||||
|
||||
private void enableForm(final boolean on) {
|
||||
groupNameTxt.setEnabled(on);
|
||||
descTxt.setEnabled(on);
|
||||
addMember.setEnabled(on);
|
||||
nameTxtBox.setEnabled(on);
|
||||
@@ -87,95 +94,123 @@ public class AccountGroupScreen extends Screen {
|
||||
}
|
||||
|
||||
private void initUI() {
|
||||
{
|
||||
final VerticalPanel vp = new VerticalPanel();
|
||||
final Label descHdr = new Label(Util.C.headingDescription());
|
||||
descHdr.setStyleName("gerrit-SmallHeading");
|
||||
vp.add(descHdr);
|
||||
initName();
|
||||
initDescription();
|
||||
initMemberList();
|
||||
}
|
||||
|
||||
descTxt = new TextArea();
|
||||
descTxt.setVisibleLines(6);
|
||||
descTxt.setCharacterWidth(60);
|
||||
new TextSaveButtonListener(descTxt, saveDesc);
|
||||
vp.add(descTxt);
|
||||
private void initName() {
|
||||
final VerticalPanel vp = new VerticalPanel();
|
||||
|
||||
saveDesc = new Button(Util.C.buttonSaveDescription());
|
||||
saveDesc.addClickListener(new ClickListener() {
|
||||
public void onClick(Widget sender) {
|
||||
final String txt = descTxt.getText().trim();
|
||||
Util.GROUP_SVC.changeGroupDescription(groupId, txt,
|
||||
new GerritCallback<VoidResult>() {
|
||||
public void onSuccess(final VoidResult result) {
|
||||
saveDesc.setEnabled(false);
|
||||
}
|
||||
});
|
||||
groupNameTxt = new TextBox();
|
||||
groupNameTxt.setVisibleLength(60);
|
||||
vp.add(groupNameTxt);
|
||||
|
||||
saveName = new Button(Util.C.buttonRenameGroup());
|
||||
saveName.addClickListener(new ClickListener() {
|
||||
public void onClick(Widget sender) {
|
||||
final String newName = groupNameTxt.getText().trim();
|
||||
Util.GROUP_SVC.renameGroup(groupId, newName,
|
||||
new GerritCallback<VoidResult>() {
|
||||
public void onSuccess(final VoidResult result) {
|
||||
saveName.setEnabled(false);
|
||||
setTitleText(Util.M.group(newName));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
vp.add(saveName);
|
||||
add(vp);
|
||||
|
||||
new TextSaveButtonListener(groupNameTxt, saveName);
|
||||
}
|
||||
|
||||
private void initDescription() {
|
||||
final VerticalPanel vp = new VerticalPanel();
|
||||
final Label descHdr = new Label(Util.C.headingDescription());
|
||||
descHdr.setStyleName("gerrit-SmallHeading");
|
||||
vp.add(descHdr);
|
||||
|
||||
descTxt = new TextArea();
|
||||
descTxt.setVisibleLines(6);
|
||||
descTxt.setCharacterWidth(60);
|
||||
vp.add(descTxt);
|
||||
|
||||
saveDesc = new Button(Util.C.buttonSaveDescription());
|
||||
saveDesc.addClickListener(new ClickListener() {
|
||||
public void onClick(Widget sender) {
|
||||
final String txt = descTxt.getText().trim();
|
||||
Util.GROUP_SVC.changeGroupDescription(groupId, txt,
|
||||
new GerritCallback<VoidResult>() {
|
||||
public void onSuccess(final VoidResult result) {
|
||||
saveDesc.setEnabled(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
vp.add(saveDesc);
|
||||
add(vp);
|
||||
|
||||
new TextSaveButtonListener(descTxt, saveDesc);
|
||||
}
|
||||
|
||||
private void initMemberList() {
|
||||
final Label memberHdr = new Label(Util.C.headingMembers());
|
||||
memberHdr.setStyleName("gerrit-SmallHeading");
|
||||
|
||||
final FlowPanel addPanel = new FlowPanel();
|
||||
addPanel.setStyleName("gerrit-ProjectWatchPanel-AddPanel");
|
||||
|
||||
nameTxtBox = new TextBox();
|
||||
nameTxt = new SuggestBox(new AccountSuggestOracle(), nameTxtBox);
|
||||
nameTxtBox.setVisibleLength(50);
|
||||
nameTxtBox.setText(Util.C.defaultAccountName());
|
||||
nameTxtBox.addStyleName("gerrit-InputFieldTypeHint");
|
||||
nameTxtBox.addFocusListener(new FocusListenerAdapter() {
|
||||
@Override
|
||||
public void onFocus(Widget sender) {
|
||||
if (Util.C.defaultAccountName().equals(nameTxtBox.getText())) {
|
||||
nameTxtBox.setText("");
|
||||
nameTxtBox.removeStyleName("gerrit-InputFieldTypeHint");
|
||||
}
|
||||
});
|
||||
vp.add(saveDesc);
|
||||
add(vp);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
final Label memberHdr = new Label(Util.C.headingMembers());
|
||||
memberHdr.setStyleName("gerrit-SmallHeading");
|
||||
add(memberHdr);
|
||||
}
|
||||
|
||||
{
|
||||
final FlowPanel fp = new FlowPanel();
|
||||
fp.setStyleName("gerrit-ProjectWatchPanel-AddPanel");
|
||||
|
||||
nameTxtBox = new TextBox();
|
||||
nameTxt = new SuggestBox(new AccountSuggestOracle(), nameTxtBox);
|
||||
nameTxtBox.setVisibleLength(50);
|
||||
nameTxtBox.setText(Util.C.defaultAccountName());
|
||||
nameTxtBox.addStyleName("gerrit-InputFieldTypeHint");
|
||||
nameTxtBox.addFocusListener(new FocusListenerAdapter() {
|
||||
@Override
|
||||
public void onFocus(Widget sender) {
|
||||
if (Util.C.defaultAccountName().equals(nameTxtBox.getText())) {
|
||||
nameTxtBox.setText("");
|
||||
nameTxtBox.removeStyleName("gerrit-InputFieldTypeHint");
|
||||
}
|
||||
@Override
|
||||
public void onLostFocus(Widget sender) {
|
||||
if ("".equals(nameTxtBox.getText())) {
|
||||
nameTxtBox.setText(Util.C.defaultAccountName());
|
||||
nameTxtBox.addStyleName("gerrit-InputFieldTypeHint");
|
||||
}
|
||||
}
|
||||
});
|
||||
addPanel.add(nameTxt);
|
||||
|
||||
@Override
|
||||
public void onLostFocus(Widget sender) {
|
||||
if ("".equals(nameTxtBox.getText())) {
|
||||
nameTxtBox.setText(Util.C.defaultAccountName());
|
||||
nameTxtBox.addStyleName("gerrit-InputFieldTypeHint");
|
||||
}
|
||||
}
|
||||
});
|
||||
fp.add(nameTxt);
|
||||
|
||||
addMember = new Button(Util.C.buttonAddGroupMember());
|
||||
addMember.addClickListener(new ClickListener() {
|
||||
public void onClick(final Widget sender) {
|
||||
doAddNew();
|
||||
}
|
||||
});
|
||||
fp.add(addMember);
|
||||
add(fp);
|
||||
}
|
||||
addMember = new Button(Util.C.buttonAddGroupMember());
|
||||
addMember.addClickListener(new ClickListener() {
|
||||
public void onClick(final Widget sender) {
|
||||
doAddNew();
|
||||
}
|
||||
});
|
||||
addPanel.add(addMember);
|
||||
|
||||
members = new MemberTable();
|
||||
|
||||
delMember = new Button(Util.C.buttonDeleteGroupMembers());
|
||||
delMember.addClickListener(new ClickListener() {
|
||||
public void onClick(final Widget sender) {
|
||||
members.deleteChecked();
|
||||
}
|
||||
});
|
||||
|
||||
add(memberHdr);
|
||||
add(addPanel);
|
||||
add(members);
|
||||
{
|
||||
final FlowPanel fp = new FlowPanel();
|
||||
delMember = new Button(Util.C.buttonDeleteGroupMembers());
|
||||
delMember.addClickListener(new ClickListener() {
|
||||
public void onClick(final Widget sender) {
|
||||
members.deleteChecked();
|
||||
}
|
||||
});
|
||||
fp.add(delMember);
|
||||
add(fp);
|
||||
}
|
||||
add(delMember);
|
||||
}
|
||||
|
||||
private void display(final AccountGroupDetail result) {
|
||||
setTitleText(Util.M.group(result.group.getName()));
|
||||
groupNameTxt.setText(result.group.getName());
|
||||
descTxt.setText(result.group.getDescription());
|
||||
accounts = result.accounts;
|
||||
members.display(result.members);
|
||||
|
@@ -22,6 +22,7 @@ public interface AdminConstants extends Constants {
|
||||
String buttonDeleteGroupMembers();
|
||||
String buttonAddGroupMember();
|
||||
String buttonSaveDescription();
|
||||
String buttonRenameGroup();
|
||||
|
||||
String headingDescription();
|
||||
String headingMembers();
|
||||
|
@@ -2,6 +2,7 @@ defaultAccountName = Name or Email
|
||||
|
||||
buttonDeleteGroupMembers = Delete
|
||||
buttonAddGroupMember = Add
|
||||
buttonRenameGroup = Rename Group
|
||||
buttonSaveDescription = Save Description
|
||||
|
||||
headingDescription = Description
|
||||
|
@@ -32,6 +32,10 @@ public interface GroupAdminService extends RemoteJsonService {
|
||||
void changeGroupDescription(AccountGroup.Id groupId, String description,
|
||||
AsyncCallback<VoidResult> callback);
|
||||
|
||||
@SignInRequired
|
||||
void renameGroup(AccountGroup.Id groupId, String newName,
|
||||
AsyncCallback<VoidResult> callback);
|
||||
|
||||
@SignInRequired
|
||||
void addGroupMember(AccountGroup.Id groupId, String nameOrEmail,
|
||||
AsyncCallback<AccountGroupDetail> callback);
|
||||
|
@@ -20,6 +20,7 @@ import com.google.gerrit.client.reviewdb.AccountGroup;
|
||||
import com.google.gerrit.client.reviewdb.AccountGroupMember;
|
||||
import com.google.gerrit.client.reviewdb.ReviewDb;
|
||||
import com.google.gerrit.client.rpc.BaseServiceImplementation;
|
||||
import com.google.gerrit.client.rpc.NameAlreadyUsedException;
|
||||
import com.google.gerrit.client.rpc.NoSuchEntityException;
|
||||
import com.google.gerrit.client.rpc.RpcUtil;
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
@@ -70,6 +71,28 @@ public class GroupAdminServiceImpl extends BaseServiceImplementation implements
|
||||
});
|
||||
}
|
||||
|
||||
public void renameGroup(final AccountGroup.Id groupId, final String newName,
|
||||
final AsyncCallback<VoidResult> callback) {
|
||||
run(callback, new Action<VoidResult>() {
|
||||
public VoidResult run(final ReviewDb db) throws OrmException, Failure {
|
||||
assertAmGroupOwner(db, groupId);
|
||||
final AccountGroup group = db.accountGroups().get(groupId);
|
||||
if (group == null) {
|
||||
throw new Failure(new NoSuchEntityException());
|
||||
}
|
||||
final AccountGroup.NameKey nameKey = new AccountGroup.NameKey(newName);
|
||||
if (!nameKey.equals(group.getNameKey())) {
|
||||
if (db.accountGroups().get(nameKey) != null) {
|
||||
throw new Failure(new NameAlreadyUsedException());
|
||||
}
|
||||
group.setNameKey(nameKey);
|
||||
db.accountGroups().update(Collections.singleton(group));
|
||||
}
|
||||
return VoidResult.INSTANCE;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void addGroupMember(final AccountGroup.Id groupId,
|
||||
final String nameOrEmail, final AsyncCallback<AccountGroupDetail> callback) {
|
||||
run(callback, new Action<AccountGroupDetail>() {
|
||||
|
@@ -100,6 +100,14 @@ public final class AccountGroup {
|
||||
return name.get();
|
||||
}
|
||||
|
||||
public AccountGroup.NameKey getNameKey() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setNameKey(final AccountGroup.NameKey nameKey) {
|
||||
name = nameKey;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
@@ -20,10 +20,10 @@ import com.google.gwtorm.client.PrimaryKey;
|
||||
import com.google.gwtorm.client.SecondaryKey;
|
||||
|
||||
public interface AccountGroupAccess extends
|
||||
Access<AccountGroup, AccountGroup.NameKey> {
|
||||
@PrimaryKey("name")
|
||||
AccountGroup get(AccountGroup.NameKey name) throws OrmException;
|
||||
|
||||
@SecondaryKey("groupId")
|
||||
Access<AccountGroup, AccountGroup.Id> {
|
||||
@PrimaryKey("groupId")
|
||||
AccountGroup get(AccountGroup.Id id) throws OrmException;
|
||||
|
||||
@SecondaryKey("name")
|
||||
AccountGroup get(AccountGroup.NameKey name) throws OrmException;
|
||||
}
|
||||
|
@@ -30,6 +30,9 @@ public abstract class GerritCallback<T> implements AsyncCallback<T> {
|
||||
} else if (isNoSuchEntity(caught)) {
|
||||
new ErrorDialog(Gerrit.C.notFoundBody()).center();
|
||||
|
||||
} else if (isNameAlreadyUsed(caught)) {
|
||||
new ErrorDialog(Gerrit.C.nameAlreadyUsedBody()).center();
|
||||
|
||||
} else if (caught instanceof ServerUnavailableException) {
|
||||
new ErrorDialog(RpcUtil.C.errorServerUnavailable()).center();
|
||||
|
||||
@@ -54,4 +57,12 @@ public abstract class GerritCallback<T> implements AsyncCallback<T> {
|
||||
return caught instanceof RemoteJsonException
|
||||
&& caught.getMessage().equals(NoSuchEntityException.MESSAGE);
|
||||
}
|
||||
|
||||
public static boolean isNameAlreadyUsed(final Throwable caught) {
|
||||
if (caught instanceof NameAlreadyUsedException) {
|
||||
return true;
|
||||
}
|
||||
return caught instanceof RemoteJsonException
|
||||
&& caught.getMessage().equals(NameAlreadyUsedException.MESSAGE);
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,24 @@
|
||||
// Copyright 2008 Google Inc.
|
||||
//
|
||||
// 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.rpc;
|
||||
|
||||
/** Error indicating entity name is already taken by another entity. */
|
||||
public class NameAlreadyUsedException extends Exception {
|
||||
public static final String MESSAGE = "Name Already Used";
|
||||
|
||||
public NameAlreadyUsedException() {
|
||||
super(MESSAGE);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user