chore: Add version to analytics events (#20295)
Currently, analytics events don't include Appsmith version information. This PR adds version, and edition information to all events.
This commit is contained in:
parent
ad5d236a05
commit
04f6208f86
|
|
@ -16,6 +16,8 @@ import org.springframework.context.annotation.PropertySource;
|
|||
@Getter
|
||||
public class ProjectProperties {
|
||||
|
||||
public static final String EDITION = "CE";
|
||||
|
||||
@Value("${version:UNKNOWN}")
|
||||
private String version;
|
||||
|
||||
|
|
|
|||
|
|
@ -15,4 +15,7 @@ public interface CustomUserDataRepositoryCE extends AppsmithRepository<UserData>
|
|||
Mono<UpdateResult> removeIdFromRecentlyUsedList(String userId, String workspaceId, List<String> applicationIds);
|
||||
|
||||
Flux<UserData> findPhotoAssetsByUserIds(Iterable<String> userId);
|
||||
|
||||
Mono<String> fetchMostRecentlyUsedWorkspaceId(String userId);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import com.mongodb.client.result.UpdateResult;
|
|||
import org.springframework.data.mongodb.core.ReactiveMongoOperations;
|
||||
import org.springframework.data.mongodb.core.convert.MongoConverter;
|
||||
import org.springframework.data.mongodb.core.query.Criteria;
|
||||
import org.springframework.data.mongodb.core.query.Query;
|
||||
import org.springframework.data.mongodb.core.query.Update;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
|
@ -66,4 +67,17 @@ public class CustomUserDataRepositoryCEImpl extends BaseAppsmithRepositoryImpl<U
|
|||
return queryAll(List.of(criteria), Optional.of(fieldsToInclude), Optional.empty(), Optional.empty());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<String> fetchMostRecentlyUsedWorkspaceId(String userId) {
|
||||
final Query query = query(where(fieldName(QUserData.userData.userId)).is(userId));
|
||||
|
||||
query.fields().include(fieldName(QUserData.userData.recentlyUsedWorkspaceIds));
|
||||
|
||||
return mongoOperations.findOne(query, UserData.class)
|
||||
.map(userData -> {
|
||||
final List<String> recentlyUsedWorkspaceIds = userData.getRecentlyUsedWorkspaceIds();
|
||||
return CollectionUtils.isEmpty(recentlyUsedWorkspaceIds) ? "" : recentlyUsedWorkspaceIds.get(0);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
package com.appsmith.server.services;
|
||||
|
||||
import com.appsmith.server.configurations.CommonConfig;
|
||||
import com.appsmith.server.configurations.ProjectProperties;
|
||||
import com.appsmith.server.helpers.PolicyUtils;
|
||||
import com.appsmith.server.helpers.UserUtils;
|
||||
import com.appsmith.server.repositories.UserDataRepository;
|
||||
import com.appsmith.server.services.ce.AnalyticsServiceCEImpl;
|
||||
import com.google.gson.Gson;
|
||||
import com.segment.analytics.Analytics;
|
||||
|
|
@ -19,12 +21,10 @@ public class AnalyticsServiceImpl extends AnalyticsServiceCEImpl implements Anal
|
|||
SessionUserService sessionUserService,
|
||||
CommonConfig commonConfig,
|
||||
ConfigService configService,
|
||||
PolicyUtils policyUtils,
|
||||
UserUtils userUtils,
|
||||
Gson gson) {
|
||||
|
||||
super(analytics, sessionUserService, commonConfig, configService, policyUtils, userUtils, gson);
|
||||
ProjectProperties projectProperties,
|
||||
UserDataRepository userDataRepository) {
|
||||
super(analytics, sessionUserService, commonConfig, configService, userUtils, projectProperties, userDataRepository);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ public interface AnalyticsServiceCE {
|
|||
|
||||
Mono<User> identifyUser(User user, UserData userData);
|
||||
|
||||
Mono<User> identifyUser(User user, UserData userData, String recentlyUsedWorkspaceId);
|
||||
|
||||
void identifyInstance(String instanceId, String role, String useCase);
|
||||
|
||||
Mono<Void> sendEvent(String event, String userId, Map<String, ?> properties);
|
||||
|
|
|
|||
|
|
@ -3,17 +3,17 @@ package com.appsmith.server.services.ce;
|
|||
import com.appsmith.external.constants.AnalyticsEvents;
|
||||
import com.appsmith.external.models.BaseDomain;
|
||||
import com.appsmith.server.configurations.CommonConfig;
|
||||
import com.appsmith.server.configurations.ProjectProperties;
|
||||
import com.appsmith.server.constants.FieldName;
|
||||
import com.appsmith.server.domains.NewAction;
|
||||
import com.appsmith.server.domains.NewPage;
|
||||
import com.appsmith.server.domains.User;
|
||||
import com.appsmith.server.domains.UserData;
|
||||
import com.appsmith.server.helpers.ExchangeUtils;
|
||||
import com.appsmith.server.helpers.PolicyUtils;
|
||||
import com.appsmith.server.helpers.UserUtils;
|
||||
import com.appsmith.server.repositories.UserDataRepository;
|
||||
import com.appsmith.server.services.ConfigService;
|
||||
import com.appsmith.server.services.SessionUserService;
|
||||
import com.google.gson.Gson;
|
||||
import com.segment.analytics.Analytics;
|
||||
import com.segment.analytics.messages.IdentifyMessage;
|
||||
import com.segment.analytics.messages.TrackMessage;
|
||||
|
|
@ -39,22 +39,25 @@ public class AnalyticsServiceCEImpl implements AnalyticsServiceCE {
|
|||
|
||||
private final UserUtils userUtils;
|
||||
|
||||
private final Gson gson;
|
||||
private final ProjectProperties projectProperties;
|
||||
|
||||
private final UserDataRepository userDataRepository;
|
||||
|
||||
@Autowired
|
||||
public AnalyticsServiceCEImpl(@Autowired(required = false) Analytics analytics,
|
||||
SessionUserService sessionUserService,
|
||||
CommonConfig commonConfig,
|
||||
ConfigService configService,
|
||||
PolicyUtils policyUtils,
|
||||
UserUtils userUtils,
|
||||
Gson gson) {
|
||||
ProjectProperties projectProperties,
|
||||
UserDataRepository userDataRepository) {
|
||||
this.analytics = analytics;
|
||||
this.sessionUserService = sessionUserService;
|
||||
this.commonConfig = commonConfig;
|
||||
this.configService = configService;
|
||||
this.userUtils = userUtils;
|
||||
this.gson = gson;
|
||||
this.projectProperties = projectProperties;
|
||||
this.userDataRepository = userDataRepository;
|
||||
}
|
||||
|
||||
public boolean isActive() {
|
||||
|
|
@ -65,18 +68,34 @@ public class AnalyticsServiceCEImpl implements AnalyticsServiceCE {
|
|||
return value == null ? "" : DigestUtils.sha256Hex(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<User> identifyUser(User user, UserData userData) {
|
||||
return identifyUser(user, userData, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<User> identifyUser(User user, UserData userData, String recentlyUsedWorkspaceId) {
|
||||
if (!isActive()) {
|
||||
return Mono.just(user);
|
||||
}
|
||||
|
||||
Mono<Boolean> isSuperUserMono = userUtils.isSuperUser(user);
|
||||
|
||||
return Mono.just(user)
|
||||
.zipWith(isSuperUserMono)
|
||||
final Mono<String> recentlyUsedWorkspaceIdMono = StringUtils.isEmpty(recentlyUsedWorkspaceId)
|
||||
? userDataRepository.fetchMostRecentlyUsedWorkspaceId(user.getId()).defaultIfEmpty("")
|
||||
: Mono.just(recentlyUsedWorkspaceId);
|
||||
|
||||
return Mono.zip(
|
||||
Mono.just(user),
|
||||
isSuperUserMono,
|
||||
configService.getInstanceId()
|
||||
.defaultIfEmpty("unknown-instance-id"),
|
||||
recentlyUsedWorkspaceIdMono
|
||||
)
|
||||
.map(tuple -> {
|
||||
User savedUser = tuple.getT1();
|
||||
final Boolean isSuperUser = tuple.getT2();
|
||||
final User savedUser = tuple.getT1();
|
||||
final boolean isSuperUser = tuple.getT2();
|
||||
final String instanceId = tuple.getT3();
|
||||
|
||||
String username = savedUser.getUsername();
|
||||
String name = savedUser.getName();
|
||||
|
|
@ -92,7 +111,9 @@ public class AnalyticsServiceCEImpl implements AnalyticsServiceCE {
|
|||
.traits(Map.of(
|
||||
"name", ObjectUtils.defaultIfNull(name, ""),
|
||||
"email", ObjectUtils.defaultIfNull(email, ""),
|
||||
"isSuperUser", isSuperUser != null && isSuperUser,
|
||||
"isSuperUser", isSuperUser,
|
||||
"instanceId", instanceId,
|
||||
"mostRecentlyUsedWorkspaceId", tuple.getT4(),
|
||||
"role", ObjectUtils.defaultIfNull(userData.getRole(), ""),
|
||||
"goal", ObjectUtils.defaultIfNull(userData.getUseCase(), "")
|
||||
))
|
||||
|
|
@ -174,6 +195,7 @@ public class AnalyticsServiceCEImpl implements AnalyticsServiceCE {
|
|||
TrackMessage.Builder messageBuilder = TrackMessage.builder(event).userId(userIdToSend);
|
||||
analyticsProperties.put("originService", "appsmith-server");
|
||||
analyticsProperties.put("instanceId", instanceId);
|
||||
analyticsProperties.put("version", projectProperties.getVersion());
|
||||
messageBuilder = messageBuilder.properties(analyticsProperties);
|
||||
analytics.enqueue(messageBuilder);
|
||||
return instanceId;
|
||||
|
|
@ -226,7 +248,7 @@ public class AnalyticsServiceCEImpl implements AnalyticsServiceCE {
|
|||
return Mono.just(object);
|
||||
}
|
||||
|
||||
final String username = (object instanceof User ? (User) object : user).getUsername();
|
||||
final String username = (object instanceof User objectAsUser ? objectAsUser : user).getUsername();
|
||||
|
||||
HashMap<String, Object> analyticsProperties = new HashMap<>();
|
||||
analyticsProperties.put("id", id);
|
||||
|
|
|
|||
|
|
@ -50,5 +50,4 @@ public interface UserDataServiceCE {
|
|||
Mono<UserData> setCommentState(CommentOnboardingState commentOnboardingState);
|
||||
|
||||
Mono<UpdateResult> removeRecentWorkspaceAndApps(String userId, String workspaceId);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import com.appsmith.server.solutions.ReleaseNotesService;
|
|||
import com.appsmith.server.solutions.UserChangedHandler;
|
||||
import com.mongodb.DBObject;
|
||||
import com.mongodb.client.result.UpdateResult;
|
||||
import org.apache.commons.collections.map.Flat3Map;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.mongodb.core.ReactiveMongoTemplate;
|
||||
|
|
@ -36,6 +37,8 @@ import reactor.core.publisher.Mono;
|
|||
import reactor.core.scheduler.Scheduler;
|
||||
|
||||
import jakarta.validation.Validator;
|
||||
import reactor.util.function.Tuple2;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
|
@ -261,17 +264,25 @@ public class UserDataServiceCEImpl extends BaseService<UserDataRepository, UserD
|
|||
*/
|
||||
@Override
|
||||
public Mono<UserData> updateLastUsedAppAndWorkspaceList(Application application) {
|
||||
return this.getForCurrentUser().flatMap(userData -> {
|
||||
// set recently used workspace ids
|
||||
userData.setRecentlyUsedWorkspaceIds(
|
||||
addIdToRecentList(userData.getRecentlyUsedWorkspaceIds(), application.getWorkspaceId(), 10)
|
||||
);
|
||||
// set recently used application ids
|
||||
userData.setRecentlyUsedAppIds(
|
||||
addIdToRecentList(userData.getRecentlyUsedAppIds(), application.getId(), 20)
|
||||
);
|
||||
return repository.save(userData);
|
||||
});
|
||||
return sessionUserService.getCurrentUser()
|
||||
.zipWhen(this::getForUser)
|
||||
.flatMap(tuple -> {
|
||||
final User user = tuple.getT1();
|
||||
final UserData userData = tuple.getT2();
|
||||
// set recently used workspace ids
|
||||
userData.setRecentlyUsedWorkspaceIds(
|
||||
addIdToRecentList(userData.getRecentlyUsedWorkspaceIds(), application.getWorkspaceId(), 10)
|
||||
);
|
||||
// set recently used application ids
|
||||
userData.setRecentlyUsedAppIds(
|
||||
addIdToRecentList(userData.getRecentlyUsedAppIds(), application.getId(), 20)
|
||||
);
|
||||
return Mono.zip(
|
||||
analyticsService.identifyUser(user, userData, application.getWorkspaceId()),
|
||||
repository.save(userData)
|
||||
);
|
||||
})
|
||||
.map(Tuple2::getT2);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -330,4 +341,5 @@ public class UserDataServiceCEImpl extends BaseService<UserDataRepository, UserD
|
|||
repository.removeIdFromRecentlyUsedList(userId, workspaceId, appIdsList)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,9 +15,12 @@ import org.springframework.core.ParameterizedTypeReference;
|
|||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.util.UriBuilder;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.core.scheduler.Schedulers;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
|
@ -64,7 +67,9 @@ public class ReleaseNotesServiceCEImpl implements ReleaseNotesServiceCE {
|
|||
// isCloudHosted should be true only for our cloud instance,
|
||||
// For docker images that burn the segment key with the image, the CE key will be present
|
||||
"&isSourceInstall=" + (commonConfig.isCloudHosting() || StringUtils.isEmpty(segmentConfig.getCeKey())) +
|
||||
(StringUtils.isEmpty(commonConfig.getRepo()) ? "" : ("&repo=" + commonConfig.getRepo()))
|
||||
(StringUtils.isEmpty(commonConfig.getRepo()) ? "" : ("&repo=" + commonConfig.getRepo())) +
|
||||
"&version=" + projectProperties.getVersion() +
|
||||
"&edition=" + ProjectProperties.EDITION
|
||||
)
|
||||
.get()
|
||||
.exchange()
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user