示例#1
0
    def get_static_files(self, game_path, request_path, path):
        static_path = os.path.join(game_path, path) #request_path, path)
        static_path_obj = PathDetail(static_path)

        files = [ ]
        directories = { }
        if static_path_obj.is_correct():
            files = self.iterate_dir(static_path_obj, files, directories)
        else:
            raise GamePathNotFoundError('Path not valid')

        if len(files) > 0:
            return files
        return [ ]
示例#2
0
    def get_static_files(self, game_path, request_path, path):
        static_path = os.path.join(game_path, path)  #request_path, path)
        static_path_obj = PathDetail(static_path)

        files = []
        directories = {}
        if static_path_obj.is_correct():
            files = self.iterate_dir(static_path_obj, files, directories)
        else:
            raise GamePathNotFoundError('Path not valid')

        if len(files) > 0:
            return files
        return []
示例#3
0
class Game(object):

    _executable_extensions = ('.html', '.htm', '.tzjs', '.canvas.js', '.swf')

    def __init__(self, game_list, game_path=None, slug=None, games_root=None, deploy_enable=False, manifest_name=None):
        self.game_list = game_list
        self.slug = None
        self.title = None
        self.path = None
        self.cover_art = ImageDetail(self, 'cover_art.jpg')
        self.title_logo = ImageDetail(self, 'title_logo.jpg')
        self.modified = None
        self.deployed = None
        self.is_temporary = True
        self.plugin_main = None
        self.canvas_main = None
        self.flash_main = None
        self.mapping_table = None
        self.deploy_files = None
        self.has_mapping_table = None
        self.engine_version = EngineDetail('')
        self.is_multiplayer = False
        self.aspect_ratio = AspectRatioDetail('')
        # if game_path is set, load data,
        # otherwise create a temporary game
        if manifest_name is None:
            self.manifest_name = 'manifest.yaml'
        else:
            self.manifest_name = manifest_name
        if game_path is not None:
            self.load(game_path, self.manifest_name)
        elif slug is not None:
            self.update({'slug': slug})
        self.games_root = games_root
        self.deploy_enable = deploy_enable

    def update(self, data):
        """
        Update the game object with the values supplied
        """
        self._set_slug(data)
        self._set_path(data)
        self._set_title(data)
        self._set_images(data)
        self._set_dates(data)
        self.plugin_main = GameDetail(data.get('plugin_main'))
        self.canvas_main = GameDetail(data.get('canvas_main'))
        self.flash_main = GameDetail(data.get('flash_main'))
        self.mapping_table = GameDetail(data.get('mapping_table'))
        self.deploy_files = ListDetail(data.get('deploy_files', []))
        self.engine_version = EngineDetail(data.get('engine_version'))
        self.is_multiplayer = asbool(data.get('is_multiplayer', False))
        self.aspect_ratio = AspectRatioDetail(data.get('aspect_ratio'))

    def _set_slug(self, data):
        old_slug = self.slug
        self.slug = SlugDetail(data.get('slug'))
        if old_slug and not old_slug == self.slug:
            self.game_list.change_slug(old_slug, self.slug)

    def _set_path(self, data):
        self.path = PathDetail(data.get('path'))

    def _set_title(self, data):
        self.title = GameDetail(data.get('title'))

    def _set_images(self, data):
        cover_art = data.get('cover_art', None)
        if cover_art:
            self.cover_art = ImageDetail(self, cover_art)
        title_logo = data.get('title_logo', None)
        if title_logo:
            self.title_logo = ImageDetail(self, title_logo)

    def _set_dates(self, data):
        self.modified = data.get('modified', 'Never')
        self.deployed = data.get('deployed', 'Never')

    def save(self, attrs):
        """
        Save this game object in persistent storage.
        """
        # check that there's a path in the given attributes
        if 'path' not in attrs.keys():
            raise GamePathNotFoundError('No Path given')
        # check that it can be used
        if not create_dir(attrs['path']):
            raise GamePathError('Path "%s" could not be created.' % attrs['path'])

        # update the game
        self.update(attrs)
        # update modified time
        t = localtime(time())
        self.modified = strftime("%H:%M | %d/%m/%Y", t)
        # trim unnecessary values and write game to manifest file
        write_manifest(self.to_dict(), self.manifest_name)
        # if the game has been saved, it's not temporary anymore
        self.is_temporary = False

    def load(self, game_path=None, manifest_name=None):
        """
        Update this game with data loaded from the manifest file at
        the specified path. If 'dataPath' is not provided, simply reload
        the game.
        """
        # make sure data_path is set
        if game_path is None:
            game_path = self.path
        if manifest_name is None:
            manifest_name = self.manifest_name
        # get data from manifest file...
        game_data = read_manifest(game_path, manifest_name)
        # and update it with the actual path
        game_data['path'] = game_path
        # update game with data
        self.update(game_data)
        # if the game can be loaded, it's not temporary anymore
        self.is_temporary = False

    def get_path(self):
        return self.path

    def to_dict(self):
        """
        Convert the current object to a dict, with properly encoded and
        formatted values for dumping
        """
        # grab all attributes that should be saved into a dict
        data = {
            'path': self.path,
            'title': self.title,
            'slug': self.slug,
            'is_temp': self.is_temporary,
            'cover_art': self.cover_art.image_path,
            'title_logo': self.title_logo.image_path,
            'modified': self.modified,
            'deployed': self.deployed,
            'plugin_main': self.plugin_main,
            'canvas_main': self.canvas_main,
            'flash_main': self.flash_main,
            'mapping_table': self.mapping_table,
            'deploy_files': self.deploy_files.items,
            'engine_version': self.engine_version,
            'is_multiplayer': self.is_multiplayer,
            'has_notifications': self.has_notifications,
            'aspect_ratio': self.aspect_ratio
        }
        # attempt to format the data correctly
        for k, v in data.iteritems():
            try:
                data[k] = v.encode('utf8')
            except (KeyError, AttributeError):
                pass
        return data

    #iterate through the directories and add files to list
    @classmethod
    def iterate_dir(cls, path, files, directories):
        abs_static_path = get_absolute_path(path)

        for file_name in listdir(abs_static_path):
            if os.path.isdir(os.path.join(abs_static_path, file_name)) != True:
                #file_name is not directory
                parts = path.split('/')
                if len(parts) > 2:
                    directory = parts[-1]
                else:
                    directory = ''

                files.append(_File(file_name, file_name, directory, os.path.join(abs_static_path, file_name)))
            else:
                if (file_name not in directories):
                    directories[file_name] = _File(file_name)

        return directories.values() + files

    #get the assets not on the mapping table directly from staticmax/ directory
    def get_static_files(self, game_path, request_path, path):
        static_path = os.path.join(game_path, path) #request_path, path)
        static_path_obj = PathDetail(static_path)

        files = [ ]
        directories = { }
        if static_path_obj.is_correct():
            files = self.iterate_dir(static_path_obj, files, directories)
        else:
            raise GamePathNotFoundError('Path not valid')

        if len(files) > 0:
            return files
        return [ ]

    #get assets on the mapping table
    def get_asset_list(self, request_path, path=''):
        if self.path.is_correct():
            game_path = self.path
            abs_game_path = get_absolute_path(game_path)

            # Load mapping table
            j = load_json_asset(os.path.join(game_path, self.mapping_table))
            if j:
                # pylint: disable=E1103
                mapping_table = j.get('urnmapping') or j.get('urnremapping', {})
                # pylint: enable=E1103
                self.has_mapping_table = True
                files = [ ]
                directories = { }
                len_path = len(path)
                if not path.endswith('/') and len_path > 0:
                    len_path += 1
                for k, v in mapping_table.iteritems():
                    if k.startswith(path):
                        parts = k[len_path:].split('/')
                        if len(parts) == 1:
                            abs_file_path = os.path.join(abs_game_path, request_path, v)
                            files.append(_File(parts[0], v, '%s/%s' % (request_path, v), abs_file_path))
                        else:
                            if parts[0] not in directories:
                                directories[parts[0]] = _File(parts[0])

                result = directories.values() + files
                if len(result) == 0:
                    raise GamePathNotFoundError('Asset path does not exist: %s' % path)

                return result

            else:
                self.has_mapping_table = False
                # !!! What do we expect if the user asks for Assets and there is no mapping table?
                return self.get_static_files(game_path, request_path, path)

        else:
            raise GamePathError('Game path not found: %s' % self.path)

    @property
    def has_metrics(self):
        return MetricsSession.has_metrics(self.slug)

    @property
    def has_assets(self):
        asset_list = self.get_asset_list('')
        return len(asset_list) > 0

    @property
    def has_notifications(self):
        try:
            GameNotificationKeysList.get(self)
        except GameNotificationsUnsupportedException:
            return False

        return True

    def get_versions(self):
        # if the game path is defined, find play-html files.
        versions = [ ]
        if self.path.is_correct():
            abs_path = get_absolute_path(self.path)
            slug = self.slug + '/'
            executable_extensions = self._executable_extensions
            flash_dict = None
            for file_name in listdir(abs_path):
                if file_name.endswith(executable_extensions):
                    version = { 'title': os.path.basename(file_name),
                                'url': slug + file_name }
                    if file_name.endswith('.swf'):
                        if flash_dict is None:
                            flash_dict = {}
                            flash_config_path = join_path(abs_path, 'flash.yaml')
                            if access(flash_config_path, R_OK):
                                f = open(unicode(flash_config_path), 'r')
                                try:
                                    flash_dict = yaml.load(f)
                                finally:
                                    f.close()
                        version['flash'] = flash_dict
                    versions.append(version)
        return versions

    def set_deployed(self):
        self.deployed = strftime("%H:%M | %d/%m/%Y", localtime(time()))
        write_manifest(self.to_dict(), self.manifest_name)

    def check_completeness(self):
        errors = []
        tmp = []
        if not self.deploy_enable:
            tmp.append('"deploy" is disabled.')
        if self.is_temporary:
            tmp.append('Game is temporary.')

        path = self.path
        if not path or not path.is_set():
            tmp.append('No path set.')
            path_correct = False
        else:
            path_correct = path.is_correct()
            if not path_correct:
                tmp.append('Incorrect path set.')

        if tmp:
            errors.append(('settings', {'errors': tmp}))
            tmp = []

        plugin_main = self.plugin_main
        canvas_main = self.canvas_main
        flash_main = self.flash_main
        main_correct = True
        if (not plugin_main or not plugin_main.is_set()) and \
           (not canvas_main or not canvas_main.is_set()) and \
           (not flash_main or not flash_main.is_set()):
            tmp.append('No "main"-file set. Specify at least one of plugin or canvas main.')
            main_correct = False

        abs_path = get_absolute_path(path)
        if plugin_main:
            plugin_main = join_path(abs_path, plugin_main)
            if not access(plugin_main, R_OK):
                tmp.append('Can\'t access plugin "main"-file.')
        if canvas_main:
            canvas_main = join_path(abs_path, canvas_main)
            if not access(canvas_main, R_OK):
                tmp.append('Can\'t access canvas "main"-file.')
        if flash_main:
            if not flash_main.startswith('https://'):
                flash_main = join_path(abs_path, flash_main)
                if not access(flash_main, R_OK):
                    tmp.append('Can\'t access flash "main"-file.')

        mapping_table = self.mapping_table
        if (not mapping_table or not mapping_table.is_set()) and not flash_main:
            tmp.append('No mapping-table set.')
        elif path_correct and main_correct:
            mapping_table = join_path(abs_path, mapping_table)
            if not access(mapping_table, R_OK):
                tmp.append('Can\'t access mapping-table.')

        deploy_files = self.deploy_files
        if not deploy_files or not deploy_files.is_set():
            tmp.append('No deploy files set.')

        engine_version = self.engine_version
        if not engine_version or not engine_version.is_set():
            tmp.append('No engine version set.')
        elif not engine_version.is_correct():
            tmp.append('Invalid engine version set.')

        aspect_ratio = self.aspect_ratio
        if not aspect_ratio or not aspect_ratio.is_set():
            tmp.append('No aspect ratio set.')
        elif not aspect_ratio.is_correct():
            tmp.append('Invalid aspect ratio set.')

        if tmp:
            errors.append(('files', {'errors': tmp}))

        return (len(errors) == 0, {'Project-Settings': errors})


    @property
    def can_deploy(self):
        completeness = self.check_completeness()
        return completeness[0]


    def validate_yaml(self):
        result = {}

        try:
            badges = GameBadges(self)
        except BadgesUnsupportedException:
            pass
        except ApiException as e:
            result['Badges'] = [('badges.yaml', {
                'errors': ['%s' % e]
            })]
        else:
            issues = badges.validate()
            if issues:
                result['Badges'] = issues

        try:
            notification_keys = GameNotificationKeysList.get(self)
        except GameNotificationsUnsupportedException:
            pass
        except ApiException as e:
            result['Notifications'] = [('notifications.yaml', {
                'errors': ['%s' % e]
            })]
        else:
            issues = notification_keys.validate()
            if issues:
                result['Notifications'] = issues

        try:
            leaderboards = LeaderboardsList.load(self)
        except LeaderboardsUnsupported:
            pass
        except LeaderboardError as e:
            result['Leaderboards'] = [('leaderboards.yaml', {
                'errors': ['incorrect format: %s' % e]
            })]
        except KeyError as e:
            result['Leaderboards'] = [('leaderboards.yaml', {
                'errors': ['key %s could not be found.' % e]
            })]
        except ValidationException as e:
            result['Leaderboards'] = e.issues
        else:
            issues = leaderboards.issues
            if issues:
                result['Leaderboards'] = leaderboards.issues

        try:
            store = StoreList.load(self)
        except StoreUnsupported:
            pass
        except StoreError as e:
            result['Store'] = [('store.yaml', {
                'errors': ['incorrect format: %s' % e]
            })]
        except ValidationException as e:
            result['Store'] = e.issues
        else:
            issues = store.issues
            if issues:
                result['Store'] = store.issues

        try:
            for v in result.itervalues():
                for item in v:
                    if item[1]['errors']:
                        return (result, True)
        except (KeyError, IndexError):
            LOG.error('badly formatted result structure when checking YAML issues')
            return (result, True)
        return (result, False)



    ###################################################################################################################

    # Helpers - moved from helper class onto the object

    def status(self, fields):
        """
        Returns "complete", "incorrect" or "" (empty string) to represent status
        of the given field(s) towards publishing the specified game
        """
        # set everything grey until the game is not temporary anymore
        if self.is_temporary:
            return ''
        # accept both lists and single values
        if type(fields) is not list:
            fields = [fields]

        result = 'complete'
        for field in fields:
            field = self.__getattribute__(field)

            if not field.is_set():
                result = ''
            elif not field.is_correct():
                return "incorrect"
        return result

    def get_games_root(self):
        return self.games_root
示例#4
0
 def _set_path(self, data):
     self.path = PathDetail(data.get('path'))
示例#5
0
 def _set_path(self, data):
     self.path = PathDetail(data.get('path'))
示例#6
0
class Game(object):

    _executable_extensions = ('.html', '.htm', '.tzjs', '.canvas.js', '.swf')

    def __init__(self,
                 game_list,
                 game_path=None,
                 slug=None,
                 games_root=None,
                 deploy_enable=False,
                 manifest_name=None):
        self.game_list = game_list
        self.slug = None
        self.title = None
        self.path = None
        self.cover_art = ImageDetail(self, 'cover_art.jpg')
        self.title_logo = ImageDetail(self, 'title_logo.jpg')
        self.modified = None
        self.deployed = None
        self.is_temporary = True
        self.plugin_main = None
        self.canvas_main = None
        self.flash_main = None
        self.mapping_table = None
        self.deploy_files = None
        self.has_mapping_table = None
        self.engine_version = EngineDetail('')
        self.is_multiplayer = False
        self.aspect_ratio = AspectRatioDetail('')
        # if game_path is set, load data,
        # otherwise create a temporary game
        if manifest_name is None:
            self.manifest_name = 'manifest.yaml'
        else:
            self.manifest_name = manifest_name
        if game_path is not None:
            self.load(game_path, self.manifest_name)
        elif slug is not None:
            self.update({'slug': slug})
        self.games_root = games_root
        self.deploy_enable = deploy_enable

    def update(self, data):
        """
        Update the game object with the values supplied
        """
        self._set_slug(data)
        self._set_path(data)
        self._set_title(data)
        self._set_images(data)
        self._set_dates(data)
        self.plugin_main = GameDetail(data.get('plugin_main'))
        self.canvas_main = GameDetail(data.get('canvas_main'))
        self.flash_main = GameDetail(data.get('flash_main'))
        self.mapping_table = GameDetail(data.get('mapping_table'))
        self.deploy_files = ListDetail(data.get('deploy_files', []))
        self.engine_version = EngineDetail(data.get('engine_version'))
        self.is_multiplayer = asbool(data.get('is_multiplayer', False))
        self.aspect_ratio = AspectRatioDetail(data.get('aspect_ratio'))

    def _set_slug(self, data):
        old_slug = self.slug
        self.slug = SlugDetail(data.get('slug'))
        if old_slug and not old_slug == self.slug:
            self.game_list.change_slug(old_slug, self.slug)

    def _set_path(self, data):
        self.path = PathDetail(data.get('path'))

    def _set_title(self, data):
        self.title = GameDetail(data.get('title'))

    def _set_images(self, data):
        cover_art = data.get('cover_art', None)
        if cover_art:
            self.cover_art = ImageDetail(self, cover_art)
        title_logo = data.get('title_logo', None)
        if title_logo:
            self.title_logo = ImageDetail(self, title_logo)

    def _set_dates(self, data):
        self.modified = data.get('modified', 'Never')
        self.deployed = data.get('deployed', 'Never')

    def save(self, attrs):
        """
        Save this game object in persistent storage.
        """
        # check that there's a path in the given attributes
        if 'path' not in attrs.keys():
            raise GamePathNotFoundError('No Path given')
        # check that it can be used
        if not create_dir(attrs['path']):
            raise GamePathError('Path "%s" could not be created.' %
                                attrs['path'])

        # update the game
        self.update(attrs)
        # update modified time
        t = localtime(time())
        self.modified = strftime("%H:%M | %d/%m/%Y", t)
        # trim unnecessary values and write game to manifest file
        write_manifest(self.to_dict(), self.manifest_name)
        # if the game has been saved, it's not temporary anymore
        self.is_temporary = False

    def load(self, game_path=None, manifest_name=None):
        """
        Update this game with data loaded from the manifest file at
        the specified path. If 'dataPath' is not provided, simply reload
        the game.
        """
        # make sure data_path is set
        if game_path is None:
            game_path = self.path
        if manifest_name is None:
            manifest_name = self.manifest_name
        # get data from manifest file...
        game_data = read_manifest(game_path, manifest_name)
        # and update it with the actual path
        game_data['path'] = game_path
        # update game with data
        self.update(game_data)
        # if the game can be loaded, it's not temporary anymore
        self.is_temporary = False

    def get_path(self):
        return self.path

    def to_dict(self):
        """
        Convert the current object to a dict, with properly encoded and
        formatted values for dumping
        """
        # grab all attributes that should be saved into a dict
        data = {
            'path': self.path,
            'title': self.title,
            'slug': self.slug,
            'is_temp': self.is_temporary,
            'cover_art': self.cover_art.image_path,
            'title_logo': self.title_logo.image_path,
            'modified': self.modified,
            'deployed': self.deployed,
            'plugin_main': self.plugin_main,
            'canvas_main': self.canvas_main,
            'flash_main': self.flash_main,
            'mapping_table': self.mapping_table,
            'deploy_files': self.deploy_files.items,
            'engine_version': self.engine_version,
            'is_multiplayer': self.is_multiplayer,
            'has_notifications': self.has_notifications,
            'aspect_ratio': self.aspect_ratio
        }
        # attempt to format the data correctly
        for k, v in data.iteritems():
            try:
                data[k] = v.encode('utf8')
            except (KeyError, AttributeError):
                pass
        return data

    #iterate through the directories and add files to list
    @classmethod
    def iterate_dir(cls, path, files, directories):
        abs_static_path = get_absolute_path(path)

        for file_name in listdir(abs_static_path):
            if os.path.isdir(os.path.join(abs_static_path, file_name)) != True:
                #file_name is not directory
                parts = path.split('/')
                if len(parts) > 2:
                    directory = parts[-1]
                else:
                    directory = ''

                files.append(
                    _File(file_name, file_name, directory,
                          os.path.join(abs_static_path, file_name)))
            else:
                if (file_name not in directories):
                    directories[file_name] = _File(file_name)

        return directories.values() + files

    #get the assets not on the mapping table directly from staticmax/ directory
    def get_static_files(self, game_path, request_path, path):
        static_path = os.path.join(game_path, path)  #request_path, path)
        static_path_obj = PathDetail(static_path)

        files = []
        directories = {}
        if static_path_obj.is_correct():
            files = self.iterate_dir(static_path_obj, files, directories)
        else:
            raise GamePathNotFoundError('Path not valid')

        if len(files) > 0:
            return files
        return []

    #get assets on the mapping table
    def get_asset_list(self, request_path, path=''):
        if self.path.is_correct():
            game_path = self.path
            abs_game_path = get_absolute_path(game_path)

            # Load mapping table
            j = load_json_asset(os.path.join(game_path, self.mapping_table))
            if j:
                # pylint: disable=E1103
                mapping_table = j.get('urnmapping') or j.get(
                    'urnremapping', {})
                # pylint: enable=E1103
                self.has_mapping_table = True
                files = []
                directories = {}
                len_path = len(path)
                if not path.endswith('/') and len_path > 0:
                    len_path += 1
                for k, v in mapping_table.iteritems():
                    if k.startswith(path):
                        parts = k[len_path:].split('/')
                        if len(parts) == 1:
                            abs_file_path = os.path.join(
                                abs_game_path, request_path, v)
                            files.append(
                                _File(parts[0], v, '%s/%s' % (request_path, v),
                                      abs_file_path))
                        else:
                            if parts[0] not in directories:
                                directories[parts[0]] = _File(parts[0])

                result = directories.values() + files
                if len(result) == 0:
                    raise GamePathNotFoundError(
                        'Asset path does not exist: %s' % path)

                return result

            else:
                self.has_mapping_table = False
                # !!! What do we expect if the user asks for Assets and there is no mapping table?
                return self.get_static_files(game_path, request_path, path)

        else:
            raise GamePathError('Game path not found: %s' % self.path)

    @property
    def has_metrics(self):
        return MetricsSession.has_metrics(self.slug)

    @property
    def has_assets(self):
        asset_list = self.get_asset_list('')
        return len(asset_list) > 0

    @property
    def has_notifications(self):
        try:
            GameNotificationKeysList.get(self)
        except GameNotificationsUnsupportedException:
            return False

        return True

    def get_versions(self):
        # if the game path is defined, find play-html files.
        versions = []
        if self.path.is_correct():
            abs_path = get_absolute_path(self.path)
            slug = self.slug + '/'
            executable_extensions = self._executable_extensions
            flash_dict = None
            for file_name in listdir(abs_path):
                if file_name.endswith(executable_extensions):
                    version = {
                        'title': os.path.basename(file_name),
                        'url': slug + file_name
                    }
                    if file_name.endswith('.swf'):
                        if flash_dict is None:
                            flash_dict = {}
                            flash_config_path = join_path(
                                abs_path, 'flash.yaml')
                            if access(flash_config_path, R_OK):
                                f = open(unicode(flash_config_path), 'r')
                                try:
                                    flash_dict = yaml.load(f)
                                finally:
                                    f.close()
                        version['flash'] = flash_dict
                    versions.append(version)
        return versions

    def set_deployed(self):
        self.deployed = strftime("%H:%M | %d/%m/%Y", localtime(time()))
        write_manifest(self.to_dict(), self.manifest_name)

    def check_completeness(self):
        errors = []
        tmp = []
        if not self.deploy_enable:
            tmp.append('"deploy" is disabled.')
        if self.is_temporary:
            tmp.append('Game is temporary.')

        path = self.path
        if not path or not path.is_set():
            tmp.append('No path set.')
            path_correct = False
        else:
            path_correct = path.is_correct()
            if not path_correct:
                tmp.append('Incorrect path set.')

        if tmp:
            errors.append(('settings', {'errors': tmp}))
            tmp = []

        plugin_main = self.plugin_main
        canvas_main = self.canvas_main
        flash_main = self.flash_main
        main_correct = True
        if (not plugin_main or not plugin_main.is_set()) and \
           (not canvas_main or not canvas_main.is_set()) and \
           (not flash_main or not flash_main.is_set()):
            tmp.append(
                'No "main"-file set. Specify at least one of plugin or canvas main.'
            )
            main_correct = False

        abs_path = get_absolute_path(path)
        if plugin_main:
            plugin_main = join_path(abs_path, plugin_main)
            if not access(plugin_main, R_OK):
                tmp.append('Can\'t access plugin "main"-file.')
        if canvas_main:
            canvas_main = join_path(abs_path, canvas_main)
            if not access(canvas_main, R_OK):
                tmp.append('Can\'t access canvas "main"-file.')
        if flash_main:
            if not flash_main.startswith('https://'):
                flash_main = join_path(abs_path, flash_main)
                if not access(flash_main, R_OK):
                    tmp.append('Can\'t access flash "main"-file.')

        mapping_table = self.mapping_table
        if (not mapping_table
                or not mapping_table.is_set()) and not flash_main:
            tmp.append('No mapping-table set.')
        elif path_correct and main_correct:
            mapping_table = join_path(abs_path, mapping_table)
            if not access(mapping_table, R_OK):
                tmp.append('Can\'t access mapping-table.')

        deploy_files = self.deploy_files
        if not deploy_files or not deploy_files.is_set():
            tmp.append('No deploy files set.')

        engine_version = self.engine_version
        if not engine_version or not engine_version.is_set():
            tmp.append('No engine version set.')
        elif not engine_version.is_correct():
            tmp.append('Invalid engine version set.')

        aspect_ratio = self.aspect_ratio
        if not aspect_ratio or not aspect_ratio.is_set():
            tmp.append('No aspect ratio set.')
        elif not aspect_ratio.is_correct():
            tmp.append('Invalid aspect ratio set.')

        if tmp:
            errors.append(('files', {'errors': tmp}))

        return (len(errors) == 0, {'Project-Settings': errors})

    @property
    def can_deploy(self):
        completeness = self.check_completeness()
        return completeness[0]

    def validate_yaml(self):
        result = {}

        try:
            badges = GameBadges(self)
        except BadgesUnsupportedException:
            pass
        except ApiException as e:
            result['Badges'] = [('badges.yaml', {'errors': ['%s' % e]})]
        else:
            issues = badges.validate()
            if issues:
                result['Badges'] = issues

        try:
            notification_keys = GameNotificationKeysList.get(self)
        except GameNotificationsUnsupportedException:
            pass
        except ApiException as e:
            result['Notifications'] = [('notifications.yaml', {
                'errors': ['%s' % e]
            })]
        else:
            issues = notification_keys.validate()
            if issues:
                result['Notifications'] = issues

        try:
            leaderboards = LeaderboardsList.load(self)
        except LeaderboardsUnsupported:
            pass
        except LeaderboardError as e:
            result['Leaderboards'] = [('leaderboards.yaml', {
                'errors': ['incorrect format: %s' % e]
            })]
        except KeyError as e:
            result['Leaderboards'] = [('leaderboards.yaml', {
                'errors': ['key %s could not be found.' % e]
            })]
        except ValidationException as e:
            result['Leaderboards'] = e.issues
        else:
            issues = leaderboards.issues
            if issues:
                result['Leaderboards'] = leaderboards.issues

        try:
            store = StoreList.load(self)
        except StoreUnsupported:
            pass
        except StoreError as e:
            result['Store'] = [('store.yaml', {
                'errors': ['incorrect format: %s' % e]
            })]
        except ValidationException as e:
            result['Store'] = e.issues
        else:
            issues = store.issues
            if issues:
                result['Store'] = store.issues

        try:
            for v in result.itervalues():
                for item in v:
                    if item[1]['errors']:
                        return (result, True)
        except (KeyError, IndexError):
            LOG.error(
                'badly formatted result structure when checking YAML issues')
            return (result, True)
        return (result, False)

    ###################################################################################################################

    # Helpers - moved from helper class onto the object

    def status(self, fields):
        """
        Returns "complete", "incorrect" or "" (empty string) to represent status
        of the given field(s) towards publishing the specified game
        """
        # set everything grey until the game is not temporary anymore
        if self.is_temporary:
            return ''
        # accept both lists and single values
        if type(fields) is not list:
            fields = [fields]

        result = 'complete'
        for field in fields:
            field = self.__getattribute__(field)

            if not field.is_set():
                result = ''
            elif not field.is_correct():
                return "incorrect"
        return result

    def get_games_root(self):
        return self.games_root