Esempio n. 1
0
def get_analytics_alerts(discussion, user_id, types, all_users=False):
    from assembl.semantic.virtuoso_mapping import AssemblQuadStorageManager, AESObfuscator

    settings = get_config()
    metrics_server_endpoint = settings.get(
        "metrics_server_endpoint", "https://discussions.bluenove.com/analytics/accept"
    )
    verify_metrics = False  # weird SNI bug on some platforms
    protocol = "https" if asbool(settings.get("accept_secure_connection", False)) else "http"
    host = settings.get("public_hostname")
    if settings.get("public_port", 80) != 80:
        # TODO: public_secure_port?
        host += ":" + str(settings.get("public_port"))
    seed = urandom(8)
    obfuscator = AESObfuscator(seed)
    token = permission_token(user_id, discussion.id, [P_READ_PUBLIC_CIF], seed)
    metrics_requests = [{"metric": "alerts", "types": types}]
    if user_id != Everyone and not all_users:
        obfuscated_userid = "local:AgentProfile/" + obfuscator.encrypt(str(user_id))
        metrics_requests[0]["users"] = [obfuscated_userid]
    mapurl = "%s://%s/data/Discussion/%d/jsonld?token=%s" % (protocol, host, discussion.id, token)
    alerts = requests.post(
        metrics_server_endpoint,
        data=dict(mapurl=mapurl, requests=json.dumps(metrics_requests), recency=60),
        verify=verify_metrics,
    )
    result = AssemblQuadStorageManager.deobfuscate(alerts.text, obfuscator.decrypt)
    # AgentAccount is a pseudo for AgentProfile
    result = re.sub(r"local:AgentAccount\\/", r"local:AgentProfile\\/", result)
    return result
Esempio n. 2
0
def test_app_no_login_real_policy(request, test_app_no_perm):
    """A configured Assembl fixture with permissions
    and no user logged in"""
    config = testing.setUp(
        registry=test_app_no_perm.app.registry,
        settings=get_config(),
    )

    from ...auth.util import authentication_callback
    from pyramid.authorization import ACLAuthorizationPolicy
    from pyramid.path import DottedNameResolver
    resolver = DottedNameResolver(__package__)
    auth_policy_name = "assembl.auth.util.UpgradingSessionAuthenticationPolicy"
    auth_policy = resolver.resolve(auth_policy_name)(
        callback=authentication_callback)

    config.set_authorization_policy(ACLAuthorizationPolicy())
    config.set_authentication_policy(auth_policy)

    import transaction
    # ensure default roles and permissions at startup
    from ...models import get_session_maker
    with transaction.manager:
        session = get_session_maker()
        from ...lib.migration import bootstrap_db_data
        bootstrap_db_data(session, False)

    return test_app_no_perm
Esempio n. 3
0
def copy_discussion(source_config, dest_config, source_slug, dest_slug,
                    delete=False, debug=False, permissions=None):
    if (session_maker_is_initialized() and abspath(source_config) == get_config()["__file__"]):
        # not running from script
        dest_session = get_session_maker()()
        dest_metadata = get_metadata()
    else:
        dest_metadata, dest_session = engine_from_settings(
            dest_config, True)
    dest_tables = dest_metadata.sorted_tables
    if source_config != dest_config:
        from assembl.lib.sqla import _session_maker
        temp = _session_maker
        assert temp == dest_session
        source_metadata, source_session = engine_from_settings(
            source_config, False)
        source_tables_by_name = {
            table.name: table.tometadata(source_metadata, source_metadata.schema)
            for table in dest_tables
        }
        _session_maker = dest_session
    else:
        source_metadata, source_session = dest_metadata, dest_session
    try:
        init_key_for_classes(dest_session)
        from assembl.models import Discussion
        discussion = source_session.query(Discussion).filter_by(
            slug=source_slug).one()
        assert discussion, "No discussion named " + source_slug
        permissions = [x.split('+') for x in permissions or ()]
        for (role, permission) in permissions:
            assert role in SYSTEM_ROLES
            assert permission in ASSEMBL_PERMISSIONS
        existing = dest_session.query(Discussion).filter_by(slug=dest_slug).first()
        if existing:
            if delete:
                print("deleting", dest_slug)
                with transaction.manager:
                    delete_discussion(dest_session, existing.id)
            else:
                print("Discussion", dest_slug),
                print("already exists! Add -d to delete it.")
                exit(0)
        from assembl.models import Role, Permission, DiscussionPermission
        with dest_session.no_autoflush:
            copy = clone_discussion(
                source_session, discussion.id, dest_session, dest_slug)
            for (role, permission) in permissions:
                role = dest_session.query(Role).filter_by(name=role).one()
                permission = dest_session.query(Permission).filter_by(
                    name=permission).one()
                # assumption: Not already defined.
                dest_session.add(DiscussionPermission(
                    discussion=copy, role=role, permission=permission))
    except Exception:
        traceback.print_exc()
        if debug:
            pdb.post_mortem()
        capture_exception()
    return dest_session
Esempio n. 4
0
def test_app_no_perm(request, base_registry):
    global_config = {
        '__file__': request.config.getoption('test_settings_file'),
        'here': get_distribution('assembl').location
    }
    return TestApp(assembl.main(
        global_config, nosecurity=True, **get_config()))
Esempio n. 5
0
def upgrade_semantic_mapping():
    from .virtuoso_mapping import AssemblQuadStorageManager
    from assembl.lib.config import get_config
    settings = get_config()
    if settings['sqlalchemy.url'].startswith('virtuoso:'):
        aqsm = AssemblQuadStorageManager()
        aqsm.update_all_storages()
Esempio n. 6
0
def test_app_no_perm(request, base_registry):
    global_config = {
        '__file__': request.config.getoption('test_settings_file'),
        'here': get_distribution('assembl').location
    }
    return TestApp(assembl.main(
        global_config, nosecurity=True, **get_config()))
Esempio n. 7
0
def test_app_no_login_real_policy(request, test_app_no_perm):
    """A configured Assembl fixture with permissions
    and no user logged in"""
    config = testing.setUp(
        registry=test_app_no_perm.app.registry,
        settings=get_config(),
    )

    from ...auth.util import authentication_callback
    from pyramid.authorization import ACLAuthorizationPolicy
    from pyramid.path import DottedNameResolver
    resolver = DottedNameResolver(__package__)
    auth_policy_name = "assembl.auth.util.UpgradingSessionAuthenticationPolicy"
    auth_policy = resolver.resolve(auth_policy_name)(
        callback=authentication_callback)

    config.set_authorization_policy(ACLAuthorizationPolicy())
    config.set_authentication_policy(auth_policy)

    import transaction
    # ensure default roles and permissions at startup
    from ...models import get_session_maker
    with transaction.manager:
        session = get_session_maker()
        from ...lib.migration import bootstrap_db_data
        bootstrap_db_data(session, False)

    return test_app_no_perm
Esempio n. 8
0
def copy_discussion(source_config, dest_config, source_slug, dest_slug,
                    delete=False, debug=False, permissions=None):
    if (session_maker_is_initialized() and abspath(source_config) == get_config()["__file__"]):
        # not running from script
        dest_session = get_session_maker()()
        dest_metadata = get_metadata()
    else:
        dest_metadata, dest_session = engine_from_settings(
            dest_config, True)
    dest_tables = dest_metadata.sorted_tables
    if source_config != dest_config:
        from assembl.lib.sqla import _session_maker
        temp = _session_maker
        assert temp == dest_session
        source_metadata, source_session = engine_from_settings(
            source_config, False)
        source_tables_by_name = {
            table.name: table.tometadata(source_metadata, source_metadata.schema)
            for table in dest_tables
        }
        _session_maker = dest_session
    else:
        source_metadata, source_session = dest_metadata, dest_session
    try:
        init_key_for_classes(dest_session)
        from assembl.models import Discussion
        discussion = source_session.query(Discussion).filter_by(
            slug=source_slug).one()
        assert discussion, "No discussion named " + source_slug
        permissions = [x.split('+') for x in permissions or ()]
        for (role, permission) in permissions:
            assert role in SYSTEM_ROLES
            assert permission in ASSEMBL_PERMISSIONS
        existing = dest_session.query(Discussion).filter_by(slug=dest_slug).first()
        if existing:
            if delete:
                print "deleting", dest_slug
                with transaction.manager:
                    delete_discussion(dest_session, existing.id)
            else:
                print "Discussion", dest_slug,
                print "already exists! Add -d to delete it."
                exit(0)
        from assembl.models import Role, Permission, DiscussionPermission
        with dest_session.no_autoflush:
            copy = clone_discussion(
                source_session, discussion.id, dest_session, dest_slug)
            for (role, permission) in permissions:
                role = dest_session.query(Role).filter_by(name=role).one()
                permission = dest_session.query(Permission).filter_by(
                    name=permission).one()
                # assumption: Not already defined.
                dest_session.add(DiscussionPermission(
                    discussion=copy, role=role, permission=permission))
    except Exception:
        traceback.print_exc()
        if debug:
            pdb.post_mortem()
        capture_exception()
    return dest_session
Esempio n. 9
0
def testing_configurator(request, test_app_no_perm):
    """The testing configurator"""

    return testing.setUp(
        registry=test_app_no_perm.app.registry,
        settings=get_config(),
    )
Esempio n. 10
0
def get_analytics_alerts(discussion, user_id, types, all_users=False):
    from assembl.semantic.virtuoso_mapping import (AssemblQuadStorageManager,
                                                   AESObfuscator)
    settings = get_config()
    metrics_server_endpoint = settings.get(
        'metrics_server_endpoint',
        'https://discussions.bluenove.com/analytics/accept')
    verify_metrics = False  # weird SNI bug on some platforms
    protocol = 'https' if asbool(
        settings.get('accept_secure_connection', False)) else 'http'
    host = settings.get('public_hostname')
    if settings.get('public_port', 80) != 80:
        # TODO: public_secure_port?
        host += ':' + str(settings.get('public_port'))
    seed = urandom(8)
    obfuscator = AESObfuscator(seed)
    token = permission_token(user_id, discussion.id, [P_READ_PUBLIC_CIF], seed)
    metrics_requests = [{"metric": "alerts", "types": types}]
    if user_id != Everyone and not all_users:
        obfuscated_userid = "local:AgentProfile/" + obfuscator.encrypt(
            str(user_id))
        metrics_requests[0]['users'] = [obfuscated_userid]
    mapurl = '%s://%s/data/Discussion/%d/jsonld?token=%s' % (
        protocol, host, discussion.id, token)
    alerts = requests.post(metrics_server_endpoint,
                           data=dict(mapurl=mapurl,
                                     requests=json.dumps(metrics_requests),
                                     recency=60),
                           verify=verify_metrics)
    result = AssemblQuadStorageManager.deobfuscate(alerts.text,
                                                   obfuscator.decrypt)
    # AgentAccount is a pseudo for AgentProfile
    result = re.sub(r'local:AgentAccount\\/', r'local:AgentProfile\\/', result)
    return result
Esempio n. 11
0
File: base.py Progetto: jean/assembl
 def fin():
     print "finalizer db_default_data"
     session = db_tables()
     clear_rows(get_config(), session)
     transaction.commit()
     from assembl.models import Locale, LangString
     Locale.reset_cache()
     LangString.reset_cache()
Esempio n. 12
0
 def fin():
     print "finalizer db_default_data"
     session = db_tables()
     clear_rows(get_config(), session)
     transaction.commit()
     from assembl.models import Locale, LangString
     Locale.reset_cache()
     LangString.reset_cache()
Esempio n. 13
0
 def fin():
     print("finalizer test_app_no_perm")
     session = db_tables()
     with transaction.manager:
         clear_rows(get_config(), session)
     from assembl.models import Locale, LangString
     Locale.reset_cache()
     LangString.reset_cache()
Esempio n. 14
0
def test_app_no_perm(request, base_registry, db_tables):
    global_config = {
        '__file__': request.config.getoption('test_settings_file'),
        'here': get_distribution('assembl').location
    }
    app = TestApp(assembl.main(
        global_config, nosecurity=True, **get_config()))
    app.PyramidWebTestRequest = PyramidWebTestRequest
    return app
Esempio n. 15
0
def test_app_complex_password(request, test_app):
    """A configured Assembl fixture with permissions
    and an admin user logged in and strong password
    requirements enabled"""
    settings = get_config()
    settings['minimum_password_complexity'] = 3
    settings['password_required_classes'] = None
    config = testing.setUp(settings=settings)
    return test_app
Esempio n. 16
0
 def discussion_locales(self):
     # Ordered list, not empty.
     # TODO: Guard. Each locale should be 2-letter or posix.
     # Waiting for utility function.
     if self.preferred_locales:
         return self.preferred_locales.split(' ')
     # Use installation settings otherwise.
     return config.get_config().get('available_languages',
                                    'fr_CA en_CA').split()
Esempio n. 17
0
def test_app_no_perm(request, base_registry, db_tables):
    """A configured Assembl fixture with no permissions"""
    global_config = {
        '__file__': request.config.getoption('test_settings_file'),
        'here': get_distribution('assembl').location
    }
    app = TestApp(assembl.main(global_config, nosecurity=True, **get_config()))
    app.PyramidWebTestRequest = PyramidWebTestRequest
    return app
Esempio n. 18
0
 def import_content(self, only_new=True):
     from assembl.lib.config import get_config
     from pyramid.settings import asbool
     assert self.id
     config = get_config()
     if asbool(config.get('use_source_reader_for_mail', False)):
         super(AbstractMailbox, self).import_content(only_new)
     else:
         import_mails.delay(self.id, only_new)
Esempio n. 19
0
 def import_content(self, only_new=True):
     from assembl.lib.config import get_config
     from pyramid.settings import asbool
     assert self.id
     config = get_config()
     if asbool(config.get('use_source_reader_for_mail', False)):
         super(AbstractMailbox, self).import_content(only_new)
     else:
         import_mails.delay(self.id, only_new)
Esempio n. 20
0
def test_results(request):
    mailer = get_mailer(request)
    config = get_config()
    message = Message(subject="test_results",
                      sender=config.get('assembl.admin_email'),
                      recipients=["*****@*****.**"],
                      body=json.dumps(request.POST.dict_of_lists()))
    mailer.send(message)
    return Response(body="Thank you!", content_type="text/text")
Esempio n. 21
0
 def discussion_locales(self):
     # Ordered list, not empty.
     # TODO: Guard. Each locale should be 2-letter or posix.
     # Waiting for utility function.
     if self.preferred_locales:
         return self.preferred_locales.split(' ')
     # Use installation settings otherwise.
     return config.get_config().get(
         'available_languages', 'fr_CA en_CA').split()
Esempio n. 22
0
def test_results(request):
    mailer = get_mailer(request)
    config = get_config()
    message = Message(
        subject="test_results",
        sender=config.get('assembl.admin_email'),
        recipients=["*****@*****.**"],
        body=json.dumps(request.POST.dict_of_lists()))
    mailer.send(message)
    return Response(body="Thank you!", content_type="text/text")
Esempio n. 23
0
 def discussion_locales(self):
     # Ordered list, not empty.
     # TODO: Guard. Each locale should be 2-letter or posix.
     # Waiting for utility function.
     locales = self.preferences['preferred_locales']
     if locales:
         return locales
     # Use installation settings otherwise.
     return [strip_country(l) for l in config.get_config().get(
         'available_languages', 'fr en').split()]
Esempio n. 24
0
def test_app(request, admin_user, test_app_no_perm):
    config = testing.setUp(
        registry=test_app_no_perm.app.registry,
        settings=get_config(),
    )
    dummy_policy = config.testing_securitypolicy(
        userid=admin_user.id, permissive=True)
    config.set_authorization_policy(dummy_policy)
    config.set_authentication_policy(dummy_policy)
    return test_app_no_perm
Esempio n. 25
0
def test_app(request, admin_user, test_app_no_perm):
    config = testing.setUp(
        registry=test_app_no_perm.app.registry,
        settings=get_config(),
    )
    dummy_policy = config.testing_securitypolicy(
        userid=admin_user.id, permissive=True)
    config.set_authorization_policy(dummy_policy)
    config.set_authentication_policy(dummy_policy)
    return test_app_no_perm
Esempio n. 26
0
 def discussion_locales(self):
     # Ordered list, not empty.
     # TODO: Guard. Each locale should be 2-letter or posix.
     # Waiting for utility function.
     locales = self.preferences['preferred_locales']
     if locales:
         return locales
     # Use installation settings otherwise.
     return [strip_country(l) for l in config.get_config().get(
         'available_languages', 'fr en').split()]
Esempio n. 27
0
def base_registry(request):
    from assembl.views.traversal import root_factory
    from pyramid.config import Configurator
    from zope.component import getGlobalSiteManager
    registry = getGlobalSiteManager()
    config = Configurator(registry)
    config.setup_registry(
        settings=get_config(), root_factory=root_factory)
    configure_tasks(registry, 'assembl')
    config.add_tween('assembl.tests.pytest_fixtures.zopish_session_tween_factory')
    return registry
Esempio n. 28
0
def test_app_no_login(request, admin_user, test_app_no_perm):
    """A configured Assembl fixture with permissions
    and no user logged in"""
    config = testing.setUp(
        registry=test_app_no_perm.app.registry,
        settings=get_config(),
    )
    dummy_policy = config.testing_securitypolicy(userid=None, permissive=False)
    config.set_authorization_policy(dummy_policy)
    config.set_authentication_policy(dummy_policy)
    return test_app_no_perm
Esempio n. 29
0
def base_registry(request):
    """A Zope registry that is configured by with the testing.ini"""
    from assembl.views.traversal import root_factory
    from pyramid.config import Configurator
    from zope.component import getGlobalSiteManager
    registry = getGlobalSiteManager()
    config = Configurator(registry)
    config.setup_registry(settings=get_config(), root_factory=root_factory)
    configure_tasks(registry, 'assembl')
    config.add_tween('assembl.tests.utils.committing_session_tween_factory')
    return registry
Esempio n. 30
0
def base_registry(request):
    from assembl.views.traversal import root_factory
    from pyramid.config import Configurator
    from zope.component import getGlobalSiteManager
    registry = getGlobalSiteManager()
    config = Configurator(registry)
    config.setup_registry(
        settings=get_config(), root_factory=root_factory)
    configure_tasks(registry, 'assembl')
    config.add_tween('assembl.tests.pytest_fixtures.zopish_session_tween_factory')
    return registry
Esempio n. 31
0
def base_registry(request):
    """A Zope registry that is configured by with the testing.ini"""
    from assembl.views.traversal import root_factory
    from pyramid.config import Configurator
    from zope.component import getGlobalSiteManager
    registry = getGlobalSiteManager()
    config = Configurator(registry)
    config.setup_registry(
        settings=get_config(), root_factory=root_factory)
    configure_tasks(registry, 'assembl')
    config.add_tween('assembl.tests.utils.committing_session_tween_factory')
    return registry
Esempio n. 32
0
def test_app_no_login(request, admin_user, test_app_no_perm):
    """A configured Assembl fixture with permissions
    and no user logged in"""
    config = testing.setUp(
        registry=test_app_no_perm.app.registry,
        settings=get_config(),
    )
    dummy_policy = config.testing_securitypolicy(
        userid=None, permissive=False)
    config.set_authorization_policy(dummy_policy)
    config.set_authentication_policy(dummy_policy)
    return test_app_no_perm
Esempio n. 33
0
def test_app_strong_password(request, test_app):
    """A configured Assembl fixture with permissions
    and an admin user logged in and strong password
    requirements enabled"""
    settings = get_config()
    settings['minimum_password_complexity'] = 3
    settings['password_required_classes'] = \
        {"[a-z]": {"en": "lower-case letter"}, \
         "[A-Z]": {"en": "upper-case letter"}, \
         "\\d": {"en": "digit"}, \
         "\\W": {"en": "special character"}}
    config = testing.setUp(settings=settings)
    return test_app
Esempio n. 34
0
def test_app_no_perm(request, base_registry, db_tables):
    """A configured IdeaLoom fixture with no permissions"""
    global_config = {
        '__file__': request.config.getoption('test_settings_file'),
        'here': get_distribution('idealoom').location
    }
    config = dict(get_config())
    config['nosecurity'] = True
    app = TestApp(assembl.main(global_config, **config))
    app.PyramidWebTestRequest = PyramidWebTestRequest
    PyramidWebTestRequest._pyramid_app = app.app
    PyramidWebTestRequest.registry = base_registry
    return app
Esempio n. 35
0
def test_app_no_perm(request, base_registry, db_tables):
    """A configured Assembl fixture with no permissions"""
    global_config = {
        '__file__': request.config.getoption('test_settings_file'),
        'here': get_distribution('assembl').location
    }
    config = dict(get_config())
    config['nosecurity'] = True
    app = TestApp(assembl.main(global_config, **config))
    app.PyramidWebTestRequest = PyramidWebTestRequest
    PyramidWebTestRequest._pyramid_app = app.app
    PyramidWebTestRequest._registry = base_registry
    return app
Esempio n. 36
0
def test_app_participant1(request, participant1_user, test_app_no_perm):
    """A configured IdeaLoom fixture with permissions
    and an participant1 user logged in"""

    config = testing.setUp(
        registry=test_app_no_perm.app.registry,
        settings=get_config(),
    )
    dummy_policy = config.testing_securitypolicy(
        userid=participant1_user.id, permissive=True)
    config.set_authorization_policy(dummy_policy)
    config.set_authentication_policy(dummy_policy)
    return test_app_no_perm
Esempio n. 37
0
def show_optics_cluster(request):
    discussion = request.context._instance
    eps = float(request.GET.get("eps", "0.02"))
    min_points = int(request.GET.get("min_points", "3"))
    test_code = request.GET.get("test_code", None)
    scrambler = None
    if test_code:
        from random import Random
        scrambler = Random()
        scrambler.seed(get_config().get('session.key') + test_code +
                       discussion.slug)
    discussion = request.context._instance
    output = StringIO()
    from assembl.nlp.clusters import as_html_optics
    as_html_optics(discussion, output, min_points, eps, scrambler)
    output.seek(0)
    return Response(body_file=output, content_type='text/html')
Esempio n. 38
0
def create_dictionaries(discussion_id=None):
    db = Discussion.default_db
    by_main_lang = defaultdict(list)
    default_locales = get_config().get(
        'available_languages', 'fr_CA en_CA').split()
    only_for_lang = None
    for d_id, locales in db.query(
            Discussion.id, Discussion.preferred_locales).all():
        locales = locales.split() if locales else default_locales
        main_lang = locales[0].split('_')[0]
        by_main_lang[main_lang].append(d_id)
        if discussion_id == d_id:
            only_for_lang = main_lang
    for lang, discussion_ids in by_main_lang.iteritems():
        if only_for_lang and only_for_lang != lang:
            continue
        dirname = join(nlp_data, lang)
        if not exists(dirname):
            makedirs(dirname)
        corpus_fname = join(dirname, CORPUS_FNAME)
        if exists(corpus_fname):
            corpus = IdMmCorpus(corpus_fname)
            doc_count = db.query(Content).with_polymorphic(
                Content).options(defer(Content.like_count)).join(
                Discussion).filter(Discussion.id.in_(discussion_ids)
                                   ).count()
            if corpus.num_docs == doc_count:
                if only_for_lang:
                    return corpus
                continue
        tokenizer = Tokenizer(lang)
        bowizer = BOWizer(lang, tokenizer, False)
        posts = db.query(Content).join(Discussion).filter(
            Discussion.id.in_(discussion_ids))
        bowizer.phrases.add_vocab((
            tokenizer.tokenize_post(post) for post in posts))
        bowizer.dictionary.add_documents((
            bowizer.phrases[tokenizer.tokenize_post(post)]
            for post in posts))
        IdMmCorpus.serialize(corpus_fname, (
            (post.id, bowizer.post_to_bow(post))
            for post in posts))
        bowizer.save()
        return IdMmCorpus(corpus_fname)
Esempio n. 39
0
    def mutate(root, args, context, info):
        discussion_id = context.matchdict['discussion_id']
        discussion = models.Discussion.get(discussion_id)

        cls = models.Document

        require_cls_permission(CrudPermissions.CREATE, cls, context)

        allowed_filetypes = aslist(
            get_config()['attachment_allowed_mime_types'])

        def is_matched_type(s):
            for mime in allowed_filetypes:
                if re.match(mime, s):
                    return True
            return False

        uploaded_file = args.get('file')
        if uploaded_file is not None:

            # Because the server is on GNU/Linux, os.path.basename will only work
            # with path using "/". Using ntpath works for both Linux and Windows path
            filename = ntpath.basename(context.POST[uploaded_file].filename)
            content = context.POST[uploaded_file].file.read()
            context.POST[uploaded_file].file.seek(0)
            filetype = magic.from_buffer(content, mime=True)

            if not is_matched_type(filetype):
                error = _('Sorry, this file type is not allowed.')
                log.warn(
                    "A MIME-TYPE of %s was uploaded. It was not found in allowed_filetypes."
                    % filetype)
                raise HTTPUnauthorized(context.localizer.translate(error))

            mime_type = context.POST[uploaded_file].type
            document = models.File(discussion=discussion,
                                   mime_type=mime_type,
                                   title=filename)
            document.add_file_data(context.POST[uploaded_file].file)
            discussion.db.add(document)
            document.db.flush()

        return UploadDocument(document=document)
Esempio n. 40
0
def test_app_no_perm(request, base_registry, db_tables):
    """A configured IdeaLoom fixture with no permissions"""
    global_config = {
        '__file__': request.config.getoption('test_settings_file'),
        'here': get_distribution('idealoom').location
    }
    config = dict(get_config())
    config['nosecurity'] = True
    app = TestApp(assembl.main(global_config, **config))
    app.PyramidWebTestRequest = PyramidWebTestRequest
    PyramidWebTestRequest._pyramid_app = app.app
    PyramidWebTestRequest.registry = base_registry

    def fin():
        print("finalizer test_app_no_perm")
        session = db_tables()
        with transaction.manager:
            clear_rows(get_config(), session)

    request.addfinalizer(fin)

    return app
Esempio n. 41
0
def empty_db(request, session_factory):
    """An SQLAlchemy Session Maker fixture with all tables dropped"""
    session = session_factory()
    drop_tables(get_config(), session)
    return session_factory
Esempio n. 42
0
             permission=P_ADMIN_DISC,
             header=JSON_HEADER,
             name="settings")
@view_config(context=InstanceContext,
             request_method='PUT',
             ctx_instance_class=Discussion,
             permission=P_ADMIN_DISC,
             header=JSON_HEADER,
             name="settings")
def discussion_settings_put(request):
    request.context._instance.settings_json = request.json_body
    return HTTPOk()


dogpile_fname = join(dirname(dirname(dirname(dirname(__file__)))),
                     get_config().get('dogpile_cache.arguments.filename'))

discussion_jsonld_cache = get_region('discussion_jsonld',
                                     **{"arguments.filename": dogpile_fname})
userprivate_jsonld_cache = get_region('userprivate_jsonld',
                                      **{"arguments.filename": dogpile_fname})


@discussion_jsonld_cache.cache_on_arguments()
def discussion_jsonld(discussion_id):
    from assembl.semantic.virtuoso_mapping import AssemblQuadStorageManager
    aqsm = AssemblQuadStorageManager()
    return aqsm.as_jsonld(discussion_id)


@userprivate_jsonld_cache.cache_on_arguments()
Esempio n. 43
0
 def fin():
     print("finalizer db_tables")
     session = empty_db()
     drop_tables(get_config(), session)
     session.commit()
Esempio n. 44
0
def empty_db(request, session_factory):
    """An SQLAlchemy Session Maker fixture with all tables dropped"""
    session = session_factory()
    drop_tables(get_config(), session)
    return session_factory
Esempio n. 45
0
    name="settings",
)
@view_config(
    context=InstanceContext,
    request_method="PUT",
    ctx_instance_class=Discussion,
    permission=P_ADMIN_DISC,
    header=JSON_HEADER,
    name="settings",
)
def discussion_settings_put(request):
    request.context._instance.settings_json = request.json_body
    return HTTPOk()


dogpile_fname = join(dirname(dirname(dirname(dirname(__file__)))), get_config().get("dogpile_cache.arguments.filename"))

discussion_jsonld_cache = get_region("discussion_jsonld", **{"arguments.filename": dogpile_fname})
userprivate_jsonld_cache = get_region("userprivate_jsonld", **{"arguments.filename": dogpile_fname})


@discussion_jsonld_cache.cache_on_arguments()
def discussion_jsonld(discussion_id):
    from assembl.semantic.virtuoso_mapping import AssemblQuadStorageManager

    aqsm = AssemblQuadStorageManager()
    return aqsm.as_jsonld(discussion_id)


@userprivate_jsonld_cache.cache_on_arguments()
def userprivate_jsonld(discussion_id):
Esempio n. 46
0
 def get_discussion_locales(self):
     # TODO: Notion of active locales per discussion.
     # Use installation settings for now.
     # Ordered list, not empty.
     from assembl.lib.config import get_config
     return get_config().get('available_languages', 'fr en').split()
Esempio n. 47
0
 def fin():
     print "finalizer db_default_data"
     session = db_tables()
     clear_rows(get_config(), session)
     transaction.commit()
Esempio n. 48
0
def empty_db(request, session_factory):
    session = session_factory()
    drop_tables(get_config(), session)
    return session_factory
Esempio n. 49
0
class Preferences(MutableMapping, Base, NamedClassMixin):
    """
    Cascading preferences
    """
    __metaclass__ = DeclarativeAbstractMeta
    __tablename__ = "preferences"
    BASE_PREFS_NAME = "default"
    id = Column(Integer, primary_key=True)
    name = Column(CoerceUnicode, nullable=False, unique=True)
    cascade_id = Column(Integer, ForeignKey(id), nullable=True)
    pref_json = Column("values", Text())  # JSON blob

    cascade_preferences = relationship("Preferences", remote_side=[id])

    @classmethod
    def get_naming_column_name(self):
        return "name"

    @classmethod
    def get_by_name(cls, name=None, session=None):
        name = name or cls.BASE_PREFS_NAME
        session = session or cls.default_db
        return session.query(cls).filter_by(name=name).first()

    @classmethod
    def get_default_preferences(cls, session=None):
        return cls.get_by_name('default', session) or cls(name='default')

    @classmethod
    def get_discussion_conditions(cls, discussion_id):
        # This is not a DiscussionBoundBase, but protocol is otherwise useful
        from .discussion import Discussion
        return ((cls.id == Discussion.preferences_id),
                (Discussion.id == discussion_id))

    @classmethod
    def init_from_settings(cls, settings):
        """Initialize some preference values"""
        from ..auth.social_auth import get_active_auth_strategies
        # TODO: Give linguistic names to social auth providers.
        active_strategies = {
            k: k
            for k in get_active_auth_strategies(settings)
        }
        active_strategies[''] = _("No special authentication")
        cls.preference_data['authorization_server_backend'][
            'scalar_values'] = active_strategies

    @property
    def local_values_json(self):
        values = {}
        if self.pref_json:
            values = json.loads(self.pref_json)
            assert isinstance(values, dict)
        return values

    @local_values_json.setter
    def local_values_json(self, val):
        assert isinstance(val, dict)
        self.pref_json = json.dumps(val)

    @property
    def values_json(self):
        if not self.cascade_preferences:
            return self.local_values_json
        values = self.cascade_preferences.values_json
        values.update(self.local_values_json)
        return values

    def _get_local(self, key):
        if key not in self.preference_data:
            raise KeyError("Unknown preference: " + key)
        values = self.local_values_json
        if key in values:
            value = values[key]
            return True, value
        return False, None

    def get_local(self, key):
        exists, value = self._get_local(key)
        if exists:
            return value

    def __getitem__(self, key):
        if key == 'name':
            return self.name
        if key == '@extends':
            return (self.uri_generic(self.cascade_id)
                    if self.cascade_id else None)
        exists, value = self._get_local(key)
        if exists:
            return value
        elif self.cascade_id:
            return self.cascade_preferences[key]
        if key == "preference_data":
            return self.get_preference_data_list()
        return self.get_preference_data()[key].get("default", None)

    def __len__(self):
        return len(self.preference_data_list) + 2

    def __iter__(self):
        return chain(self.preference_data_key_list, ('name', '@extends'))

    def __contains__(self, key):
        return key in self.preference_data_key_set

    def __delitem__(self, key):
        values = self.local_values_json
        if key in values:
            oldval = values[key]
            del values[key]
            self.local_values_json = values
            return oldval

    def __setitem__(self, key, value):
        if key == 'name':
            old_value = self.name
            self.name = unicode(value)
            return old_value
        elif key == '@extends':
            old_value = self.get('@extends')
            new_pref = self.get_instance(value)
            if new_pref is None:
                raise KeyError("Does not exist:" + value)
            self.cascade_preferences = new_pref
            return old_value
        if key not in self.preference_data_key_set:
            raise KeyError("Unknown preference: " + key)
        values = self.local_values_json
        old_value = values.get(key, None)
        value = self.validate(key, value)
        values[key] = value
        self.local_values_json = values
        return old_value

    def can_edit(self, key, permissions=(P_READ, ), pref_data=None):
        if P_SYSADMIN in permissions:
            if key == 'name' and self.name == self.BASE_PREFS_NAME:
                # Protect the base name
                return False
            return True
        if key in ('name', '@extends', 'preference_data'):
            # TODO: Delegate permissions.
            return False
        if key not in self.preference_data_key_set:
            raise KeyError("Unknown preference: " + key)
        if pref_data is None:
            pref_data = self.get_preference_data()[key]
        req_permission = pref_data.get('modification_permission', P_ADMIN_DISC)
        if req_permission not in permissions:
            return False
        return True

    def safe_del(self, key, permissions=(P_READ, )):
        if not self.can_edit(key, permissions):
            raise HTTPUnauthorized("Cannot delete " + key)
        del self[key]

    def safe_set(self, key, value, permissions=(P_READ, )):
        if not self.can_edit(key, permissions):
            raise HTTPUnauthorized("Cannot edit " + key)
        self[key] = value

    def validate(self, key, value, pref_data=None):
        if pref_data is None:
            pref_data = self.get_preference_data()[key]
        validator = pref_data.get('backend_validator_function', None)
        if validator:
            # This has many points of failure, but all failures are meaningful.
            module, function = validator.rsplit(".", 1)
            from importlib import import_module
            mod = import_module(module)
            try:
                value = getattr(mod, function)(value)
                if value is None:
                    raise ValueError("Empty value after validation")
            except Exception as e:
                raise ValueError(e.message)
        data_type = pref_data.get("value_type", "json")
        return self.validate_single_value(key, value, pref_data, data_type)

    def validate_single_value(self, key, value, pref_data, data_type):
        # TODO: Validation for the datatypes.
        # base_type: (bool|json|int|string|text|scalar|url|email|domain|locale|langstr|permission|role)
        # type: base_type|list_of_(type)|dict_of_(base_type)_to_(type)
        if data_type.startswith("list_of_"):
            assert isinstance(value, (list, tuple)), "Not a list"
            return [
                self.validate_single_value(key, val, pref_data, data_type[8:])
                for val in value
            ]
        elif data_type.startswith("dict_of_"):
            assert isinstance(value, (dict)), "Not a dict"
            key_type, value_type = data_type[8:].split("_to_", 1)
            assert "_" not in key_type
            return {
                self.validate_single_value(key, k, pref_data, key_type):
                self.validate_single_value(key, v, pref_data, value_type)
                for (k, v) in value.iteritems()
            }
        elif data_type == "langstr":
            # Syntactic sugar for dict_of_locale_to_string
            assert isinstance(value, (dict)), "Not a dict"
            return {
                self.validate_single_value(key, k, pref_data, "locale"):
                self.validate_single_value(key, v, pref_data, "string")
                for (k, v) in value.iteritems()
            }
        elif data_type == "bool":
            assert isinstance(value, bool), "Not a boolean"
        elif data_type == "int":
            assert isinstance(value, int), "Not an integer"
        elif data_type == "json":
            # Will raise a JSONDecodeError if not a valid JSON
            json.loads(value)
        else:
            assert isinstance(value, (str, unicode)), "Not a string"
            if data_type in ("string", "text"):
                pass
            elif data_type == "scalar":
                assert value in pref_data.get(
                    "scalar_values", ()), ("value not allowed: " + value)
            elif data_type == "url":
                condition = False
                parsed_val = urlparse(value)
                val = parsed_val.netloc
                while not condition:
                    # Whilst not an address, requested feature
                    if value in ("*", ):
                        condition = True
                        break
                    elif not bool(parsed_val.scheme):
                        # Must have a scheme, as defined a definition of a URI
                        break
                    elif not val.strip():
                        # No empty strings allowed
                        break
                    elif is_valid_ipv4_address(val):
                        condition = True
                        break
                    elif is_valid_ipv6_address(val):
                        condition = True
                        break
                    else:
                        # Must be a regular URL then. TODO: Check that the location has a DNS record
                        condition = True
                        break
                assert condition, "Not a valid URL. Must follow the specification of a URI."
            elif data_type == "email":
                from pyisemail import is_email
                assert is_email(value), "Not an email"
            elif data_type == "locale":
                pass  # TODO
            elif data_type == "permission":
                assert value in ASSEMBL_PERMISSIONS
            elif data_type == "role":
                if value not in SYSTEM_ROLES:
                    from .auth import Role
                    assert self.db.query(Role).filter_by(
                        name=value).count() == 1, "Unknown role"
            elif data_type == "domain":
                from pyisemail.validators.dns_validator import DNSValidator
                v = DNSValidator()
                assert v.is_valid(value), "Not a valid domain"
                value = value.lower()
            else:
                raise RuntimeError("Invalid data_type: " + data_type)
        return value

    def generic_json(self,
                     view_def_name='default',
                     user_id=Everyone,
                     permissions=(P_READ, ),
                     base_uri='local:'):
        # TODO: permissions
        values = self.local_values_json
        values['name'] = self.name
        if self.cascade_preferences:
            values['@extends'] = self.cascade_preferences.name
        values['@id'] = self.uri()
        return values

    def _do_update_from_json(self,
                             json,
                             parse_def,
                             aliases,
                             context,
                             permissions,
                             user_id,
                             duplicate_handling=None,
                             jsonld=None):
        for key, value in json.iteritems():
            if key == '@id':
                if value != self.uri():
                    raise RuntimeError("Wrong id")
            else:
                self[key] = value
        return self

    def __hash__(self):
        return Base.__hash__(self)

    @classproperty
    def property_defaults(cls):
        return {
            p['id']: p.get("default", None)
            for p in cls.preference_data_list
        }

    def get_preference_data(self):
        if self.cascade_id:
            base = self.cascade_preferences.get_preference_data()
        else:
            base = self.preference_data
        exists, patch = self._get_local("preference_data")
        if exists:
            return merge_json(base, patch)
        else:
            return base

    def get_preference_data_list(self):
        data = self.get_preference_data()
        keys = self.preference_data_key_list
        return [data[key] for key in keys]

    crud_permissions = CrudPermissions(create=P_SYSADMIN, update=P_ADMIN_DISC)

    # This defines the allowed properties and their data format
    # Each preference metadata has the following format:
    # id (the key for the preference as a dictionary)
    # name (for interface)
    # description (for interface, hover help)
    # value_type: given by the following grammar:
    #       base_type = (bool|json|int|string|text|scalar|address|url|email|domain|locale|langstr|permission|role)
    #       type = base_type|list_of_(type)|dict_of_(base_type)_to_(type)
    #   more types may be added, but need to be added to both frontend and backend
    # show_in_preferences: Do we always hide this preference?
    # modification_permission: What permission do you need to change that preference?
    #   (default: P_DISCUSSION_ADMIN)
    # allow_user_override: Do we allow users to have their personal value for that permission?
    #   if so what permission is required? (default False)
    # scalar_values: "{value: "label"}" a dictionary of permitted options for a scalar value type
    # default: the default value
    # item_default: the default value for new items in a list_of_T... or dict_of_BT_to_T...

    preference_data_list = [
        # Languages used in the discussion.
        {
            "id":
            "preferred_locales",
            "value_type":
            "list_of_locale",
            "name":
            _("Languages used"),
            "description":
            _("All languages expected in the discussion"),
            "allow_user_override":
            None,
            "item_default":
            "en",
            "default": [
                strip_country(x) for x in config.get_config().get(
                    'available_languages', 'fr en').split()
            ]
        },
        # Whether the discussion uses the new React landing page
        {
            "id":
            "landing_page",
            "value_type":
            "bool",
            "name":
            _("Use landing page"),
            "description":
            _("Are users directed to the landing page and phases at login, or diretly to the debate"
              ),
            "allow_user_override":
            None,
            "default":
            False,
        },
        # full class name of translation service to use, if any
        # e.g. assembl.nlp.translate.GoogleTranslationService
        {
            "id": "translation_service",
            "name": _("Translation service"),
            "value_type": "scalar",
            "scalar_values": {
                "":
                _("No translation"),
                "assembl.nlp.translation_service.DummyTranslationServiceTwoSteps":
                _("Dummy translation service (two steps)"),
                "assembl.nlp.translation_service.DummyTranslationServiceOneStep":
                _("Dummy translation service (one step)"),
                "assembl.nlp.translation_service.DummyTranslationServiceTwoStepsWithErrors":
                _("Dummy translation service (two steps) with errors"),
                "assembl.nlp.translation_service.DummyTranslationServiceOneStepWithErrors":
                _("Dummy translation service (one step) with errors"),
                "assembl.nlp.translation_service.GoogleTranslationService":
                _("Google Translate")
            },
            "description": _("Translation service"),
            "allow_user_override": None,
            "modification_permission": P_SYSADMIN,
            # "frontend_validator_function": func_name...?,
            # "backend_validator_function": func_name...?,
            "default": ""
        },

        # Simple view panel order, eg NIM or NMI
        {
            "id": "simple_view_panel_order",
            "name": _("Panel order in simple view"),
            "value_type": "scalar",
            "scalar_values": {
                "NIM": _("Navigation, Idea, Messages"),
                "NMI": _("Navigation, Messages, Idea")
            },
            "description": _("Order of panels"),
            "allow_user_override": P_READ,
            "modification_permission": P_ADMIN_DISC,
            # "frontend_validator_function": func_name...?,
            # "backend_validator_function": func_name...?,
            "default": "NMI"
        },

        # Parameters for frontend settings, for experimentation purposes.
        # What is put there should become separate parameters for typechecking
        {
            "id": "extra_json",
            "name": _("Extra JSON parameters"),
            "value_type": "json",
            "description": _("Parameters for quick frontend settings"),
            "allow_user_override": None,
            "modification_permission": P_ADMIN_DISC,
            "default": {}
        },

        # Discussion terms of use
        {
            "id":
            "terms_of_use_url",
            "name":
            _("Terms of use URL"),
            "value_type":
            "url",
            "description":
            _("URL of a document presenting terms of use for the discussion"),
            "allow_user_override":
            None,
            "modification_permission":
            P_ADMIN_DISC,
            "default":
            None
        },

        # Discussion Video
        {
            "id": "video_url",
            "name": _("Video URL"),
            "value_type": "url",
            "description": _("URL of a video presenting the discussion"),
            "allow_user_override": None,
            "modification_permission": P_ADMIN_DISC,
            "default": None
        },

        # Title in the tab
        {
            "id": "tab_title",
            "name": _("Tab title"),
            "value_type": "string",
            "description":
            _("Title which appears on the tab, by default assembl"),
            "allow_user_override": None,
            "modification_permission": P_ADMIN_DISC,
            "default": ""
        },

        # Discussion Video description
        {
            "id": "video_description",
            "name": _("Video description"),
            "value_type": "dict_of_locale_to_text",
            "description":
            _("Description of the video presenting the discussion"),
            "allow_user_override": None,
            "modification_permission": P_ADMIN_DISC,
            "default": None
        },

        # Allow social sharing
        {
            "id": "social_sharing",
            "name": _("Social sharing"),
            "value_type": "bool",
            # "scalar_values": {value: "label"},
            "description": _("Show the share button on posts and ideas"),
            "allow_user_override": None,
            "modification_permission": P_ADMIN_DISC,
            # "frontend_validator_function": func_name...?,
            # "backend_validator_function": func_name...?,
            "default": True
        },

        # Public or private social Sharing
        {
            "id": "private_social_sharing",
            "name": _("Private social sharing"),
            "value_type": "bool",
            "description": _("Publicizing or privatizing social sharing"),
            "allow_user_override": None,
            "modification_permission": P_ADMIN_DISC,
            "default": True,
        },

        # Show generic error message
        {
            "id": "generic_errors",
            "name": _("Generic Errors"),
            "value_type": "bool",
            "description": _("Display a generic error message."),
            "allow_user_override": None,
            "modification_permission": P_ADMIN_DISC,
            "default": config.get_config().get('assembl.generic_errors'),
        },

        # Extra data from social fields to put in CSV reports
        {
            "id":
            "extra_csv_data",
            "name":
            _("Extra data for CSV reports"),
            "value_type":
            "dict_of_string_to_langstr",
            # "scalar_values": {value: "label"},
            "description":
            _("data taken from social_auth's extra_data to add to CSV reports"
              ),
            "allow_user_override":
            None,
            "modification_permission":
            P_ADMIN_DISC,
            # "frontend_validator_function": func_name...?,
            "backend_validator_function":
            "assembl.models.social_data_extraction.validate_json_paths",
            "item_default": {
                "": {
                    "en": ""
                }
            },
            "default": {}  # for development
        },

        # Require virus check
        {
            "id": "requires_virus_check",
            "name": _("Require anti-virus check"),
            "value_type": "bool",
            # "scalar_values": {value: "label"},
            "description": _("Run an anti-virus on file attachments"),
            "allow_user_override": None,
            "modification_permission": P_ADMIN_DISC,
            # "frontend_validator_function": func_name...?,
            # "backend_validator_function": func_name...?,
            "default": False  # for development
        },
        {
            "id":
            "authorization_server_backend",
            "value_type":
            "scalar",
            "scalar_values": {
                "": _("No special authentication"),
            },
            "name":
            _("Authentication service type"),
            "description":
            _("A primary authentication server for this discussion, defined "
              "as a python-social-auth backend. Participants will be "
              "auto-logged in to that server, and discussion auto-"
              "subscription will require an account from this backend."),
            "allow_user_override":
            None,
            "modification_permission":
            P_SYSADMIN,
            # "frontend_validator_function": func_name...?,
            # "backend_validator_function": func_name...?,
            "default":
            ""
        },

        # Are moderated posts simply hidden or made inaccessible by default?
        {
            "id":
            "default_allow_access_to_moderated_text",
            "name":
            _("Allow access to moderated text"),
            "value_type":
            "bool",
            # "scalar_values": {value: "label"},
            "description":
            _("Are moderated posts simply hidden or made inaccessible "
              "by default?"),
            "allow_user_override":
            None,
            "modification_permission":
            P_ADMIN_DISC,
            # "frontend_validator_function": func_name...?,
            # "backend_validator_function": func_name...?,
            "default":
            True
        },

        # Does the Idea panel automatically open when an idea is clicked? (and close when a special section is clicked)
        {
            "id":
            "idea_panel_opens_automatically",
            "name":
            _("Idea panel opens automatically"),
            "value_type":
            "bool",
            # "scalar_values": {value: "label"},
            "description":
            _("Does the Idea panel automatically open when an idea is clicked ? (and close when a special section is clicked)"
              ),
            "allow_user_override":
            P_READ,
            "modification_permission":
            P_ADMIN_DISC,
            # "frontend_validator_function": func_name...?,
            # "backend_validator_function": func_name...?,
            "default":
            True
        },

        # What are (ordered) identifiers of columns in multi-column views?
        {
            "id":
            "default_column_identifiers",
            "name":
            _("Ids of columns in column view"),
            "value_type":
            "list_of_string",
            "description":
            _("What are (ordered) identifiers of columns in multi-column views?"
              ),
            "allow_user_override":
            None,
            "modification_permission":
            P_ADMIN_DISC,
            # "frontend_validator_function": func_name...?,
            # "backend_validator_function": func_name...?,
            "item_default":
            "",
            "default": ["positive", "negative"],
        },

        # What are default theme colors of columns in multi-column view
        {
            "id":
            "default_column_colors",
            "name":
            _("Default colors of columns in column view"),
            "value_type":
            "dict_of_string_to_string",
            "description":
            _("What are (default) theme colors of columns in multi-column views?"
              ),
            "allow_user_override":
            None,
            "modification_permission":
            P_ADMIN_DISC,
            # "frontend_validator_function": func_name...?,
            # "backend_validator_function": func_name...?,
            "default": {
                "positive": "green",
                "negative": "red"
            },
        },

        # What are (default) names of columns in multi-column views, in each discussion language?
        {
            "id":
            "default_column_names",
            "name":
            _("Names of columns in column view"),
            "value_type":
            "dict_of_string_to_langstr",
            "description":
            _("What are (default) names of columns in multi-column views, in each discussion language?"
              ),
            "allow_user_override":
            None,
            "modification_permission":
            P_ADMIN_DISC,
            # "frontend_validator_function": func_name...?,
            # "backend_validator_function": func_name...?,
            "default": {
                "negative": {
                    "en": "Negative",
                    "fr": "Négatif"
                },
                "positive": {
                    "en": "Positive",
                    "fr": "Positif"
                }
            },
            "item_default": {
                "": {
                    "en": ""
                }
            },
        },

        # The specification of the default permissions for a discussion
        {
            "id": "default_permissions",
            "name": _("Default permissions"),
            "value_type": "dict_of_role_to_list_of_permission",
            "show_in_preferences": False,
            "description": _("The basic permissions for a new discussion"),
            "allow_user_override": None,
            "modification_permission": P_SYSADMIN,
            # "frontend_validator_function": func_name...?,
            # "backend_validator_function": func_name...?,
            "item_default": {
                R_PARTICIPANT: [P_READ],
            },
            "default": {
                R_ADMINISTRATOR: [
                    P_ADD_EXTRACT,
                    P_ADD_IDEA,
                    P_ADD_POST,
                    P_ADMIN_DISC,
                    P_DELETE_MY_POST,
                    P_DELETE_POST,
                    P_DISC_STATS,
                    P_EDIT_EXTRACT,
                    P_EDIT_IDEA,
                    P_EDIT_MY_EXTRACT,
                    P_EDIT_MY_POST,
                    P_EDIT_POST,
                    P_EDIT_SYNTHESIS,
                    P_EXPORT_EXTERNAL_SOURCE,
                    P_MANAGE_RESOURCE,
                    P_MODERATE,
                    P_OVERRIDE_SOCIAL_AUTOLOGIN,
                    P_SEND_SYNTHESIS,
                    P_VOTE,
                ],
                R_CATCHER: [
                    P_ADD_EXTRACT,
                    P_ADD_IDEA,
                    P_ADD_POST,
                    P_DELETE_MY_POST,
                    P_EDIT_EXTRACT,
                    P_EDIT_IDEA,
                    P_EDIT_MY_EXTRACT,
                    P_EDIT_MY_POST,
                    P_OVERRIDE_SOCIAL_AUTOLOGIN,
                    P_VOTE,
                ],
                R_MODERATOR: [
                    P_ADD_EXTRACT,
                    P_ADD_IDEA,
                    P_ADD_POST,
                    P_DELETE_MY_POST,
                    P_DELETE_POST,
                    P_DISC_STATS,
                    P_EDIT_EXTRACT,
                    P_EDIT_IDEA,
                    P_EDIT_MY_EXTRACT,
                    P_EDIT_MY_POST,
                    P_EDIT_POST,
                    P_EDIT_SYNTHESIS,
                    P_EXPORT_EXTERNAL_SOURCE,
                    P_MANAGE_RESOURCE,
                    P_MODERATE,
                    P_OVERRIDE_SOCIAL_AUTOLOGIN,
                    P_SEND_SYNTHESIS,
                    P_VOTE,
                ],
                R_PARTICIPANT: [
                    P_ADD_POST,
                    P_DELETE_MY_POST,
                    P_EDIT_MY_POST,
                    P_VOTE,
                ],
                Authenticated: [
                    P_SELF_REGISTER,
                ],
                Everyone: [
                    P_READ,
                    P_READ_PUBLIC_CIF,
                ],
            },
        },

        # Registration requires being a member of this email domain.
        {
            "id":
            "require_email_domain",
            "name":
            _("Require Email Domain"),
            "value_type":
            "list_of_domain",
            # "scalar_values": {value: "label"},
            "description":
            _("List of domain names of user email address required for "
              "self-registration. Only accounts with at least an email from those "
              "domains can self-register to this discussion. Anyone can "
              "self-register if this is empty."),
            "allow_user_override":
            None,
            "modification_permission":
            P_ADMIN_DISC,
            # "frontend_validator_function": func_name...?,
            # "backend_validator_function": func_name...?,
            "default": [],
            "item_default":
            ""
        },

        # Allow whitelist to be applied to SSO login process
        {
            "id":
            "whitelist_on_authentication_backend",
            "name":
            _("Whitelist on authentication service"),
            "value_type":
            "bool",
            # "scalar_values": {value: "label"},
            "description":
            _("Allow white list to be applied to the authentication service chosen"
              ),
            "allow_user_override":
            None,
            "modification_permission":
            P_ADMIN_DISC,
            # "frontend_validator_function": func_name...?,
            # "backend_validator_function": func_name...?,
            "default":
            False
        },

        # Allow whitelist to be applied to the regular login process
        {
            "id":
            "whitelist_on_register",
            "name":
            _("Whitelist on standard registration"),
            "value_type":
            "bool",
            # "scalar_values": {value: "label"},
            "description":
            _("Allow white list to be applied to the default login process"),
            "allow_user_override":
            None,
            "modification_permission":
            P_ADMIN_DISC,
            # "frontend_validator_function": func_name...?,
            # "backend_validator_function": func_name...?,
            "default":
            True
        },

        # A discussion administrator, if different from the server administrator
        {
            "id":
            "discussion_administrators",
            "name":
            _("Discussion administrators"),
            "value_type":
            "list_of_email",
            # "scalar_values": {value: "label"},
            "description":
            _("A list of discussion administrators, if different from the server administrator"
              ),
            "allow_user_override":
            None,
            "modification_permission":
            P_ADMIN_DISC,
            # "frontend_validator_function": func_name...?,
            # "backend_validator_function": func_name...?,
            "default":
            False
        },

        # Show the CI Dashboard in the panel group window
        {
            "id": "show_ci_dashboard",
            "name": _("Show CI Dashboard"),
            "value_type": "bool",
            # "scalar_values": {value: "label"},
            "description":
            _("Show the CI Dashboard in the panel group window"),
            "allow_user_override": None,
            "modification_permission": P_ADMIN_DISC,
            # "frontend_validator_function": func_name...?,
            # "backend_validator_function": func_name...?,
            "default": False
        },

        # Configuration of the visualizations shown in the CI Dashboard
        {
            "id":
            "ci_dashboard_url",
            "name":
            _("URL of CI Dashboard"),
            "value_type":
            "url",
            "description":
            _("Configuration of the visualizations shown in the "
              "CI Dashboard"),
            "allow_user_override":
            None,
            "modification_permission":
            P_ADMIN_DISC,
            # "frontend_validator_function": func_name...?,
            # "backend_validator_function": func_name...?,
            "default":
            "//cidashboard.net/ui/visualisations/index.php?"
            "width=1000&height=1000&vis=11,23,p22,13,p7,7,12,p2,p15,p9,"
            "p8,p1,p10,p14,5,6,16,p16,p17,18,p20,p4&lang=<%= lang %>"
            "&title=&url=<%= url %>&userurl=<%= user_url %>"
            "&langurl=&timeout=60"
        },

        # List of visualizations
        {
            "id":
            "visualizations",
            "name":
            _("Catalyst Visualizations"),
            "value_type":
            "json",
            # "scalar_values": {value: "label"},
            "description":
            _("A JSON description of available Catalyst visualizations"),
            "allow_user_override":
            None,
            "modification_permission":
            P_ADMIN_DISC,
            # "frontend_validator_function": func_name...?,
            # "backend_validator_function": func_name...?,
            "default": {}
        },

        # Extra navigation sections (refers to visualizations)
        {
            "id":
            "navigation_sections",
            "name":
            _("Navigation sections"),
            "value_type":
            "json",
            # "scalar_values": {value: "label"},
            "description":
            _("A JSON specification of Catalyst visualizations to show "
              "in the navigation section"),
            "allow_user_override":
            None,
            "modification_permission":
            P_ADMIN_DISC,
            # "frontend_validator_function": func_name...?,
            # "backend_validator_function": func_name...?,
            "default": {}
        },

        # Translations for the navigation sections
        {
            "id":
            "translations",
            "name":
            _("Catalyst translations"),
            "value_type":
            "json",
            # "scalar_values": {value: "label"},
            "description":
            _("Translations applicable to Catalyst visualizations, "
              "in Jed (JSON) format"),
            "allow_user_override":
            None,
            # "view_permission": P_READ,  # by default
            "modification_permission":
            P_ADMIN_DISC,
            # "frontend_validator_function": func_name...?,
            # "backend_validator_function": func_name...?,
            "default": {}
        },

        # Default expanded/collapsed state of each idea in the table of ideas.
        # A user can override it by opening/closing an idea.
        # This is a hash where keys are ideas ids, and values are booleans.
        # We could use dict_of_string_to_bool, but that would clutter the interface.
        {
            "id":
            "default_table_of_ideas_collapsed_state",
            "name":
            _("Default Table of Ideas Collapsed state"),
            "value_type":
            "json",
            # "scalar_values": {value: "label"},
            "description":
            _("Default expanded/collapsed state of each idea in the table "
              "of ideas. A user can override it by opening/closing an idea"),
            "allow_user_override":
            None,
            # "view_permission": P_READ,  # by default
            "modification_permission":
            P_ADD_IDEA,
            # "frontend_validator_function": func_name...?,
            # "backend_validator_function": func_name...?,
            "default": {},
            "show_in_preferences":
            False
        },

        # The specification of the preference data
        {
            "id":
            "preference_data",
            "name":
            _("Preference data"),
            "value_type":
            "json",
            "show_in_preferences":
            False,
            "description":
            _("The preference configuration; override only with care"),
            "allow_user_override":
            None,
            "modification_permission":
            P_SYSADMIN,
            # "frontend_validator_function": func_name...?,
            # "backend_validator_function": func_name...?,
            "default":
            None  # this should be recursive...
        },

        # The specification of the cookies banner
        {
            "id": "cookies_banner",
            "name": _("Cookies banner"),
            "value_type": "bool",
            "show_in_preferences": True,
            "description":
            _("Show the banner offering to disable Piwik cookies"),
            "allow_user_override": None,
            "modification_permission": P_ADMIN_DISC,
            # "frontend_validator_function": func_name...?,
            # "backend_validator_function": func_name...?,
            "default": True  # this should be recursive...
        },

        # Custom HTML code that will be integrated on the landing page of the debate, right after the <body> tag
        {
            "id":
            "custom_html_code_landing_page",
            "name":
            _("Custom HTML code on the landing page"),
            "value_type":
            "text",
            "show_in_preferences":
            True,
            "description":
            _("Custom HTML code that will be integrated on the landing page of the debate, right after the <body> tag"
              ),
            "allow_user_override":
            None,
            "modification_permission":
            P_ADMIN_DISC,
            "default":
            None
        },

        # Custom HTML code that will be integrated on the user registration page of the debate, right after the <body> tag
        {
            "id":
            "custom_html_code_user_registration_page",
            "name":
            _("Custom HTML code on the user registration page"),
            "value_type":
            "text",
            "show_in_preferences":
            True,
            "description":
            _("Custom HTML code that will be integrated on the user registration page of the debate, right after the <body> tag"
              ),
            "allow_user_override":
            None,
            "modification_permission":
            P_ADMIN_DISC,
            "default":
            None
        },

        # Harvesting translation
        {
            "id": "harvesting_translation",
            "name": _("Harvesting translation"),
            "value_type": "dict_of_string_to_string",
            "show_in_preferences": True,
            "description": _("Harvesting translation"),
            "allow_user_override": P_READ,
            "default": None
        },

        # Valid CORS paths
        {
            "id":
            "graphql_valid_cors",
            "name":
            _("Valid CORS paths for GraphQL API calls"),
            "value_type":
            "list_of_url",
            "show_in_preferences":
            True,
            "description":
            _("A list of valid domain names or IP addresses that are allowed to make CORS api calls to the GraphQL API"
              ),
            "allow_user_override":
            False,
            "default": [],
            "item_default":
            ""
        },
    ]

    # Precompute, this is not mutable.
    preference_data_key_list = [p["id"] for p in preference_data_list]
    preference_data_key_set = set(preference_data_key_list)
    preference_data = {p["id"]: p for p in preference_data_list}
Esempio n. 50
0
    return request.context._instance.settings_json


@view_config(context=InstanceContext, request_method='PATCH',
             ctx_instance_class=Discussion, permission=P_ADMIN_DISC,
             header=JSON_HEADER, name="settings")
@view_config(context=InstanceContext, request_method='PUT',
             ctx_instance_class=Discussion, permission=P_ADMIN_DISC,
             header=JSON_HEADER, name="settings")
def discussion_settings_put(request):
    request.context._instance.settings_json = request.json_body
    return HTTPOk()

dogpile_fname = join(
    dirname(dirname(dirname(dirname(__file__)))),
    get_config().get('dogpile_cache.arguments.filename'))

discussion_jsonld_cache = get_region(
    'discussion_jsonld', **{"arguments.filename": dogpile_fname})
userprivate_jsonld_cache = get_region(
    'userprivate_jsonld', **{"arguments.filename": dogpile_fname})


@discussion_jsonld_cache.cache_on_arguments()
def discussion_jsonld(discussion_id):
    from assembl.semantic.virtuoso_mapping import AssemblQuadStorageManager
    aqsm = AssemblQuadStorageManager()
    return aqsm.as_jsonld(discussion_id)


@userprivate_jsonld_cache.cache_on_arguments()
Esempio n. 51
0
 def fin():
     print "finalizer db_tables"
     session = empty_db()
     drop_tables(get_config(), session)
     transaction.commit()
Esempio n. 52
0
File: base.py Progetto: jean/assembl
 def fin():
     print "finalizer db_tables"
     session = empty_db()
     drop_tables(get_config(), session)
     transaction.commit()