def get_app_xp_for_challenge(app, challenge_no): xp_file_json = read_json(xp_file) try: return xp_file_json[app]['level'][challenge_no] except KeyError: return 0
def calculate_kano_level(): ''' Calculates the current level of the user Returns: level, percentage and current xp ''' level_rules = read_json(levels_file) if not level_rules: return -1, 0, 0 max_level = max([int(n) for n in level_rules.keys()]) xp_now = calculate_xp() for level in xrange(1, max_level + 1): level_min = level_rules[str(level)] if level != max_level: level_max = level_rules[str(level + 1)] - 1 else: level_max = float("inf") if level_min <= xp_now <= level_max: reached_level = level reached_percentage = (xp_now - level_min) / (level_max + 1 - level_min) return int(reached_level), reached_percentage, xp_now
def load_badge_rules(): if not os.path.exists(rules_dir): logger.error('rules dir missing') return merged_rules = dict() subfolders = ['badges', 'environments'] for folder in subfolders: folder_fullpath = os.path.join(rules_dir, folder) if not os.path.exists(folder_fullpath): logger.error('rules subfolder missing: {}'.format(folder_fullpath)) return rule_files = os.listdir(folder_fullpath) if not rule_files: logger.error('no rule files in subfolder: {}'.format(folder_fullpath)) return for rule_file in rule_files: rule_file_fullpath = os.path.join(folder_fullpath, rule_file) rule_data = read_json(rule_file_fullpath) if not rule_data: logger.error('rule file empty: {}'.format(rule_file_fullpath)) continue category = folder subcategory = rule_file.split('.')[0] merged_rules.setdefault(category, dict())[subcategory] = rule_data return merged_rules
def load_badge_rules(): if not os.path.exists(rules_dir): logger.error("rules dir missing") return merged_rules = dict() subfolders = ['badges', 'environments'] for folder in subfolders: folder_fullpath = os.path.join(rules_dir, folder) if not os.path.exists(folder_fullpath): logger.error("rules subfolder missing: {}".format(folder_fullpath)) return rule_files = os.listdir(folder_fullpath) if not rule_files: logger.error( "no rule files in subfolder: {}".format(folder_fullpath)) return for rule_file in rule_files: rule_file_fullpath = os.path.join(folder_fullpath, rule_file) if os.path.splitext(rule_file_fullpath)[1] != '.json': logger.debug( "Skipping over non json {}".format(rule_file_fullpath)) continue rule_data = read_json(rule_file_fullpath) if not rule_data: logger.error("rule file empty: {}".format(rule_file_fullpath)) continue category = folder subcategory = rule_file.split('.')[0] merged_rules.setdefault(category, dict())[subcategory] = rule_data return merged_rules
def calculate_xp(): allrules = read_json(xp_file) if not allrules: return -1 points = 0 for app, groups in allrules.iteritems(): appstate = load_app_state(app) if not appstate: continue for group, rules in groups.iteritems(): # calculating points based on level if group == 'level' and 'level' in appstate: maxlevel = int(appstate['level']) for level, value in rules.iteritems(): level = int(level) value = int(value) if level <= maxlevel: points += value # calculating points based on multipliers if group == 'multipliers': for thing, value in rules.iteritems(): value = float(value) if thing in appstate: points += value * appstate[thing] qm = Quests() return int(points) + qm.evaluate_xp()
def calculate_kano_level(): ''' Calculates the current level of the user Returns: level, percentage and current xp ''' level_rules = read_json(levels_file) if not level_rules: return -1, 0, 0 max_level = max([int(n) for n in level_rules.keys()]) xp_now = calculate_xp() for level in xrange(1, max_level + 1): level_min = level_rules[str(level)] if level != max_level: level_max = level_rules[str(level + 1)] - 1 else: level_max = float('inf') if level_min <= xp_now <= level_max: reached_level = level reached_percentage = (xp_now - level_min) / (level_max + 1 - level_min) return int(reached_level), reached_percentage, xp_now
def launch_project(app, filename, data_dir): logger.info('launch_project: {} {} {}'.format(app, filename, data_dir)) app_profiles = read_json(app_profiles_file) fullpath = os.path.join(data_dir, filename) cmd = app_profiles[app]['cmd'].format(fullpath=fullpath, filename=filename) _, _, rc = run_print_output_error(cmd) return rc
def get_gamestate_variables(app_name): allrules = read_json(xp_file) if not allrules: return list() groups = allrules[app_name] for group, rules in groups.iteritems(): if group == 'multipliers': return [str(key) for key in rules.keys()]
def get_setting(variable): try: value = read_json(settings_file)[variable] except Exception: key = get_pi_key() if variable not in defaults[key]: logger.info('Defaults not found for variable: {}'.format(variable)) value = defaults[key][variable] return value
def upload_share(self, file_path, title, app_name, featured): if not os.path.exists(file_path): return False, "File path not found: {}".format(file_path) extensionless_path = os.path.splitext(file_path)[0] # attachment try: files = {"attachment": open(file_path, "rb")} # List of attachments to search for in (name, extension) format attachment_files = [("cover", "png"), ("resource", "tar.gz"), ("sample", "mp3")] for attachment in attachment_files: key, ext = attachment attachment_path = "{}.{}".format(extensionless_path, ext) if os.path.exists(attachment_path): logger.debug("uploading {}: {}".format(key, attachment_path)) files[key] = open(attachment_path, "rb") except IOError as e: files = None txt = "Error opening the files to be shared {}".format(str(e)) # Since we can't open the file, there is no need to continue if not files: return False, txt # data payload = {"title": title, "featured": featured} # description jsonfile_path = "{}.json".format(extensionless_path) try: description = read_json(jsonfile_path)["description"] logger.debug("uploading json: {}".format(jsonfile_path)) payload["description"] = description except Exception: description = None logger.debug("uploading payload: {}".format(payload)) logger.debug("uploading files: {}".format(files)) endpoint = "/share/{}".format(app_name) success, text, data = request_wrapper("post", endpoint, session=self.session, files=files, data=payload) if not success: return False, text success = "success" in data and data["success"] if not success: return False, "Share upload not successful!" return True, None
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 set_setting(variable, value): if username == 'root': return logger.debug('config_file / set_setting: {} {}'.format(variable, value)) data = read_json(settings_file) if not data: data = dict() data[variable] = value write_json(settings_file, data) chown_path(settings_file)
def launch_project(app, filename, data_dir, background=False): # This is necessary to support the new official names # TODO: once the apps have been renamed this will not be necessary name_translation = { 'make-art': 'kano-draw', 'terminal-quest': 'linux-story' } app_tr = name_translation.get(app, app) logger.info("launch_project: {} {} {}".format(app_tr, filename, data_dir)) app_profiles = read_json(app_profiles_file) # XML file with complete pathname fullpath = os.path.join(data_dir, filename) # Prepare the command line to open the app with the new project try: cmd = (app_profiles[app_tr]['cmd'].format(fullpath=fullpath, filename=filename)) except KeyError as exc: logger.warn("Can't find app '{}' in the app profiles - [{}]".format( app_tr, exc)) raise ValueError(_("App '{}' not available").format(app_tr)) # Try to load the project if the app is already running, via a signal. _, _, rc = run_cmd('/usr/bin/kano-signal launch-share {}'.format(fullpath)) if rc: # Likely the app is not running and the signal could not be sent, so start it now logger.warn( "Error sending launch signal, starting the app now, rc={}".format( rc)) if background: # TODO: After migrating to launching apps via systemd, shares for make-snake # stopped launching from KW. Created a special case here to avoid # fixing the make-snake cmd through systemd temporarily. FIX THIS. if app == 'make-snake': run_bg(cmd) else: run_cmd('systemd-run --user {cmd}'.format(cmd=cmd)) else: _, _, rc = run_print_output_error(cmd) return rc else: logger.info("Sent signal to app: {} to open : {}".format( app_tr, fullpath)) return 0
def count_stat(key): allrules = read_json(xp_file) if not allrules: return -1 count = 0 for app, _ in allrules.iteritems(): appstate = load_app_state(app) try: count += int(appstate[key]) except Exception: pass return count
def count_completed_challenges(): allrules = read_json(xp_file) if not allrules: return -1 completed_challenges = 0 for app, groups in allrules.iteritems(): appstate = load_app_state(app) try: completed_challenges += int(appstate['level']) except Exception: pass return completed_challenges
def launch_project(app, filename, data_dir, background=False): # This is necessary to support the new official names # TODO: once the apps have been renamed this will not be necessary name_translation = { 'make-art': 'kano-draw', 'terminal-quest': 'linux-story' } app_tr = name_translation.get(app, app) logger.info("launch_project: {} {} {}".format(app_tr, filename, data_dir)) app_profiles = read_json(app_profiles_file) # XML file with complete pathname fullpath = os.path.join(data_dir, filename) # Prepare the command line to open the app with the new project try: cmd = (app_profiles[app_tr]['cmd'] .format(fullpath=fullpath, filename=filename)) except KeyError as exc: logger.warn( "Can't find app '{}' in the app profiles - [{}]" .format(app_tr, exc) ) raise ValueError(_("App '{}' not available").format(app_tr)) # Try to load the project if the app is already running, via a signal. _, _, rc = run_cmd('/usr/bin/kano-signal launch-share {}'.format(fullpath)) if rc: # Likely the app is not running and the signal could not be sent, so start it now logger.warn("Error sending launch signal, starting the app now, rc={}".format(rc)) if background: # TODO: After migrating to launching apps via systemd, shares for make-snake # stopped launching from KW. Created a special case here to avoid # fixing the make-snake cmd through systemd temporarily. FIX THIS. if app == 'make-snake': run_bg(cmd) else: run_cmd('systemd-run --user {cmd}'.format(cmd=cmd)) else: _, _, rc = run_print_output_error(cmd) return rc else: logger.info("Sent signal to app: {} to open : {}".format(app_tr, fullpath)) return 0
def __init__(self): self._app_profiles = read_json(app_profiles_file) if not self._app_profiles: logger.error("Error reading app_profiles.json") raise RuntimeError("Couldn't read app profiles") self._app_list = get_app_list() + ['computed'] self._app_state = dict() for app in self._app_list: self._app_state[app] = load_app_state(app) self._app_state.setdefault('computed', dict())['kano_level'] = \ calculate_kano_level()[0] self._all_rules = load_badge_rules() self._calculated_badges = {}
def load_profile(): ''' Read profile data from file containing profile information and return it as a dict. If such a file is not present, then a new dict is created :returns: profile data as a dict :rtype: dict ''' data = read_json(profile_file) if not data: data = dict() # if the profile file doesn't exist make sure that the new one # is created with the right version data['version'] = 2 if 'version' not in data: data.pop('avatar', None) data.pop('environment', None) data['username_linux'] = get_user_unsudoed() return data
def calculate_xp(): allrules = read_json(xp_file) if not allrules: return -1 points = 0 for app, groups in allrules.iteritems(): appstate = load_app_state(app) if not appstate: continue for group, rules in groups.iteritems(): # calculating points based on level if group == 'level' and 'level' in appstate: maxlevel = int(appstate['level']) for level, value in rules.iteritems(): level = int(level) value = int(value) if level <= maxlevel: points += value # calculating points based on multipliers if group == 'multipliers': for thing, value in rules.iteritems(): value = float(value) if thing in appstate: points += value * appstate[thing] if group == 'groups': # Iterate over the groups of the local profile groups_item_iter = appstate.get('groups', {}).iteritems for grp_name, grp_obj in groups_item_iter(): level_achieved = int( appstate['groups'][grp_name]['challengeNo'] ) for level, value in rules.get(grp_name, {}).iteritems(): level = int(level) value = int(value) if level <= level_achieved: points += value qm = Quests() return int(points) + qm.evaluate_xp()
def calculate_xp(): allrules = read_json(xp_file) if not allrules: return -1 points = 0 for app, groups in allrules.iteritems(): appstate = load_app_state(app) if not appstate: continue for group, rules in groups.iteritems(): # calculating points based on level if group == 'level' and 'level' in appstate: maxlevel = int(appstate['level']) for level, value in rules.iteritems(): level = int(level) value = int(value) if level <= maxlevel: points += value # calculating points based on multipliers if group == 'multipliers': for thing, value in rules.iteritems(): value = float(value) if thing in appstate: points += value * appstate[thing] if group == 'groups': # Iterate over the groups of the local profile groups_item_iter = appstate.get('groups', {}).iteritems for grp_name, grp_obj in groups_item_iter(): level_achieved = int( appstate['groups'][grp_name]['challengeNo']) for level, value in rules.get(grp_name, {}).iteritems(): level = int(level) value = int(value) if level <= level_achieved: points += value qm = Quests() return int(points) + qm.evaluate_xp()
def calculate_min_current_max_xp(): level_rules = read_json(levels_file) if not level_rules: return -1, 0 max_level = max([int(n) for n in level_rules.keys()]) xp_now = calculate_xp() level_min = 0 level_max = 0 for level in xrange(1, max_level + 1): level_min = level_rules[str(level)] if level != max_level: level_max = level_rules[str(level + 1)] else: level_max = float('inf') if level_min <= xp_now <= level_max: return level_min, xp_now, level_max
def calculate_min_current_max_xp(): level_rules = read_json(levels_file) if not level_rules: return -1, 0 max_level = max([int(n) for n in level_rules.keys()]) xp_now = calculate_xp() level_min = 0 level_max = 0 for level in xrange(1, max_level + 1): level_min = level_rules[str(level)] if level != max_level: level_max = level_rules[str(level + 1)] else: level_max = float("inf") if level_min <= xp_now <= level_max: return level_min, xp_now, level_max
def load_app_state(app_name): app_state_file = get_app_state_file(app_name) app_state = read_json(app_state_file) if not app_state: app_state = dict() return app_state
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 upload_share(self, file_path, title, app_name, featured): if not os.path.exists(file_path): return False, 'File path not found: {}'.format(file_path) extensionless_path = os.path.splitext(file_path)[0] # attachment try: files = { 'attachment': open(file_path, 'rb'), } # List of attachments to search for in (name, extension) format attachment_files = [ ('cover', 'png'), ('resource', 'tar.gz'), ('sample', 'mp3') ] for attachment in attachment_files: key, ext = attachment attachment_path = "{}.{}".format(extensionless_path, ext) if os.path.exists(attachment_path): logger.debug( 'uploading {}: {}'.format(key, attachment_path)) files[key] = open(attachment_path, 'rb') except IOError as e: files = None txt = 'Error opening the files to be shared {}'.format(str(e)) # Since we can't open the file, there is no need to continue if not files: return False, txt # data payload = { 'title': title, 'featured': featured } # description jsonfile_path = '{}.json'.format(extensionless_path) try: description = read_json(jsonfile_path)['description'] logger.debug('uploading json: {}'.format(jsonfile_path)) payload['description'] = description except Exception: description = None logger.debug('uploading payload: {}'.format(payload)) logger.debug('uploading files: {}'.format(files)) endpoint = '/share/{}'.format(app_name) success, text, data = request_wrapper('post', endpoint, session=self.session, files=files, data=payload) if not success: return False, text success = 'success' in data and data['success'] if not success: return False, 'Share upload not successful!' return True, None
def upload_share(self, file_path, title, app_name): """Upload a share that is stored in a file. This function assumes that a media file/other necessary accompanying file shares the same name (but with not extension) with the file to be shared. :param file_path: Path to the file that contains the content of the share. :type file_path: str :param title: Title to be given to the share :type title: str :param app_name: App that this share is made from/associated with :type app_name: str :returns: Success and in case of failure the error message :rtype: tuple of form (boolean, string) """ if not os.path.exists(file_path): return False, "File path not found: {}".format(file_path) extensionless_path = os.path.splitext(file_path)[0] # attachment try: files = { 'attachment': open(file_path, 'rb'), } # TODO A config file would be better suited for such a structure # List of attachments to search for in (name, [extensions...]) fmt attachment_files = [('cover', ['png', 'gif']), ('resource', ['tar.gz']), ('sample', ['mp3', 'ogg'])] for attachment in attachment_files: key, extensions = attachment for ext in extensions: attachment_path = "{}.{}".format(extensionless_path, ext) if os.path.exists(attachment_path): logger.debug("uploading {}: {}".format( key, attachment_path)) files[key] = open(attachment_path, 'rb') break except IOError as e: files = None txt = "Error opening the files to be shared {}".format(str(e)) # Since we can't open the file, there is no need to continue if not files: return False, txt # data payload = { 'title': title, } # description jsonfile_path = '{}.json'.format(extensionless_path) try: description = read_json(jsonfile_path)['description'] logger.debug('uploading json: {}'.format(jsonfile_path)) payload['description'] = description except Exception: description = None logger.debug('uploading payload: {}'.format(payload)) logger.debug('uploading files: {}'.format(files)) endpoint = '/share/{}'.format(app_name) success, text, data = request_wrapper('post', endpoint, session=self.session, files=files, data=payload) if not success: return False, text success = 'success' in data and data['success'] if not success: return False, 'Share upload not successful!' return True, None
from kano.utils import download_url, read_json, ensure_dir, chown_path from kano_profile.profile import (load_profile, set_avatar, set_environment, save_profile, save_profile_variable, recreate_char) from kano_profile.badges import calculate_xp from kano_profile.apps import get_app_list, load_app_state, save_app_state from kano_profile.paths import app_profiles_file, online_badges_dir, \ online_badges_file, profile_dir from kano_profile.tracker import get_tracker_events, clear_tracker_events from kano_profile_gui.paths import media_dir from kano_avatar.paths import (AVATAR_DEFAULT_LOC, AVATAR_DEFAULT_NAME, AVATAR_ENV_DEFAULT, AVATAR_CIRC_PLAIN_DEFAULT) from .connection import request_wrapper, content_type_json app_profiles_data = read_json(app_profiles_file) def is_private(app_name): try: private = app_profiles_data[app_name]['private'] except Exception: private = False return private class KanoWorldSession(object): session = requests.Session() def __init__(self, token): self.session.headers.update({'Authorization': token})
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.profile import (load_profile, set_avatar, set_environment, save_profile, save_profile_variable, recreate_char) from kano_profile.badges import calculate_xp from kano_profile.apps import get_app_list, load_app_state, save_app_state from kano_profile.paths import app_profiles_file, online_badges_dir, \ online_badges_file, profile_dir from kano_profile.tracker import get_tracker_events, clear_tracker_events from kano_profile_gui.paths import media_dir from kano_avatar.paths import (AVATAR_DEFAULT_LOC, AVATAR_DEFAULT_NAME, AVATAR_ENV_DEFAULT, AVATAR_CIRC_PLAIN_DEFAULT) from .connection import request_wrapper, content_type_json app_profiles_data = read_json(app_profiles_file) def is_private(app_name): try: private = app_profiles_data[app_name]['private'] except Exception: private = False return private class KanoWorldSession(object): session = requests.Session() def __init__(self, token): self.session.headers.update({'Authorization': token})
def upload_share(self, file_path, title, app_name): """Upload a share that is stored in a file. This function assumes that a media file/other necessary accompanying file shares the same name (but with not extension) with the file to be shared. :param file_path: Path to the file that contains the content of the share. :type file_path: str :param title: Title to be given to the share :type title: str :param app_name: App that this share is made from/associated with :type app_name: str :returns: Success and in case of failure the error message :rtype: tuple of form (boolean, string) """ if not os.path.exists(file_path): return False, "File path not found: {}".format(file_path) extensionless_path = os.path.splitext(file_path)[0] # attachment try: files = { 'attachment': open(file_path, 'rb'), } # TODO A config file would be better suited for such a structure # List of attachments to search for in (name, [extensions...]) fmt attachment_files = [ ('cover', ['png', 'gif']), ('resource', ['tar.gz']), ('sample', ['mp3', 'ogg']) ] for attachment in attachment_files: key, extensions = attachment for ext in extensions: attachment_path = "{}.{}".format(extensionless_path, ext) if os.path.exists(attachment_path): logger.debug( "uploading {}: {}".format(key, attachment_path)) files[key] = open(attachment_path, 'rb') break except IOError as e: files = None txt = "Error opening the files to be shared {}".format(str(e)) # Since we can't open the file, there is no need to continue if not files: return False, txt # data payload = { 'title': title, } # description jsonfile_path = '{}.json'.format(extensionless_path) try: description = read_json(jsonfile_path)['description'] logger.debug('uploading json: {}'.format(jsonfile_path)) payload['description'] = description except Exception: description = None logger.debug('uploading payload: {}'.format(payload)) logger.debug('uploading files: {}'.format(files)) endpoint = '/share/{}'.format(app_name) success, text, data = request_wrapper('post', endpoint, session=self.session, files=files, data=payload) if not success: return False, text success = 'success' in data and data['success'] if not success: return False, 'Share upload not successful!' return True, None
# License: http://www.gnu.org/licenses/gpl-2.0.txt GNU General Public License v2 # import os from gi.repository import Gtk from kano.utils import get_home, read_json from kano_profile.apps import get_app_list, get_app_data_dir, launch_project from kano_profile.paths import app_profiles_file from kano.logging import logger import kano.gtk3.cursor as cursor from kano.gtk3.scrolled_window import ScrolledWindow import kano_profile_gui.components.icons as icons from .paths import image_dir from kdesk.hourglass import hourglass_start, hourglass_end app_profiles = read_json(app_profiles_file) # The list of the displayed items class ProjectList(): def __init__(self): self.width = 646 self.height = 88 apps = get_app_list() self.projects_list = [] for app in apps: if app in app_profiles: if 'ext' in app_profiles[app]:
def calculate_badges(): # helper function to calculate operations def do_calculate(select_push_back): for category, subcats in all_rules.iteritems(): for subcat, items in subcats.iteritems(): for item, rules in items.iteritems(): target_pushback = 'push_back' in rules and rules['push_back'] is True if target_pushback != select_push_back: continue if rules['operation'] == 'each_greater': achieved = True for target in rules['targets']: app = target[0] variable = target[1] value = target[2] if variable == 'level' and value == -1: value = app_profiles[app]['max_level'] if app not in app_list or variable not in app_state[app]: achieved = False break achieved &= app_state[app][variable] >= value elif rules['operation'] == 'sum_greater': sum = 0 for target in rules['targets']: app = target[0] variable = target[1] if app not in app_list or variable not in app_state[app]: continue sum += float(app_state[app][variable]) achieved = sum >= rules['value'] else: continue calculated_badges.setdefault(category, dict()).setdefault(subcat, dict())[item] \ = all_rules[category][subcat][item] calculated_badges[category][subcat][item]['achieved'] = achieved def count_offline_badges(): count = 0 for category, subcats in calculated_badges.iteritems(): for subcat, items in subcats.iteritems(): for item, rules in items.iteritems(): if category == 'badges' and subcat != 'online' and rules['achieved']: count += 1 return count app_profiles = read_json(app_profiles_file) if not app_profiles: logger.error('Error reading app_profiles.json') app_list = get_app_list() + ['computed'] app_state = dict() for app in app_list: app_state[app] = load_app_state(app) app_state.setdefault('computed', dict())['kano_level'] = calculate_kano_level()[0] all_rules = load_badge_rules() calculated_badges = dict() # normal ones do_calculate(False) # count offline badges app_state['computed']['num_offline_badges'] = count_offline_badges() # add pushed back ones do_calculate(True) # Inject badges from quests to the dict qm = Quests() calculated_badges['badges']['quests'] = qm.evaluate_badges() return calculated_badges