def generate_tracker_token(): """ Generating the token is a simple md5hash of the current time. The token is saved to the `tracker_token_file`. :returns: The token. :rtype: str """ token = hashlib.md5(str(time.time())).hexdigest() ensure_dir(tracker_dir) try: f = open_locked(tracker_token_file, "w") except IOError as e: logger.error( 'Error opening tracker token file (generate) {}'.format(e)) else: with f: f.write(token) if 'SUDO_USER' in os.environ: chown_path(tracker_token_file) # Make sure that the events file exist try: f = open(tracker_events_file, 'a') except IOError as e: logger.error('Error opening tracker events file {}'.format(e)) else: f.close() if 'SUDO_USER' in os.environ: chown_path(tracker_events_file) return token
def copy_screenshot(filename): ''' Copies screenshot 'filename' into SCREENSHOT_PATH ''' ensure_dir(TMP_DIR) if os.path.isfile(filename): run_cmd("cp %s %s" % (filename, SCREENSHOT_PATH))
def take_screenshot(): ''' Takes a screenshot and saves it into SCREENSHOT_PATH ''' ensure_dir(TMP_DIR) cmd = "kano-screenshot -w 1024 -p " + SCREENSHOT_PATH _, _, rc = run_cmd(cmd)
def _cache_pip_packages(progress, priority=Priority.NONE): """ Downloads all updatable python modules and caches them in pip's internal pacakge cache. """ # Urgent updates don't do PIP updates if priority == Priority.URGENT: return phase_name = 'downloading-pip-pkgs' progress.start(phase_name) ensure_dir(PIP_CACHE_DIR) packages = read_file_contents_as_lines(PIP_PACKAGES_LIST) progress.init_steps(phase_name, len(packages)) for pkg in packages: progress.next_step(phase_name, _("Downloading {}").format(pkg)) # The `--no-install` parameter has been deprecated in pip. However, the # version of pip in wheezy doesn't yet support the new approach which # is supposed to provide the same behaviour. args = "download --dest '{}' '{}'".format(PIP_CACHE_DIR, pkg) success = run_pip_command(args) # TODO: abort the install? if not success: msg = "Downloading the '{}' pip package failed.".format(pkg) logger.error(msg)
def copy_screenshot(filename): ''' Copies screenshot 'filename' into SCREENSHOT_PATH ''' ensure_dir(TMP_DIR) if os.path.isfile(filename): run_cmd("cp %s %s" % (filename, SCREENSHOT_PATH))
def take_screenshot(): ''' Takes a screenshot and saves it into SCREENSHOT_PATH ''' ensure_dir(TMP_DIR) cmd = "kano-screenshot -w 1024 -p " + SCREENSHOT_PATH _, _, rc = run_cmd(cmd)
def download_online_badges(self): profile = load_profile() if "kanoworld_id" in profile: user_id = profile["kanoworld_id"] else: return False, "Profile not registered!" success, text, data = request_wrapper("get", "/users/{}".format(user_id), session=self.session) if not success: return False, text if "user" not in data: return False, "Corrupt response (the 'user' key not found)" if "profile" not in data["user"]: return False, "Corrupt response (the 'user.profile' key not found)" if "badges" not in data["user"]["profile"]: msg = "Corrupt response (the 'user.profile.badges' key not found)" return False, msg online_badges_data = {} ensure_dir(online_badges_dir) badges = data["user"]["profile"]["badges"] for badge in badges: if "assigned" not in badge or not badge["assigned"]: continue if "image_url" not in badge: return False, "Couldn't find an image for the badge" image_loc = os.path.join(online_badges_dir, "{}.png".format(badge["id"])) download_url(badge["image_url"], image_loc) online_badges_data[badge["id"]] = { "achieved": True, "bg_color": badge["bg_color"].replace("#", ""), "desc_locked": badge["desc_locked"], "desc_unlocked": badge["desc_unlocked"], "title": badge["title"], } try: may_write = True txt = None f = open(online_badges_file, "w") except IOError as e: may_write = False txt = "Error opening badges file {}".format(str(e)) else: with f: f.write(json.dumps(online_badges_data)) if "SUDO_USER" in os.environ: chown_path(online_badges_dir) chown_path(online_badges_file) return may_write, txt
def _cache_pip_packages(progress, priority=Priority.NONE): """ Downloads all updatable python modules and caches them in pip's internal pacakge cache. """ # Urgent updates don't do PIP updates if priority == Priority.URGENT: return phase_name = 'downloading-pip-pkgs' progress.start(phase_name) ensure_dir(PIP_CACHE_DIR) packages = read_file_contents_as_lines(PIP_PACKAGES_LIST) progress.init_steps(phase_name, len(packages)) for pkg in packages: progress.next_step(phase_name, "Downloading {}".format(pkg)) # The `--no-install` parameter has been deprecated in pip. However, the # version of pip in wheezy doesn't yet support the new approach which # is supposed to provide the same behaviour. args = "install --upgrade --download '{}' '{}'".format(PIP_CACHE_DIR, pkg) success = run_pip_command(args) # TODO: abort the install? if not success: msg = "Downloading the '{}' pip package failed.".format(pkg) logger.error(msg)
def get_metadata_archive(): ''' It creates a file (ARCHIVE_NAME) with all the information Returns the file ''' ensure_dir(TMP_DIR) file_list = [ {'name': 'kanux_version.txt', 'contents': get_version()}, {'name': 'kanux_stamp.txt', 'contents': get_stamp()}, {'name': 'process.txt', 'contents': get_processes()}, {'name': 'packages.txt', 'contents': get_packages()}, {'name': 'dmesg.txt', 'contents': get_dmesg()}, {'name': 'syslog.txt', 'contents': get_syslog()}, {'name': 'cmdline.txt', 'contents': read_file_contents('/boot/cmdline.txt')}, {'name': 'config.txt', 'contents': read_file_contents('/boot/config.txt')}, {'name': 'wifi-info.txt', 'contents': get_wifi_info()}, {'name': 'usbdevices.txt', 'contents': get_usb_devices()}, # TODO: Remove raw logs when json ones become stable {'name': 'app-logs.txt', 'contents': get_app_logs_raw()}, {'name': 'app-logs-json.txt', 'contents': get_app_logs_json()}, {'name': 'hdmi-info.txt', 'contents': get_hdmi_info()}, {'name': 'edid.dat', 'contents': get_edid()}, {'name': 'screen-log.txt', 'contents': get_screen_log()}, {'name': 'xorg-log.txt', 'contents': get_xorg_log()}, {'name': 'cpu-info.txt', 'contents': get_cpu_info()}, {'name': 'lsof.txt', 'contents': get_lsof()}, {'name': 'content-objects.txt', 'contents': get_co_list()} ] # Include the screenshot if it exists if os.path.isfile(SCREENSHOT_PATH): file_list.append({ 'name': SCREENSHOT_NAME, 'contents': read_file_contents(SCREENSHOT_PATH) }) # Collect all coredumps, for applications that terminated unexpectedly for f in os.listdir('/var/tmp/'): if f.startswith('core-'): file_list.append({ 'name': f, 'contents': read_file_contents(os.path.join('/var/tmp', f)) }) # create files for each non empty metadata info for file in file_list: if file['contents']: write_file_contents(TMP_DIR + file['name'], file['contents']) # archive all the metadata files # need to change dir to avoid tar subdirectories current_directory = os.getcwd() os.chdir(TMP_DIR) run_cmd("tar -zcvf {} *".format(ARCHIVE_NAME)) # open the file and return it archive = open(ARCHIVE_NAME, 'rb') # restore the current working directory os.chdir(current_directory) return archive
def init(): # Copy custom-theme from /usr/share if necessary if not os.path.exists(theme_file): src_file = '/usr/share/make-snake/%s' % CUSTOM_THEME if not os.path.exists(src_file): sys.exit('Error: custom-theme.xml missing from home and /usr/share/make-snake') ensure_dir(THEMES_DIR) shutil.copyfile(src_file, theme_file) load_theme() menus.update_naming()
def get_metadata_archive(): ''' It creates a file (ARCHIVE_NAME) with all the information Returns the file ''' ensure_dir(TMP_DIR) file_list = [ {'name': 'kanux_version.txt', 'contents': get_version()}, {'name': 'process.txt', 'contents': get_processes()}, {'name': 'packages.txt', 'contents': get_packages()}, {'name': 'dmesg.txt', 'contents': get_dmesg()}, {'name': 'syslog.txt', 'contents': get_syslog()}, {'name': 'cmdline.txt', 'contents': read_file_contents('/boot/cmdline.txt')}, {'name': 'config.txt', 'contents': read_file_contents('/boot/config.txt')}, {'name': 'wifi-info.txt', 'contents': get_wifi_info()}, {'name': 'usbdevices.txt', 'contents': get_usb_devices()}, # TODO: Remove raw logs when json ones become stable {'name': 'app-logs.txt', 'contents': get_app_logs_raw()}, {'name': 'app-logs-json.txt', 'contents': get_app_logs_json()}, {'name': 'hdmi-info.txt', 'contents': get_hdmi_info()}, {'name': 'xorg-log.txt', 'contents': get_xorg_log()}, {'name': 'cpu-info.txt', 'contents': get_cpu_info()}, {'name': 'lsof.txt', 'contents': get_lsof()}, {'name': 'content-objects.txt', 'contents': get_co_list()} ] # Include the screenshot if it exists if os.path.isfile(SCREENSHOT_PATH): file_list.append({ 'name': SCREENSHOT_NAME, 'contents': read_file_contents(SCREENSHOT_PATH) }) # create files for each non empty metadata info for file in file_list: if file['contents']: write_file_contents(TMP_DIR + file['name'], file['contents']) # Collect all coredumps, for applications that terminated unexpectedly for f in os.listdir('/var/tmp/'): if f.startswith('core-'): file_list.append({ 'name': f, 'contents': read_file_contents(os.path.join('/var/tmp', f)) }) # archive all the metadata files # need to change dir to avoid tar subdirectories current_directory = os.getcwd() os.chdir(TMP_DIR) run_cmd("tar -zcvf {} *".format(ARCHIVE_NAME)) # open the file and return it archive = open(ARCHIVE_NAME, 'rb') # restore the current working directory os.chdir(current_directory) return archive
def set_chromium_policies(policies): if not os.path.exists(chromium_policy_file): ensure_dir(os.path.dirname(chromium_policy_file)) policy_config = {} else: policy_config = read_json(chromium_policy_file) for policy in policies: policy_config[policy[0]] = policy[1] write_json(chromium_policy_file, policy_config)
def copy_archive_report(target_archive): ''' Copies source archive (TMP_DIR/ARCHIVE_NAME) into target_archive ''' ensure_dir(TMP_DIR) source_archive = os.path.join(TMP_DIR, ARCHIVE_NAME) if os.path.isfile(source_archive): _, _, rc = run_cmd("cp %s %s" % (source_archive, target_archive)) return (rc == 0) else: return False
def set_chromium_policies(policies): if not os.path.exists(chromium_policy_file): ensure_dir(os.path.dirname(chromium_policy_file)) policy_config = {} else: policy_config = read_json(chromium_policy_file) for policy in policies: policy_config[policy[0]] = policy[1] write_json(chromium_policy_file, policy_config)
def copy_archive_report(target_archive): ''' Copies source archive (TMP_DIR/ARCHIVE_NAME) into target_archive ''' ensure_dir(TMP_DIR) source_archive = os.path.join(TMP_DIR, ARCHIVE_NAME) if os.path.isfile(source_archive): _, _, rc = run_cmd("cp %s %s" % (source_archive, target_archive)) return (rc == 0) else: return False
def init(): # Copy custom-theme from /usr/share if necessary if not os.path.exists(theme_file): src_file = '/usr/share/make-snake/%s' % CUSTOM_THEME if not os.path.exists(src_file): sys.exit( 'Error: custom-theme.xml missing from home and /usr/share/make-snake' ) ensure_dir(THEMES_DIR) shutil.copyfile(src_file, theme_file) load_theme() menus.update_naming()
def _save_state(self): ensure_dir(os.path.dirname(QUESTS_STORE)) if os.path.exists(QUESTS_STORE): with open(QUESTS_STORE, 'r') as quest_store_f: store = json.load(quest_store_f) else: store = {} if self._id not in store: store[self._id] = {} store[self._id]['state'] = self._state with open(QUESTS_STORE, 'w') as quest_store_f: json.dump(store, quest_store_f)
def _save_state(self): ensure_dir(os.path.dirname(QUESTS_STORE)) if os.path.exists(QUESTS_STORE): with open(QUESTS_STORE, 'r') as quest_store_f: store = json.load(quest_store_f) else: store = {} if self._id not in store: store[self._id] = {} store[self._id]['state'] = self._state with open(QUESTS_STORE, 'w') as quest_store_f: json.dump(store, quest_store_f)
def __init__(self): if UpdaterStatus._singleton_instance: raise Exception('This class is a singleton!') else: UpdaterStatus._singleton_instance = self self._state = self.NO_UPDATES self._last_check = 0 self._last_update = 0 ensure_dir(os.path.dirname(self._status_file)) if not os.path.exists(self._status_file): self.save() else: self.load()
def __init__(self): if Status._singleton_instance: raise Exception('This class is a singleton!') else: Status._singleton_instance = self self._location = None self._completed = False # Initialise as True, and change if debug mode is set self._saving_enabled = True ensure_dir(os.path.dirname(self._status_file)) if not os.path.exists(self._status_file): self.save() else: self.load()
def __init__(self): if Status._singleton_instance: raise Exception('This class is a singleton!') else: Status._singleton_instance = self self._location = None self._completed = False # Initialise as True, and change if debug mode is set self._saving_enabled = True ensure_dir(os.path.dirname(self._status_file)) if not os.path.exists(self._status_file): self.save() else: self.load()
def init(): global theme, colors_map if parser.args.theme in DEFAULT_THEMES: try: theme = themes.game_themes[parser.args.theme] except: theme = themes.game_themes['minimal'] else: # copy custom-theme.xml if it doesn't exist if not os.path.exists(CUSTOM_FILE): if not os.path.exists(CUSTOM_THEME_PATH): sys.exit('Error: custom-theme.xml missing from home and /usr/share/make-snake') ensure_dir(app_dir) shutil.copyfile(CUSTOM_THEME_PATH, CUSTOM_FILE) # Load the customn theme load_theme() colors_map = get_colors_map()
def save_profile(data): ''' Write profile data to file :param data: JSON serialisable data about the profile ''' logger.debug('save_profile') data.pop('cpu_id', None) data.pop('mac_addr', None) data['save_date'] = get_date_now() ensure_dir(profile_dir) write_json(profile_file, data) if 'SUDO_USER' in os.environ: chown_path(kanoprofile_dir) chown_path(profile_dir) chown_path(profile_file) if os.path.exists('/usr/bin/kdesk') and not is_running('kano-sync'): logger.info('refreshing kdesk from save_profile') run_bg('kdesk -a profile')
def save_app_state(app_name, data): """ Save a state of an application to the user's Kano profile. :param app_name: The application that this data are associated with. :type app_name: str :param data: The data to be stored. :type data: dict """ logger.debug("save_app_state {}".format(app_name)) app_state_file = get_app_state_file(app_name) data['save_date'] = get_date_now() ensure_dir(get_app_dir(app_name)) write_json(app_state_file, data) if 'SUDO_USER' in os.environ: chown_path(kanoprofile_dir) chown_path(apps_dir) chown_path(get_app_dir(app_name)) chown_path(app_state_file)
def save_app_state(app_name, data): """ Save a state of an application to the user's Kano profile. :param app_name: The application that this data are associated with. :type app_name: str :param data: The data to be stored. :type data: dict """ logger.debug('save_app_state {}'.format(app_name)) app_state_file = get_app_state_file(app_name) data['save_date'] = get_date_now() ensure_dir(get_app_dir(app_name)) write_json(app_state_file, data) if 'SUDO_USER' in os.environ: chown_path(kanoprofile_dir) chown_path(apps_dir) chown_path(get_app_dir(app_name)) chown_path(app_state_file)
def init(): global theme, colors_map if parser.args.theme in DEFAULT_THEMES: try: theme = themes.game_themes[parser.args.theme] except: theme = themes.game_themes['minimal'] else: # copy custom-theme.xml if it doesn't exist if not os.path.exists(CUSTOM_FILE): if not os.path.exists(CUSTOM_THEME_PATH): sys.exit( 'Error: custom-theme.xml missing from home and /usr/share/make-snake' ) ensure_dir(app_dir) shutil.copyfile(CUSTOM_THEME_PATH, CUSTOM_FILE) # Load the customn theme load_theme() colors_map = get_colors_map()
def __init__(self): if UpdaterStatus._singleton_instance: raise Exception('This class is a singleton!') else: UpdaterStatus._singleton_instance = self self._state = self.NO_UPDATES self._last_check = 0 self._last_check_urgent = 0 self._last_update = 0 self._first_boot_countdown = 0 self._is_urgent = False self._is_scheduled = False self._notifications_muted = False self._is_shutdown = False ensure_dir(os.path.dirname(self._status_file)) if not os.path.exists(self._status_file): self.save() else: self.load()
def save_profile(data, skip_kdesk_refresh=False): ''' Write profile data to file :param data: JSON serialisable data about the profile ''' logger.debug('save_profile') data.pop('cpu_id', None) data.pop('mac_addr', None) data['save_date'] = get_date_now() ensure_dir(profile_dir) write_json(profile_file, data) if 'SUDO_USER' in os.environ: chown_path(kanoprofile_dir) chown_path(profile_dir) chown_path(profile_file) if (not skip_kdesk_refresh and os.path.exists('/usr/bin/kdesk') and not is_running('kano-sync')): logger.info("refreshing kdesk from save_profile") run_bg('kdesk -a profile')
def __init__(self): logger.debug("Creating new status instance") if UpdaterStatus._singleton_instance: raise Exception("This class is a singleton!") else: UpdaterStatus._singleton_instance = self self._state = self.NO_UPDATES self._last_check = 0 self._updatable_independent_packages = [] self._last_check_urgent = 0 self._last_update = 0 self._first_boot_countdown = 0 self._is_urgent = False self._is_scheduled = False self._notifications_muted = False self._is_shutdown = False ensure_dir(os.path.dirname(self._status_file)) if not os.path.exists(self._status_file): self.save() else: self.load()
def __init__(self): logger.debug("Creating new status instance") if UpdaterStatus._singleton_instance: raise Exception("This class is a singleton!") else: UpdaterStatus._singleton_instance = self self._state = self.NO_UPDATES self._last_check = 0 self._updatable_independent_packages = [] self._last_check_urgent = 0 self._last_update = 0 self._first_boot_countdown = 0 self._is_urgent = False self._is_scheduled = False self._notifications_muted = False self._is_shutdown = False ensure_dir(os.path.dirname(self._status_file)) if not os.path.exists(self._status_file): self.save() else: self.load()
def do_white_rabbit_stage(flow_params): init_status = Status.get_instance() if not flow_params.get('skip', False): clear_screen() try: rabbit(1, 'left-to-right') except: pass clear_screen() msg = _("{string_username}, follow the white rabbit").format( string_username=init_status.username) typewriter_echo(msg, trailing_linebreaks=2) command = decorate_with_preset('cd rabbithole', 'code') typewriter_echo(_("Type {string_code_to_type}, then [ENTER]").format( string_code_to_type=command), trailing_linebreaks=2) # TODO: open shell rabbithole = "/home/{}/rabbithole".format(init_status.username) ensure_dir(rabbithole) cmd = "sudo -u {} -H bash --init-file {}".format( init_status.username, SUBSHELLRC_PATH) os.system(cmd) delete_dir(rabbithole) reset_overscan() matrix_binary(1, False) set_overscan() clear_screen() init_status.stage = Status.LOVE_STAGE init_status.save()
def download_online_badges(self): profile = load_profile() if 'kanoworld_id' in profile: user_id = profile['kanoworld_id'] else: return False, 'Profile not registered!' success, text, data = request_wrapper('get', '/users/{}'.format(user_id), session=self.session) if not success: return False, text if 'user' not in data: return False, _("Corrupt response (the 'user' key not found)") if 'profile' not in data['user']: return False, _( "Corrupt response (the 'user.profile' key not found)") if 'badges' not in data['user']['profile']: return False, _( "Corrupt response (the 'user.profile.badges' key not found)") online_badges_data = {} ensure_dir(online_badges_dir) badges = data['user']['profile']['badges'] for badge in badges: if 'assigned' not in badge or not badge['assigned']: continue if 'image_url' not in badge: return False, _("Couldn't find an image for the badge") image_loc = os.path.join(online_badges_dir, "{}.png".format(badge['id'])) download_url(badge['image_url'], image_loc) online_badges_data[badge['id']] = { 'achieved': True, 'bg_color': badge['bg_color'].replace("#", ""), 'desc_locked': badge['desc_locked'], 'desc_unlocked': badge['desc_unlocked'], 'title': badge['title'] } try: may_write = True txt = None f = open(online_badges_file, 'w') except IOError as e: may_write = False txt = 'Error opening badges file {}'.format(str(e)) else: with f: f.write(json.dumps(online_badges_data)) if 'SUDO_USER' in os.environ: chown_path(online_badges_dir) chown_path(online_badges_file) return may_write, txt
def get_metadata_archive(title='', desc=''): ''' It creates a file (ARCHIVE_NAME) with all the information Returns the file ''' ensure_dir(TMP_DIR) file_list = [ { 'name': 'metadata.json', 'contents': json.dumps({ 'title': title, 'description': desc }) }, { 'name': 'kanux_version.txt', 'contents': get_version() }, { 'name': 'kanux_stamp.txt', 'contents': get_stamp() }, { 'name': 'process.txt', 'contents': get_processes() }, { 'name': 'process-tree.txt', 'contents': get_process_tree() }, { 'name': 'packages.txt', 'contents': get_packages() }, { 'name': 'dmesg.txt', 'contents': get_dmesg() }, { 'name': 'syslog.txt', 'contents': get_syslog() }, { 'name': 'cmdline.txt', 'contents': read_file_contents('/boot/cmdline.txt') }, { 'name': 'config.txt', 'contents': read_file_contents('/boot/config.txt') }, { 'name': 'wifi-info.txt', 'contents': get_wifi_info() }, { 'name': 'usbdevices.txt', 'contents': get_usb_devices() }, # TODO: Remove raw logs when json ones become stable { 'name': 'app-logs.txt', 'contents': get_app_logs_raw() }, { 'name': 'app-logs-json.txt', 'contents': get_app_logs_json() }, { 'name': 'hdmi-info.txt', 'contents': get_hdmi_info() }, { 'name': 'edid.dat', 'contents': get_edid() }, { 'name': 'screen-log.txt', 'contents': get_screen_log() }, { 'name': 'xorg-log.txt', 'contents': get_xorg_log() }, { 'name': 'cpu-info.txt', 'contents': get_cpu_info() }, { 'name': 'mem-stats.txt', 'contents': get_mem_stats() }, { 'name': 'lsof.txt', 'contents': get_lsof() }, { 'name': 'content-objects.txt', 'contents': get_co_list() }, { 'name': 'disk-space.txt', 'contents': get_disk_space() }, { 'name': 'lsblk.txt', 'contents': get_lsblk() }, { 'name': 'sources-list.txt', 'contents': get_sources_list() }, ] file_list += get_install_logs() # Include the screenshot if it exists if os.path.isfile(SCREENSHOT_PATH): file_list.append({ 'name': SCREENSHOT_NAME, 'contents': read_file_contents(SCREENSHOT_PATH) }) # Collect all coredumps, for applications that terminated unexpectedly for f in os.listdir('/var/tmp/'): if f.startswith('core-'): file_list.append({ 'name': f, 'contents': read_file_contents(os.path.join('/var/tmp', f)) }) # create files for each non empty metadata info for file in file_list: if file['contents']: write_file_contents(os.path.join(TMP_DIR, file['name']), file['contents']) # archive all the metadata files import tarfile with tarfile.open(ARCHIVE_PATH, mode='w') as archive: for f in os.listdir(TMP_DIR): archive.add(os.path.join(TMP_DIR, f), arcname=f) # open the file and return it archive = open(ARCHIVE_PATH, 'rb') return archive
def download_share(entry): app = entry['app'] title = entry['title'] description = entry['description'] attachment_url = entry['attachment_url'] cover_url = entry['cover_url'] resource_url = entry['resource_url'] data = {'title': title, 'description': description} app_profiles = read_json(app_profiles_file) if app not in app_profiles: logger.error("Cannot download share, app not found in app-profiles") return app_profile = app_profiles[app] folder = os.path.join(get_home(), app_profile['dir'], 'webload') ensure_dir(folder) title_slugified = slugify(title) # Download attachment attachment_ext = attachment_url.split('.')[-1] attachment_name = '{}.{}'.format(title_slugified, attachment_ext) attachment_path = os.path.join(folder, attachment_name) success, text = download_url(attachment_url, attachment_path) if not success: msg = "Error with downloading share file: {}".format(text) logger.error(msg) return False, msg # Download screenshot if cover_url: cover_ext = cover_url.split('.')[-1] cover_name = '{}.{}'.format(title_slugified, cover_ext) cover_path = os.path.join(folder, cover_name) success, text = download_url(cover_url, cover_path) if not success: msg = "Error with downloading cover file: {}".format(text) logger.error(msg) return False, msg # Download resource file if resource_url: resource_ext = resource_url.split('.')[-1] # Make sure we don't remove the tar from gz if 'tar.gz' in resource_url: resource_ext = 'tar.' + resource_ext resource_name = '{}.{}'.format(title_slugified, resource_ext) resource_path = os.path.join(folder, resource_name) success, text = download_url(resource_url, resource_path) if not success: msg = "Error with downloading resource file: {}".format(text) logger.error(msg) return False, msg # JSON file json_name = '{}.{}'.format(title_slugified, 'json') json_path = os.path.join(folder, json_name) write_json(json_path, data) return True, [title, attachment_path, app, attachment_name, folder]
def _process_notification(self, entry): """ Cherry picks information from a Kano World notification based on its type and returns it in a dict. :param entry: A notification entry from the World API :returns: A dict that can be passed to the notification widget """ MINECRAFT_SHARE_IMG = media_dir + \ '/images/notification/280x170/share-pong.png' PONG_SHARE_IMG = media_dir + \ '/images/notification/280x170/share-minecraft.png' SP_IMG = media_dir + \ '/images/notification/280x170/saturday-project.png' FOLLOWER_IMG = media_dir + \ '/images/notification/280x170/follower.png' GENERIC_ALERT_IMG = media_dir + \ '/images/notification/280x170/notification.png' n = { 'id': entry['id'], 'title': 'Kano World', 'byline': '', 'image': GENERIC_ALERT_IMG, 'command': 'kano-world-launcher /notifications/open/{}'.format( entry['id']) } # Customise settings for known types if entry['category'] == 'follows': n['title'] = 'New follower!' n['byline'] = entry['title'] n['image'] = FOLLOWER_IMG # Link to whomever followed this user user = self._get_dict_value(entry, ['meta', 'author', 'username']) if user: n['command'] = "kano-world-launcher /users/{}".format(user) elif entry['category'] in ['share-items', 'shares']: n['title'] = 'New share!' n['byline'] = entry['title'] if entry['type'] == 'make-minecraft': n['image'] = MINECRAFT_SHARE_IMG elif entry['type'] == 'make-pong': n['image'] = PONG_SHARE_IMG # Link to the share share_id = self._get_dict_value(entry, ['meta', 'item', 'id']) if share_id: n['command'] = "kano-world-launcher /shared/{}".format( share_id) elif entry['category'] == 'comments': n['title'] = 'New comment!' n['byline'] = entry['title'] slug = self._get_dict_value(entry, ['meta', 'item', 'slug']) if slug: obj_type = entry['meta']['item']['type'] if obj_type == "app": n['command'] = "kano-world-launcher /apps/{}".format(slug) elif obj_type == "share": n['command'] = "kano-world-launcher /shared/{}".format( slug) elif obj_type == "project": n['command'] = "kano-world-launcher /projects/{}".format( slug) # If a notification has both the title and text, override the default if 'title' in entry and entry['title'] and \ 'text' in entry and entry['text']: n['title'] = entry['title'] n['byline'] = entry['text'] # Some notifications may have images # If so, we need to download them and resize if 'image_url' in entry and entry['image_url']: filename = os.path.basename(entry['image_url']) img_path = "{}/notifications/{}".format(profile_dir, filename) ensure_dir(os.path.dirname(img_path)) rv, e = download_url(entry['image_url'], img_path) if rv: # Resize image to 280x170 # FIXME: We import GdkPixbuf locally to make sure not to # bugger up anything else, but we should move it up to the top. from gi.repository import GdkPixbuf pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size( img_path, 280, 170) pixbuf.savev(img_path, 'png', [None], [None]) n['image'] = img_path else: msg = "Notifications image failed to download ({}).".format(e) logger.error(msg) # Certain notifications may come with a command as well. # If so, override the default one. cmd = self._get_dict_value(entry, ['meta', 'cmd']) if cmd: n['command'] = cmd return n
import os import re import shutil from kano.utils import ensure_dir, get_user_unsudoed, read_json, write_json, chown_path from kano.logging import logger from kano_settings.common import settings_dir from kano.utils import is_model_2_b USER = None USER_ID = None username = get_user_unsudoed() if username != 'root': if os.path.exists(settings_dir) and os.path.isfile(settings_dir): os.rename(settings_dir, settings_dir + '.bak') ensure_dir(settings_dir) chown_path(settings_dir) settings_file = os.path.join(settings_dir, 'settings') defaults = { 'pi1': { 'Keyboard-continent-index': 1, 'Keyboard-country-index': 21, 'Keyboard-variant-index': 0, 'Keyboard-continent-human': 'america', 'Keyboard-country-human': 'United States', 'Keyboard-variant-human': 'Generic', 'Audio': 'Analogue', 'Wifi': '', 'Wifi-connection-attempted': False, 'Overclocking': 'High',
def _process_notification(self, entry): """ Cherry picks information from a Kano World notification based on its type and returns it in a dict. :param entry: A notification entry from the World API :returns: A dict that can be passed to the notification widget """ notification_dir = os.path.join( media_dir, 'images', 'notification', '280x170' ) FEATURED_SHARE_IMG = os.path.join(notification_dir, 'featured.png') PONG_SHARE_IMG = os.path.join(notification_dir, 'share-pong.png') MUSIC_SHARE_IMG = os.path.join(notification_dir, 'share-music.png') LIGHT_SHARE_IMG = os.path.join(notification_dir, 'share-light.png') ART_SHARE_IMG = os.path.join(notification_dir, 'share-art.png') SNAKE_SHARE_IMG = os.path.join(notification_dir, 'snake-art.png') MINECRAFT_SHARE_IMG = os.path.join(notification_dir, 'share-minecraft.png') FOLLOWER_IMG = os.path.join(notification_dir, 'follower.png') COMMENT_IMG = os.path.join(notification_dir, 'comment.png') LIKE_IMG = os.path.join(notification_dir, 'like.png') GENERIC_ALERT_IMG = os.path.join(notification_dir, 'notification.png') n = { 'id': entry['id'], 'title': 'Kano World', 'byline': '', 'image': GENERIC_ALERT_IMG, 'command': 'kano-world-launcher /notifications/open/{}'.format( entry['id']) } # Some notifications may have images # If so, we need to download them and resize if 'image_url' in entry and entry['image_url']: filename = os.path.basename(entry['image_url']) img_path = "{}/notifications/{}".format(profile_dir, filename) ensure_dir(os.path.dirname(img_path)) rv, e = download_url(entry['image_url'], img_path) if rv: # Resize image to 280x170 # FIXME: We import GdkPixbuf locally to make sure not to # bugger up anything else, but we should move it up to the top. from gi.repository import GdkPixbuf pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size( img_path, 280, 170) pixbuf.savev(img_path, 'png', [None], [None]) n['image'] = img_path else: msg = "Notifications image failed to download ({}).".format(e) logger.error(msg) # Certain notifications may come with a command as well. # If so, override the default one. cmd = self._get_dict_value(entry, ['meta', 'cmd']) if cmd: n['command'] = cmd # Customise settings for known types if entry['category'] == 'follows': n['title'] = 'New follower!' n['byline'] = entry['title'] n['image'] = FOLLOWER_IMG elif entry['category'] in ['share-items', 'shares']: n['title'] = 'New share!' n['byline'] = entry['title'] if entry['type'] == 'make-minecraft': n['image'] = MINECRAFT_SHARE_IMG elif entry['type'] == 'make-pong': n['image'] = PONG_SHARE_IMG elif entry['type'] == 'make-music': n['image'] = MUSIC_SHARE_IMG elif entry['type'] == 'make-light': n['image'] = LIGHT_SHARE_IMG elif entry['type'] == 'kano-draw': n['image'] = ART_SHARE_IMG elif entry['type'] == 'featured': n['title'] = 'Staff picked!' n['image'] = FEATURED_SHARE_IMG elif entry['category'] == 'comments': n['title'] = 'New comment!' n['byline'] = entry['title'] n['image'] = COMMENT_IMG elif entry['category'] == 'likes': n['title'] = 'New like!' n['byline'] = entry['title'] n['image'] = LIKE_IMG else: return None return n
def _process_notification(self, entry): """ Cherry picks information from a Kano World notification based on its type and returns it in a dict. :param entry: A notification entry from the World API :returns: A dict that can be passed to the notification widget """ MINECRAFT_SHARE_IMG = media_dir + "/images/notification/280x170/share-pong.png" PONG_SHARE_IMG = media_dir + "/images/notification/280x170/share-minecraft.png" SP_IMG = media_dir + "/images/notification/280x170/saturday-project.png" FOLLOWER_IMG = media_dir + "/images/notification/280x170/follower.png" GENERIC_ALERT_IMG = media_dir + "/images/notification/280x170/notification.png" n = { "id": entry["id"], "title": "Kano World", "byline": "", "image": GENERIC_ALERT_IMG, "command": "kano-world-launcher /notifications/open/{}".format(entry["id"]), } # Customise settings for known types if entry["category"] == "follows": n["title"] = "New follower!" n["byline"] = entry["title"] n["image"] = FOLLOWER_IMG # Link to whomever followed this user user = self._get_dict_value(entry, ["meta", "author", "username"]) if user: n["command"] = "kano-world-launcher /users/{}".format(user) elif entry["category"] in ["share-items", "shares"]: n["title"] = "New share!" n["byline"] = entry["title"] if entry["type"] == "make-minecraft": n["image"] = MINECRAFT_SHARE_IMG elif entry["type"] == "make-pong": n["image"] = PONG_SHARE_IMG # Link to the share share_id = self._get_dict_value(entry, ["meta", "item", "id"]) if share_id: n["command"] = "kano-world-launcher /shared/{}".format(share_id) elif entry["category"] == "comments": n["title"] = "New comment!" n["byline"] = entry["title"] slug = self._get_dict_value(entry, ["meta", "item", "slug"]) if slug: obj_type = entry["meta"]["item"]["type"] if obj_type == "app": n["command"] = "kano-world-launcher /apps/{}".format(slug) elif obj_type == "share": n["command"] = "kano-world-launcher /shared/{}".format(slug) elif obj_type == "project": n["command"] = "kano-world-launcher /projects/{}".format(slug) # If a notification has both the title and text, override the default if "title" in entry and entry["title"] and "text" in entry and entry["text"]: n["title"] = entry["title"] n["byline"] = entry["text"] # Some notifications may have images # If so, we need to download them and resize if "image_url" in entry and entry["image_url"]: filename = os.path.basename(entry["image_url"]) img_path = "{}/notifications/{}".format(profile_dir, filename) ensure_dir(os.path.dirname(img_path)) rv, e = download_url(entry["image_url"], img_path) if rv: # Resize image to 280x170 # FIXME: We import GdkPixbuf locally to make sure not to # bugger up anything else, but we should move it up to the top. from gi.repository import GdkPixbuf pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(img_path, 280, 170) pixbuf.savev(img_path, "png", [None], [None]) n["image"] = img_path else: msg = "Notifications image failed to download ({}).".format(e) logger.error(msg) # Certain notifications may come with a command as well. # If so, override the default one. cmd = self._get_dict_value(entry, ["meta", "cmd"]) if cmd: n["command"] = cmd return n
def get_metadata_archive(title='', desc=''): ''' It creates a file (ARCHIVE_NAME) with all the information Returns the file ''' ensure_dir(TMP_DIR) file_list = [ { 'name': 'metadata.json', 'contents': json.dumps({'title': title, 'description': desc}) }, {'name': 'kanux_version.txt', 'contents': get_version()}, {'name': 'kanux_stamp.txt', 'contents': get_stamp()}, {'name': 'process.txt', 'contents': get_processes()}, {'name': 'process-tree.txt', 'contents': get_process_tree()}, {'name': 'packages.txt', 'contents': get_packages()}, {'name': 'dmesg.txt', 'contents': get_dmesg()}, {'name': 'syslog.txt', 'contents': get_syslog()}, { 'name': 'cmdline.txt', 'contents': read_file_contents('/boot/cmdline.txt') }, { 'name': 'config.txt', 'contents': read_file_contents('/boot/config.txt') }, {'name': 'wifi-info.txt', 'contents': get_wifi_info()}, {'name': 'usbdevices.txt', 'contents': get_usb_devices()}, # TODO: Remove raw logs when json ones become stable {'name': 'app-logs.txt', 'contents': get_app_logs_raw()}, {'name': 'app-logs-json.txt', 'contents': get_app_logs_json()}, {'name': 'hdmi-info.txt', 'contents': get_hdmi_info()}, {'name': 'edid.dat', 'contents': get_edid()}, {'name': 'screen-log.txt', 'contents': get_screen_log()}, {'name': 'xorg-log.txt', 'contents': get_xorg_log()}, {'name': 'cpu-info.txt', 'contents': get_cpu_info()}, {'name': 'mem-stats.txt', 'contents': get_mem_stats()}, {'name': 'lsof.txt', 'contents': get_lsof()}, {'name': 'content-objects.txt', 'contents': get_co_list()}, {'name': 'disk-space.txt', 'contents': get_disk_space()}, {'name': 'lsblk.txt', 'contents': get_lsblk()}, {'name': 'sources-list.txt', 'contents': get_sources_list()}, ] file_list += get_install_logs() # Include the screenshot if it exists if os.path.isfile(SCREENSHOT_PATH): file_list.append({ 'name': SCREENSHOT_NAME, 'contents': read_file_contents(SCREENSHOT_PATH) }) # Collect all coredumps, for applications that terminated unexpectedly for f in os.listdir('/var/tmp/'): if f.startswith('core-'): file_list.append({ 'name': f, 'contents': read_file_contents(os.path.join('/var/tmp', f)) }) # create files for each non empty metadata info for file in file_list: if file['contents']: write_file_contents( os.path.join(TMP_DIR, file['name']), file['contents'] ) # archive all the metadata files import tarfile with tarfile.open(ARCHIVE_PATH, mode='w') as archive: for f in os.listdir(TMP_DIR): archive.add(os.path.join(TMP_DIR, f), arcname=f) # open the file and return it archive = open(ARCHIVE_PATH, 'rb') return archive
def create_tmp_dir(): ''' Creates TMP_DIR directory ''' ensure_dir(TMP_DIR)
from kano_world.functions import login_using_token from kano_world.share import upload_share from kano.network import is_internet from kano.utils import play_sound from kano.logging import logger APP_NAME = 'kano-draw' PARENT_PID = None CHALLENGE_DIR = os.path.expanduser('~/Draw-content') WALLPAPER_DIR = os.path.join(CHALLENGE_DIR, 'wallpapers') STATIC_ASSET_DIR = os.path.join(os.path.expanduser('~'), '.make-art-assets') ensure_dir(CHALLENGE_DIR) ensure_dir(WALLPAPER_DIR) ensure_dir(STATIC_ASSET_DIR) def _copy_package_assets(): # Use abs paths for both src and dest for subsequent replacements to work src_dir = os.path.abspath(_get_package_static_dir()) dest_dir = os.path.abspath(STATIC_ASSET_DIR) # First Clear this cache for existing_file in os.listdir(dest_dir): cur_file = os.path.abspath(os.path.join(dest_dir, existing_file)) if os.path.islink(cur_file): os.unlink(cur_file) else:
def download_share(entry): app = entry['app'] title = entry['title'] description = entry['description'] attachment_url = entry['attachment_url'] cover_url = entry['cover_url'] resource_url = entry['resource_url'] data = { 'title': title, 'description': description } app_profiles = read_json(app_profiles_file) if app not in app_profiles: logger.error("Cannot download share, app not found in app-profiles") return app_profile = app_profiles[app] folder = os.path.join(get_home(), app_profile['dir'], 'webload') ensure_dir(folder) title_slugified = slugify(title) # Download attachment attachment_ext = attachment_url.split('.')[-1] attachment_name = '{}.{}'.format(title_slugified, attachment_ext) attachment_path = os.path.join(folder, attachment_name) success, text = download_url(attachment_url, attachment_path) if not success: msg = "Error with downloading share file: {}".format(text) logger.error(msg) return False, msg # Download screenshot if cover_url: cover_ext = cover_url.split('.')[-1] cover_name = '{}.{}'.format(title_slugified, cover_ext) cover_path = os.path.join(folder, cover_name) success, text = download_url(cover_url, cover_path) if not success: msg = "Error with downloading cover file: {}".format(text) logger.error(msg) return False, msg # Download resource file if resource_url: resource_ext = resource_url.split('.')[-1] # Make sure we don't remove the tar from gz if 'tar.gz' in resource_url: resource_ext = 'tar.' + resource_ext resource_name = '{}.{}'.format(title_slugified, resource_ext) resource_path = os.path.join(folder, resource_name) success, text = download_url(resource_url, resource_path) if not success: msg = "Error with downloading resource file: {}".format(text) logger.error(msg) return False, msg # JSON file json_name = '{}.{}'.format(title_slugified, 'json') json_path = os.path.join(folder, json_name) write_json(json_path, data) return True, [title, attachment_path, app, attachment_name, folder]
from kano_profile.apps import load_app_state_variable from kano_profile.badges import increment_app_state_variable_with_dialog from kano_world.functions import login_using_token from kano_world.share import upload_share from kano.network import is_internet from kano.utils import play_sound from kano.logging import logger APP_NAME = 'kano-draw' PARENT_PID = None CHALLENGE_DIR = os.path.expanduser('~/Draw-content') WALLPAPER_DIR = os.path.join(CHALLENGE_DIR, 'wallpapers') STATIC_ASSET_DIR = os.path.join(os.path.expanduser('~'), '.make-art-assets') ensure_dir(CHALLENGE_DIR) ensure_dir(WALLPAPER_DIR) ensure_dir(STATIC_ASSET_DIR) def _copy_package_assets(): # Use abs paths for both src and dest for subsequent replacements to work src_dir = os.path.abspath(_get_package_static_dir()) dest_dir = os.path.abspath(STATIC_ASSET_DIR) # First Clear this cache for existing_file in os.listdir(dest_dir): cur_file = os.path.abspath(os.path.join(dest_dir, existing_file)) if os.path.islink(cur_file): os.unlink(cur_file) else:
def download_online_badges(self): profile = load_profile() if 'kanoworld_id' in profile: user_id = profile['kanoworld_id'] else: return False, 'Profile not registered!' success, text, data = request_wrapper( 'get', '/users/{}'.format(user_id), session=self.session ) if not success: return False, text if 'user' not in data: return False, _("Corrupt response (the 'user' key not found)") if 'profile' not in data['user']: return False, _("Corrupt response (the 'user.profile' key not found)") if 'badges' not in data['user']['profile']: return False, _("Corrupt response (the 'user.profile.badges' key not found)") online_badges_data = {} ensure_dir(online_badges_dir) badges = data['user']['profile']['badges'] for badge in badges: if 'assigned' not in badge or not badge['assigned']: continue if 'image_url' not in badge: return False, _("Couldn't find an image for the badge") image_loc = os.path.join(online_badges_dir, "{}.png".format(badge['id'])) download_url(badge['image_url'], image_loc) online_badges_data[badge['id']] = { 'achieved': True, 'bg_color': badge['bg_color'].replace("#", ""), 'desc_locked': badge['desc_locked'], 'desc_unlocked': badge['desc_unlocked'], 'title': badge['title'] } try: may_write = True txt = None f = open(online_badges_file, 'w') except IOError as e: may_write = False txt = 'Error opening badges file {}'.format(str(e)) else: with f: f.write(json.dumps(online_badges_data)) if 'SUDO_USER' in os.environ: chown_path(online_badges_dir) chown_path(online_badges_file) return may_write, txt
def _process_notification(self, entry): """ Cherry picks information from a Kano World notification based on its type and returns it in a dict. :param entry: A notification entry from the World API :returns: A dict that can be passed to the notification widget """ notification_dir = os.path.join(media_dir, 'images', 'notification', '280x170') FEATURED_SHARE_IMG = os.path.join(notification_dir, 'featured.png') PONG_SHARE_IMG = os.path.join(notification_dir, 'share-pong.png') MUSIC_SHARE_IMG = os.path.join(notification_dir, 'share-music.png') LIGHT_SHARE_IMG = os.path.join(notification_dir, 'share-light.png') ART_SHARE_IMG = os.path.join(notification_dir, 'share-art.png') SNAKE_SHARE_IMG = os.path.join(notification_dir, 'snake-art.png') MINECRAFT_SHARE_IMG = os.path.join(notification_dir, 'share-minecraft.png') FOLLOWER_IMG = os.path.join(notification_dir, 'follower.png') COMMENT_IMG = os.path.join(notification_dir, 'comment.png') LIKE_IMG = os.path.join(notification_dir, 'like.png') GENERIC_ALERT_IMG = os.path.join(notification_dir, 'notification.png') n = { 'id': entry['id'], 'title': 'Kano World', 'byline': '', 'image': GENERIC_ALERT_IMG, 'command': 'kano-world-launcher /notifications/open/{}'.format(entry['id']) } # Some notifications may have images # If so, we need to download them and resize if 'image_url' in entry and entry['image_url']: filename = os.path.basename(entry['image_url']) img_path = "{}/notifications/{}".format(profile_dir, filename) ensure_dir(os.path.dirname(img_path)) rv, e = download_url(entry['image_url'], img_path) if rv: # Resize image to 280x170 # FIXME: We import GdkPixbuf locally to make sure not to # bugger up anything else, but we should move it up to the top. from gi.repository import GdkPixbuf pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size( img_path, 280, 170) pixbuf.savev(img_path, 'png', [None], [None]) n['image'] = img_path else: msg = "Notifications image failed to download ({}).".format(e) logger.error(msg) # Certain notifications may come with a command as well. # If so, override the default one. cmd = self._get_dict_value(entry, ['meta', 'cmd']) if cmd: n['command'] = cmd # Customise settings for known types if entry['category'] == 'follows': n['title'] = 'New follower!' n['byline'] = entry['title'] n['image'] = FOLLOWER_IMG elif entry['category'] in ['share-items', 'shares']: n['title'] = 'New share!' n['byline'] = entry['title'] if entry['type'] == 'make-minecraft': n['image'] = MINECRAFT_SHARE_IMG elif entry['type'] == 'make-pong': n['image'] = PONG_SHARE_IMG elif entry['type'] == 'make-music': n['image'] = MUSIC_SHARE_IMG elif entry['type'] == 'make-light': n['image'] = LIGHT_SHARE_IMG elif entry['type'] == 'kano-draw': n['image'] = ART_SHARE_IMG elif entry['type'] == 'featured': n['title'] = 'Staff picked!' n['image'] = FEATURED_SHARE_IMG elif entry['category'] == 'comments': n['title'] = 'New comment!' n['byline'] = entry['title'] n['image'] = COMMENT_IMG elif entry['category'] == 'likes': n['title'] = 'New like!' n['byline'] = entry['title'] n['image'] = LIKE_IMG else: return None return n
calculate_xp from kano_profile.apps import load_app_state_variable from kano_profile.badges import increment_app_state_variable_with_dialog from kano_world.functions import login_using_token from kano_world.share import upload_share from kano.network import is_internet from kano.utils import play_sound APP_NAME = 'kano-draw' PARENT_PID = None CHALLENGE_DIR = os.path.expanduser('~/Draw-content') WALLPAPER_DIR = os.path.join(CHALLENGE_DIR, 'wallpapers') ensure_dir(CHALLENGE_DIR) ensure_dir(WALLPAPER_DIR) def _get_static_dir(): bin_path = os.path.abspath(os.path.dirname(__file__)) if bin_path.startswith('/usr'): return '/usr/share/kano-draw' else: return os.path.abspath(os.path.join(bin_path, '../www')) def _get_image_from_str(img_str): import base64 image_b64 = img_str.split(',')[-1]
def _initialise_status_file(self): ensure_dir(os.path.dirname(self._status_file)) if not os.path.exists(self._status_file): self.save() else: self.load()
from kano_profile.badges import save_app_state_variable_with_dialog, \ calculate_xp from kano_profile.apps import load_app_state_variable from kano_profile.badges import increment_app_state_variable_with_dialog from kano_world.functions import login_using_token from kano_world.share import upload_share from kano.network import is_internet APP_NAME = 'kano-draw' PARENT_PID = None CHALLENGE_DIR = os.path.expanduser('~/Draw-content') WALLPAPER_DIR = os.path.join(CHALLENGE_DIR, 'wallpapers') ensure_dir(CHALLENGE_DIR) ensure_dir(WALLPAPER_DIR) def _get_static_dir(): bin_path = os.path.abspath(os.path.dirname(__file__)) if bin_path.startswith('/usr'): return '/usr/share/kano-draw' else: return os.path.abspath(os.path.join(bin_path, '../www')) def _get_image_from_str(img_str): import base64 image_b64 = img_str.split(',')[-1]
def create_tmp_dir(): ''' Creates TMP_DIR directory ''' ensure_dir(TMP_DIR)