Exemplo n.º 1
0
    def __init__(self, renderer_globals, app):
        """
            Initializes a slide renderer with the given globals.
            :param renderer_globals: a dictionary in the form
                {
                    '[field-type]': Python function,
                    ...
                }
            Each function is responsible of rendering the corresponding field and will be called by the renderer when
            a corresponding function is parsed in a slide template.
        """
        renderer_globals['base'] = "base.html"
        self.renderer_globals = renderer_globals
        self.renderer_globals[
            'get_template_id'] = lambda: utils.generate_secret(digits='')

        ### Jinja2 ###
        self.slide_renderer = render_jinja(
            os.path.join(get_root_path(), 'renderer/templates/'))
        self.slide_renderer._lookup.globals.update(**self.renderer_globals)

        self.preview_renderer = render_jinja(
            os.path.join(get_root_path(), 'renderer/'))
        self.preview_renderer._lookup.globals.update(**self.renderer_globals)
        ###########

        self.app = app
        super(SlideRenderer, self).__init__()
Exemplo n.º 2
0
def main(config_path, address_port):
    logger = logging.getLogger('app')
    try:
        app = get_app(config_path).get_app_dispatcher()
        if is_test() or app.config['debug']['serve_static']:
            cwd = os.getcwd()
            os.chdir(get_root_path())
            if not os.path.exists(os.path.join(get_root_path(), 'sessions')):
                os.mkdir(os.path.join(get_root_path(), 'sessions'))
            os.chdir(cwd)
        if not is_test():
            address_port = address_port.rsplit(':', 1)
            address = '0.0.0.0' if len(address_port) == 1 else address_port[0]
            port = address_port[0] if len(
                address_port) == 1 else address_port[1]
            werkzeug.serving.run_simple(
                address,
                int(port),
                app,
                use_debugger=app.config['debug'] != None)
        else:
            return app
    except Exception as e:
        logger.error('Exception encountered when starting the application',
                     exc_info=True)
        raise e
Exemplo n.º 3
0
def on_asset_deleted(instance, kwargs):
    """ Deletes the file associated with this asset when this asset is deleted. """
    try:
        os.remove(os.path.join(get_root_path(), instance.path))
    except (OSError, TypeError) as e:
        # TODO: log message to app.log
        print(e)
Exemplo n.º 4
0
def make_client_zip():
    client_zip_path = os.path.join(get_root_path(), 'client', 'ks', 'client' + os.extsep + 'zip')
    if os.path.exists(client_zip_path):
        os.unlink(client_zip_path)

    def add_file(file):
        client_zip.write(os.path.join(get_root_path(), 'client', file), arcname=file)

    with ZipFile(client_zip_path, 'w') as client_zip:
        add_file('cache_daemon.py')
        add_file('static/bootstrap.html')
        add_file('static/jquery.min.js')
        add_file('static/jquery.xmlrpc.min.js')
        add_file('static/waiting_screen.html')
        with open(os.path.join(get_root_path(), 'client', 'static', 'config' + os.extsep + 'json')) as client_config_file:
            client_zip.writestr('static/config.json', client_config_file.read() % flask.g.homedomain)
Exemplo n.º 5
0
def get_paths(file_hash):
    iframe_path = 'plugins/embed/iframe_' + file_hash + '.html'
    file_prefix = os.path.join(get_root_path(), 'static')
    full_iframe_path = os.path.join(file_prefix, iframe_path)
    inlined_page = 'plugins/embed/' + file_hash + '.html'
    full_inlined_page_path = os.path.join(file_prefix, inlined_page)
    return iframe_path, full_iframe_path, inlined_page, full_inlined_page_path
Exemplo n.º 6
0
def main(config_file):
    logger = logging.getLogger('app')
    try:
        app = get_app(config_file)
        if is_test() or app.config['debug']['serve_static']:
            os.chdir(get_root_path())
            if not os.path.exists(os.path.join(get_root_path(), 'sessions')):
                os.mkdir(os.path.join(get_root_path(), 'sessions'))
        if not is_test():
            app.run()
        else:
            return app
    except Exception as e:
        logger.error('Exception encountered when starting the application',
                     exc_info=True)
        raise e
Exemplo n.º 7
0
 def get(self):
     for name in loggers_stats:
         try:
             size = os.path.getsize(os.path.join(get_root_path(), "logs", "%s.log" % name))
         except FileNotFoundError:
             size = 0
         loggers_stats[name]["size"] = pretty_print_size(size)
     return self.renderer.logs(loggers_stats=loggers_stats, time_since=timesince)
Exemplo n.º 8
0
def init_logger(logger_name,
                level=logging.INFO,
                rotation_interval=7,
                backup_count=2):
    if not os.path.exists(os.path.join(get_root_path(), 'logs')):
        os.mkdir(os.path.join(get_root_path(), 'logs'))

    logger = logging.getLogger(logger_name)
    logger.setLevel(level)
    formatter = logging.Formatter('%(levelname)s : %(asctime)s - %(message)s')
    logger_file_path = os.path.join(get_root_path(), 'logs',
                                    logger_name + os.extsep + 'log')
    file_handler = logging.handlers.TimedRotatingFileHandler(
        logger_file_path,
        when='D',
        interval=rotation_interval,
        backupCount=backup_count)
    file_handler.setFormatter(formatter)
    logger.addHandler(file_handler)
    logger.addHandler(StatHandler(logger_name, logger_file_path))
Exemplo n.º 9
0
def make_system_zip():
    system_zip_path = os.path.join(get_root_path(), 'client', 'ks', 'system' + os.extsep + 'zip')
    if os.path.exists(system_zip_path):
        os.unlink(system_zip_path)

    def add_file(file):
        system_zip.write(os.path.join(get_root_path(), 'client', 'ks', file), arcname=file)

    with ZipFile(system_zip_path, 'w') as system_zip:
        add_file(os.path.join('etc', 'pam.d', 'xserver'))
        add_file(os.path.join('home', 'ictv', '.xinitrc'))
Exemplo n.º 10
0
class FakePluginTestCase(ICTVTestCase):
    fake_plugin_root = os.path.join(get_root_path(), 'plugins', 'fake_plugin')

    def setUp(self, fake_plugin_middleware=lambda: None, ictv_middleware=lambda: None):
        create_fake_plugin(self.fake_plugin_root)
        fake_plugin_middleware()
        super(FakePluginTestCase, self).setUp(middleware=ictv_middleware)

    def tearDown(self):
        shutil.rmtree(self.fake_plugin_root)
        super(FakePluginTestCase, self).tearDown()
Exemplo n.º 11
0
 def get_plugins_modules():
     """ Returns a list of Python modules containing all the plugin modules found in the plugin directory. """
     dirs = next(os.walk(os.path.join(get_root_path(), 'plugins')))[1]
     if '__pycache__' in dirs:
         dirs.remove("__pycache__")
     modules_list = []
     for d in dirs:
         try:
             modules_list.append(importlib.import_module("ictv.plugins." + d + "." + d))
         except ModuleNotFoundError:
             raise Warning('Directory %s did not contain a valid plugin module' % d)
     return modules_list
Exemplo n.º 12
0
def count_entries(logger_name):
    """ Count the number of entries in each log file and return this number for the logger_name """
    n_entries = 0
    try:
        with open(os.path.join(get_root_path(), "logs",
                               "%s.log" % logger_name)) as log_file:
            for line in log_file:
                if line.startswith("DEBUG : ") or line.startswith(
                        "INFO : ") or line.startswith(
                            "WARNING : ") or line.startswith("ERROR : "):
                    n_entries += 1
    except FileNotFoundError:  # loggers in db with no log file anymore (the file can be created later): their
        # number of entries will be 0
        pass
    return n_entries
Exemplo n.º 13
0
    def runTest(self):
        """ Tests the Asset SQLObject. """
        fake_plugin = Plugin(name='fake_plugin', activated='notfound')
        asset_channel = PluginChannel(name='Asset Channel',
                                      plugin=fake_plugin,
                                      subscription_right='public')

        a1 = Asset(plugin_channel=asset_channel,
                   user=None,
                   filename='path_test',
                   extension='.txt')
        last_ref_a1 = a1.last_reference
        time.sleep(1)
        assert a1.path == os.path.join('static', 'storage',
                                       str(asset_channel.id),
                                       str(a1.id) + '.txt')
        assert a1.last_reference > last_ref_a1

        a2 = Asset(plugin_channel=asset_channel,
                   user=None,
                   filename='path_test')
        assert a2.path == os.path.join('static', 'storage',
                                       str(asset_channel.id), str(a2.id))

        a3 = Asset(plugin_channel=asset_channel,
                   user=None,
                   filename='cache_test',
                   in_flight=True)
        a3_path = os.path.join('static', 'storage', str(asset_channel.id),
                               str(a3.id))
        assert a3.path is None
        assert a3._get_path(force=True) == a3_path
        a3.in_flight = False
        assert a3.path == a3_path

        a4 = Asset(plugin_channel=asset_channel,
                   user=None,
                   filename='test_write',
                   extension='.txt')
        a4_path = os.path.join(get_root_path(), 'static', 'storage',
                               str(asset_channel.id),
                               str(a4.id) + '.txt')
        a4_content = 'a4 file content'.encode()
        a4.write_to_asset_file(a4_content)
        with open(a4_path, 'rb') as f:
            assert f.read() == a4_content
        a4.destroySelf()
        assert not os.path.exists(a4_path)
Exemplo n.º 14
0
    def get(self, file):
        path = os.path.join(get_root_path(), 'client', 'ks', file)
        if os.path.exists(path):
            flags = 'r'
            if self._path_has_ext(path, 'zip'):
                flags += 'b'
                make_client_zip()
            with open(path, flags) as f:
                content = f.read()
            if self._path_has_ext(path, 'ks') or self._path_has_ext(path, 'cfg'):
                content = content.format(ictv_root_url=flask.g.homedomain, **self.config['client'])

            response = flask.Response(content)
            response.headers['Content-Type'] = 'application/zip'
            return response
        resp.notfound()
Exemplo n.º 15
0
 def GET(self, file):
     path = os.path.join(get_root_path(), 'client', 'ks', file)
     if os.path.exists(path):
         flags = 'r'
         if self._path_has_ext(path, 'zip'):
             flags += 'b'
             make_client_zip()
             web.header('Content-Type', 'application/zip')
         with open(path, flags) as f:
             content = f.read()
         if self._path_has_ext(path, 'ks') or self._path_has_ext(
                 path, 'cfg'):
             content = content.format(ictv_root_url=web.ctx.homedomain,
                                      **self.config['client'])
         return content
     raise web.notfound()
Exemplo n.º 16
0
    def load_default_slides(config_dict):
        """ Loads the default slides configuration file inside the main configuration dict. Returns the dict. """
        default_slides_path = config_dict.get(
            'default_slides') or os.path.join(
                get_root_path(), 'default_slides.default' + os.extsep + 'yaml')
        default_slides_path = os.path.join(os.path.dirname(config_path),
                                           default_slides_path)

        if not os.path.exists(default_slides_path):
            raise Exception(
                'Default slides config file could not be found in %s' %
                default_slides_path)
        with open(default_slides_path) as default_slides_file:
            config_dict['default_slides'] = yaml.load(default_slides_file)

        return config_dict
Exemplo n.º 17
0
def get_app(ictv_app):
    app = web.application(urls, globals())
    app.renderer = web.template.render(
        os.path.join(os.path.dirname(__file__), 'templates'),
        base=os.path.join(get_root_path(), 'templates', 'base'),
        globals={
            'session': ictv_app.session,
            'get_feedbacks': get_feedbacks,
            'get_next_feedbacks': get_next_feedbacks,
            'pop_previous_form': pop_previous_form,
            'UserPermissions': UserPermissions,
            'str': str,
            'sidebar_collapse': True,
            'show_header': False,
            'show_footer': False,
            'User': User
        })

    RssPage.plugin_app = app
    return app
Exemplo n.º 18
0
    def get_templates():
        """ Returns a list of templates usable by the editor. """
        templates = OrderedDict()

        for template in Templates:
            templates[template] = {
                'themes': {},
                'name': Templates[template]['name'],
                'description': Templates[template]['description']
            }
            for theme in Themes:
                image_filename = '%s-%s.png' % (template, theme)
                if os.path.isfile(
                        os.path.join(get_root_path(),
                                     'plugins/editor/static/images',
                                     image_filename)):
                    templates[template]['themes'][theme] = image_filename
                else:
                    templates[template]['themes'][
                        theme] = 'placeholder_template.png'
        return templates
Exemplo n.º 19
0
def create_iframe_page(src, width, height, file_hash):
    html = """<html>
            <head>
                <meta charset="UTF-8">
                <title></title>
            </head>
            <body style="margin: 0;">
                <iframe scrolling="no" src="{0}" width="{1}" height="{2}"
                        frameborder="0" marginwidth="0" marginheight="0">
                </iframe>
                <script>
                    function resize() {{
                        var width = window.innerWidth
                                || document.documentElement.clientWidth
                                || document.body.clientWidth;

                        var height = window.innerHeight
                                || document.documentElement.clientHeight
                                || document.body.clientHeight;

                        var iframe = document.getElementsByTagName('iframe')[0];
                        var iframe_width = iframe.getAttribute('width');
                        var iframe_height = iframe.getAttribute('height');
                        var scale_width = width / iframe_width;
                        var scale_height = height / iframe_height;

                        var scale = Math.min(scale_width, scale_height);
                        var transform_x = -(((width / scale_width) - iframe_width) / 2);
                        var transform_y = -(((height / scale_height) - iframe_height) / 2);
                        iframe.setAttribute('style', 'transform: scale('+scale_width+','+scale_height+'); transform-origin: '+transform_x+'px '+transform_y+'px;-webkit-transform: scale('+scale_width+','+scale_height+'); -webkit-transform-origin: '+transform_x+'px '+transform_y+'px;')
                    }}
                    window.addEventListener('load', resize, true);
                    window.addEventListener('resize', resize, true);
                </script>
            </body>
            </html>""".format(src, width, height)
    iframe_page = 'plugins/embed/iframe_' + file_hash + '.html'
    with open(os.path.join(get_root_path(), 'static', iframe_page), 'w') as f:
        f.write(html)
    return iframe_page
Exemplo n.º 20
0
    def instantiate_plugin(self, app, plugin):
        """
            Loads the plugin. Returns whether the plugin could be instantiated or not.
            Plugin state may be changed to disabled if an error occurs.
        """
        self.missing_dependencies[plugin.name] = self.get_plugin_missing_dependencies(plugin.name)
        if self.missing_dependencies[plugin.name]:
            plugin.activated = 'no'
            logger.warning(
                'Plugin %s has missing dependencies, could not instantiate it. Plugin is now disabled' % plugin.name)
            get_logger(plugin.name).error('Could not instantiate plugin due to the following missing modules: %s'
                                          % (', '.join(self.missing_dependencies[plugin.name])))
            return False
        try:
            plugin_module = self.get_plugin(plugin.name, reload=True)
        except ImportError:
            plugin.activated = 'no'
            logger.error('Encountered an exception when importing plugin %s' % plugin.name, exc_info=True)
            return False

        if hasattr(plugin_module, 'install'):
            getattr(plugin_module, 'install')()
        if hasattr(plugin_module, 'update'):
            getattr(plugin_module, 'update')(plugin)
        if plugin.static:
            static_dir = os.path.join(plugin.package_path, "static")
            os.makedirs(static_dir, exist_ok=True)
            if os.path.isdir(static_dir):
                link_name = os.path.join(get_root_path(), 'static/plugins', plugin.name)
                if not os.path.exists(link_name):
                    os.makedirs(os.path.dirname(link_name), exist_ok=True)
                    os.symlink(static_dir, link_name, target_is_directory=True)
            else:
                plugin.activated = 'no'
                logger.warning(
                    'Plugin %s static directory is a file, could not instantiate it. Plugin is now disabled' % plugin.name)
                return False
        if plugin.webapp:
            self.add_mappings(app, plugin)
        return True
Exemplo n.º 21
0
def get_app(ictv_app):
    app = FrankenFlask(__name__)
    template_globals = {
        'session': ictv_app.session,
        'get_feedbacks': get_feedbacks,
        'get_next_feedbacks': get_next_feedbacks,
        'pop_previous_form': pop_previous_form,
        'UserPermissions': UserPermissions,
        'str': str,
        'sidebar_collapse': True,
        'show_header': False,
        'show_footer': False,
        'User': User,
        'base': 'base.html'
    }
    app.renderer = render_jinja([
        os.path.join(os.path.dirname(__file__), 'templates/'),
        os.path.join(get_root_path(), 'templates/')
    ])
    app.renderer._lookup.globals.update(**template_globals)

    # Registering views
    app.add_url_rule('/index',
                     view_func=IndexPage.as_view('IndexPage'),
                     methods=get_methods(IndexPage))
    app.add_url_rule('/feed',
                     view_func=FeedGetter.as_view('FeedGetter'),
                     methods=get_methods(FeedGetter))
    app.add_url_rule('/content',
                     view_func=ContentPage.as_view('ContentPage'),
                     methods=get_methods(ContentPage))
    app.add_url_rule('/preview',
                     view_func=PreviewPage.as_view('PreviewPage'),
                     methods=get_methods(PreviewPage))

    RssPage.plugin_app = app

    return app
Exemplo n.º 22
0
    def __init__(self, *args, **kwargs):
        templates = {}
        for template in os.listdir(
                os.path.join(get_root_path(), 'renderer/templates')):
            if template != 'base.html':
                templates[os.path.splitext(template)[0]] = {}

        for template in templates:

            def f(type):
                def g(*args, **kwargs):
                    id = type + '-' + str(kwargs['number'])
                    templates[template][id] = {
                        'max_chars': kwargs['max_chars']
                    } if 'max_chars' in kwargs else {}

                return g

            dummy_renderer = SlideRenderer(
                {
                    'title': f('title'),
                    'subtitle': f('subtitle'),
                    'img': f('image'),
                    'logo': f('logo'),
                    'text': f('text'),
                    'background': f('background')
                }, None)

            # Useful to set some attribute in the template
            getattr(dummy_renderer.slide_renderer, template)(slide=None)

            variables = get_const_in_template(template)
            templates[template]['name'] = variables['name']
            templates[template]['description'] = variables['description']

        self._templates = templates
        super().__init__(self)
Exemplo n.º 23
0
def load_templates_and_themes():
    Template.deleteMany(None)
    for template in next(
        (os.walk(os.path.join(get_root_path(), 'renderer/templates/'))))[2]:
        Template(name=template.replace('.html', ''))
Exemplo n.º 24
0
def get_app(ictv_app):
    """ Returns the web.py application of the editor. """

    urls = (
        'index',
        'ictv.plugins.editor.capsules_page.CapsulesPage',
        'template/(\d+)/(.+)',
        'ictv.plugins.editor.app.ServeTemplate',
        'capsules',
        'ictv.plugins.editor.capsules_page.CapsulesPage',
        'capsules/(\d+)',
        'ictv.plugins.editor.slides_page.SlidesPage',
        'capsules/(\d+)/newslide',
        'ictv.plugins.editor.app.Index',
        'edit/(\d+)',
        'ictv.plugins.editor.app.Edit',
        'preview/expired',
        'ictv.plugins.editor.rendering_pages.RenderExpired',
        'preview/currentandfuture',
        'ictv.plugins.editor.rendering_pages.RenderCurrentAndFuture',
        'render/(\d+)/(\d+)?/?(.*)',
        'ictv.plugins.editor.app.LocalSlideRender',
        'api/capsules',
        'ictv.plugins.editor.api.APIIndex',
        'api/capsules/(\d+)',
        'ictv.plugins.editor.api.APICapsules',
        'api/capsules/(\d+)/slides',
        'ictv.plugins.editor.api.APIIndexSlides',
        'api/capsules/(\d+)/slides/(\d+)',
        'ictv.plugins.editor.api.APISlides',
        'api/templates',
        'ictv.plugins.editor.api.APITemplates',
    )

    app = web.application(urls, globals())
    app.renderer = web.template.render(
        os.path.join(os.path.dirname(__file__), 'templates'),
        base=os.path.join(get_root_path(), 'templates', 'base'),
        globals={
            'session': ictv_app.session,
            'get_feedbacks': get_feedbacks,
            'get_next_feedbacks': get_next_feedbacks,
            'pop_previous_form': pop_previous_form,
            'json': json,
            'UserPermissions': UserPermissions,
            'str': str,
            'sidebar_collapse': True,
            'show_header': False,
            'show_footer': False,
            'User': User
        },
        cache=not ictv_app.config['debug']['debug_on_error'])

    def get_templates():
        """ Returns a list of templates usable by the editor. """
        templates = OrderedDict()

        for template in Templates:
            templates[template] = {
                'themes': {},
                'name': Templates[template]['name'],
                'description': Templates[template]['description']
            }
            for theme in Themes:
                image_filename = '%s-%s.png' % (template, theme)
                if os.path.isfile(
                        os.path.join(get_root_path(),
                                     'plugins/editor/static/images',
                                     image_filename)):
                    templates[template]['themes'][theme] = image_filename
                else:
                    templates[template]['themes'][
                        theme] = 'placeholder_template.png'
        return templates

    def get_editor_slide_renderer():
        """ Returns an editor slide renderer. """
        def make_title(**kwargs):
            h = HTML()
            try:
                args = {
                    'id': 'title-' + str(kwargs['number']),
                    'klass': 'title',
                    'data-editor-type': "text",
                    'data-editor-placeholder': kwargs['editor_placeholder'],
                    'data-editor-label': kwargs['editor_label'],
                    'data-editor-default': kwargs['editor_default']
                }
            except KeyError:
                args = {
                    'id': 'title-' + str(kwargs['number']),
                    'klass': 'title',
                    'data-editor-type': "text",
                    'data-editor-placeholder': 'Title',
                    'data-editor-label': 'Title',
                    'data-editor-default': 'Title'
                }
            if kwargs['content'] is not None:
                text = kwargs['content']['title-' +
                                         str(kwargs['number'])]['text']
                args['data-editor-default'] = text
            if 'max_chars' in kwargs:
                args['data-editor-max-chars'] = str(kwargs['max_chars'])
            h.h1('', **args)
            return str(h)

        def make_subtitle(**kwargs):
            h = HTML()
            try:
                args = {
                    'id': 'subtitle-' + str(kwargs['number']),
                    'klass': 'subtitle',
                    'data-editor-type': "text",
                    'data-editor-placeholder': kwargs['editor_placeholder'],
                    'data-editor-label': kwargs['editor_label'],
                    'data-editor-default': kwargs['editor_default'],
                    'data-editor-optional': "true"
                }
            except KeyError:
                args = {
                    'id': 'subtitle-' + str(kwargs['number']),
                    'klass': 'subtitle',
                    'data-editor-type': "text",
                    'data-editor-placeholder': 'Subtitle',
                    'data-editor-label': 'Subtitle',
                    'data-editor-default': 'Subtitle',
                    'data-editor-optional': "true"
                }
            if kwargs['content'] is not None:
                text = kwargs['content']['subtitle-' +
                                         str(kwargs['number'])]['text']
                args['data-editor-default'] = text
            if 'max_chars' in kwargs:
                args['data-editor-max-chars'] = str(kwargs['max_chars'])
            h.h4('', **args)
            return str(h)

        def make_img(**kwargs):
            h = HTML()
            try:
                args = {
                    'id': 'image-' + str(kwargs['number']),
                    'klass': 'sub-image',
                    'data-editor-type': "image",
                    'data-editor-placeholder': kwargs['editor_placeholder'],
                    'data-editor-label': kwargs['editor_label'],
                    'data-editor-default': kwargs['editor_default'],
                    'data-editor-mediatype': "image"
                }
            except KeyError:
                args = {
                    'id': 'image-' + str(kwargs['number']),
                    'klass': 'sub-image',
                    'data-editor-type': "image",
                    'data-editor-placeholder':
                    "/static/plugins/editor/placeholders/270x350.png",
                    'data-editor-label': 'Image',
                    'data-editor-default':
                    "/static/plugins/editor/placeholders/270x350.png",
                    'data-editor-mediatype': "image"
                }
            if kwargs['content'] is not None:
                src = kwargs['content']['image-' +
                                        str(kwargs['number'])]['src']
                args['data-editor-default'] = src
            if 'style' in kwargs:
                args['style'] = kwargs['style']
            h.img(src='/static/plugins/editor/placeholders/270x350.png',
                  **args)
            return str(h)

        def make_logo(**kwargs):
            h = HTML()
            try:
                args = {
                    'id': 'logo-' + str(kwargs['number']),
                    'data-editor-type': "image",
                    'data-editor-placeholder': kwargs['editor_placeholder'],
                    'data-editor-label': kwargs['editor_label'],
                    'data-editor-default': kwargs['editor_default'],
                    'data-editor-mediatype': "image"
                }
            except KeyError:
                args = {
                    'id': 'logo-' + str(kwargs['number']),
                    'data-editor-type': "image",
                    'data-editor-placeholder':
                    "/static/plugins/editor/placeholders/270x350.png",
                    'data-editor-label': 'Logo',
                    'data-editor-default':
                    "/static/plugins/editor/placeholders/270x350.png",
                    'data-editor-mediatype': "image"
                }
            if kwargs['content'] is not None:
                src = kwargs['content']['logo-' + str(kwargs['number'])]['src']
                args['data-editor-default'] = src
            h.img(src=args['data-editor-default'], **args)
            return str(h)

        def make_text(**kwargs):
            h = HTML()
            try:
                args = {
                    'id': 'text-' + str(kwargs['number']),
                    'data-editor-type': "textarea",
                    'data-editor-placeholder': kwargs['editor_placeholder'],
                    'data-editor-label': kwargs['editor_label'],
                    'data-editor-default': kwargs['editor_default'],
                    'style': kwargs.get('style') or 'text-align:justify',
                    'klass': 'text'
                }
            except KeyError:
                args = {
                    'id': 'text-' + str(kwargs['number']),
                    'data-editor-type': "textarea",
                    'data-editor-placeholder': "Text",
                    'data-editor-label': 'Text',
                    'data-editor-default': "Text",
                    'style': kwargs.get('style') or 'text-align:justify',
                    'klass': 'text'
                }
            if kwargs['content'] is not None:
                text = kwargs['content']['text-' +
                                         str(kwargs['number'])]['text']
                args = args['data-editor-default'] = text
            if 'max_chars' in kwargs:
                args['data-editor-max-chars'] = str(kwargs['max_chars'])
            h.div('', **args)
            return str(h)

        def make_background(**kwargs):
            if kwargs['content'] is None:
                src = kwargs['editor_default']
                size = 'cover'
                color = 'black'
            else:
                id = 'background-' + str(kwargs['number'])
                src = kwargs['content'][id]['src']
                size = kwargs['content'][id]['size']
                color = kwargs['content'][id]['color'] if 'color' in kwargs[
                    'content'][id] else 'black'
            src = '/static/plugins/editor/%s' % src if not src.startswith(
                '/static/plugins/editor/') else src
            return 'data-background-image="' + src + '" data-background-size="' + size + '" data-background-color="' + color + '" ' \
                                                                                         'data-editor-type="background" ' \
                                                                                         'data-editor-placeholder="/static/plugins/editor/images/beach.jpg"' \
                                                                                         'data-editor-default="' + src + '"' \
                                                                                         'data-editor-label="Arrière-plan"'

        renderer_globals = {
            'title': make_title,
            'subtitle': make_subtitle,
            'img': make_img,
            'logo': make_logo,
            'text': make_text,
            'background': make_background
        }

        return SlideRenderer(renderer_globals=renderer_globals, app=ictv_app)

    app.slide_templates = get_templates()
    app.slide_renderer = get_editor_slide_renderer()

    EditorPage.plugin_app = app

    return app
Exemplo n.º 25
0
def get_app(config_path):
    """
        Returns the flask main application of ICTV.
        Currently, only one application can be run a time due to how data such as assets, database, config files
        or plugins is stored.
    """
    config = get_config(config_path)
    if database.database_path is None:
        database.database_path = config['database_uri']

    # Create a base flask application
    app = FrankenFlask(__name__)

    # The following line might be used to speedup queries
    app.config["SEND_FILE_MAX_AGE_DEFAULT"] = 300

    app.config.update(**config)

    init_flask_url_mapping(app)

    app.version = ictv.common.__version__

    with open(os.path.join(get_root_path(), 'info' + os.extsep + 'yaml')) as f:
        # Loads ICTV user info texts
        info_texts = yaml.unsafe_load(f)

    # Load the SMTP config into web.py
    smtp_conf = app.config.get('smtp', None)
    if smtp_conf:
        app.config['MAIL_DEFAULT_SENDER'] = smtp_conf['sender_name']
        app.config['MAIL_SERVER'] = smtp_conf['host']
        app.config['MAIL_PORT'] = smtp_conf['port']
        app.config['MAIL_USERNAME'] = smtp_conf.get('username', '')
        app.config['MAIL_PASSWORD'] = smtp_conf.get('password', '')
        app.config['MAIL_USE_TLS'] = smtp_conf.get('starttls', False)

    # Create a persistent HTTP session storage for the app
    app.secret_key = app.config['session_secret_key']
    # Populate the jinja templates globals
    template_globals = {
        'session': app.session,
        'get_feedbacks': get_feedbacks,
        'get_next_feedbacks': get_next_feedbacks,
        'pop_previous_form': pop_previous_form,
        'UserPermissions': UserPermissions,
        'json': json,
        'str': str,
        'sorted': sorted,
        'hasattr': hasattr,
        'sidebar_collapse': False,
        'show_header': True,
        'show_footer': True,
        're': re,
        'info': info_texts,
        'make_tooltip': make_tooltip,
        'make_alert': make_alert,
        'escape': html.escape,
        'show_reset_password': '******' in app.config['authentication'],
        'homedomain': lambda: flask.request.url_root[:-1],
        'generate_secret': generate_secret,
        'version': lambda: app.version,
        'pretty_print_size': pretty_print_size,
        'timesince': timesince,
        'User': User,
        'get_user': lambda: User.get(app.session['user']['id'])
    }

    ### Jinja2 renderer ###
    app.renderer = render_jinja(os.path.join(get_root_path(), 'templates/'))
    app.renderer._lookup.globals.update(base='base.html', **template_globals)

    app.standalone_renderer = render_jinja(
        os.path.join(get_root_path(), 'templates/'))
    app.standalone_renderer._lookup.globals.update(**template_globals)

    # Init loggers
    load_loggers_stats()
    # Determine logging level and user feedback when an internal error occurs based on ICTV core config
    level = logging.INFO

    loggers_to_init = [
        'app', 'pages', 'screens', 'plugin_manager', 'storage_manager',
        'local_login', 'database', 'transcoding_queue'
    ]
    for logger_name in loggers_to_init:
        init_logger(logger_name,
                    level,
                    rotation_interval=app.config['logs']['rotation_interval'],
                    backup_count=app.config['logs']['backup_count'])

    # Init the renderer used for slide, capsule, channel and screen rendering
    app.ictv_renderer = ICTVRenderer(app)
    # Init the plugin manager, used as a gateway between ICTV core and its plugins.
    app.plugin_manager = PluginManager(app)

    # Init the download manager, a download queue which asynchronously downloads assets from the network
    app.download_manager = DownloadManager()
    # Init the cleanup manager which will regularly cleanup unused cached assets
    app.cleanup_scheduler = CleanupScheduler()
    app.cleanup_scheduler.start()
    # Init the video transcoding queue which will convert videos to WebM format using FFmpeg
    app.transcoding_queue = TranscodingQueue()

    # Add an general authentication processor to handle user authentication
    app.register_before_request(get_authentication_processor,
                                cascade=True,
                                needs_app=True)

    # Add a preprocessor to populate flask.g and mimic the old web.ctx
    app.register_before_request(get_web_ctx_processor, cascade=True)

    # Add a preprocessor to encapsulate every SQL requests in a transaction on a per HTTP request basis
    app.register_before_request(get_db_thread_preprocessor, cascade=True)
    app.prepare_error_handler(DatabaseError, lambda: database_error_handler)
    app.prepare_error_handler(werkzeug.exceptions.InternalServerError,
                              lambda: internal_error_handler)

    # Add a hook to clean feedbacks from the previous request and prepare next feedbacks to be shown to the user
    app.register_after_request(lambda: rotate_feedbacks,
                               cascade=True,
                               needs_app=False)

    # Instantiate plugins through the plugin manager
    app.plugin_manager.instantiate_plugins(app)

    # Load themes and templates into database
    sqlhub.doInTransaction(load_templates_and_themes)

    return app
Exemplo n.º 26
0
def get_config(config_path):
    with open(config_path) as f:
        config = yaml.unsafe_load(f)
    with open(
            os.path.join(get_root_path(),
                         'configuration.metadata' + os.extsep + 'yaml')) as f:
        metadata = yaml.unsafe_load(f)
    with open(
            os.path.join(get_root_path(),
                         'configuration.default' + os.extsep + 'yaml')) as f:
        defaults = yaml.unsafe_load(f)

    def validate_config(config_dict, metadata, defaults, prefix=''):
        """
            Ensures config parameters have valid values.
            Modifies the given configuration with default values when none can be found in the given config.
            Returns a list of parameters that are invalid.
        """
        sentinel = []
        for key, key_metadata in metadata.items():
            key_name = prefix + key
            if key in config_dict:
                value = config_dict[key]
            elif key in defaults:
                value = defaults[key]
            else:
                value = sentinel
                yield key_name, KeyError, None

            if value is not sentinel:
                config_dict[key] = value
                key_type = key_metadata['type']
                if key_type in vars(builtins):
                    if type(value) != vars(
                            builtins)[key_type] and value is not None:
                        yield key_name, TypeError, (key_type,
                                                    type(value).__name__)
                    elif key_type == 'int':
                        if ('min' in key_metadata and value < key_metadata['min']) \
                                or ('max' in key_metadata and value > key_metadata['max']):
                            yield key_name, ValueError, None
                    elif key_type == 'dict':
                        yield from validate_config(value,
                                                   key_metadata['items'],
                                                   defaults.get(key),
                                                   prefix=key_name + '.')
                elif key_type.startswith('list['):
                    if type(value) is not list:
                        yield key_name, TypeError, (key_type,
                                                    type(value).__name__)
                    else:
                        inner_type = vars(builtins)[key_type[5:-1]]
                        for i, v in enumerate(value):
                            if type(v) is not inner_type and value is not None:
                                yield '%s[%d]' % (key_name, i), TypeError, (
                                    key_type[5:-1], type(v).__name__)

    def check_for_unused_keys(config_dict, metadata, prefix=''):
        """ Checks if the given configuration contains parameters that are not used by ICTV and alerts the user. """
        for key, value in config_dict.items():
            key_name = prefix + key
            key_metadata = metadata.get(key)
            if not key_metadata:
                print(
                    'Config file specifies parameter %s but this parameter has no influence on ICTV'
                    % key_name,
                    file=sys.stderr)
            if key_metadata['type'] == 'dict':
                check_for_unused_keys(value,
                                      key_metadata['items'],
                                      prefix=key_name + '.')

    check_for_unused_keys(config, metadata)
    config_errors = list(validate_config(config, metadata, defaults))

    if config_errors:
        for key, error, info in config_errors:
            if error is KeyError:
                print(
                    'Parameter %s was not specified in config file and no default value could be found'
                    % key,
                    file=sys.stderr)
            elif error is TypeError:
                print(
                    'Parameter %s has an inappropriate type, expected %s but found %s'
                    % (key, *info),
                    file=sys.stderr)
            elif error is ValueError:
                print(
                    'Parameter %s has an inappropriate value, please check the additional constraints on this parameter'
                    % key,
                    file=sys.stderr)
        raise Exception('Config file is incorrect')

    def load_default_slides(config_dict):
        """ Loads the default slides configuration file inside the main configuration dict. Returns the dict. """
        default_slides_path = config_dict.get(
            'default_slides') or os.path.join(
                get_root_path(), 'default_slides.default' + os.extsep + 'yaml')
        default_slides_path = os.path.join(os.path.dirname(config_path),
                                           default_slides_path)

        if not os.path.exists(default_slides_path):
            raise Exception(
                'Default slides config file could not be found in %s' %
                default_slides_path)
        with open(default_slides_path) as default_slides_file:
            config_dict['default_slides'] = yaml.unsafe_load(
                default_slides_file)

        return config_dict

    return load_default_slides(config)
Exemplo n.º 27
0
 def add_file(file):
     client_zip.write(os.path.join(get_root_path(), 'client', file),
                      arcname=file)
Exemplo n.º 28
0
    def __init__(self, *args, **kwargs):
        self._themes = {}
        themes = set()
        self._child_themes = {}
        themes_directory = os.path.join(get_root_path(), 'renderer', 'themes')
        for theme in [
                p for p in os.listdir(themes_directory)
                if os.path.isdir(os.path.join(themes_directory, p))
        ]:
            try:
                with open(
                        os.path.join(themes_directory, theme, 'config' +
                                     os.extsep + 'yaml')) as config_file:
                    config = yaml.unsafe_load(config_file)
                self._themes[theme] = config
                if 'base_color' in self._themes[theme]:
                    theme_base_color = self._themes[theme]['base_color']
                    theme_base_color = (theme_base_color['h'],
                                        theme_base_color['s'],
                                        theme_base_color['v'])
                    self._themes[theme]['palette'] = [
                        colorsys.hsv_to_rgb(
                            (theme_base_color[0] + (i / 360)) % 1,
                            theme_base_color[1], theme_base_color[2])
                        for i in range(30, 360, 30)
                    ]
                    self._themes[theme]['ckeditor_palette'] = ','.join([
                        ''.join('%02X' % round(i * 255) for i in color)
                        for color in self._themes[theme]['palette']
                    ])
                parent = self._themes[theme].get('parent')
                if parent:
                    self._child_themes[parent] = self._child_themes.get(
                        parent, set()) | {theme}
                themes.add(theme)
            except FileNotFoundError:
                print(
                    'Theme %s does not have a config.yaml. It will be ignored'
                    % theme,
                    file=sys.stderr)

        def remove_theme(theme):
            if theme in self._child_themes:
                for child in self._child_themes[theme]:
                    print(
                        'Theme %s referenced %s as its parent, but %s could not be found. It will be ignored.'
                        % (child, theme, theme),
                        file=sys.stderr)
                    remove_theme(child)
            themes.discard(theme)
            self._themes.pop(theme)

        for parent in self._child_themes.keys():
            if parent not in themes:
                remove_theme(parent)

        themes_static_dir = os.path.join(get_root_path(), 'static', 'themes')
        if not os.path.exists(themes_static_dir):
            os.mkdir(themes_static_dir)

        for theme, config in self._themes.items():
            link_name = os.path.join(themes_static_dir, theme)
            assets_path = os.path.join(get_root_path(), 'renderer', 'themes',
                                       theme, 'assets')
            if os.path.exists(assets_path) and not os.path.exists(link_name):
                os.symlink(assets_path, link_name, target_is_directory=True)

        def set_theme_level(theme, level=0):
            if self._themes[theme].get('level', -1) < level:
                self._themes[theme]['level'] = level
                for child in self._child_themes.get(theme, []):
                    set_theme_level(child, level + 1)

        for theme in [
                t for t in self._themes.keys()
                if self._themes[t].get('parent') is None
        ]:
            set_theme_level(theme)

        super().__init__(self)
Exemplo n.º 29
0
def read_raw_template(template):
    with open(
            os.path.join(get_root_path(),
                         'renderer/templates/' + template + ".html")) as f:
        content = f.read()
    return content
Exemplo n.º 30
0
 def write_to_asset_file(self, content):
     """ Writes the content to the asset file. """
     asset_path = os.path.join(get_root_path(), self.path)
     os.makedirs(os.path.dirname(asset_path), exist_ok=True)
     with open(asset_path, 'wb') as f:
         f.write(content)