Create two magical groups 'Anonymous Users' and 'Registered Users'
These groups represent everyone on Gerrit. Anonymous users is used for a user account when they are not yet signed in to the site. Registered users are used for any account which is signed in. Like the admin group, these groups are blessed by being marked in the system config table as the special groups. Since their membership is managed automatically by Gerrit we do not permit a group owner to edit the membership list in the web UI. We also don't show the membership, as the membership isn't stored in the database, its computed on the fly under the assumption that everyone is in either group if they have an Account.Id assigned. Signed-off-by: Shawn O. Pearce <sop@google.com>
This commit is contained in:
@@ -33,19 +33,28 @@ public class AccountGroupDetail {
|
||||
protected AccountGroup group;
|
||||
protected List<AccountGroupMember> members;
|
||||
protected AccountGroup ownerGroup;
|
||||
protected boolean autoGroup;
|
||||
|
||||
public AccountGroupDetail() {
|
||||
}
|
||||
|
||||
public void load(final ReviewDb db, final AccountInfoCacheFactory acc,
|
||||
final AccountGroup g) throws OrmException {
|
||||
final AccountGroup g, final boolean isAuto) throws OrmException {
|
||||
group = g;
|
||||
if (group.getId().equals(group.getOwnerGroupId())) {
|
||||
ownerGroup = group;
|
||||
} else {
|
||||
ownerGroup = db.accountGroups().get(group.getOwnerGroupId());
|
||||
}
|
||||
autoGroup = isAuto;
|
||||
|
||||
if (!autoGroup) {
|
||||
loadMembers(db, acc);
|
||||
}
|
||||
}
|
||||
|
||||
private void loadMembers(final ReviewDb db, final AccountInfoCacheFactory acc)
|
||||
throws OrmException {
|
||||
members = db.accountGroupMembers().byGroup(group.getId()).toList();
|
||||
for (final AccountGroupMember m : members) {
|
||||
acc.want(m.getAccountId());
|
||||
|
||||
@@ -31,6 +31,7 @@ import com.google.gwt.user.client.ui.ClickListener;
|
||||
import com.google.gwt.user.client.ui.FlowPanel;
|
||||
import com.google.gwt.user.client.ui.FocusListenerAdapter;
|
||||
import com.google.gwt.user.client.ui.Label;
|
||||
import com.google.gwt.user.client.ui.Panel;
|
||||
import com.google.gwt.user.client.ui.SourcesTableEvents;
|
||||
import com.google.gwt.user.client.ui.SuggestBox;
|
||||
import com.google.gwt.user.client.ui.TableListener;
|
||||
@@ -59,6 +60,7 @@ public class AccountGroupScreen extends AccountScreen {
|
||||
private TextArea descTxt;
|
||||
private Button saveDesc;
|
||||
|
||||
private Panel memberPanel;
|
||||
private Button addMember;
|
||||
private TextBox nameTxtBox;
|
||||
private SuggestBox nameTxt;
|
||||
@@ -241,10 +243,12 @@ public class AccountGroupScreen extends AccountScreen {
|
||||
}
|
||||
});
|
||||
|
||||
add(memberHdr);
|
||||
add(addPanel);
|
||||
add(members);
|
||||
add(delMember);
|
||||
memberPanel = new FlowPanel();
|
||||
memberPanel.add(memberHdr);
|
||||
memberPanel.add(addPanel);
|
||||
memberPanel.add(members);
|
||||
memberPanel.add(delMember);
|
||||
add(memberPanel);
|
||||
}
|
||||
|
||||
private void display(final AccountGroupDetail result) {
|
||||
@@ -252,9 +256,14 @@ public class AccountGroupScreen extends AccountScreen {
|
||||
groupNameTxt.setText(result.group.getName());
|
||||
ownerTxt.setText(result.ownerGroup.getName());
|
||||
descTxt.setText(result.group.getDescription());
|
||||
accounts = result.accounts;
|
||||
members.display(result.members);
|
||||
members.finishDisplay(true);
|
||||
if (result.autoGroup) {
|
||||
memberPanel.setVisible(false);
|
||||
} else {
|
||||
memberPanel.setVisible(true);
|
||||
accounts = result.accounts;
|
||||
members.display(result.members);
|
||||
members.finishDisplay(true);
|
||||
}
|
||||
}
|
||||
|
||||
void doAddNew() {
|
||||
|
||||
@@ -91,6 +91,14 @@ public final class SystemConfig {
|
||||
@Column
|
||||
public AccountGroup.Id adminGroupId;
|
||||
|
||||
/** Identity of the anonymous group, which permits anyone. */
|
||||
@Column
|
||||
public AccountGroup.Id anonymousGroupId;
|
||||
|
||||
/** Identity of the registered users group, which permits anyone. */
|
||||
@Column
|
||||
public AccountGroup.Id registeredGroupId;
|
||||
|
||||
protected SystemConfig() {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,11 +158,27 @@ public class GerritServer {
|
||||
admin.setDescription("Gerrit Site Administrators");
|
||||
c.accountGroups().insert(Collections.singleton(admin));
|
||||
|
||||
final AccountGroup anonymous =
|
||||
new AccountGroup(new AccountGroup.NameKey("Anonymous Users"),
|
||||
new AccountGroup.Id(c.nextAccountGroupId()));
|
||||
anonymous.setDescription("Any user, signed-in or not");
|
||||
anonymous.setOwnerGroupId(admin.getId());
|
||||
c.accountGroups().insert(Collections.singleton(anonymous));
|
||||
|
||||
final AccountGroup registered =
|
||||
new AccountGroup(new AccountGroup.NameKey("Registered Users"),
|
||||
new AccountGroup.Id(c.nextAccountGroupId()));
|
||||
registered.setDescription("Any signed-in user");
|
||||
registered.setOwnerGroupId(admin.getId());
|
||||
c.accountGroups().insert(Collections.singleton(registered));
|
||||
|
||||
final SystemConfig s = SystemConfig.create();
|
||||
s.xsrfPrivateKey = SignedToken.generateRandomKey();
|
||||
s.accountPrivateKey = SignedToken.generateRandomKey();
|
||||
s.sshdPort = 29418;
|
||||
s.adminGroupId = admin.getId();
|
||||
s.anonymousGroupId = anonymous.getId();
|
||||
s.registeredGroupId = registered.getId();
|
||||
c.systemConfig().insert(Collections.singleton(s));
|
||||
}
|
||||
|
||||
|
||||
@@ -108,7 +108,8 @@ public class GroupAdminServiceImpl extends BaseServiceImplementation implements
|
||||
}
|
||||
|
||||
final AccountGroupDetail d = new AccountGroupDetail();
|
||||
d.load(db, new AccountInfoCacheFactory(db), group);
|
||||
final boolean isAuto = groupCache.isAutoGroup(group.getId());
|
||||
d.load(db, new AccountInfoCacheFactory(db), group, isAuto);
|
||||
return d;
|
||||
}
|
||||
});
|
||||
@@ -181,6 +182,9 @@ public class GroupAdminServiceImpl extends BaseServiceImplementation implements
|
||||
run(callback, new Action<AccountGroupDetail>() {
|
||||
public AccountGroupDetail run(ReviewDb db) throws OrmException, Failure {
|
||||
assertAmGroupOwner(db, groupId);
|
||||
if (groupCache.isAutoGroup(groupId)) {
|
||||
throw new Failure(new NameAlreadyUsedException());
|
||||
}
|
||||
final Account a = findAccount(db, nameOrEmail);
|
||||
final AccountGroupMember.Key key =
|
||||
new AccountGroupMember.Key(a.getId(), groupId);
|
||||
|
||||
@@ -32,6 +32,8 @@ import java.util.Set;
|
||||
public class GroupCache {
|
||||
private final SchemaFactory<ReviewDb> schema;
|
||||
private AccountGroup.Id adminGroupId;
|
||||
private AccountGroup.Id anonymousGroupId;
|
||||
private AccountGroup.Id registeredGroupId;
|
||||
|
||||
private final LinkedHashMap<Account.Id, Set<AccountGroup.Id>> byAccount =
|
||||
new LinkedHashMap<Account.Id, Set<AccountGroup.Id>>(16, 0.75f, true) {
|
||||
@@ -45,6 +47,39 @@ public class GroupCache {
|
||||
protected GroupCache(final SchemaFactory<ReviewDb> rdf, final SystemConfig cfg) {
|
||||
schema = rdf;
|
||||
adminGroupId = cfg.adminGroupId;
|
||||
anonymousGroupId = cfg.anonymousGroupId;
|
||||
registeredGroupId = cfg.registeredGroupId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this group membership managed automatically by Gerrit?
|
||||
*
|
||||
* @param groupId the group to test.
|
||||
* @return true if Gerrit handles this group membership automatically; false
|
||||
* if it can be manually managed.
|
||||
*/
|
||||
public boolean isAutoGroup(final AccountGroup.Id groupId) {
|
||||
return isAnonymousUsers(groupId) || isRegisteredUsers(groupId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this group designate the magical 'Anonymous Users' group?
|
||||
*
|
||||
* @param groupId the group to test.
|
||||
* @return true if this is the magical 'Anonymous' group; false otherwise.
|
||||
*/
|
||||
public boolean isAnonymousUsers(final AccountGroup.Id groupId) {
|
||||
return anonymousGroupId.equals(groupId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this group designate the magical 'Registered Users' group?
|
||||
*
|
||||
* @param groupId the group to test.
|
||||
* @return true if this is the magical 'Registered' group; false otherwise.
|
||||
*/
|
||||
public boolean isRegisteredUsers(final AccountGroup.Id groupId) {
|
||||
return registeredGroupId.equals(groupId);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -67,8 +102,10 @@ public class GroupCache {
|
||||
*/
|
||||
public boolean isInGroup(final Account.Id accountId,
|
||||
final AccountGroup.Id groupId) {
|
||||
final Set<AccountGroup.Id> m = getGroups(accountId);
|
||||
return m.contains(groupId);
|
||||
if (isAnonymousUsers(groupId) || isRegisteredUsers(groupId)) {
|
||||
return true;
|
||||
}
|
||||
return getGroups(accountId).contains(groupId);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -88,6 +125,9 @@ public class GroupCache {
|
||||
* @param m the account-group pairing that was just inserted.
|
||||
*/
|
||||
public void notifyGroupAdd(final AccountGroupMember m) {
|
||||
if (isAutoGroup(m.getAccountGroupId())) {
|
||||
return;
|
||||
}
|
||||
synchronized (byAccount) {
|
||||
final Set<AccountGroup.Id> e = byAccount.get(m.getAccountId());
|
||||
if (e != null) {
|
||||
@@ -104,6 +144,9 @@ public class GroupCache {
|
||||
* @param m the account-group pairing that was just deleted.
|
||||
*/
|
||||
public void notifyGroupDelete(final AccountGroupMember m) {
|
||||
if (isAutoGroup(m.getAccountGroupId())) {
|
||||
return;
|
||||
}
|
||||
synchronized (byAccount) {
|
||||
final Set<AccountGroup.Id> e = byAccount.get(m.getAccountId());
|
||||
if (e != null) {
|
||||
@@ -137,15 +180,16 @@ public class GroupCache {
|
||||
accountId)) {
|
||||
m.add(g.getAccountGroupId());
|
||||
}
|
||||
m = Collections.unmodifiableSet(m);
|
||||
} finally {
|
||||
db.close();
|
||||
}
|
||||
} catch (OrmException e) {
|
||||
m = Collections.emptySet();
|
||||
m.clear();
|
||||
}
|
||||
m.add(anonymousGroupId);
|
||||
m.add(registeredGroupId);
|
||||
synchronized (byAccount) {
|
||||
byAccount.put(accountId, m);
|
||||
byAccount.put(accountId, Collections.unmodifiableSet(m));
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user