satellite/analytics: Added analytics for "passphrase created", "account verified" and "external_link_clicked" (#4078)

This commit is contained in:
prerna-parashar 2021-04-12 09:58:36 -07:00 committed by GitHub
parent 037c7799b5
commit d2705c1143
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 98 additions and 8 deletions

View File

@ -11,11 +11,14 @@ import (
)
const (
eventAccountCreated = "Account Created"
eventSignedIn = "Signed In"
eventProjectCreated = "Project Created"
eventAccessGrantCreated = "Access Grant Created"
gatewayCredentialsCreated = "Credentials Created"
eventAccountCreated = "Account Created"
eventSignedIn = "Signed In"
eventProjectCreated = "Project Created"
eventAccessGrantCreated = "Access Grant Created"
eventAccountVerified = "Account Verified"
eventGatewayCredentialsCreated = "Credentials Created"
eventPassphraseCreated = "Passphrase Created"
eventExternalLinkClicked = "External Link Clicked"
)
// Config is a configuration struct for analytics Service.
@ -47,7 +50,7 @@ func NewService(log *zap.Logger, config Config, satelliteName string) *Service {
if config.Enabled {
service.segment = segment.New(config.SegmentWriteKey)
}
for _, name := range []string{gatewayCredentialsCreated} {
for _, name := range []string{eventGatewayCredentialsCreated, eventPassphraseCreated, eventExternalLinkClicked} {
service.clientEvents[name] = true
}
return service
@ -170,6 +173,26 @@ func (service *Service) TrackAccessGrantCreated(userID uuid.UUID) {
})
}
// TrackAccountVerified sends an "Account Verified" event to Segment.
func (service *Service) TrackAccountVerified(userID uuid.UUID, email string) {
traits := segment.NewTraits()
traits.SetEmail(email)
service.enqueueMessage(segment.Identify{
UserId: userID.String(),
Traits: traits,
})
props := segment.NewProperties()
props.Set("email", email)
service.enqueueMessage(segment.Track{
UserId: userID.String(),
Event: eventAccountVerified,
Properties: props,
})
}
// TrackEvent sends an arbitrary event associated with user ID to Segment.
// It is used for tracking occurrences of client-side events.
func (service *Service) TrackEvent(eventName string, userID uuid.UUID) {
@ -178,9 +201,28 @@ func (service *Service) TrackEvent(eventName string, userID uuid.UUID) {
service.log.Error("Invalid client-triggered event", zap.String("eventName", eventName))
return
}
service.enqueueMessage(segment.Track{
UserId: userID.String(),
Event: eventName,
})
}
// TrackLinkEvent sends an arbitrary event and link associated with user ID to Segment.
// It is used for tracking occurrences of client-side events.
func (service *Service) TrackLinkEvent(eventName string, userID uuid.UUID, link string) {
// do not track if the event name is an invalid client-side event
if !service.clientEvents[eventName] {
service.log.Error("Invalid client-triggered event", zap.String("eventName", eventName))
return
}
props := segment.NewProperties()
props.Set("link", link)
service.enqueueMessage(segment.Track{
UserId: userID.String(),
Event: eventName,
Properties: props,
})
}

View File

@ -38,6 +38,7 @@ func NewAnalytics(log *zap.Logger, service *console.Service, a *analytics.Servic
type eventTriggeredBody struct {
EventName string `json:"eventName"`
Link string `json:"link"`
}
// EventTriggered tracks the occurrence of an arbitrary event on the client.
@ -61,7 +62,11 @@ func (a *Analytics) EventTriggered(w http.ResponseWriter, r *http.Request) {
return
}
a.analytics.TrackEvent(et.EventName, userID)
if et.Link != "" {
a.analytics.TrackLinkEvent(et.EventName, userID, et.Link)
} else {
a.analytics.TrackEvent(et.EventName, userID)
}
w.WriteHeader(http.StatusOK)
}

View File

@ -698,6 +698,8 @@ func (s *Service) ActivateAccount(ctx context.Context, activationToken string) (
s.log.Debug(fmt.Sprintf("could not add promotional coupon for user %s", user.ID.String()), zap.Error(Error.Wrap(err)))
}
s.analytics.TrackAccountVerified(user.ID, user.Email)
return nil
}

View File

@ -29,4 +29,17 @@ export class AnalyticsHttpApi {
throw new Error('Can not track event');
}
public async linkEventTriggered(eventName: string, link: string): Promise<void> {
const path = `${this.ROOT_PATH}/event`;
const body = {
eventName: eventName,
link: link,
};
const response = await this.http.post(path, JSON.stringify(body));
if (response.ok) {
return;
}
throw new Error('Can not track event');
}
}

View File

@ -85,6 +85,9 @@ import VButton from '@/components/common/VButton.vue';
import BackIcon from '@/../static/images/accessGrants/back.svg';
import WarningIcon from '@/../static/images/accessGrants/warning.svg';
import { AnalyticsEvent } from '@/utils/constants/analyticsEventNames';
import { AnalyticsHttpApi } from '@/api/analytics';
@Component({
components: {
WarningIcon,
@ -100,6 +103,7 @@ export default class GeneratePassphrase extends Vue {
public readonly setParentPassphrase: (passphrase: string) => void;
@Prop({ default: false })
public readonly isLoading: boolean;
private readonly analytics: AnalyticsHttpApi = new AnalyticsHttpApi();
public isGenerateState: boolean = true;
public isCreateState: boolean = false;
@ -130,6 +134,8 @@ export default class GeneratePassphrase extends Vue {
return;
}
this.analytics.eventTriggered(AnalyticsEvent.PASSPHRASE_CREATED);
this.onButtonClick();
}

View File

@ -12,6 +12,9 @@ import SupportIcon from '@/../static/images/header/support.svg';
import { RouteConfig } from '@/router';
import { AnalyticsEvent } from '@/utils/constants/analyticsEventNames';
import { AnalyticsHttpApi } from '@/api/analytics';
@Component({
components: {
DocsIcon,
@ -20,12 +23,26 @@ import { RouteConfig } from '@/router';
},
})
export default class ResourcesDropdown extends Vue {
private readonly analytics: AnalyticsHttpApi = new AnalyticsHttpApi();
/**
* Indicates if current route is onboarding tour.
*/
public get isOnboardingTour(): boolean {
return this.$route.path.includes(RouteConfig.OnboardingTour.path);
}
public onDocsIconClick(): void {
this.analytics.linkEventTriggered(AnalyticsEvent.EXTERNAL_LINK_CLICKED, "https://documentation.storj.io");
}
public onCommunityIconClick(): void {
this.analytics.linkEventTriggered(AnalyticsEvent.EXTERNAL_LINK_CLICKED, "https://storj.io/community/");
}
public onSupportIconClick(): void {
this.analytics.linkEventTriggered(AnalyticsEvent.EXTERNAL_LINK_CLICKED, "mailto:support@storj.io");
}
}
</script>

View File

@ -7,6 +7,7 @@
href="https://documentation.storj.io"
target="_blank"
rel="noopener noreferrer"
@click="onDocsIconClick"
>
<DocsIcon class="resources-dropdown__item-container__image"/>
<p class="resources-dropdown__item-container__title">Docs</p>
@ -16,6 +17,7 @@
href="https://storj.io/community/"
target="_blank"
rel="noopener noreferrer"
@click="onCommunityIconClick"
>
<CommunityIcon class="resources-dropdown__item-container__image"/>
<p class="resources-dropdown__item-container__title">Community</p>
@ -25,6 +27,7 @@
href="mailto:support@storj.io"
target="_blank"
rel="noopener noreferrer"
@click="onSupportIconClick"
>
<SupportIcon class="resources-dropdown__item-container__image"/>
<p class="resources-dropdown__item-container__title">Support</p>

View File

@ -4,4 +4,6 @@
// Make sure these event names match up with the client-side event names in satellite/analytics/service.go
export enum AnalyticsEvent {
GATEWAY_CREDENTIALS_CREATED = 'Credentials Created',
PASSPHRASE_CREATED = 'Passphrase Created',
EXTERNAL_LINK_CLICKED = 'External Link Clicked',
}