@@ -150,15 +150,21 @@ class AdminBackend {
150150
151151 /// Removes user from the Datastore and updates the packages and other
152152 /// entities they may have controlled.
153+ ///
154+ /// Verifies the current authenticated user for admin permissions.
153155 Future <void > removeUser (String userId) async {
154156 final caller = await requireAuthenticatedAdmin (AdminPermission .removeUsers);
155157 final user = await accountBackend.lookupUserById (userId);
156158 if (user == null ) return ;
157159 if (user.isDeleted) return ;
158-
159160 _logger.info ('${caller .displayId }) initiated the delete '
160161 'of ${user .userId } (${user .email })' );
162+ await _removeUser (user);
163+ }
161164
165+ /// Removes user from the Datastore and updates the packages and other
166+ /// entities they may have controlled.
167+ Future <void > _removeUser (User user) async {
162168 // Package.uploaders
163169 final pool = Pool (10 );
164170 final futures = < Future > [];
@@ -874,7 +880,57 @@ class AdminBackend {
874880 'Deleted moderated package version: ${version .qualifiedVersionKey }' );
875881 }
876882
877- // TODO: delete publisher instances
878- // TODO: mark user instances deleted
883+ // delete publishers
884+ final publisherQuery = _db.query <Publisher >()
885+ ..filter ('moderatedAt <' , before)
886+ ..order ('moderatedAt' );
887+ await for (final publisher in publisherQuery.run ()) {
888+ // sanity check
889+ if (! publisher.isModerated) {
890+ continue ;
891+ }
892+
893+ _logger.info ('Deleting moderated publisher: ${publisher .publisherId }' );
894+
895+ // removes packages of this publisher, no uploaders will be set, marks discontinued
896+ final pkgQuery = _db.query <Package >()
897+ ..filter ('publisherId =' , publisher.publisherId);
898+ await for (final pkg in pkgQuery.run ()) {
899+ await withRetryTransaction (_db, (tx) async {
900+ final p = await tx.lookupOrNull <Package >(pkg.key);
901+ if (p == null ) return ;
902+ if (p.publisherId != publisher.publisherId) return ;
903+
904+ p.publisherId = null ;
905+ p.updated = clock.now ().toUtc ();
906+ p.isDiscontinued = true ;
907+ tx.insert (p);
908+ });
909+ }
910+
911+ // removes publisher members
912+ await _db.deleteWithQuery (
913+ _db.query <PublisherMember >(ancestorKey: publisher.key));
914+
915+ // removes publisher entity
916+ await _db.commit (deletes: [publisher.key]);
917+
918+ _logger.info ('Deleted moderated publisher: ${publisher .publisherId }' );
919+ }
920+
921+ // mark user instances deleted
922+ final userQuery = _db.query <User >()
923+ ..filter ('moderatedAt <' , before)
924+ ..order ('moderatedAt' );
925+ await for (final user in userQuery.run ()) {
926+ // sanity check
927+ if (! user.isModerated || user.isDeleted) {
928+ continue ;
929+ }
930+
931+ _logger.info ('Deleting moderated user: ${user .userId }' );
932+ await _removeUser (user);
933+ _logger.info ('Deleting moderated user: ${user .userId }' );
934+ }
879935 }
880936}
0 commit comments