fix: Provide accurate instance stats for active user count (#29327)

Fixes https://github.com/appsmithorg/cloud-services/issues/1457
EE PR: https://github.com/appsmithorg/appsmith-ee/pull/3033

## Summary by CodeRabbit

- **New Features**
- Introduced a new indicator to distinguish system-generated users from
regular users.

- **Enhancements**
- Improved user count accuracy by excluding system-generated users from
active user statistics.

- **Database Changes**
- Executed a migration to mark existing anonymous users as
system-generated.

- **Bug Fixes**
- Adjusted user repository queries to correctly count
non-system-generated users.
This commit is contained in:
Abhijeet 2023-12-13 15:58:03 +05:30 committed by GitHub
parent 60692629c5
commit d1b997d147
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 64 additions and 2 deletions

View File

@ -110,6 +110,12 @@ public class User extends BaseDomain implements UserDetails, OidcUser {
@JsonView(Views.Public.class)
private String tenantId;
// Field to indicate if the user is system generated or not. Expected to be `true` for system generated users, null
// otherwise.
// e.g. AnonymousUser is created by the system migration during the first time startup.
@JsonView(Views.Internal.class)
Boolean isSystemGenerated;
// TODO: Populate these attributes for a user. Generally required for OAuth2 logins
@Override
@JsonView(Views.Public.class)

View File

@ -0,0 +1,43 @@
package com.appsmith.server.migrations.db.ce;
import com.appsmith.server.domains.QUser;
import com.appsmith.server.domains.User;
import com.mongodb.client.result.UpdateResult;
import io.mongock.api.annotations.ChangeUnit;
import io.mongock.api.annotations.Execution;
import io.mongock.api.annotations.RollbackExecution;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Update;
import static com.appsmith.server.repositories.ce.BaseAppsmithRepositoryCEImpl.fieldName;
import static org.springframework.data.mongodb.core.query.Criteria.where;
import static org.springframework.data.mongodb.core.query.Query.query;
@Slf4j
@ChangeUnit(order = "037", id = "mark-anonymous-user-as-system-generated", author = " ")
public class Migration037MarkAnonymousUserAsSystemGenerated {
private final MongoTemplate mongoTemplate;
public Migration037MarkAnonymousUserAsSystemGenerated(MongoTemplate mongoTemplate) {
this.mongoTemplate = mongoTemplate;
}
@RollbackExecution
public void rollbackExecution() {}
@Execution
public void executeMigration() {
final Update update = new Update();
update.set(fieldName(QUser.user.isSystemGenerated), true);
try {
// We expect only 1 anonymous user to be present in the system, but we are using updateMulti to be safe.
UpdateResult result = mongoTemplate.updateMulti(
query(where(fieldName(QUser.user.isAnonymous)).is(true)), update, User.class);
log.info("Marked {} anonymous users as system generated", result.getModifiedCount());
} catch (Exception e) {
log.error("Error while marking anonymous user as system generated", e);
}
}
}

View File

@ -11,7 +11,14 @@ public interface UserRepositoryCE extends BaseRepository<User, String>, CustomUs
Mono<User> findByCaseInsensitiveEmail(String email);
Mono<Long> countByDeletedAtNull();
/**
* This method returns the count of all users that are not deleted and are not system generated.
*
* @param excludeSystemGenerated If true, then the count of all users that are not deleted and are not system
* generated is returned.
* @return The count of all users that are not deleted and are not system generated.
*/
Mono<Long> countByDeletedAtIsNullAndIsSystemGeneratedIsNot(Boolean excludeSystemGenerated);
Mono<User> findByEmailAndTenantId(String email, String tenantId);
}

View File

@ -122,13 +122,19 @@ public class PingScheduledTaskCEImpl implements PingScheduledTaskCE {
}
Mono<String> publicPermissionGroupIdMono = permissionGroupService.getPublicPermissionGroupId();
// Get the non-system generated active user count
Mono<Long> userCountMono = userRepository
.countByDeletedAtIsNullAndIsSystemGeneratedIsNot(true)
.defaultIfEmpty(0L);
Mono<Tuple6<Long, Long, Long, Long, Long, Long>> nonDeletedObjectsCountMono = Mono.zip(
workspaceRepository.countByDeletedAtNull().defaultIfEmpty(0L),
applicationRepository.countByDeletedAtNull().defaultIfEmpty(0L),
newPageRepository.countByDeletedAtNull().defaultIfEmpty(0L),
newActionRepository.countByDeletedAtNull().defaultIfEmpty(0L),
datasourceRepository.countByDeletedAtNull().defaultIfEmpty(0L),
userRepository.countByDeletedAtNull().defaultIfEmpty(0L));
userCountMono);
publicPermissionGroupIdMono
.flatMap(publicPermissionGroupId -> Mono.zip(