Merge "Make audit of account group membership changes pluggable"

This commit is contained in:
Saša Živkov
2014-07-28 15:56:58 +00:00
committed by Gerrit Code Review
13 changed files with 356 additions and 98 deletions

View File

@@ -15,6 +15,7 @@
package com.google.gerrit.httpd.rpc.account; package com.google.gerrit.httpd.rpc.account;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import com.google.gerrit.audit.AuditService;
import com.google.gerrit.common.ChangeHooks; import com.google.gerrit.common.ChangeHooks;
import com.google.gerrit.common.data.AccountSecurity; import com.google.gerrit.common.data.AccountSecurity;
import com.google.gerrit.common.data.ContributorAgreement; import com.google.gerrit.common.data.ContributorAgreement;
@@ -27,7 +28,6 @@ import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountExternalId; import com.google.gerrit.reviewdb.client.AccountExternalId;
import com.google.gerrit.reviewdb.client.AccountGroup; import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.AccountGroupMember; import com.google.gerrit.reviewdb.client.AccountGroupMember;
import com.google.gerrit.reviewdb.client.AccountGroupMemberAudit;
import com.google.gerrit.reviewdb.client.ContactInformation; import com.google.gerrit.reviewdb.client.ContactInformation;
import com.google.gerrit.reviewdb.server.ReviewDb; import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.CurrentUser; import com.google.gerrit.server.CurrentUser;
@@ -71,6 +71,7 @@ class AccountSecurityImpl extends BaseServiceImplementation implements
private final ChangeHooks hooks; private final ChangeHooks hooks;
private final GroupCache groupCache; private final GroupCache groupCache;
private final AuditService auditService;
@Inject @Inject
AccountSecurityImpl(final Provider<ReviewDb> schema, AccountSecurityImpl(final Provider<ReviewDb> schema,
@@ -82,7 +83,8 @@ class AccountSecurityImpl extends BaseServiceImplementation implements
final ChangeUserName.CurrentUser changeUserNameFactory, final ChangeUserName.CurrentUser changeUserNameFactory,
final DeleteExternalIds.Factory deleteExternalIdsFactory, final DeleteExternalIds.Factory deleteExternalIdsFactory,
final ExternalIdDetailFactory.Factory externalIdDetailFactory, final ExternalIdDetailFactory.Factory externalIdDetailFactory,
final ChangeHooks hooks, final GroupCache groupCache) { final ChangeHooks hooks, final GroupCache groupCache,
final AuditService auditService) {
super(schema, currentUser); super(schema, currentUser);
contactStore = cs; contactStore = cs;
realm = r; realm = r;
@@ -92,6 +94,7 @@ class AccountSecurityImpl extends BaseServiceImplementation implements
byEmailCache = abec; byEmailCache = abec;
accountCache = uac; accountCache = uac;
accountManager = am; accountManager = am;
this.auditService = auditService;
useContactInfo = contactStore != null && contactStore.isEnabled(); useContactInfo = contactStore != null && contactStore.isEnabled();
@@ -198,9 +201,8 @@ class AccountSecurityImpl extends BaseServiceImplementation implements
AccountGroupMember m = db.accountGroupMembers().get(key); AccountGroupMember m = db.accountGroupMembers().get(key);
if (m == null) { if (m == null) {
m = new AccountGroupMember(key); m = new AccountGroupMember(key);
db.accountGroupMembersAudit().insert( auditService.dispatchAddAccountsToGroup(account.getId(), Collections
Collections.singleton(new AccountGroupMemberAudit( .singleton(m));
m, account.getId(), TimeUtil.nowTs())));
db.accountGroupMembers().insert(Collections.singleton(m)); db.accountGroupMembers().insert(Collections.singleton(m));
accountCache.evict(m.getAccountId()); accountCache.evict(m.getAccountId());
} }

View File

@@ -22,6 +22,7 @@ public class AuditModule extends AbstractModule {
@Override @Override
protected void configure() { protected void configure() {
DynamicSet.setOf(binder(), AuditListener.class); DynamicSet.setOf(binder(), AuditListener.class);
DynamicSet.setOf(binder(), GroupMemberAuditListener.class);
bind(AuditService.class); bind(AuditService.class);
} }

View File

@@ -15,16 +15,30 @@
package com.google.gerrit.audit; package com.google.gerrit.audit;
import com.google.gerrit.extensions.registration.DynamicSet; import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountGroupById;
import com.google.gerrit.reviewdb.client.AccountGroupMember;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Singleton; import com.google.inject.Singleton;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.Collection;
@Singleton @Singleton
public class AuditService { public class AuditService {
private static final Logger log = LoggerFactory.getLogger(AuditService.class);
private final DynamicSet<AuditListener> auditListeners; private final DynamicSet<AuditListener> auditListeners;
private final DynamicSet<GroupMemberAuditListener> groupMemberAuditListeners;
@Inject @Inject
public AuditService(DynamicSet<AuditListener> auditListeners) { public AuditService(DynamicSet<AuditListener> auditListeners,
DynamicSet<GroupMemberAuditListener> groupMemberAuditListeners) {
this.auditListeners = auditListeners; this.auditListeners = auditListeners;
this.groupMemberAuditListeners = groupMemberAuditListeners;
} }
public void dispatch(AuditEvent action) { public void dispatch(AuditEvent action) {
@@ -32,4 +46,48 @@ public class AuditService {
auditListener.onAuditableAction(action); auditListener.onAuditableAction(action);
} }
} }
public void dispatchAddAccountsToGroup(Account.Id actor,
Collection<AccountGroupMember> added) {
for (GroupMemberAuditListener auditListener : groupMemberAuditListeners) {
try {
auditListener.onAddAccountsToGroup(actor, added);
} catch (RuntimeException e) {
log.error("failed to log add accounts to group event", e);
}
}
}
public void dispatchDeleteAccountsFromGroup(Account.Id actor,
Collection<AccountGroupMember> removed) {
for (GroupMemberAuditListener auditListener : groupMemberAuditListeners) {
try {
auditListener.onDeleteAccountsFromGroup(actor, removed);
} catch (RuntimeException e) {
log.error("failed to log delete accounts from group event", e);
}
}
}
public void dispatchAddGroupsToGroup(Account.Id actor,
Collection<AccountGroupById> added) {
for (GroupMemberAuditListener auditListener : groupMemberAuditListeners) {
try {
auditListener.onAddGroupsToGroup(actor, added);
} catch (RuntimeException e) {
log.error("failed to log add groups to group event", e);
}
}
}
public void dispatchDeleteGroupsFromGroup(Account.Id actor,
Collection<AccountGroupById> removed) {
for (GroupMemberAuditListener auditListener : groupMemberAuditListeners) {
try {
auditListener.onDeleteGroupsFromGroup(actor, removed);
} catch (RuntimeException e) {
log.error("failed to log delete groups from group event", e);
}
}
}
} }

View File

@@ -0,0 +1,37 @@
// Copyright (C) 2014 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.audit;
import com.google.gerrit.extensions.annotations.ExtensionPoint;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.Account.Id;
import com.google.gerrit.reviewdb.client.AccountGroupById;
import com.google.gerrit.reviewdb.client.AccountGroupMember;
import java.util.Collection;
@ExtensionPoint
public interface GroupMemberAuditListener {
void onAddAccountsToGroup(Account.Id actor,
Collection<AccountGroupMember> added);
void onDeleteAccountsFromGroup(Account.Id actor,
Collection<AccountGroupMember> removed);
void onAddGroupsToGroup(Id actor, Collection<AccountGroupById> added);
void onDeleteGroupsFromGroup(Id actor, Collection<AccountGroupById> deleted);
}

View File

@@ -14,6 +14,8 @@
package com.google.gerrit.server.account; package com.google.gerrit.server.account;
import com.google.gerrit.audit.AuditService;
import com.google.gerrit.common.auth.openid.OpenIdUrls;
import com.google.gerrit.common.data.AccessSection; import com.google.gerrit.common.data.AccessSection;
import com.google.gerrit.common.data.GlobalCapability; import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.common.data.Permission; import com.google.gerrit.common.data.Permission;
@@ -23,7 +25,6 @@ import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountExternalId; import com.google.gerrit.reviewdb.client.AccountExternalId;
import com.google.gerrit.reviewdb.client.AccountGroup; import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.AccountGroupMember; import com.google.gerrit.reviewdb.client.AccountGroupMember;
import com.google.gerrit.reviewdb.client.AccountGroupMemberAudit;
import com.google.gerrit.reviewdb.server.ReviewDb; import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.IdentifiedUser; import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.project.ProjectCache; import com.google.gerrit.server.project.ProjectCache;
@@ -53,6 +54,7 @@ public class AccountManager {
private final ChangeUserName.Factory changeUserNameFactory; private final ChangeUserName.Factory changeUserNameFactory;
private final ProjectCache projectCache; private final ProjectCache projectCache;
private final AtomicBoolean awaitsFirstAccountCheck; private final AtomicBoolean awaitsFirstAccountCheck;
private final AuditService auditService;
@Inject @Inject
AccountManager(final SchemaFactory<ReviewDb> schema, AccountManager(final SchemaFactory<ReviewDb> schema,
@@ -60,7 +62,8 @@ public class AccountManager {
final Realm accountMapper, final Realm accountMapper,
final IdentifiedUser.GenericFactory userFactory, final IdentifiedUser.GenericFactory userFactory,
final ChangeUserName.Factory changeUserNameFactory, final ChangeUserName.Factory changeUserNameFactory,
final ProjectCache projectCache) throws OrmException { final ProjectCache projectCache,
final AuditService auditService) throws OrmException {
this.schema = schema; this.schema = schema;
this.byIdCache = byIdCache; this.byIdCache = byIdCache;
this.byEmailCache = byEmailCache; this.byEmailCache = byEmailCache;
@@ -69,6 +72,7 @@ public class AccountManager {
this.changeUserNameFactory = changeUserNameFactory; this.changeUserNameFactory = changeUserNameFactory;
this.projectCache = projectCache; this.projectCache = projectCache;
this.awaitsFirstAccountCheck = new AtomicBoolean(true); this.awaitsFirstAccountCheck = new AtomicBoolean(true);
this.auditService = auditService;
} }
/** /**
@@ -227,8 +231,7 @@ public class AccountManager {
final AccountGroup.Id adminId = g.getId(); final AccountGroup.Id adminId = g.getId();
final AccountGroupMember m = final AccountGroupMember m =
new AccountGroupMember(new AccountGroupMember.Key(newId, adminId)); new AccountGroupMember(new AccountGroupMember.Key(newId, adminId));
db.accountGroupMembersAudit().insert(Collections.singleton( auditService.dispatchAddAccountsToGroup(newId, Collections.singleton(m));
new AccountGroupMemberAudit(m, newId, TimeUtil.nowTs())));
db.accountGroupMembers().insert(Collections.singleton(m)); db.accountGroupMembers().insert(Collections.singleton(m));
} }

View File

@@ -15,6 +15,7 @@
package com.google.gerrit.server.account; package com.google.gerrit.server.account;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.google.gerrit.audit.AuditService;
import com.google.gerrit.common.data.GlobalCapability; import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.common.data.GroupDescriptions; import com.google.gerrit.common.data.GroupDescriptions;
import com.google.gerrit.common.errors.InvalidSshKeyException; import com.google.gerrit.common.errors.InvalidSshKeyException;
@@ -30,7 +31,6 @@ import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountExternalId; import com.google.gerrit.reviewdb.client.AccountExternalId;
import com.google.gerrit.reviewdb.client.AccountGroup; import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.AccountGroupMember; import com.google.gerrit.reviewdb.client.AccountGroupMember;
import com.google.gerrit.reviewdb.client.AccountGroupMemberAudit;
import com.google.gerrit.reviewdb.client.AccountSshKey; import com.google.gerrit.reviewdb.client.AccountSshKey;
import com.google.gerrit.reviewdb.server.ReviewDb; import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.IdentifiedUser; import com.google.gerrit.server.IdentifiedUser;
@@ -74,13 +74,14 @@ public class CreateAccount implements RestModifyView<TopLevelResource, Input> {
private final AccountByEmailCache byEmailCache; private final AccountByEmailCache byEmailCache;
private final AccountInfo.Loader.Factory infoLoader; private final AccountInfo.Loader.Factory infoLoader;
private final String username; private final String username;
private final AuditService auditService;
@Inject @Inject
CreateAccount(ReviewDb db, Provider<IdentifiedUser> currentUser, CreateAccount(ReviewDb db, Provider<IdentifiedUser> currentUser,
GroupsCollection groupsCollection, SshKeyCache sshKeyCache, GroupsCollection groupsCollection, SshKeyCache sshKeyCache,
AccountCache accountCache, AccountByEmailCache byEmailCache, AccountCache accountCache, AccountByEmailCache byEmailCache,
AccountInfo.Loader.Factory infoLoader, AccountInfo.Loader.Factory infoLoader,
@Assisted String username) { @Assisted String username, AuditService auditService) {
this.db = db; this.db = db;
this.currentUser = currentUser; this.currentUser = currentUser;
this.groupsCollection = groupsCollection; this.groupsCollection = groupsCollection;
@@ -89,6 +90,7 @@ public class CreateAccount implements RestModifyView<TopLevelResource, Input> {
this.byEmailCache = byEmailCache; this.byEmailCache = byEmailCache;
this.infoLoader = infoLoader; this.infoLoader = infoLoader;
this.username = username; this.username = username;
this.auditService = auditService;
} }
@Override @Override
@@ -169,9 +171,8 @@ public class CreateAccount implements RestModifyView<TopLevelResource, Input> {
for (AccountGroup.Id groupId : groups) { for (AccountGroup.Id groupId : groups) {
AccountGroupMember m = AccountGroupMember m =
new AccountGroupMember(new AccountGroupMember.Key(id, groupId)); new AccountGroupMember(new AccountGroupMember.Key(id, groupId));
db.accountGroupMembersAudit().insert(Collections.singleton( auditService.dispatchAddAccountsToGroup(currentUser.get().getAccountId(),
new AccountGroupMemberAudit( Collections.singleton(m));
m, currentUser.get().getAccountId(), TimeUtil.nowTs())));
db.accountGroupMembers().insert(Collections.singleton(m)); db.accountGroupMembers().insert(Collections.singleton(m));
} }

View File

@@ -14,19 +14,17 @@
package com.google.gerrit.server.account; package com.google.gerrit.server.account;
import com.google.gerrit.audit.AuditService;
import com.google.gerrit.common.errors.NameAlreadyUsedException; import com.google.gerrit.common.errors.NameAlreadyUsedException;
import com.google.gerrit.common.errors.PermissionDeniedException; import com.google.gerrit.common.errors.PermissionDeniedException;
import com.google.gerrit.reviewdb.client.Account; import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountGroup; import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.AccountGroupById; import com.google.gerrit.reviewdb.client.AccountGroupById;
import com.google.gerrit.reviewdb.client.AccountGroupByIdAud;
import com.google.gerrit.reviewdb.client.AccountGroupMember; import com.google.gerrit.reviewdb.client.AccountGroupMember;
import com.google.gerrit.reviewdb.client.AccountGroupMemberAudit;
import com.google.gerrit.reviewdb.client.AccountGroupName; import com.google.gerrit.reviewdb.client.AccountGroupName;
import com.google.gerrit.reviewdb.server.ReviewDb; import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.GerritPersonIdent; import com.google.gerrit.server.GerritPersonIdent;
import com.google.gerrit.server.IdentifiedUser; import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.util.TimeUtil;
import com.google.gwtorm.server.OrmDuplicateKeyException; import com.google.gwtorm.server.OrmDuplicateKeyException;
import com.google.gwtorm.server.OrmException; import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject; import com.google.inject.Inject;
@@ -52,12 +50,13 @@ public class PerformCreateGroup {
private final PersonIdent serverIdent; private final PersonIdent serverIdent;
private final GroupCache groupCache; private final GroupCache groupCache;
private final CreateGroupArgs createGroupArgs; private final CreateGroupArgs createGroupArgs;
private final AuditService auditService;
@Inject @Inject
PerformCreateGroup(ReviewDb db, AccountCache accountCache, PerformCreateGroup(ReviewDb db, AccountCache accountCache,
GroupIncludeCache groupIncludeCache, IdentifiedUser currentUser, GroupIncludeCache groupIncludeCache, IdentifiedUser currentUser,
@GerritPersonIdent PersonIdent serverIdent, GroupCache groupCache, @GerritPersonIdent PersonIdent serverIdent, GroupCache groupCache,
@Assisted CreateGroupArgs createGroupArgs) { @Assisted CreateGroupArgs createGroupArgs, AuditService auditService) {
this.db = db; this.db = db;
this.accountCache = accountCache; this.accountCache = accountCache;
this.groupIncludeCache = groupIncludeCache; this.groupIncludeCache = groupIncludeCache;
@@ -65,6 +64,7 @@ public class PerformCreateGroup {
this.serverIdent = serverIdent; this.serverIdent = serverIdent;
this.groupCache = groupCache; this.groupCache = groupCache;
this.createGroupArgs = createGroupArgs; this.createGroupArgs = createGroupArgs;
this.auditService = auditService;
} }
/** /**
@@ -127,18 +127,13 @@ public class PerformCreateGroup {
private void addMembers(final AccountGroup.Id groupId, private void addMembers(final AccountGroup.Id groupId,
final Collection<? extends Account.Id> members) throws OrmException { final Collection<? extends Account.Id> members) throws OrmException {
List<AccountGroupMember> memberships = new ArrayList<>(); List<AccountGroupMember> memberships = new ArrayList<>();
List<AccountGroupMemberAudit> membershipsAudit = new ArrayList<>();
for (Account.Id accountId : members) { for (Account.Id accountId : members) {
final AccountGroupMember membership = final AccountGroupMember membership =
new AccountGroupMember(new AccountGroupMember.Key(accountId, groupId)); new AccountGroupMember(new AccountGroupMember.Key(accountId, groupId));
memberships.add(membership); memberships.add(membership);
final AccountGroupMemberAudit audit = new AccountGroupMemberAudit(
membership, currentUser.getAccountId(), TimeUtil.nowTs());
membershipsAudit.add(audit);
} }
db.accountGroupMembers().insert(memberships); db.accountGroupMembers().insert(memberships);
db.accountGroupMembersAudit().insert(membershipsAudit); auditService.dispatchAddAccountsToGroup(currentUser.getAccountId(), memberships);
for (Account.Id accountId : members) { for (Account.Id accountId : members) {
accountCache.evict(accountId); accountCache.evict(accountId);
@@ -148,18 +143,13 @@ public class PerformCreateGroup {
private void addGroups(final AccountGroup.Id groupId, private void addGroups(final AccountGroup.Id groupId,
final Collection<? extends AccountGroup.UUID> groups) throws OrmException { final Collection<? extends AccountGroup.UUID> groups) throws OrmException {
List<AccountGroupById> includeList = new ArrayList<>(); List<AccountGroupById> includeList = new ArrayList<>();
List<AccountGroupByIdAud> includesAudit = new ArrayList<>();
for (AccountGroup.UUID includeUUID : groups) { for (AccountGroup.UUID includeUUID : groups) {
final AccountGroupById groupInclude = final AccountGroupById groupInclude =
new AccountGroupById(new AccountGroupById.Key(groupId, includeUUID)); new AccountGroupById(new AccountGroupById.Key(groupId, includeUUID));
includeList.add(groupInclude); includeList.add(groupInclude);
final AccountGroupByIdAud audit = new AccountGroupByIdAud(
groupInclude, currentUser.getAccountId(), TimeUtil.nowTs());
includesAudit.add(audit);
} }
db.accountGroupById().insert(includeList); db.accountGroupById().insert(includeList);
db.accountGroupByIdAud().insert(includesAudit); auditService.dispatchAddGroupsToGroup(currentUser.getAccountId(), includeList);
for (AccountGroup.UUID uuid : groups) { for (AccountGroup.UUID uuid : groups) {
groupIncludeCache.evictMemberIn(uuid); groupIncludeCache.evictMemberIn(uuid);

View File

@@ -18,6 +18,7 @@ import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.gerrit.audit.AuditService;
import com.google.gerrit.common.data.GroupDescription; import com.google.gerrit.common.data.GroupDescription;
import com.google.gerrit.extensions.restapi.AuthException; import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.DefaultInput; import com.google.gerrit.extensions.restapi.DefaultInput;
@@ -27,14 +28,12 @@ import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
import com.google.gerrit.reviewdb.client.Account; import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountGroup; import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.AccountGroupById; import com.google.gerrit.reviewdb.client.AccountGroupById;
import com.google.gerrit.reviewdb.client.AccountGroupByIdAud;
import com.google.gerrit.reviewdb.server.ReviewDb; import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.IdentifiedUser; import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.account.GroupControl; import com.google.gerrit.server.account.GroupControl;
import com.google.gerrit.server.account.GroupIncludeCache; import com.google.gerrit.server.account.GroupIncludeCache;
import com.google.gerrit.server.group.AddIncludedGroups.Input; import com.google.gerrit.server.group.AddIncludedGroups.Input;
import com.google.gerrit.server.group.GroupJson.GroupInfo; import com.google.gerrit.server.group.GroupJson.GroupInfo;
import com.google.gerrit.server.util.TimeUtil;
import com.google.gwtorm.server.OrmException; import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Provider; import com.google.inject.Provider;
@@ -75,15 +74,17 @@ public class AddIncludedGroups implements RestModifyView<GroupResource, Input> {
private final GroupIncludeCache groupIncludeCache; private final GroupIncludeCache groupIncludeCache;
private final Provider<ReviewDb> db; private final Provider<ReviewDb> db;
private final GroupJson json; private final GroupJson json;
private final AuditService auditService;
@Inject @Inject
public AddIncludedGroups(GroupsCollection groupsCollection, public AddIncludedGroups(GroupsCollection groupsCollection,
GroupIncludeCache groupIncludeCache, GroupIncludeCache groupIncludeCache, Provider<ReviewDb> db,
Provider<ReviewDb> db, GroupJson json) { GroupJson json, AuditService auditService) {
this.groupsCollection = groupsCollection; this.groupsCollection = groupsCollection;
this.groupIncludeCache = groupIncludeCache; this.groupIncludeCache = groupIncludeCache;
this.db = db; this.db = db;
this.json = json; this.json = json;
this.auditService = auditService;
} }
@Override @Override
@@ -98,7 +99,6 @@ public class AddIncludedGroups implements RestModifyView<GroupResource, Input> {
GroupControl control = resource.getControl(); GroupControl control = resource.getControl();
Map<AccountGroup.UUID, AccountGroupById> newIncludedGroups = Maps.newHashMap(); Map<AccountGroup.UUID, AccountGroupById> newIncludedGroups = Maps.newHashMap();
List<AccountGroupByIdAud> newIncludedGroupsAudits = Lists.newLinkedList();
List<GroupInfo> result = Lists.newLinkedList(); List<GroupInfo> result = Lists.newLinkedList();
Account.Id me = ((IdentifiedUser) control.getCurrentUser()).getAccountId(); Account.Id me = ((IdentifiedUser) control.getCurrentUser()).getAccountId();
@@ -117,15 +117,13 @@ public class AddIncludedGroups implements RestModifyView<GroupResource, Input> {
if (agi == null) { if (agi == null) {
agi = new AccountGroupById(agiKey); agi = new AccountGroupById(agiKey);
newIncludedGroups.put(d.getGroupUUID(), agi); newIncludedGroups.put(d.getGroupUUID(), agi);
newIncludedGroupsAudits.add(
new AccountGroupByIdAud(agi, me, TimeUtil.nowTs()));
} }
} }
result.add(json.format(d)); result.add(json.format(d));
} }
if (!newIncludedGroups.isEmpty()) { if (!newIncludedGroups.isEmpty()) {
db.get().accountGroupByIdAud().insert(newIncludedGroupsAudits); auditService.dispatchAddGroupsToGroup(me, newIncludedGroups.values());
db.get().accountGroupById().insert(newIncludedGroups.values()); db.get().accountGroupById().insert(newIncludedGroups.values());
for (AccountGroupById agi : newIncludedGroups.values()) { for (AccountGroupById agi : newIncludedGroups.values()) {
groupIncludeCache.evictMemberIn(agi.getIncludeUUID()); groupIncludeCache.evictMemberIn(agi.getIncludeUUID());

View File

@@ -17,6 +17,7 @@ package com.google.gerrit.server.group;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.gerrit.audit.AuditService;
import com.google.gerrit.extensions.restapi.AuthException; import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.DefaultInput; import com.google.gerrit.extensions.restapi.DefaultInput;
import com.google.gerrit.extensions.restapi.MethodNotAllowedException; import com.google.gerrit.extensions.restapi.MethodNotAllowedException;
@@ -25,7 +26,6 @@ import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
import com.google.gerrit.reviewdb.client.Account; import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountGroup; import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.AccountGroupMember; import com.google.gerrit.reviewdb.client.AccountGroupMember;
import com.google.gerrit.reviewdb.client.AccountGroupMemberAudit;
import com.google.gerrit.reviewdb.client.AuthType; import com.google.gerrit.reviewdb.client.AuthType;
import com.google.gerrit.reviewdb.server.ReviewDb; import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.IdentifiedUser; import com.google.gerrit.server.IdentifiedUser;
@@ -39,7 +39,6 @@ import com.google.gerrit.server.account.AuthRequest;
import com.google.gerrit.server.account.GroupControl; import com.google.gerrit.server.account.GroupControl;
import com.google.gerrit.server.config.AuthConfig; import com.google.gerrit.server.config.AuthConfig;
import com.google.gerrit.server.group.AddMembers.Input; import com.google.gerrit.server.group.AddMembers.Input;
import com.google.gerrit.server.util.TimeUtil;
import com.google.gwtorm.server.OrmException; import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Provider; import com.google.inject.Provider;
@@ -82,6 +81,7 @@ public class AddMembers implements RestModifyView<GroupResource, Input> {
private final AccountCache accountCache; private final AccountCache accountCache;
private final AccountInfo.Loader.Factory infoFactory; private final AccountInfo.Loader.Factory infoFactory;
private final Provider<ReviewDb> db; private final Provider<ReviewDb> db;
private final AuditService auditService;
@Inject @Inject
AddMembers(AccountManager accountManager, AddMembers(AccountManager accountManager,
@@ -90,8 +90,10 @@ public class AddMembers implements RestModifyView<GroupResource, Input> {
AccountResolver accountResolver, AccountResolver accountResolver,
AccountCache accountCache, AccountCache accountCache,
AccountInfo.Loader.Factory infoFactory, AccountInfo.Loader.Factory infoFactory,
Provider<ReviewDb> db) { Provider<ReviewDb> db,
AuditService auditService) {
this.accountManager = accountManager; this.accountManager = accountManager;
this.auditService = auditService;
this.authType = authConfig.getAuthType(); this.authType = authConfig.getAuthType();
this.accounts = accounts; this.accounts = accounts;
this.accountResolver = accountResolver; this.accountResolver = accountResolver;
@@ -112,7 +114,6 @@ public class AddMembers implements RestModifyView<GroupResource, Input> {
GroupControl control = resource.getControl(); GroupControl control = resource.getControl();
Map<Account.Id, AccountGroupMember> newAccountGroupMembers = Maps.newHashMap(); Map<Account.Id, AccountGroupMember> newAccountGroupMembers = Maps.newHashMap();
List<AccountGroupMemberAudit> newAccountGroupMemberAudits = Lists.newLinkedList();
List<AccountInfo> result = Lists.newLinkedList(); List<AccountInfo> result = Lists.newLinkedList();
Account.Id me = ((IdentifiedUser) control.getCurrentUser()).getAccountId(); Account.Id me = ((IdentifiedUser) control.getCurrentUser()).getAccountId();
AccountInfo.Loader loader = infoFactory.create(true); AccountInfo.Loader loader = infoFactory.create(true);
@@ -135,14 +136,12 @@ public class AddMembers implements RestModifyView<GroupResource, Input> {
if (m == null) { if (m == null) {
m = new AccountGroupMember(key); m = new AccountGroupMember(key);
newAccountGroupMembers.put(m.getAccountId(), m); newAccountGroupMembers.put(m.getAccountId(), m);
newAccountGroupMemberAudits.add(
new AccountGroupMemberAudit(m, me, TimeUtil.nowTs()));
} }
} }
result.add(loader.get(a.getId())); result.add(loader.get(a.getId()));
} }
db.get().accountGroupMembersAudit().insert(newAccountGroupMemberAudits); auditService.dispatchAddAccountsToGroup(me, newAccountGroupMembers.values());
db.get().accountGroupMembers().insert(newAccountGroupMembers.values()); db.get().accountGroupMembers().insert(newAccountGroupMembers.values());
for (AccountGroupMember m : newAccountGroupMembers.values()) { for (AccountGroupMember m : newAccountGroupMembers.values()) {
accountCache.evict(m.getAccountId()); accountCache.evict(m.getAccountId());

View File

@@ -0,0 +1,201 @@
// Copyright (C) 2014 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.group;
import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.google.gerrit.audit.GroupMemberAuditListener;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.AccountGroupById;
import com.google.gerrit.reviewdb.client.AccountGroupByIdAud;
import com.google.gerrit.reviewdb.client.AccountGroupMember;
import com.google.gerrit.reviewdb.client.AccountGroupMemberAudit;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.account.AccountCache;
import com.google.gerrit.server.account.GroupCache;
import com.google.gerrit.server.account.UniversalGroupBackend;
import com.google.gerrit.server.util.TimeUtil;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
import org.slf4j.Logger;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
class DbGroupMemberAuditListener implements GroupMemberAuditListener {
private static final Logger log = org.slf4j.LoggerFactory
.getLogger(DbGroupMemberAuditListener.class);
private final Provider<ReviewDb> db;
private final AccountCache accountCache;
private final GroupCache groupCache;
private final UniversalGroupBackend groupBackend;
@Inject
public DbGroupMemberAuditListener(Provider<ReviewDb> db,
AccountCache accountCache, GroupCache groupCache,
UniversalGroupBackend groupBackend) {
this.db = db;
this.accountCache = accountCache;
this.groupCache = groupCache;
this.groupBackend = groupBackend;
}
@Override
public void onAddAccountsToGroup(Account.Id me,
Collection<AccountGroupMember> added) {
List<AccountGroupMemberAudit> auditInserts = Lists.newLinkedList();
for (AccountGroupMember m : added) {
AccountGroupMemberAudit audit =
new AccountGroupMemberAudit(m, me, TimeUtil.nowTs());
auditInserts.add(audit);
}
try {
db.get().accountGroupMembersAudit().insert(auditInserts);
} catch (OrmException e) {
logOrmExceptionForAccounts(
"Cannot log add accounts to group event performed by user", me,
added, e);
}
}
@Override
public void onDeleteAccountsFromGroup(Account.Id me,
Collection<AccountGroupMember> removed) {
List<AccountGroupMemberAudit> auditInserts = Lists.newLinkedList();
List<AccountGroupMemberAudit> auditUpdates = Lists.newLinkedList();
ReviewDb reviewDB = db.get();
try {
for (AccountGroupMember m : removed) {
AccountGroupMemberAudit audit = null;
for (AccountGroupMemberAudit a : reviewDB.accountGroupMembersAudit()
.byGroupAccount(m.getAccountGroupId(), m.getAccountId())) {
if (a.isActive()) {
audit = a;
break;
}
}
if (audit != null) {
audit.removed(me, TimeUtil.nowTs());
auditUpdates.add(audit);
} else {
audit = new AccountGroupMemberAudit(m, me, TimeUtil.nowTs());
audit.removedLegacy();
auditInserts.add(audit);
}
}
reviewDB.accountGroupMembersAudit().update(auditUpdates);
reviewDB.accountGroupMembersAudit().insert(auditInserts);
} catch (OrmException e) {
logOrmExceptionForAccounts(
"Cannot log delete accounts from group event performed by user", me,
removed, e);
}
}
@Override
public void onAddGroupsToGroup(Account.Id me,
Collection<AccountGroupById> added) {
List<AccountGroupByIdAud> includesAudit = new ArrayList<>();
for (AccountGroupById groupInclude : added) {
AccountGroupByIdAud audit =
new AccountGroupByIdAud(groupInclude, me, TimeUtil.nowTs());
includesAudit.add(audit);
}
try {
db.get().accountGroupByIdAud().insert(includesAudit);
} catch (OrmException e) {
logOrmExceptionForGroups(
"Cannot log add groups to group event performed by user", me, added,
e);
}
}
@Override
public void onDeleteGroupsFromGroup(Account.Id me,
Collection<AccountGroupById> removed) {
final List<AccountGroupByIdAud> auditUpdates = Lists.newLinkedList();
try {
for (final AccountGroupById g : removed) {
AccountGroupByIdAud audit = null;
for (AccountGroupByIdAud a : db.get().accountGroupByIdAud()
.byGroupInclude(g.getGroupId(), g.getIncludeUUID())) {
if (a.isActive()) {
audit = a;
break;
}
}
if (audit != null) {
audit.removed(me, TimeUtil.nowTs());
auditUpdates.add(audit);
}
}
db.get().accountGroupByIdAud().update(auditUpdates);
} catch (OrmException e) {
logOrmExceptionForGroups(
"Cannot log delete groups from group event performed by user", me,
removed, e);
}
}
private void logOrmExceptionForAccounts(String header, Account.Id me,
Collection<AccountGroupMember> values, OrmException e) {
List<String> descriptions = new ArrayList<>();
for (AccountGroupMember m : values) {
Account.Id accountId = m.getAccountId();
String userName = accountCache.get(accountId).getUserName();
AccountGroup.Id groupId = m.getAccountGroupId();
String groupName = groupCache.get(groupId).getName();
descriptions.add(MessageFormat.format("account {0}/{1}, group {2}/{3}",
accountId, userName, groupId, groupName));
}
logOrmException(header, me, descriptions, e);
}
private void logOrmExceptionForGroups(String header, Account.Id me,
Collection<AccountGroupById> values, OrmException e) {
List<String> descriptions = new ArrayList<>();
for (AccountGroupById m : values) {
AccountGroup.UUID groupUuid = m.getIncludeUUID();
String groupName = groupBackend.get(groupUuid).getName();
AccountGroup.Id targetGroupId = m.getGroupId();
String targetGroupName = groupCache.get(targetGroupId).getName();
descriptions.add(MessageFormat.format("group {0}/{1}, group {2}/{3}",
groupUuid, groupName, targetGroupId, targetGroupName));
}
logOrmException(header, me, descriptions, e);
}
private void logOrmException(String header, Account.Id me,
Iterable<?> values, OrmException e) {
StringBuilder message = new StringBuilder(header);
message.append(" ");
message.append(me);
message.append("/");
message.append(accountCache.get(me).getUserName());
message.append(": ");
message.append(Joiner.on("; ").join(values));
log.error(message.toString(), e);
}
}

View File

@@ -17,6 +17,7 @@ package com.google.gerrit.server.group;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.gerrit.audit.AuditService;
import com.google.gerrit.common.data.GroupDescription; import com.google.gerrit.common.data.GroupDescription;
import com.google.gerrit.extensions.restapi.AuthException; import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.MethodNotAllowedException; import com.google.gerrit.extensions.restapi.MethodNotAllowedException;
@@ -26,14 +27,12 @@ import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
import com.google.gerrit.reviewdb.client.Account; import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountGroup; import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.AccountGroupById; import com.google.gerrit.reviewdb.client.AccountGroupById;
import com.google.gerrit.reviewdb.client.AccountGroupByIdAud;
import com.google.gerrit.reviewdb.server.ReviewDb; import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.CurrentUser; import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.IdentifiedUser; import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.account.GroupControl; import com.google.gerrit.server.account.GroupControl;
import com.google.gerrit.server.account.GroupIncludeCache; import com.google.gerrit.server.account.GroupIncludeCache;
import com.google.gerrit.server.group.AddIncludedGroups.Input; import com.google.gerrit.server.group.AddIncludedGroups.Input;
import com.google.gerrit.server.util.TimeUtil;
import com.google.gwtorm.server.OrmException; import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Provider; import com.google.inject.Provider;
@@ -48,16 +47,17 @@ public class DeleteIncludedGroups implements RestModifyView<GroupResource, Input
private final GroupIncludeCache groupIncludeCache; private final GroupIncludeCache groupIncludeCache;
private final Provider<ReviewDb> db; private final Provider<ReviewDb> db;
private final Provider<CurrentUser> self; private final Provider<CurrentUser> self;
private final AuditService auditService;
@Inject @Inject
DeleteIncludedGroups(GroupsCollection groupsCollection, DeleteIncludedGroups(GroupsCollection groupsCollection,
GroupIncludeCache groupIncludeCache, GroupIncludeCache groupIncludeCache, Provider<ReviewDb> db,
Provider<ReviewDb> db, Provider<CurrentUser> self, AuditService auditService) {
Provider<CurrentUser> self) {
this.groupsCollection = groupsCollection; this.groupsCollection = groupsCollection;
this.groupIncludeCache = groupIncludeCache; this.groupIncludeCache = groupIncludeCache;
this.db = db; this.db = db;
this.self = self; this.self = self;
this.auditService = auditService;
} }
@Override @Override
@@ -109,27 +109,10 @@ public class DeleteIncludedGroups implements RestModifyView<GroupResource, Input
return groups; return groups;
} }
private void writeAudits(final List<AccountGroupById> toBeRemoved) private void writeAudits(final List<AccountGroupById> toRemoved)
throws OrmException { throws OrmException {
final Account.Id me = ((IdentifiedUser) self.get()).getAccountId(); final Account.Id me = ((IdentifiedUser) self.get()).getAccountId();
final List<AccountGroupByIdAud> auditUpdates = Lists.newLinkedList(); auditService.dispatchDeleteGroupsFromGroup(me, toRemoved);
for (final AccountGroupById g : toBeRemoved) {
AccountGroupByIdAud audit = null;
for (AccountGroupByIdAud a : db.get()
.accountGroupByIdAud().byGroupInclude(g.getGroupId(),
g.getIncludeUUID())) {
if (a.isActive()) {
audit = a;
break;
}
}
if (audit != null) {
audit.removed(me, TimeUtil.nowTs());
auditUpdates.add(audit);
}
}
db.get().accountGroupByIdAud().update(auditUpdates);
} }
@Singleton @Singleton

View File

@@ -16,6 +16,7 @@ package com.google.gerrit.server.group;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.gerrit.audit.AuditService;
import com.google.gerrit.extensions.restapi.AuthException; import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.MethodNotAllowedException; import com.google.gerrit.extensions.restapi.MethodNotAllowedException;
import com.google.gerrit.extensions.restapi.Response; import com.google.gerrit.extensions.restapi.Response;
@@ -24,7 +25,6 @@ import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
import com.google.gerrit.reviewdb.client.Account; import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountGroup; import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.AccountGroupMember; import com.google.gerrit.reviewdb.client.AccountGroupMember;
import com.google.gerrit.reviewdb.client.AccountGroupMemberAudit;
import com.google.gerrit.reviewdb.server.ReviewDb; import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.CurrentUser; import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.IdentifiedUser; import com.google.gerrit.server.IdentifiedUser;
@@ -32,7 +32,6 @@ import com.google.gerrit.server.account.AccountCache;
import com.google.gerrit.server.account.AccountsCollection; import com.google.gerrit.server.account.AccountsCollection;
import com.google.gerrit.server.account.GroupControl; import com.google.gerrit.server.account.GroupControl;
import com.google.gerrit.server.group.AddMembers.Input; import com.google.gerrit.server.group.AddMembers.Input;
import com.google.gerrit.server.util.TimeUtil;
import com.google.gwtorm.server.OrmException; import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Provider; import com.google.inject.Provider;
@@ -47,15 +46,18 @@ public class DeleteMembers implements RestModifyView<GroupResource, Input> {
private final AccountCache accountCache; private final AccountCache accountCache;
private final Provider<ReviewDb> db; private final Provider<ReviewDb> db;
private final Provider<CurrentUser> self; private final Provider<CurrentUser> self;
private final AuditService auditService;
@Inject @Inject
DeleteMembers(AccountsCollection accounts, DeleteMembers(AccountsCollection accounts,
AccountCache accountCache, Provider<ReviewDb> db, AccountCache accountCache, Provider<ReviewDb> db,
Provider<CurrentUser> self) { Provider<CurrentUser> self,
AuditService auditService) {
this.accounts = accounts; this.accounts = accounts;
this.accountCache = accountCache; this.accountCache = accountCache;
this.db = db; this.db = db;
this.self = self; this.self = self;
this.auditService = auditService;
} }
@Override @Override
@@ -94,32 +96,9 @@ public class DeleteMembers implements RestModifyView<GroupResource, Input> {
return Response.none(); return Response.none();
} }
private void writeAudits(final List<AccountGroupMember> toBeRemoved) private void writeAudits(final List<AccountGroupMember> toRemove) {
throws OrmException {
final Account.Id me = ((IdentifiedUser) self.get()).getAccountId(); final Account.Id me = ((IdentifiedUser) self.get()).getAccountId();
final List<AccountGroupMemberAudit> auditUpdates = Lists.newLinkedList(); auditService.dispatchDeleteAccountsFromGroup(me, toRemove);
final List<AccountGroupMemberAudit> auditInserts = Lists.newLinkedList();
for (final AccountGroupMember m : toBeRemoved) {
AccountGroupMemberAudit audit = null;
for (AccountGroupMemberAudit a : db.get().accountGroupMembersAudit()
.byGroupAccount(m.getAccountGroupId(), m.getAccountId())) {
if (a.isActive()) {
audit = a;
break;
}
}
if (audit != null) {
audit.removed(me, TimeUtil.nowTs());
auditUpdates.add(audit);
} else {
audit = new AccountGroupMemberAudit(m, me, TimeUtil.nowTs());
audit.removedLegacy();
auditInserts.add(audit);
}
}
db.get().accountGroupMembersAudit().update(auditUpdates);
db.get().accountGroupMembersAudit().insert(auditInserts);
} }
private Map<Account.Id, AccountGroupMember> getMembers( private Map<Account.Id, AccountGroupMember> getMembers(

View File

@@ -18,7 +18,9 @@ import static com.google.gerrit.server.group.GroupResource.GROUP_KIND;
import static com.google.gerrit.server.group.IncludedGroupResource.INCLUDED_GROUP_KIND; import static com.google.gerrit.server.group.IncludedGroupResource.INCLUDED_GROUP_KIND;
import static com.google.gerrit.server.group.MemberResource.MEMBER_KIND; import static com.google.gerrit.server.group.MemberResource.MEMBER_KIND;
import com.google.gerrit.audit.GroupMemberAuditListener;
import com.google.gerrit.extensions.registration.DynamicMap; import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.extensions.restapi.RestApiModule; import com.google.gerrit.extensions.restapi.RestApiModule;
import com.google.gerrit.server.group.AddIncludedGroups.UpdateIncludedGroup; import com.google.gerrit.server.group.AddIncludedGroups.UpdateIncludedGroup;
import com.google.gerrit.server.group.AddMembers.UpdateMember; import com.google.gerrit.server.group.AddMembers.UpdateMember;
@@ -65,5 +67,9 @@ public class Module extends RestApiModule {
delete(INCLUDED_GROUP_KIND).to(DeleteIncludedGroup.class); delete(INCLUDED_GROUP_KIND).to(DeleteIncludedGroup.class);
install(new FactoryModuleBuilder().build(CreateGroup.Factory.class)); install(new FactoryModuleBuilder().build(CreateGroup.Factory.class));
DynamicSet.bind(binder(), GroupMemberAuditListener.class).to(
DbGroupMemberAuditListener.class);
} }
} }