Allow users to see what groups they are members of

Knowing what groups a user is in may help a site administrator debug
a specific user's access problems, and it may also help a project
owner to decide which group they want to give out some access for.

Bug: GERRIT-276
Change-Id: Ic06d8d5ba9d96354e47e8eda751c40b1fc360374
Signed-off-by: Shawn O. Pearce <sop@google.com>
This commit is contained in:
Shawn O. Pearce
2009-09-03 11:36:49 -07:00
parent 2f90a2bf2d
commit e04a97ffd2
11 changed files with 149 additions and 7 deletions

View File

@@ -51,6 +51,7 @@ public class Link implements ValueChangeHandler<String> {
public static final String SETTINGS = "settings"; public static final String SETTINGS = "settings";
public static final String SETTINGS_SSHKEYS = "settings,ssh-keys"; public static final String SETTINGS_SSHKEYS = "settings,ssh-keys";
public static final String SETTINGS_WEBIDENT = "settings,web-identities"; public static final String SETTINGS_WEBIDENT = "settings,web-identities";
public static final String SETTINGS_MYGROUPS = "settings,group-memberships";
public static final String SETTINGS_AGREEMENTS = "settings,agreements"; public static final String SETTINGS_AGREEMENTS = "settings,agreements";
public static final String SETTINGS_CONTACT = "settings,contact"; public static final String SETTINGS_CONTACT = "settings,contact";
public static final String SETTINGS_PROJECTS = "settings,projects"; public static final String SETTINGS_PROJECTS = "settings,projects";

View File

@@ -35,6 +35,7 @@ public interface AccountConstants extends Constants {
String tabContactInformation(); String tabContactInformation();
String tabSshKeys(); String tabSshKeys();
String tabWebIdentities(); String tabWebIdentities();
String tabMyGroups();
String tabAgreements(); String tabAgreements();
String buttonShowAddSshKey(); String buttonShowAddSshKey();

View File

@@ -15,6 +15,7 @@ tabPreferences = Preferences
tabContactInformation = Contact Information tabContactInformation = Contact Information
tabSshKeys = SSH Keys tabSshKeys = SSH Keys
tabWebIdentities = Identities tabWebIdentities = Identities
tabMyGroups = Groups
tabAgreements = Agreements tabAgreements = Agreements
buttonShowAddSshKey = Add Key ... buttonShowAddSshKey = Add Key ...

View File

@@ -16,6 +16,7 @@ package com.google.gerrit.client.account;
import com.google.gerrit.client.reviewdb.Account; import com.google.gerrit.client.reviewdb.Account;
import com.google.gerrit.client.reviewdb.AccountExternalId; import com.google.gerrit.client.reviewdb.AccountExternalId;
import com.google.gerrit.client.reviewdb.AccountGroup;
import com.google.gerrit.client.reviewdb.AccountSshKey; import com.google.gerrit.client.reviewdb.AccountSshKey;
import com.google.gerrit.client.reviewdb.ContactInformation; import com.google.gerrit.client.reviewdb.ContactInformation;
import com.google.gerrit.client.reviewdb.ContributorAgreement; import com.google.gerrit.client.reviewdb.ContributorAgreement;
@@ -44,6 +45,9 @@ public interface AccountSecurity extends RemoteJsonService {
@SignInRequired @SignInRequired
void myExternalIds(AsyncCallback<List<AccountExternalId>> callback); void myExternalIds(AsyncCallback<List<AccountExternalId>> callback);
@SignInRequired
void myGroups(AsyncCallback<List<AccountGroup>> callback);
@SignInRequired @SignInRequired
void deleteExternalIds(Set<AccountExternalId.Key> keys, void deleteExternalIds(Set<AccountExternalId.Key> keys,
AsyncCallback<Set<AccountExternalId.Key>> callback); AsyncCallback<Set<AccountExternalId.Key>> callback);

View File

@@ -128,6 +128,14 @@ public class AccountSettings extends AccountScreen {
}, Util.C.tabWebIdentities()); }, Util.C.tabWebIdentities());
tabTokens.add(Link.SETTINGS_WEBIDENT); tabTokens.add(Link.SETTINGS_WEBIDENT);
tabs.add(new LazyPanel() {
@Override
protected MyGroupsPanel createWidget() {
return new MyGroupsPanel();
}
}, Util.C.tabMyGroups());
tabTokens.add(Link.SETTINGS_MYGROUPS);
if (Gerrit.getConfig().isUseContributorAgreements()) { if (Gerrit.getConfig().isUseContributorAgreements()) {
tabs.add(new LazyPanel() { tabs.add(new LazyPanel() {
@Override @Override

View File

@@ -0,0 +1,50 @@
// Copyright (C) 2009 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.account;
import com.google.gerrit.client.admin.GroupTable;
import com.google.gerrit.client.reviewdb.AccountGroup;
import com.google.gerrit.client.rpc.GerritCallback;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlowPanel;
import java.util.List;
class MyGroupsPanel extends Composite {
private GroupTable groups;
MyGroupsPanel() {
final FlowPanel body = new FlowPanel();
groups = new GroupTable(false /* do not hyperlink to admin */);
body.add(groups);
initWidget(body);
}
@Override
protected void onLoad() {
super.onLoad();
refresh();
}
private void refresh() {
Util.ACCOUNT_SEC.myGroups(new GerritCallback<List<AccountGroup>>() {
public void onSuccess(final List<AccountGroup> result) {
groups.display(result);
}
});
}
}

View File

@@ -53,7 +53,7 @@ public class GroupListScreen extends AccountScreen {
super.onInitUI(); super.onInitUI();
setPageTitle(Util.C.groupListTitle()); setPageTitle(Util.C.groupListTitle());
groups = new GroupTable(Link.ADMIN_GROUPS); groups = new GroupTable(true /* hyperlink to admin */, Link.ADMIN_GROUPS);
add(groups); add(groups);
final VerticalPanel fp = new VerticalPanel(); final VerticalPanel fp = new VerticalPanel();

View File

@@ -29,11 +29,15 @@ import java.util.List;
public class GroupTable extends NavigationTable<AccountGroup> { public class GroupTable extends NavigationTable<AccountGroup> {
public GroupTable() { private final boolean enableLink;
this(null);
public GroupTable(final boolean enableLink) {
this(enableLink, null);
} }
public GroupTable(final String pointerId) { public GroupTable(final boolean enableLink, final String pointerId) {
this.enableLink = enableLink;
setSavePointerId(pointerId); setSavePointerId(pointerId);
keysNavigation.add(new PrevKeyCommand(0, 'k', Util.C.groupListPrev())); keysNavigation.add(new PrevKeyCommand(0, 'k', Util.C.groupListPrev()));
keysNavigation.add(new NextKeyCommand(0, 'j', Util.C.groupListNext())); keysNavigation.add(new NextKeyCommand(0, 'j', Util.C.groupListNext()));
@@ -82,8 +86,12 @@ public class GroupTable extends NavigationTable<AccountGroup> {
} }
void populate(final int row, final AccountGroup k) { void populate(final int row, final AccountGroup k) {
if (enableLink) {
table.setWidget(row, 1, new Hyperlink(k.getName(), Link.toAccountGroup(k table.setWidget(row, 1, new Hyperlink(k.getName(), Link.toAccountGroup(k
.getId()))); .getId())));
} else {
table.setText(row, 1, k.getName());
}
table.setText(row, 2, k.getDescription()); table.setText(row, 2, k.getDescription());
final FlexCellFormatter fmt = table.getFlexCellFormatter(); final FlexCellFormatter fmt = table.getFlexCellFormatter();

View File

@@ -31,6 +31,7 @@ public class AccountModule extends RpcServletModule {
factory(AgreementInfoFactory.Factory.class); factory(AgreementInfoFactory.Factory.class);
factory(ExternalIdDetailFactory.Factory.class); factory(ExternalIdDetailFactory.Factory.class);
factory(GroupDetailFactory.Factory.class); factory(GroupDetailFactory.Factory.class);
factory(MyGroupsFactory.Factory.class);
} }
}); });
rpc(AccountSecurityImpl.class); rpc(AccountSecurityImpl.class);

View File

@@ -18,6 +18,7 @@ import com.google.gerrit.client.account.AccountSecurity;
import com.google.gerrit.client.reviewdb.Account; import com.google.gerrit.client.reviewdb.Account;
import com.google.gerrit.client.reviewdb.AccountAgreement; import com.google.gerrit.client.reviewdb.AccountAgreement;
import com.google.gerrit.client.reviewdb.AccountExternalId; import com.google.gerrit.client.reviewdb.AccountExternalId;
import com.google.gerrit.client.reviewdb.AccountGroup;
import com.google.gerrit.client.reviewdb.AccountSshKey; import com.google.gerrit.client.reviewdb.AccountSshKey;
import com.google.gerrit.client.reviewdb.ContactInformation; import com.google.gerrit.client.reviewdb.ContactInformation;
import com.google.gerrit.client.reviewdb.ContributorAgreement; import com.google.gerrit.client.reviewdb.ContributorAgreement;
@@ -78,6 +79,7 @@ class AccountSecurityImpl extends BaseServiceImplementation implements
private final boolean useContactInfo; private final boolean useContactInfo;
private final ExternalIdDetailFactory.Factory externalIdDetailFactory; private final ExternalIdDetailFactory.Factory externalIdDetailFactory;
private final MyGroupsFactory.Factory myGroupsFactory;
@Inject @Inject
AccountSecurityImpl(final Provider<ReviewDb> schema, AccountSecurityImpl(final Provider<ReviewDb> schema,
@@ -86,7 +88,8 @@ class AccountSecurityImpl extends BaseServiceImplementation implements
final RegisterNewEmailSender.Factory esf, final SshKeyCache skc, final RegisterNewEmailSender.Factory esf, final SshKeyCache skc,
final AccountByEmailCache abec, final AccountCache uac, final AccountByEmailCache abec, final AccountCache uac,
final AccountManager am, final AccountManager am,
final ExternalIdDetailFactory.Factory externalIdDetailFactory) { final ExternalIdDetailFactory.Factory externalIdDetailFactory,
final MyGroupsFactory.Factory myGroupsFactory) {
super(schema, currentUser); super(schema, currentUser);
contactStore = cs; contactStore = cs;
authConfig = ac; authConfig = ac;
@@ -100,6 +103,7 @@ class AccountSecurityImpl extends BaseServiceImplementation implements
useContactInfo = contactStore != null && contactStore.isEnabled(); useContactInfo = contactStore != null && contactStore.isEnabled();
this.externalIdDetailFactory = externalIdDetailFactory; this.externalIdDetailFactory = externalIdDetailFactory;
this.myGroupsFactory = myGroupsFactory;
} }
public void mySshKeys(final AsyncCallback<List<AccountSshKey>> callback) { public void mySshKeys(final AsyncCallback<List<AccountSshKey>> callback) {
@@ -220,6 +224,11 @@ class AccountSecurityImpl extends BaseServiceImplementation implements
externalIdDetailFactory.create().to(callback); externalIdDetailFactory.create().to(callback);
} }
@Override
public void myGroups(final AsyncCallback<List<AccountGroup>> callback) {
myGroupsFactory.create().to(callback);
}
public void deleteExternalIds(final Set<AccountExternalId.Key> keys, public void deleteExternalIds(final Set<AccountExternalId.Key> keys,
final AsyncCallback<Set<AccountExternalId.Key>> callback) { final AsyncCallback<Set<AccountExternalId.Key>> callback) {
run(callback, new Action<Set<AccountExternalId.Key>>() { run(callback, new Action<Set<AccountExternalId.Key>>() {

View File

@@ -0,0 +1,59 @@
// Copyright (C) 2009 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.server.rpc.account;
import com.google.gerrit.client.reviewdb.AccountGroup;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.account.GroupCache;
import com.google.gerrit.server.rpc.Handler;
import com.google.inject.Inject;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
class MyGroupsFactory extends Handler<List<AccountGroup>> {
interface Factory {
MyGroupsFactory create();
}
private final GroupCache groupCache;
private final IdentifiedUser user;
@Inject
MyGroupsFactory(final GroupCache groupCache, final IdentifiedUser user) {
this.groupCache = groupCache;
this.user = user;
}
@Override
public List<AccountGroup> call() throws Exception {
final Set<AccountGroup.Id> effective = user.getEffectiveGroups();
final int cnt = effective.size();
final List<AccountGroup> groupList = new ArrayList<AccountGroup>(cnt);
for (final AccountGroup.Id groupId : effective) {
groupList.add(groupCache.get(groupId));
}
Collections.sort(groupList, new Comparator<AccountGroup>() {
@Override
public int compare(AccountGroup a, AccountGroup b) {
return a.getName().compareTo(b.getName());
}
});
return groupList;
}
}