def send(self, action, install_method, num_errors): """Sends analytics track data to segmentIO. variant: string | open or enterprise action: string | preflight, deploy, or postflight install_method: string | gui, cli or advanced """ analytics.write_key = "51ybGTeFEFU1xo6u10XMDrr6kATFyRyh" # We set customer key from config to avoid loading the config during class init customer_key = backend.get_config().get("customer_key", None) analytics.track(user_id=customer_key, anonymous_id=self.uuid, event=action, properties={ "provider": "onprem", "source": "installer", "variant": os.environ["BOOTSTRAP_VARIANT"], "install_id": self.uuid, "bootstrap_id": os.environ["BOOTSTRAP_ID"], "install_method": install_method, "stage": action, "errors": num_errors, "customerKey": customer_key, }) analytics.flush()
def login_analytics(strategy, auth_entry, current_partial=None, *args, **kwargs): """ Sends login info to Segment """ event_name = None if auth_entry == AUTH_ENTRY_LOGIN: event_name = 'edx.bi.user.account.authenticated' elif auth_entry in [AUTH_ENTRY_ACCOUNT_SETTINGS]: event_name = 'edx.bi.user.account.linked' if event_name is not None and hasattr(settings, 'LMS_SEGMENT_KEY') and settings.LMS_SEGMENT_KEY: tracking_context = tracker.get_tracker().resolve_context() analytics.track( kwargs['user'].id, event_name, { 'category': "conversion", 'label': None, 'provider': kwargs['backend'].name }, context={ 'ip': tracking_context.get('ip'), 'Google Analytics': { 'clientId': tracking_context.get('client_id') } } )
def _track_user_login(user, request): """ Sends a tracking event for a successful login. """ if hasattr(settings, 'LMS_SEGMENT_KEY') and settings.LMS_SEGMENT_KEY: tracking_context = tracker.get_tracker().resolve_context() analytics.identify( user.id, { 'email': request.POST['email'], 'username': user.username }, { # Disable MailChimp because we don't want to update the user's email # and username in MailChimp on every page load. We only need to capture # this data on registration/activation. 'MailChimp': False } ) analytics.track( user.id, "edx.bi.user.account.authenticated", { 'category': "conversion", 'label': request.POST.get('course_id'), 'provider': None }, context={ 'ip': tracking_context.get('ip'), 'Google Analytics': { 'clientId': tracking_context.get('client_id') } } )
def register_item(alias, api_key, myredis, mydao): if not is_valid_key(api_key): raise InvalidApiKeyException if is_registered(alias, api_key): raise ItemAlreadyRegisteredToThisKey registered_item = None (namespace, nid) = alias tiid = item.get_tiid_by_alias(namespace, nid, mydao) if not tiid: if is_over_quota(api_key): analytics.track("CORE", "Raised Exception", { "exception class": "ApiLimitExceededException", "api_key": api_key }) raise ApiLimitExceededException else: tiid = item.create_item(namespace, nid, myredis, mydao) analytics.identify(api_key, {"name": api_key, "api_user": True}) analytics.track(api_key, "Created item because of registration", { "tiid": tiid, "namespace": namespace, "nid": nid, "api_key": api_key }) api_user = get_api_user(api_key) if api_user: registered_item = save_registered_item(alias, api_user) return {"tiid":tiid, "registered_item":registered_item}
def emit_event(self, event_name): """ Emits an event to explicitly track course enrollment and unenrollment. """ try: context = contexts.course_context_from_course_id(self.course_id) assert(isinstance(self.course_id, CourseKey)) data = { 'user_id': self.user.id, 'course_id': self.course_id.to_deprecated_string(), 'mode': self.mode, } with tracker.get_tracker().context(event_name, context): tracker.emit(event_name, data) if settings.FEATURES.get('SEGMENT_IO_LMS') and settings.SEGMENT_IO_LMS_KEY: tracking_context = tracker.get_tracker().resolve_context() analytics.track(self.user_id, event_name, { 'category': 'conversion', 'label': self.course_id.to_deprecated_string(), 'org': self.course_id.org, 'course': self.course_id.course, 'run': self.course_id.run, 'mode': self.mode, }, context={ 'Google Analytics': { 'clientId': tracking_context.get('client_id') } }) except: # pylint: disable=bare-except if event_name and self.course_id: log.exception('Unable to emit event %s for user %s and course %s', event_name, self.user.username, self.course_id)
def track_event(event, metadata=None): """ Track segment event if user opted-in. Args: event: name of event to track in segment. metadata: dict of metadata """ try: from zenml.repo import GlobalConfig config = GlobalConfig.get_instance() opt_in = config.get_analytics_opt_in() logger.debug(f"Analytics opt-in: {opt_in}.") if opt_in is False and event is not INITIALIZE: return user_id = config.get_user_id() if metadata is None: metadata = {} # add basics metadata.update(get_system_info()) metadata.update({'version': __version__}) analytics.track(user_id, event, metadata) logger.debug( f'Analytics sent: User: {user_id}, Event: {event}, Metadata: ' f'{metadata}') except Exception as e: # We should never fail main thread logger.debug(f'Analytics failed due to: {e}') return
def send_download_status(app, status, extra=None): analytics.track( 'downloader', 'download_status', { 'title': app, 'message': "downloaded" if status else "failed", 'extra': extra, })
def send(self, event): """Use the segment.com python API to send the event to segment.com""" if analytics is None: return context = event.get('context', {}) user_id = context.get('user_id') name = event.get('name') if name is None or user_id is None: return segment_context = {} ga_client_id = context.get('client_id') if ga_client_id is not None: segment_context['Google Analytics'] = { 'clientId': ga_client_id } analytics.track( user_id, name, event, context=segment_context )
def test_new_user(uid, type, properties, endpoint, api_root, api_key, streams): """Test processing a new user.""" kg_input = KinesisGenerator(streams.input, timeout=5) kg_output = KinesisGenerator(streams.output, timeout=10) # Cloudwatch logs automatically compresses with GZIP all records before # delivering them to Kinesis. kg_log = KinesisGenerator(streams.log, timeout=30, preprocess=gzip.decompress) # Forget the current analytics endpoint setting imp.reload(analytics) analytics.write_key = api_key analytics.endpoint = api_root + endpoint analytics.track(uid, type, properties) recs_input = [rec for rec in kg_input] recs_output = [rec for rec in kg_output] recs_log = [x for x in _get_log_events(kg_log) if x["message"].find("New user") > -1] assert len(recs_input) == 1 assert len(recs_output) == 1 assert len(recs_log) == 1 assert "sentAt" in recs_input[0] and "context" in recs_input[0] \ and "event" in recs_input[0] assert parse_datetime(recs_input[0]["sentAt"]) assert recs_input[0]["event"]["userId"] == uid assert "userName" not in recs_input[0] and "user_name" in recs_output[0]
def unsubscribe_newsletter(request): email = request.GET.get('email', None) if not email: return HttpResponseBadRequest("") else: email = email.lower() subscriber = None try: subscriber = NewsletterSubscriber.objects.get(email=email) subscriber.delete() useremail = get_or_create_user_id(email) analytics.identify(useremail.user_id, traits={ 'newsletter': False, 'unsubscribed': True, }) analytics.track(useremail.user_id, 'unsubscribed_newsletter', { 'email': email, }) except: pass # Let's handle the unsubscription if even we don't have the user! return render_to_response("unsubscribed.html", {}, content_type="application/json")
def invite_contact_list(request): """Get a list of contact items {'name': Shahin, 'email': [email protected]} and trigger invitation email from inviter user. """ contacts = request.POST.get('contacts', None) result = {} try: contacts = json.loads(contacts) inviter = request.user inviter_id = request.user.id.user_id inviter_name = inviter.first_name + inviter.last_name for item in contacts: email = item['email'] name = item['name'] user_id = get_or_create_user_id(email).user_id analytics.identify(str(user_id), { "email": email, "firstName": name, }) data = { 'name': name, 'inviter': str(inviter), 'inviter_id': inviter_id, 'inviter_name': inviter_name, } analytics.track(user_id, 'invited', data) result['done'] = True except: result['error'] = 'Invalid data' return HttpResponse(json.dumps(result))
def buy_app_checkout(request): """ Send a user with session created in start_app_buy to pay the bill. F5 token is needed in session to get no errors. """ user_id = request.session.get('user_id', None) if not user_id: return HttpResponse(json.dumps({'error': True})) gateway = 'mellat' request_data = {'gateway': gateway, 'token': request.session.get('token', None)} headers = f5.get_api_header() res = requests.post(GenericPayAPI, headers=headers, data=request_data) if res.status_code == 200: # Set order_status to 1 => StartPayment order_id = request.session['order_id'] change_order_status(order_id, 1) analytics.track(user_id, 'buyapp_payment', { "gateway": gateway, }) return HttpResponse(res) return HttpResponse(json.dumps({'error': True}))
def redirect_to_short_url(shorturl=""): analytics.track('plinky-server', 'redirect_to_short_url', { 'shorturl': shorturl }) return redirect(shortcuts.lookup_shorturl(shorturl), 302)
def track_completed_order(sender, order=None, **kwargs): # pylint: disable=unused-argument """Emit a tracking event when an order is placed.""" if not (is_segment_configured() and order.total_excl_tax > 0): return user_tracking_id, lms_client_id = parse_tracking_context(order.user) analytics.track( user_tracking_id, 'Completed Order', { 'orderId': order.number, 'total': str(order.total_excl_tax), 'currency': order.currency, 'products': [ { # For backwards-compatibility with older events the `sku` field is (ab)used to # store the product's `certificate_type`, while the `id` field holds the product's # SKU. Marketing is aware that this approach will not scale once we start selling # products other than courses, and will need to change in the future. 'id': line.partner_sku, 'sku': mode_for_seat(line.product), 'name': line.product.course.id, 'price': str(line.line_price_excl_tax), 'quantity': line.quantity, 'category': line.product.get_product_class().name, } for line in order.lines.all() ], }, context={ 'Google Analytics': { 'clientId': lms_client_id } }, )
def send_message(self, email_outbox_message): """ Creates a task to asynchronously send out a reply or forward an email message. Args: email_outbox_message (instance): EmailOutboxMessage instance Returns: Task instance """ send_logger = logging.getLogger('email_errors_temp_logger') send_logger.info('Begin creating reply/forward task for email_outbox_message %d to %s' % ( email_outbox_message.id, email_outbox_message.to )) task = send_message.apply_async( args=(email_outbox_message.id, self.object.id), max_retries=1, default_retry_delay=100, ) send_logger.info('Reply/forward Task (%s) status %s for email_outbox_message %d' % ( task.id, task.status, email_outbox_message.id )) if task: messages.info( self.request, _('Sending email as fast as I can.') ) self.request.session['tasks'].update({'send_message': task.id}) self.request.session.modified = True # Track sending forward or reply messages in Segment. mail_type = '' if email_outbox_message.subject.startswith('Re: '): mail_type = 'Reply' elif email_outbox_message.subject.startswith('Fwd: '): mail_type = 'Forward' analytics.track(self.request.user.id, 'email-message-sent', { 'recipient_to': email_outbox_message.to, 'recipient_cc': email_outbox_message.cc, 'recipient_bcc': email_outbox_message.bcc, 'type': mail_type, }) else: messages.error( self.request, _('Sorry, I couldn\'t send your email.') ) logging.error(_('Failed to create %s task for email account %d. Outbox message id was %d.') % ( self.action, email_outbox_message.send_from, email_outbox_message.id, )) return task
def log_analytics(request, event, properties): try: import analytics from ipware.ip import get_ip as get_ip if settings.DEBUG: return if not hasattr(settings, "SEGMENT_IO_KEY"): logger.warning("Cannot send analytics. No Segment IO Key has been set") return if "pingdom" in request.META.get("HTTP_USER_AGENT", ""): logger.warning("Not recording analytics. Ignored pingdom bot") return api_key = settings.SEGMENT_IO_KEY ip = get_ip(request) name = names.get_full_name() uid = request.session.get("uid", name) request.session["uid"] = uid analytics.init(api_key) analytics.identify(uid, { "$name" : uid, }, { "$ip" : ip} ) analytics.track(uid, event=event, properties=properties) except Exception, e: logger.exception("Error handling analytics")
def add_person(request): myself = get_person_from_user(request.user) if request.method == 'POST': form = PersonForm(request.POST) if form.is_valid(): new_person = form.save() new_person.invited_by = myself.login_user new_person.save() myself.recipients.add(new_person) new_person.recipients.add(myself) # let's start them off with one person on their list # send an email letting them know how to sign up: send_signup_email(myself, new_person) analytics.track(request.user.id, 'Invited a new Person', { 'person_id': new_person.id }) return HttpResponseRedirect(reverse('Gifts.views.view_all_people')) else: form = PersonForm() analytics.page(request.user.id, 'giftlist', 'add_person') return render(request, 'add_item.html', {'form': form, 'add_title': 'Add a new person you would like to give a gift to.', 'add_description': ("By adding a new person, you can track what gift you'd like to give them. " "This will also send them an email inviting them to join Gift Exchange " "so that you can see the gifts they want.")})
def tracking_order_paid(sender, order, **kwargs): event = sender analytics.write_key = event.settings.get('segment_api_key') analytics.debug = True analytics.track(order.email, 'order_paid')
def track_api_event(): api_key = request.values.get('key') if not api_key: api_key = request.args.get("api_admin_key", "") if not api_user.is_internal_key(api_key): if request.path not in ["/favicon.ico"]: requested_to_create_item = False requested_to_view_item = False if ("/v1/item" in request.url): if (request.method == "POST"): requested_to_create_item = True elif (request.method == "GET"): requested_to_view_item = True if (request.args.get("register", 0) in ["1", "true", "True"]): requested_to_create_item = True analytics.track("CORE", "Received API request from external", { "path": request.path, "url": request.url, "method": request.method, "requested_to_create_item": requested_to_create_item, "requested_to_view_item": requested_to_view_item, "user_agent": request.user_agent.string, "api_key": api_key }, context={ "providers": { 'Mixpanel': False } })
def create(self, validated_data): tenant = self.context.get('request').user.tenant contact_count = Contact.objects.filter(is_deleted=False).count() if tenant.billing.is_free_plan and contact_count >= settings.FREE_PLAN_ACCOUNT_CONTACT_LIMIT: raise serializers.ValidationError({ 'limit_reached': _('You\'ve reached the limit of contacts for the free plan.'), }) instance = super(ContactSerializer, self).create(validated_data) credentials = get_credentials('moneybird') if has_required_tier(2) and credentials and credentials.integration_context.get('auto_sync'): self.send_moneybird_contact(validated_data, instance, credentials) # Track newly ceated accounts in segment. if not settings.TESTING: analytics.track( self.context.get('request').user.id, 'contact-created', { 'creation_type': 'automatic' if is_external_referer(self.context.get('request')) else 'manual', }, ) return instance
def update(self, instance, validated_data): current_user = self.context.get('request').user if instance.picture is validated_data.get('picture'): validated_data['picture'] = None increment_users = False if 'is_active' in validated_data: if current_user.is_admin: is_active = validated_data.get('is_active') # Only continue if we're actually activating a user. if is_active != instance.is_active and is_active: increment_users = True else: raise PermissionDenied if 'internal_number' in validated_data: internal_number = validated_data.get('internal_number') if internal_number: try: user = LilyUser.objects.get( internal_number=internal_number, tenant=current_user.tenant) except (LilyUser.DoesNotExist, PermissionDenied): pass else: if current_user.is_admin: # If an internal number is passed we want to clear it if # there's already a user with that internal number. user.internal_number = None user.save() else: if current_user.id != instance.id: raise PermissionDenied elif internal_number != instance.internal_number: raise serializers.ValidationError({ 'internal_number': [ _('Another user is already using this internal number.' ) ] }) # Track changing internal number in Segment. analytics.track( instance.id, 'internal-number-updated', { 'internal_number_updated_by': current_user.id, 'type': 'Admin' if current_user.is_admin else 'User', }) instance = super(LilyUserSerializer, self).update(instance, validated_data) # Increment after saving the user in case of errors. if increment_users: # Increment the plan's quantity. instance.tenant.billing.update_subscription(1) return instance
def track_command(user_id, command_name): analytics.write_key = ANALYTICS_WRITE_KEY analytics.identify(user_id) analytics.track(user_id, "Run Command", { "category": "ST3", "label": command_name, })
def login_analytics(*args, **kwargs): """ Sends login info to Segment.io """ event_name = None action_to_event_name = { 'is_login': '******', 'is_dashboard': 'edx.bi.user.account.linked', 'is_profile': 'edx.bi.user.account.linked', } # Note: we assume only one of the `action` kwargs (is_dashboard, is_login) to be # `True` at any given time for action in action_to_event_name.keys(): if kwargs.get(action): event_name = action_to_event_name[action] if event_name is not None: registration_course_id = kwargs['request'].session.get('registration_course_id') tracking_context = tracker.get_tracker().resolve_context() analytics.track( kwargs['user'].id, event_name, { 'category': "conversion", 'label': registration_course_id, 'provider': getattr(kwargs['backend'], 'name') }, context={ 'Google Analytics': { 'clientId': tracking_context.get('client_id') } } )
def track_activate(user_id): analytics.write_key = ANALYTICS_WRITE_KEY analytics.identify(user_id) analytics.track(user_id, "Activate", { "category": "ST3", "label": sublime.platform(), })
def _track_reverification_events(self, event_name, user_id, course_id, checkpoint): # pylint: disable=invalid-name """Track re-verification events for user against course checkpoints Arguments: user_id (str): The ID of the user generting the certificate. course_id (unicode): id associated with the course checkpoint (str): checkpoint name Returns: None """ if settings.FEATURES.get('SEGMENT_IO_LMS') and hasattr(settings, 'SEGMENT_IO_LMS_KEY'): tracking_context = tracker.get_tracker().resolve_context() analytics.track( user_id, event_name, { 'category': "verification", 'label': unicode(course_id), 'checkpoint': checkpoint }, context={ 'Google Analytics': { 'clientId': tracking_context.get('client_id') } } )
def _should_randomly_suppress_schedule_creation( schedule_config, enrollment, upgrade_deadline, experience_type, content_availability_date, ): # The hold back ratio is always between 0 and 1. A value of 0 indicates that schedules should be created for all # schedules. A value of 1 indicates that no schedules should be created for any enrollments. A value of 0.2 would # mean that 20% of enrollments should *not* be given schedules. # This allows us to measure the impact of the dynamic schedule experience by comparing this "control" group that # does not receive any of benefits of the feature against the group that does. if random.random() < schedule_config.hold_back_ratio: log.debug('Schedules: Enrollment held back from dynamic schedule experiences.') upgrade_deadline_str = None if upgrade_deadline: upgrade_deadline_str = upgrade_deadline.isoformat() analytics.track( 'edx.bi.schedule.suppressed', { 'user_id': enrollment.user.id, 'course_id': unicode(enrollment.course_id), 'experience_type': experience_type, 'upgrade_deadline': upgrade_deadline_str, 'content_availability_date': content_availability_date.isoformat(), } ) return True return False
def _track_update_email_opt_in(user_id, organization, opt_in): """Track an email opt-in preference change. Arguments: user_id (str): The ID of the user making the preference change. organization (str): The organization whose emails are being opted into or out of by the user. opt_in (bool): Whether the user has chosen to opt-in to emails from the organization. Returns: None """ event_name = 'edx.bi.user.org_email.opted_in' if opt_in else 'edx.bi.user.org_email.opted_out' tracking_context = tracker.get_tracker().resolve_context() analytics.track(user_id, event_name, { 'category': 'communication', 'label': organization }, context={ 'ip': tracking_context.get('ip'), 'Google Analytics': { 'clientId': tracking_context.get('client_id') } })
def emit_event(self, event_name): """ Emits an event to explicitly track course enrollment and unenrollment. """ try: context = contexts.course_context_from_course_id(self.course_id) assert isinstance(self.course_id, CourseKey) data = {"user_id": self.user.id, "course_id": self.course_id.to_deprecated_string(), "mode": self.mode} with tracker.get_tracker().context(event_name, context): tracker.emit(event_name, data) if settings.FEATURES.get("SEGMENT_IO_LMS") and settings.SEGMENT_IO_LMS_KEY: tracking_context = tracker.get_tracker().resolve_context() analytics.track( self.user_id, event_name, { "category": "conversion", "label": self.course_id.to_deprecated_string(), "org": self.course_id.org, "course": self.course_id.course, "run": self.course_id.run, "mode": self.mode, }, context={"Google Analytics": {"clientId": tracking_context.get("client_id")}}, ) except: # pylint: disable=bare-except if event_name and self.course_id: log.exception( "Unable to emit event %s for user %s and course %s", event_name, self.user.username, self.course_id )
def track_completed_order(sender, order=None, **kwargs): # pylint: disable=unused-argument """Emit a tracking event when an order is placed.""" if not (is_segment_configured() and order.total_excl_tax > 0): return user_tracking_id, lms_client_id = parse_tracking_context(order.user) analytics.track( user_tracking_id, "Completed Order", { "orderId": order.number, "total": str(order.total_excl_tax), "currency": order.currency, "products": [ { # For backwards-compatibility with older events the `sku` field is (ab)used to # store the product's `certificate_type`, while the `id` field holds the product's # SKU. Marketing is aware that this approach will not scale once we start selling # products other than courses, and will need to change in the future. "id": line.partner_sku, "sku": line.product.attr.certificate_type, "name": line.product.title, "price": str(line.line_price_excl_tax), "quantity": line.quantity, "category": line.product.get_product_class().name, } for line in order.lines.all() ], }, context={"Google Analytics": {"clientId": lms_client_id}}, )
def run(self, invitation_id): logger = self.get_logger() try: invitation = Invitation.objects.select_related('inviter').get(id=invitation_id) except Invitation.DoesNotExist: logger.warning('Cannot notify segment.io about Invitation[id=%d] because it cannot be found.', invitation_id) return logger.info('Notify segment.io about %s.', invitation) email = invitation.email if invitation.admin_id is None: analytics.identify(email, traits={'email': email, 'Lifecycle stage': 'lead', 'source': 'Invitation'}, context={'active': False}, timestamp=self.timestamp) invitation_url = settings.INVITATION_SITE_URL + '?invitation_key=%s' % invitation.key # if invitation was created by admin, we will include it in invitation event if invitation.inviter is None: inviter = None else: inviter = invitation.inviter.email analytics.track(invitation.admin_id or email, 'Invitation received', { 'invitationUrl': invitation_url, 'inviter': inviter, 'instance': invitation.instance.name }, timestamp=self.timestamp)
def track(user, event, properties=None, context=None): """ Helper function that wraps the segment.io track and adds in the source for the event as our current hostname. """ # no op if we aren't prod if not settings.IS_PROD: return # create a context if none was passed in if context is None: context = dict() # set our source according to our hostname context["source"] = settings.HOSTNAME # create properties if none were passed in if properties is None: properties = dict() # populate value=1 in our properties if it isn't present if not "value" in properties: properties["value"] = 1 # call through to the real segment.io analytics segment_analytics.track(user, event, properties, context)
def run(self, admin_id): profile = Profile.objects.select_related('admin').get(admin_id=admin_id) analytics.track(admin_id, 'Hard limit reached', { 'hardLimit': profile.hard_limit_formatted, 'plan': profile.current_subscription.plan.name, 'period': profile.hard_limit_reached.strftime(settings.ANALYTICS_DATE_FORMAT) }, timestamp=self.timestamp)
def reserve_gift(request, recipient_id, gift_id): myself = get_person_from_user(request.user) recipient = get_object_or_404(Person, pk=recipient_id) gift = get_object_or_404(Gift, pk=gift_id) success = False if gift.reserved_by is None: # unreserve any other gifts first # clear_reserved_gifts(myself, recipient) # then reserve this gift for me gift.reserved_by = myself gift.date_reserved = datetime.now() gift.save() messages.success(request, "You've successfully reserved the %s for %s!" % (gift.title, recipient.first_name)) success = True else: messages.error(request, 'Someone has already reserved that gift!') analytics.track(request.user.id, 'Reserved a Gift', { 'gift_title': gift.title, 'recipient_id': recipient.id, 'recipient_name': recipient.name(), 'success': 'Yes' if success else 'No' }) return HttpResponseRedirect(reverse('Gifts.views.view_user', args=(recipient.pk,)))
def run(self): invoices = Invoice.objects.filter(status_sent=False, period__lt=Invoice.current_period()) invoices = invoices.select_related('admin').prefetch_related('items') invoices = invoices.order_by('pk') chunk = list(invoices[:self.chunk_size + 1]) if not chunk: return try: for invoice in chunk[:self.chunk_size]: # Don't send summary for invoices without items with API_CALL or # CODEBOX_TIME. Because we prefetched items we check this in python if any(item for item in invoice.items.all() if not item.is_fee()): analytics.track( invoice.admin.id, 'Monthly Summary', { 'apiCalls': invoice.get_usage(Transaction.SOURCES.API_CALL), 'codeboxSeconds': invoice.get_usage( Transaction.SOURCES.CODEBOX_TIME), 'apiPlan': invoice.get_display_plan_limit( Transaction.SOURCES.API_CALL), 'codeboxPlan': invoice.get_display_plan_limit( Transaction.SOURCES.CODEBOX_TIME) }, timestamp=self.timestamp) finally: invoices.filter(pk__lte=chunk[-1].pk).update(status_sent=True) if len(chunk) > self.chunk_size: self.delay()
def _get_error(self, status_code, response=None): try: headers = response.headers except AttributeError: headers = {} try: text = response.text except (AttributeError, TypeError): text = "" if response: url = response.url else: url = None analytics.track("CORE", "Received error response from Provider", { "provider": self.provider_name, "url": url, "text": text, "status_code": status_code }) if status_code >= 500: error = ProviderServerError(response) self.logger.info(u"%s ProviderServerError status code=%i, %s, %s" % (self.provider_name, status_code, text, str(headers))) else: error = ProviderClientError(response) self.logger.info(u"%s ProviderClientError status code=%i, %s, %s" % (self.provider_name, status_code, text, str(headers))) raise(error) return error
def run(self, admin_id, uid, token): url = settings.GUI_CONFIRM_RESET_PASSWORD_URL % {'uid': uid, 'token': token} analytics.track(admin_id, 'Password reset', { 'uid': uid, 'token': token, 'passwordResetUrl': url, }, timestamp=self.timestamp)
def user_logout(request): analytics.track(request.user.pk, 'Logged Out') logout(request) # Take the user back to the homepage. return HttpResponseRedirect(reverse('login'))
def test_performance(self): to_send = 100 target = analytics.stats.successful + to_send analytics.default_client.async = True analytics.default_client.flush_at = 200 analytics.default_client.max_flush_size = 50 analytics.default_client.set_log_level(logging.DEBUG) for i in range(to_send): analytics.track('*****@*****.**', 'Played a Song', { "Artist": "The Beatles", "Song": "Eleanor Rigby" }) print('Finished submitting into the queue') start = time() while analytics.stats.successful < target: print ('Successful ', analytics.stats.successful, 'Left', (target - analytics.stats.successful), 'Duration ', (time() - start)) analytics.flush() sleep(1.0)
def track_api_event(): api_key = request.values.get('key') if not api_key: api_key = request.args.get("api_admin_key", "") if not api_user.is_internal_key(api_key): if request.path not in ["/favicon.ico"]: requested_to_create_item = False requested_to_view_item = False if ("/v1/item" in request.url): if (request.method == "POST"): requested_to_create_item = True elif (request.method == "GET"): requested_to_view_item = True if (request.args.get("register", 0) in ["1", "true", "True"]): requested_to_create_item = True analytics.track( "CORE", "Received API request from external", { "path": request.path, "url": request.url, "method": request.method, "requested_to_create_item": requested_to_create_item, "requested_to_view_item": requested_to_view_item, "user_agent": request.user_agent.string, "api_key": api_key }, context={"providers": { 'Mixpanel': False }})
def send_to_segment(context): jobID = os.environ["GITHUB_RUN_ID"] analytics.identify(jobID, { "name": "model-regression-tests", "created_at": datetime.datetime.now() }) analytics.track( jobID, "results", { "dataset": os.environ["DATASET_NAME"], "dataset_repository_branch": os.environ["DATASET_REPOSITORY_BRANCH"], "workflow": os.environ["GITHUB_WORKFLOW"], "config": os.environ["CONFIG"], "pr_url": os.environ["PR_URL"], "accelerator_type": os.environ["ACCELERATOR_TYPE"], "test_run_time": os.environ["TEST_RUN_TIME"], "train_run_time": os.environ["TRAIN_RUN_TIME"], "total_run_time": os.environ["TOTAL_RUN_TIME"], "github_run_id": os.environ["GITHUB_RUN_ID"], "github_sha": os.environ["GITHUB_SHA"], "github_event": os.environ["GITHUB_EVENT_NAME"], **context, }, )
def emit_event(self, event_name): """ Emits an event to explicitly track course enrollment and unenrollment. """ try: context = contexts.course_context_from_course_id(self.course_id) assert (isinstance(self.course_id, CourseKey)) data = { 'user_id': self.user.id, 'course_id': self.course_id.to_deprecated_string(), 'mode': self.mode, } with tracker.get_tracker().context(event_name, context): tracker.emit(event_name, data) if settings.FEATURES.get( 'SEGMENT_IO_LMS') and settings.SEGMENT_IO_LMS_KEY: analytics.track( self.user_id, event_name, { 'category': 'conversion', 'label': self.course_id.to_deprecated_string(), 'org': self.course_id.org, 'course': self.course_id.course, 'run': self.course_id.run, 'mode': self.mode, }) except: # pylint: disable=bare-except if event_name and self.course_id: log.exception( 'Unable to emit event %s for user %s and course %s', event_name, self.user.username, self.course_id)
def stay_a_day(self,the_date, day): """Generate a Segment call's worth of data and perform internal upkeep for buying a single ticket.""" self.reservation_length -= 1 enthusiasm = 1.0 if "Hail" in day.events: enthusiasm -= 0.5*age_multipliers[self.age_bracket] elif "Thunderstorm" in day.events: enthusiasm -= 0.4*age_multipliers[self.age_bracket] else: if "Rain" in day.events: enthusiasm -= 0.2*age_multipliers[self.age_bracket] if "Fog" in day.events: enthusiasm -= 0.1*age_multipliers[self.age_bracket] if "Snow" in day.events: enthusiasm += 0.5 if day.max_temp >= 40: enthusiasm = enthusiasm/4.0 elif day.max_temp >= 32: enthusiasm = enthusiasm/2.0 time.sleep(.02) analytics.track(self.id, "used-pass", {"date": str(the_date), "hours-spent": 8.0*enthusiasm, "price": day.ticket_price, "enthusiasm": enthusiasm, "weather": day.events.split('-'), "cloud_cover": day.cloud_cover}) return True
def _track_reverification_events(self, event_name, user_id, course_id, checkpoint): # pylint: disable=invalid-name """Track re-verification events for a user against a reverification checkpoint of a course. Arguments: event_name (str): Name of event being tracked user_id (str): The ID of the user course_id (unicode): ID associated with the course checkpoint (str): Checkpoint name Returns: None """ log.info( u"In-course reverification: event %s occurred for user '%s' in course '%s' at checkpoint '%s'", event_name, user_id, course_id, checkpoint ) if settings.FEATURES.get('SEGMENT_IO_LMS') and hasattr(settings, 'SEGMENT_IO_LMS_KEY'): tracking_context = tracker.get_tracker().resolve_context() analytics.track( user_id, event_name, { 'category': "verification", 'label': unicode(course_id), 'checkpoint': checkpoint }, context={ 'Google Analytics': { 'clientId': tracking_context.get('client_id') } } )
def inbox(request): # segment.io track analytics.track( request.user.id, 'inbox', { 'name': request.user.trainer.name if request.user.is_trainer else request.user.client.name, }) user_threads = UserThread.objects.filter( user=request.user).order_by('-thread__last_message_date') possible_recipients = possible_recipients_for_user(request.user) try: new_message_to_user = request.session.pop('new_message_to_user') except KeyError: new_message_to_user = None return render( request, 'messages/inbox.html', { 'recipient_names_json': json.dumps([u.display_name for u in possible_recipients]), 'recipient_map_json': json.dumps({u.display_name: u.pk for u in possible_recipients}), 'user_threads': user_threads, 'new_message_to_user': new_message_to_user })
def send(self, action, install_method, num_errors): """Sends analytics track data to segmentIO. variant: string | open or enterprise action: string | preflight, deploy, or postflight install_method: string | gui, cli or advanced """ analytics.write_key = "51ybGTeFEFU1xo6u10XMDrr6kATFyRyh" # Set customer key here rather than __init__ since we want the most up to date config # and config may change between __init__ and here. config = Config(CONFIG_PATH) customer_key = config.hacky_default_get('customer_key', None) # provider is always onprem when the cli installer is used provider = "onprem" # platform defaults to provider value, if not specified platform = config.hacky_default_get('platform', provider) analytics.track(user_id=customer_key, anonymous_id=self.uuid, event="installer", properties={ "platform": platform, "provider": provider, "source": "installer", "variant": os.environ["BOOTSTRAP_VARIANT"], "install_id": self.uuid, "bootstrap_id": os.environ["BOOTSTRAP_ID"], "install_method": install_method, "action_name": action, "errors": num_errors, "customerKey": customer_key, }) analytics.flush()
def start_pay(request, gateway): if not request.session.get("token", None): print "Error in Token" return HttpResponse(json.dumps({"error": True})) if 'invoice_id' in request.session: del request.session['invoice_id'] request.session.save() if request.session.get('gift', False): return gift_start_payment(request, gateway) if request.user.is_authenticated(): user_id = request.session['user_id'] else: user_id = request.session['user_id'] payurl = settings.FPAN['host'] + settings.FPAN['urls']['v2payment'] auth = (settings.FPAN['auth']['username'], settings.FPAN['auth']['password']) payload = { 'gateway': gateway, 'token': request.session['token'], 'user_id': user_id } r = requests.post(payurl, data=payload, headers=f5.get_api_header(), verify=False) analytics.track(user_id, 'start_payment', {"gateway": gateway}) if r.status_code != 200: return HttpResponse(json.dumps({'error': True})) return HttpResponse(r.text, content_type="text/html")
def _track_update_email_opt_in(user_id, organization, opt_in): """Track an email opt-in preference change. Arguments: user_id (str): The ID of the user making the preference change. organization (str): The organization whose emails are being opted into or out of by the user. opt_in (bool): Whether the user has chosen to opt-in to emails from the organization. Returns: None """ event_name = 'edx.bi.user.org_email.opted_in' if opt_in else 'edx.bi.user.org_email.opted_out' tracking_context = tracker.get_tracker().resolve_context() analytics.track( user_id, event_name, { 'category': 'communication', 'label': organization }, context={ 'ip': tracking_context.get('ip'), 'Google Analytics': { 'clientId': tracking_context.get('client_id') } } )
def _should_randomly_suppress_schedule_creation( schedule_config, enrollment, upgrade_deadline, experience_type, content_availability_date, ): # The hold back ratio is always between 0 and 1. A value of 0 indicates that schedules should be created for all # schedules. A value of 1 indicates that no schedules should be created for any enrollments. A value of 0.2 would # mean that 20% of enrollments should *not* be given schedules. # This allows us to measure the impact of the dynamic schedule experience by comparing this "control" group that # does not receive any of benefits of the feature against the group that does. if random.random() < schedule_config.hold_back_ratio: log.debug( 'Schedules: Enrollment held back from dynamic schedule experiences.' ) upgrade_deadline_str = None if upgrade_deadline: upgrade_deadline_str = upgrade_deadline.isoformat() analytics.track( 'edx.bi.schedule.suppressed', { 'user_id': enrollment.user.id, 'course_id': unicode(enrollment.course_id), 'experience_type': experience_type, 'upgrade_deadline': upgrade_deadline_str, 'content_availability_date': content_availability_date.isoformat(), }) return True return False
def test_performance(self): to_send = 100 target = analytics.stats.successful + to_send analytics.default_client.async = True analytics.default_client.flush_at = 200 analytics.default_client.max_flush_size = 50 analytics.default_client.set_log_level(logging.DEBUG) for i in range(to_send): analytics.track('*****@*****.**', 'Played a Song', { "Artist": "The Beatles", "Song": "Eleanor Rigby" }) print 'Finished submitting into the queue' start = time() while analytics.stats.successful < target: print ('Successful ', analytics.stats.successful, 'Left', (target - analytics.stats.successful), 'Duration ', (time() - start)) analytics.flush() sleep(1.0)
def track(self, event, properties=None, timestamp=None, context=None): """track an event by js if a user isn't identified :param event: the event to track (string) :param properties: a dictionary of event details :param timestamp: a datetime.datetime timestamp :param context: optional dictionary specified by segment.io """ properties = properties or {} flattened_p = flatten_dict(properties) context = context or {} log.info('Tracked %s with properties: %s' % (event, properties)) if self.user_id: analytics.track( user_id=self.user_id, event=event, properties=flattened_p, context=context, timestamp=timestamp) return self.events.append({ 'event': event, 'properties': flattened_p, 'options': context })
def login_analytics(strategy, auth_entry, *args, **kwargs): """ Sends login info to Segment """ event_name = None if auth_entry == AUTH_ENTRY_LOGIN: event_name = 'edx.bi.user.account.authenticated' elif auth_entry in [AUTH_ENTRY_ACCOUNT_SETTINGS]: event_name = 'edx.bi.user.account.linked' if event_name is not None and hasattr(settings, 'LMS_SEGMENT_KEY') and settings.LMS_SEGMENT_KEY: tracking_context = tracker.get_tracker().resolve_context() analytics.track( kwargs['user'].id, event_name, { 'category': "conversion", 'label': None, 'provider': getattr(kwargs['backend'], 'name') }, context={ 'ip': tracking_context.get('ip'), 'Google Analytics': { 'clientId': tracking_context.get('client_id') } } )
def track_foreign(self, user_id, event, properties=None, timestamp=None, context=None): """Track an event for a user who is not attached to this instance's request attribute. :param user_id: the user_id to track an event for :param event: title of the event to track (e.g. 'user_created') :param properties: a dictionary of event details :param timestamp: a datetime.datetime timestamp :param context: optional dictionary specified by segment.io """ user_id = str(user_id) properties = properties or {} flattened_p = flatten_dict(properties) context = context or {} log.info('Tracked %s for %s with properties: %s' % (event, user_id, properties)) analytics.track( user_id=user_id, event=event, properties=flattened_p, context=context, timestamp=timestamp)
def track(user, event, properties=None, context=None): # pragma: needs cover """ Helper function that wraps the segment.io track and adds in the source for the event as our current hostname. """ # no op if we aren't prod if not settings.IS_PROD: return # create a context if none was passed in if context is None: context = dict() # set our source according to our hostname (name of the platform instance, and not machine hostname) context['source'] = settings.HOSTNAME # create properties if none were passed in if properties is None: properties = dict() # populate value=1 in our properties if it isn't present if 'value' not in properties: properties['value'] = 1 # call through to the real segment.io analytics segment_analytics.track(user, event, properties, context)
def login_analytics(strategy, *args, **kwargs): """ Sends login info to Segment.io """ event_name = None action_to_event_name = { 'is_login': '******', 'is_dashboard': 'edx.bi.user.account.linked', 'is_profile': 'edx.bi.user.account.linked', # Backwards compatibility: during an A/B test for the combined # login/registration form, we introduced a new login end-point. # Since users may continue to have this in their sessions after # the test concludes, we need to continue accepting this action. 'is_login_2': 'edx.bi.user.account.authenticated', } # Note: we assume only one of the `action` kwargs (is_dashboard, is_login) to be # `True` at any given time for action in action_to_event_name.keys(): if kwargs.get(action): event_name = action_to_event_name[action] if event_name is not None: tracking_context = tracker.get_tracker().resolve_context() analytics.track(kwargs['user'].id, event_name, { 'category': "conversion", 'label': strategy.session_get('enroll_course_id'), 'provider': getattr(kwargs['backend'], 'name') }, context={ 'Google Analytics': { 'clientId': tracking_context.get('client_id') } })
def done(self, form_list, **kwargs): user = self.get_user() login(self.request, user) if not self.request.user.info.registration_finished: # If the user has not finished registration yet, redirect them there to finish it now. redirect_to = reverse('register') else: redirect_to = self.request.POST.get( self.redirect_field_name, self.request.GET.get(self.redirect_field_name, '') ) if not is_safe_url(url=redirect_to, host=self.request.get_host()): redirect_to = resolve_url(settings.LOGIN_REDIRECT_URL) device = getattr(user, 'otp_device', None) if device: if isinstance(device, StaticDevice): # User logged in using a static backup code, refresh it with a new one. device.token_set.create(token=StaticToken.random_token()) signals.user_verified.send( sender=__name__, request=self.request, user=user, device=device ) # Track login type in Segment. analytics.track(user.id, 'user-login', { 'login_type': 'Traditional', }) return redirect(redirect_to)
def add_to_cart(request): quantity = 1 supply_id = request.GET.get('id', None) if (supply_id): user_id = "anon" if request.user.id: user_id = request.user.id supply = Supply.objects.get(id=supply_id) cart = Cart(request) cart.add(supply, supply.price, quantity) analytics.track(user_id, 'Added to cart', { 'supply_id' : supply.id, "supply_name" : supply.name }) if request.session.get('email', '') == '': return redirect('cart.views.get_email') return redirect('cart.views.view_cart')