def mark_prompt(self, prompt, answer, qid, offline=False, rotate=False): ''' This function is used to cover these 3 use cases: 1. question has been answered and sent now 2. question is answered and saved offline 3. offline answer has been sent and marked as "sent" See get_offline_answers for details on how to send offline answers when back online ''' self._cache_mark_responded(prompt, answer, qid, offline) # If the question has been answered and sent to us, add it to the tracker if not offline: track_data("feedback_widget_response_sent", { "question": prompt, "question_id": qid }) # And we jump to the next available question if rotate: self.current_prompt = self._get_next_prompt() return self.current_prompt
def apply_changes(self, button, event): pw_dialog = ParentalPasswordDialog(self.win) if not pw_dialog.verify(): return level = self.parental_level.get_value() set_parental_level(level) set_setting('Parental-level', level) # track which parental control level people use track_data("parental-control-level-changed", { "level": level }) if level == 3.0: # If on the highest parental control, prompt user to relaunch # the browser kdialog = KanoDialog( title_text='Settings', description_text=("If any browsers are open, please relaunch " "them for this setting to take effect"), parent_window=self.win ) kdialog.run() else: # Only reboot for the lower parental controls common.need_reboot = True self.win.go_to_home()
def _hw_info(): # TODO: This import is done here to avoid potential # import loops with kano-peripherals. from kano_peripherals.wrappers.detection import is_ck2_lite, is_ck2_pro, \ is_ckt, get_ck2_lite_version, get_ck2_pro_version, get_ckt_version # If CKL/CKCs cannot be detected, defaults to Computer Kits without version. kit_type = 'ck' kit_version = None # Detect CK Lite via the PiHat board. if is_ck2_lite(): kit_type = 'ckl' kit_version = get_ck2_lite_version() # Detect CK Complete via the PowerHat board and other peripherals. elif is_ck2_pro(): kit_type = 'ckc' kit_version = get_ck2_pro_version() # Detect CKT via the PowerHat board and EDID. elif is_ckt(): kit_type = 'ckt' kit_version = get_ckt_version() track_data( 'hw-info', { 'keyboard': 'kano' if detect_kano_keyboard() else 'generic', 'model': get_rpi_model(), 'partitions': get_partition_info(), 'kit': { 'type': kit_type, 'version': kit_version.vstring if kit_version else kit_version } })
def apply_changes(self, button, event): pw_dialog = ParentalPasswordDialog(self.win) if not pw_dialog.verify(): return level = self.parental_level.get_value() set_parental_level(level) # track which parental control level people use track_data('parental-control-level-changed', {'level': level}) if level == 3.0: # If on the highest parental control, prompt user to relaunch # the browser kdialog = KanoDialog( title_text=_("Settings"), description_text=(_("If any browsers are open, please relaunch " \ "them for this setting to take effect")), parent_window=self.win ) kdialog.run() else: # Only reboot for the lower parental controls common.need_reboot = True self.win.go_to_home()
def install_urgent(progress, status): progress.split( Phase( 'installing-urgent', _("Installing Hotfix"), 100, is_main=True ) ) logger.info("Installing urgent hotfix") apt_handle = AptWrapper.get_instance() packages_to_update = apt_handle.packages_to_be_upgraded() progress.start('installing-urgent') install_deb_packages(progress, priority=Priority.URGENT) status.is_urgent = False try: from kano_profile.tracker import track_data track_data('updated_hotfix', { 'packages': packages_to_update }) logger.info("Tracking Data: '{}'".format(packages_to_update)) except ImportError as imp_exc: logger.error("Couldn't track hotfix installation, failed to import " "tracking module", exception=imp_exc) except Exception: pass return True
def _hw_info(): # TODO: This import is done here to avoid potential # import loops with kano-peripherals. from kano_peripherals.wrappers.detection import is_ck2_lite, is_ck2_pro, \ is_ckt, get_ck2_lite_version, get_ck2_pro_version, get_ckt_version # If CKL/CKCs cannot be detected, defaults to Computer Kits without version. kit_type = 'ck' kit_version = None # Detect CK Lite via the PiHat board. if is_ck2_lite(): kit_type = 'ckl' kit_version = get_ck2_lite_version() # Detect CK Complete via the PowerHat board and other peripherals. elif is_ck2_pro(): kit_type = 'ckc' kit_version = get_ck2_pro_version() # Detect CKT via the PowerHat board and EDID. elif is_ckt(): kit_type = 'ckt' kit_version = get_ckt_version() track_data('hw-info', { 'keyboard': 'kano' if detect_kano_keyboard() else 'generic', 'model': get_rpi_model(), 'partitions': get_partition_info(), 'kit': { 'type': kit_type, 'version': kit_version.vstring if kit_version else kit_version } })
def apply_changes(self, button, event): # If enter key is pressed or mouse button is clicked if not hasattr(event, 'keyval') or event.keyval == Gdk.KEY_Return: # Check if there was a change to the Flip Screen state. if self.flip_preference_start != self.flip_preference_end: set_flip(self.flip_preference_end) end_config_transaction() common.need_reboot = True # Check if there was resolution change. if self.init_item != self.mode_index: # Set HDMI mode # Get mode:group string # Of the form "auto" or "cea:1" or "dmt:1" etc. parse_mode = self.mode.split(" ")[0] self.set_hdmi_mode_from_str(parse_mode) # Track the user's screen resolution track_data('screen-mode-changed', {'mode': parse_mode}) end_config_transaction() common.need_reboot = True self.win.go_to_home()
def install_urgent(progress, status): progress.split( Phase( 'installing-urgent', _('Installing Hotfix'), 100, is_main=True ) ) logger.debug('Installing urgent hotfix') packages_to_update = apt_handle.packages_to_be_upgraded() progress.start('installing-urgent') install_deb_packages(progress, priority=Priority.URGENT) status.is_urgent = False try: from kano_profile.tracker import track_data track_data('updated_hotfix', { 'packages': packages_to_update }) logger.debug('Tracking Data: "{}"'.format(packages_to_update)) except ImportError as imp_exc: logger.error(("Couldn't track hotfix installation, failed to import " "tracking module: [{}]").format(imp_exc)) except Exception: pass
def apply_changes(self, button, event): # If enter key is pressed or mouse button is clicked if not hasattr(event, 'keyval') or event.keyval == Gdk.KEY_Return: # Check if there was a change to the Flip Screen state. if self.flip_preference_start != self.flip_preference_end: set_flip(self.flip_preference_end) end_config_transaction() common.need_reboot = True # Check if there was resolution change. if self.init_item != self.mode_index: # Set HDMI mode # Get mode:group string # Of the form "auto" or "cea:1" or "dmt:1" etc. parse_mode = self.mode.split(" ")[0] self.set_hdmi_mode_from_str(parse_mode) # Track the user's screen resolution track_data('screen-mode-changed', { 'mode': parse_mode }) end_config_transaction() common.need_reboot = True self.win.go_to_home()
def track_data_and_sync(event_name, event_data): """Create a tracking event with data and upload it to the servers. This function also appends a uuid to the event data such that these immediate events can be grouped more easily. See :func:`kano_profile.tracker.tracking_uuids.get_tracking_uuid`. Note: This is a slow function, requires a network connection and the user being logged into Kano World. Args: event_name (str): See :func:`kano_profile.tracker.track_data` event_data (dict): See :func:`kano_profile.tracker.track_data` """ try: from kano_profile.tracker import track_data from kano_profile.tracker.tracking_uuids import get_tracking_uuid event_data['uuid'] = get_tracking_uuid(TRACKING_UUID_KEY) track_data(event_name, event_data) rc = os.system('kano-sync --skip-kdesk --upload-tracking-data --silent') logger.debug( 'track_data_and_sync: {} {} and sync rc {}' .format(event_name, event_data, rc) ) except: logger.error('Unexpected error:\n{}'.format(traceback.format_exc()))
def _show_username_taken_dialog(self, username): # TODO: refactor this track_data('world-registration-username-taken', {'username': username}) kd = KanoDialog(_("This username is taken!"), _("Try another one"), parent_window=self.win) kd.run() self.data_screen.username.set_text("") self.data_screen.validate_username() self._disable_register_button() self.data_screen.username.grab_focus()
def _show_username_taken_dialog(self, username): # TODO: refactor this track_data('world-registration-username-taken', {'username': username}) kd = KanoDialog( _("This username is taken!"), _("Try another one"), parent_window=self.win ) kd.run() self.data_screen.username.set_text("") self.data_screen.validate_username() self._disable_register_button() self.data_screen.username.grab_focus()
def _trigger_tracking_event(self): """ Generate a tracker event with some hardware settings. This will send a track_date event called 'user-settings' with the audio setting, parental lock level and display configuration. """ track_data('user-settings', { 'audio': 'hdmi' if is_HDMI() else 'analog', 'parental-lock-level': get_setting('Parental-level'), 'display': get_status() })
def launch(app_id, background=False): cmd = "kano-apps" args = ["install", app_id] try: try: from kano_profile.tracker import track_data track_data("app-installed", app_id) except Exception: pass os.execvp(cmd, [cmd] + args) except: logger.error("Unable to launch kano-apps")
def main(): track_data( 'safe-mode-boot', { 'os-version-stamp': _get_kano_os_version_stamp(), 'config-txt': _get_config_txt(), 'display-name': _get_display_name(), 'display-status': _get_display_status(), 'display-modes-cea': _get_display_modes('cea'), 'display-modes-dmt': _get_display_modes('dmt'), 'hdmi-audio-output': is_HDMI(), 'disk-space-usage': _get_disk_space_usage() } ) os.system('kano-sync --skip-kdesk --upload-tracking-data --silent')
def __init__(self, pipes, score): super(GameOverState, self).__init__() self.pipes = pipes self.score = score self.pipes.reset_pipes() try: # TODO: track best score as well track_data('updater-flappy-judoka-score', { 'score': score }) except: logger.warn("Tracking the users score failed!") debugger("ERROR: GameOverState: __init__: Tracking the users score failed!")
def __init__(self, pipes, score): super(GameOverState, self).__init__() self.pipes = pipes self.score = score self.pipes.reset_pipes() try: # TODO: track best score as well track_data('updater-flappy-judoka-score', {'score': score}) except: logger.warn("Tracking the users score failed!") debugger( "ERROR: GameOverState: __init__: Tracking the users score failed!" )
def install_urgent(progress, status): progress.split( Phase('installing-urgent', _("Installing Hotfix"), 100, is_main=True)) logger.debug("Installing urgent hotfix") packages_to_update = apt_handle.packages_to_be_upgraded() progress.start('installing-urgent') install_deb_packages(progress, priority=Priority.URGENT) status.is_urgent = False try: from kano_profile.tracker import track_data track_data('updated_hotfix', {'packages': packages_to_update}) logger.debug("Tracking Data: '{}'".format(packages_to_update)) except ImportError as imp_exc: logger.error("Couldn't track hotfix installation, failed to import " \ "tracking module: [{}]".format(imp_exc)) except Exception: pass
def apply_changes(self, button, event): pw_dialog = ParentalPasswordDialog(self.win) if not pw_dialog.verify(): return whitelist = [row[0] for row in self.whitelist.edit_list_store] blacklist = [row[0] for row in self.blacklist.edit_list_store] write_whitelisted_sites(whitelist) write_blacklisted_sites(blacklist) level = get_setting('Parental-level') set_parental_level(level) common.need_reboot = True # track which parental control level people use track_data('parental-control-level-changed', {'level': level}) self.win.go_to_home()
def bump_system_version(): # Store the version change with open(SYSTEM_VERSION_FILE, 'r') as v_file: system_version = v_file.read().strip() logger.info("Changed the version of the OS from {} to {}".format( system_version, TARGET_VERSION.to_version_string())) try: from kano_profile.tracker import track_data track_data('updated', {'from': system_version, 'to': VERSION}) except Exception: pass # Update stored version with open(SYSTEM_VERSION_FILE, 'w') as vfile: vfile.write(TARGET_VERSION.to_version_string() + "\n") with open(SYSTEM_ISSUE_FILE, 'w') as ifile: ifile.write(TARGET_VERSION.to_issue() + "\n")
def apply_changes(self, button, event): pw_dialog = ParentalPasswordDialog(self.win) if not pw_dialog.verify(): return whitelist = [row[0] for row in self.whitelist.edit_list_store] blacklist = [row[0] for row in self.blacklist.edit_list_store] write_whitelisted_sites(whitelist) write_blacklisted_sites(blacklist) level = get_setting('Parental-level') set_parental_level(level) common.need_reboot = True # track which parental control level people use track_data("parental-control-level-changed", { "level": level }) self.win.go_to_home()
def apply_changes(self, button, event): # If enter key is pressed or mouse button is clicked if not hasattr(event, 'keyval') or event.keyval == Gdk.KEY_Return: # Check if we have done any change if self.init_item != self.mode_index: # Set HDMI mode # Get mode:group string # Of the form "auto" or "cea:1" or "dmt:1" etc. parse_mode = self.mode.split(" ")[0] self.set_hdmi_mode_from_str(parse_mode) # Track the user's screen resolution track_data("screen-mode-changed", { "mode": parse_mode }) common.need_reboot = True self.win.go_to_home()
def first_stage(self): """ Runs the first stage. Note: The first stage is determined by the location variable from the status file, not necessarily the very first stage. """ if not self._status.debug_mode: if self._status.completed: self._return_value = self.NOT_FIRST_BOOT return False if os.path.exists(OLD_FIRST_BOOT_FILE): self._return_value = self.NOT_FIRST_BOOT self.complete() return False if self._should_skip_init_flow(): self.complete() return False self._main_window.set_key_events_handlers() if len(self._stages): index = 0 if self._status.location is not None: index = self._get_stage_index(self._status.location) track_data('init-flow-resumed', {'stage': self._status.location}) else: track_action('init-flow-started') stage_ctl = self._stages[index](self) stage_ctl.first_scene() else: raise RuntimeError('No flow stages available') self._tracking_session = session_start(stage_ctl.id, os.getpid()) return True
def bump_system_version(): system_version = get_system_version() target_version = get_target_version() logger.info("Changed the version of the OS from {} to {}".format( system_version.to_version_string(), target_version.to_version_string())) try: from kano_profile.tracker import track_data track_data('updated', { 'from': system_version.to_version_string(), 'to': VERSION }) except Exception: pass # Update stored version with open(SYSTEM_VERSION_FILE, 'w') as vfile: vfile.write(target_version.to_version_string() + "\n") with open(SYSTEM_ISSUE_FILE, 'w') as ifile: ifile.write(target_version.to_issue() + "\n")
def mark_prompt(self, prompt, answer, qid, offline=False, rotate=False): ''' This function is used to cover these 3 use cases: 1. question has been answered and sent now 2. question is answered and saved offline 3. offline answer has been sent and marked as "sent" See get_offline_answers for details on how to send offline answers when back online ''' self._cache_mark_responded(prompt, answer, qid, offline) # If the question has been answered and sent to us, add it to the tracker if not offline: track_data("feedback_widget_response_sent", {"question": prompt, "question_id": qid}) # And we jump to the next available question if rotate: self.current_prompt = self._get_next_prompt() return self.current_prompt
def bump_system_version(): # Store the version change with open(SYSTEM_VERSION_FILE, 'r') as v_file: system_version = v_file.read().strip() logger.info("Changed the version of the OS from {} to {}".format( system_version, TARGET_VERSION.to_version_string())) try: from kano_profile.tracker import track_data track_data('updated', { 'from': system_version, 'to': VERSION }) except Exception: pass # Update stored version with open(SYSTEM_VERSION_FILE, 'w') as vfile: vfile.write(TARGET_VERSION.to_version_string() + "\n") with open(SYSTEM_ISSUE_FILE, 'w') as ifile: ifile.write(TARGET_VERSION.to_issue() + "\n")
def bump_system_version(): system_version = get_system_version() target_version = get_target_version() logger.info("Changed the version of the OS from {} to {}".format( system_version.to_version_string(), target_version.to_version_string()) ) try: from kano_profile.tracker import track_data track_data('updated', { 'from': system_version.to_version_string(), 'to': VERSION }) except Exception: pass # Update stored version with open(SYSTEM_VERSION_FILE, 'w') as vfile: vfile.write(target_version.to_version_string() + "\n") with open(SYSTEM_ISSUE_FILE, 'w') as ifile: ifile.write(target_version.to_issue() + "\n")
def _on_register_button(self, widget=None): # TODO: refactor this """ """ if not is_internet(): self._show_not_internet_dialog() return # Get the username, password and birthday data = self.data_screen.get_widget_data() email = data['email'] username = data['username'] # Validate that the email address format is correct email_error = validate_email(email) if email_error: self._show_error_dialog(_("Incorrect Email address"), email_error) return if not self._is_username_available(username): self._show_username_taken_dialog(username) return # We can save the username to kano-profile # Don't save password as this is private self.data_screen.save_username_and_birthday() # TODO: rename this self.data_screen.cache_emails() data = self.data_screen.get_widget_data() # This means no threads are needed. while Gtk.events_pending(): # TODO: why is this needed? Gtk.main_iteration() # Try and register the account on the server password = data['password'] success, text = register_(email, username, password, marketing_enabled=True) # This should no longer be needed, since this is checked in the first # screen. However there is a small chance someone could take the # username while the user is in the process of registering if not success: if text.strip() == _("Cannot register, problem: " "Username already registered"): self._show_username_taken_dialog(username) else: logger.info("problem with registration: {}".format(text)) return_value = 'FAIL' self._create_dialog( title=_("Houston, we have a problem"), description=str(text) ) track_data('world-registration-failed', {'reason': text}) else: logger.info("registration successful") # saving hardware info and initial Kano version save_hardware_info() save_kano_version() # running kano-sync after registration logger.info("running kano-sync after successful registration") cmd = '{bin_dir}/kano-sync --sync -s'.format(bin_dir=bin_dir) run_bg(cmd) return_value = 'SUCCEED' self._create_dialog( title=_("Profile activated!"), description=_("Now you can share stuff, build your character, " "and connect with friends.") ) self.win.get_window().set_cursor(None) # Close the app if it was successful if return_value == 'SUCCEED': Gtk.main_quit()
def register_user_with_gui(self): self.data_screen.cache_emails() self.data_screen.cache_marketing_choice() self.page_control.disable_buttons() self.data_screen.disable_all() self.get_email_data() # Make cursor into a spinner watch_cursor = Gdk.Cursor(Gdk.CursorType.WATCH) self.win.get_window().set_cursor(watch_cursor) # This means no threads are needed. while Gtk.events_pending(): Gtk.main_iteration() # Try and register the account on the server email = self.win.data["email"] secondary_email = self.win.data["secondary_email"] username = self.win.data["username"] password = self.win.data["password"] date_year = self.win.data["year"] date_month = self.win.data["month"] date_day = self.win.data["day"] marketing_enabled = self.win.data["marketing_enabled"] logger.info('trying to register user with data {} {} {} {} {} {} {} {}' .format( email, secondary_email, username, password, date_year, date_month, date_day, marketing_enabled ) ) success, text = register_(email, username, password, date_year, date_month, date_day, secondary_email=secondary_email, marketing_enabled=marketing_enabled) # This should no longer be needed, since this is checked in the first screen. # However there is a small chance someone could take the username # while the user is in the process of registering if not success: if text.strip() == "Cannot register, problem: Username already registered": logger.info('username invalid - getting second username') self.collect_new_username() return else: logger.info('problem with registration: {}'.format(text)) return_value = "FAIL" self.create_dialog( title=_("Houston, we have a problem"), description=str(text) ) track_data('world-registration-failed', {'reason': text}) else: logger.info('registration successful') bday_date = str(datetime.date(date_year, date_month, date_day)) save_profile_variable('birthdate', bday_date) # saving hardware info and initial Kano version save_hardware_info() save_kano_version() # running kano-sync after registration logger.info('running kano-sync after successful registration') cmd = '{bin_dir}/kano-sync --sync -s'.format(bin_dir=bin_dir) run_bg(cmd) return_value = "SUCCEED" self.create_dialog( title=_("Profile activated!"), description=_("Now you can share stuff, build your character, " "and connect with friends.") ) self.page_control.enable_buttons() self.data_screen.enable_all() self.win.get_window().set_cursor(None) # Close the app if it was successful if return_value == "SUCCEED": Gtk.main_quit()
def _auto_poweroff(): track_data('battery', {'status': 'automatic-poweroff'})
def _first_boot(): track_data('first-boot', { 'language': (os.getenv('LANG') or '').split('.', 1)[0], 'variant': read_file_contents('/etc/kanux_version_variant') })
def _low_battery(): track_data('battery', {'status': 'low-charge'})
def next_page(self, widget): age, bday_date, error = self.data_screen.calculate_age() if age == -1: self._show_error_dialog(error[0], error[1]) return # Get the username, password and birthday data = self.data_screen.get_widget_data() username = data["username"] if not is_internet(): kd = KanoDialog( "You don't have internet", "Do you want to connect to WiFi?", [ { "label": "YES", "color": "green", "return_value": 0 }, { "label": "NO", "color": "red", "return_value": 1 } ], parent_window=self.win ) response = kd.run() # Close the dialog while Gtk.events_pending(): Gtk.main_iteration() if response == 0: subprocess.Popen("sudo kano-wifi-gui", shell=True) return if not self.is_username_available(username): track_data('world-registration-username-taken', {'username': username}) kd = KanoDialog( "This username is taken!", "Try another one", parent_window=self.win ) kd.run() self.data_screen.username.set_text("") self.data_screen.validate_username() self.data_screen.username.grab_focus() return self.win.data = data # We can save the username and birthday to kano-profile # Don't save password as this is private self.data_screen.save_username_and_birthday() self.win.remove_main_widget() # Pass the age to the third registration screen so we can show the # appropriate number of entries available RegistrationScreen2(self.win, age)
def _low_battery(): track_data('battery', { 'status': 'low-charge' })
def _first_boot(): track_data( 'first-boot', { 'language': (os.getenv('LANG') or '').split('.', 1)[0], 'variant': read_file_contents('/etc/kanux_version_variant') })
def _auto_poweroff(): track_data('battery', { 'status': 'automatic-poweroff' })
def _on_register_button(self, widget=None): # TODO: refactor this """ """ if not is_internet(): self._show_not_internet_dialog() return # Get the username, password and birthday data = self.data_screen.get_widget_data() email = data['email'] username = data['username'] # Validate that the email address format is correct email_error = validate_email(email) if email_error: self._show_error_dialog(_("Incorrect Email address"), email_error) return if not self._is_username_available(username): self._show_username_taken_dialog(username) return # We can save the username to kano-profile # Don't save password as this is private self.data_screen.save_username_and_birthday() # TODO: rename this self.data_screen.cache_emails() data = self.data_screen.get_widget_data() # This means no threads are needed. while Gtk.events_pending(): # TODO: why is this needed? Gtk.main_iteration() # Try and register the account on the server password = data['password'] success, text = register_(email, username, password, marketing_enabled=True) # This should no longer be needed, since this is checked in the first # screen. However there is a small chance someone could take the # username while the user is in the process of registering if not success: if text.strip() == _("Cannot register, problem: " "Username already registered"): self._show_username_taken_dialog(username) else: logger.info("problem with registration: {}".format(text)) return_value = 'FAIL' self._create_dialog(title=_("Houston, we have a problem"), description=str(text)) track_data('world-registration-failed', {'reason': text}) else: logger.info("registration successful") # saving hardware info and initial Kano version save_hardware_info() save_kano_version() # running kano-sync after registration logger.info("running kano-sync after successful registration") cmd = '{bin_dir}/kano-sync --sync -s'.format(bin_dir=bin_dir) run_bg(cmd) return_value = 'SUCCEED' self._create_dialog( title=_("Profile activated!"), description=_("Now you can share stuff, build your character, " "and connect with friends.")) self.win.get_window().set_cursor(None) # Close the app if it was successful if return_value == 'SUCCEED': Gtk.main_quit()