示例#1
0
 def resolve_locales(self, args, context, info):
     locales = DummyGoogleTranslationService.target_localesC()
     asPosixLocale = DummyGoogleTranslationService.asPosixLocale
     target_locale = strip_country(
         models.Locale.get_or_create(args.get('lang')))
     labels = models.LocaleLabel.names_of_locales_in_locale(
         [strip_country(asPosixLocale(loc)) for loc in locales],
         target_locale)
     return [
         Locale(locale_code=locale_code, label=label)
         for locale_code, label in sorted(labels.items(),
                                          key=lambda entry: entry[1])
     ]
示例#2
0
def get_locale_from_request(request, session=None, user=None):
    if user is None:
        user_id = request.authenticated_userid or Everyone
        if user_id != Everyone:
            user = User.get(user_id)
    session = session or User.default_db
    if user:
        if '_LOCALE_' in request.params:
            locale = request.params['_LOCALE_']
            process_locale(locale, user, session,
                           LanguagePreferenceOrder.Parameter)
        elif '_LOCALE_' in request.cookies:
            locale = request.cookies['_LOCALE_']
            process_locale(locale, user, session,
                           LanguagePreferenceOrder.Cookie)
        else:
            # uses my locale negotiator
            locale = request.locale_name
            process_locale(locale, user, session,
                           LanguagePreferenceOrder.OS_Default)
    else:
        locale = request.localizer.locale_name
    target_locale = Locale.get_or_create(
        strip_country(locale), session)
    return target_locale
示例#3
0
    def resolve_locales(self, args, context, info):
        locales = DummyGoogleTranslationService.target_localesC()
        asPosixLocale = DummyGoogleTranslationService.asPosixLocale
        lang = args.get('lang')
        target_locale = strip_country(models.Locale.get_or_create(lang))
        locales_without_country = [
            strip_country(asPosixLocale(loc)) for loc in locales
        ]
        labels_en = models.LocaleLabel.names_of_locales_in_locale(
            locales_without_country, models.Locale.get_or_create('en'))
        if lang == 'en':
            labels = labels_en
        else:
            # labels can be a subset of labels_en or completely empty
            # if there is no translation of the locales for target_locale
            labels = models.LocaleLabel.names_of_locales_in_locale(
                locales_without_country, target_locale)
        result = []
        for locale_code, label_en in labels_en.items():
            label = labels.get(locale_code, label_en)
            result.append(Locale(locale_code=locale_code, label=label))

        return sorted(result, key=lambda locale: locale.label)
示例#4
0
文件: schema.py 项目: assembl/assembl
    def resolve_locales(self, args, context, info):
        locales = DummyGoogleTranslationService.target_localesC()
        asPosixLocale = DummyGoogleTranslationService.asPosixLocale
        lang = args.get('lang')
        target_locale = strip_country(
            models.Locale.get_or_create(lang))
        locales_without_country = [strip_country(asPosixLocale(loc)) for loc in locales]
        labels_en = models.LocaleLabel.names_of_locales_in_locale(
            locales_without_country,
            models.Locale.get_or_create('en'))
        if lang == 'en':
            labels = labels_en
        else:
            # labels can be a subset of labels_en or completely empty
            # if there is no translation of the locales for target_locale
            labels = models.LocaleLabel.names_of_locales_in_locale(
                locales_without_country,
                target_locale)
        result = []
        for locale_code, label_en in labels_en.items():
            label = labels.get(locale_code, label_en)
            result.append(Locale(locale_code=locale_code, label=label))

        return sorted(result, key=lambda locale: locale.label)
示例#5
0
def base_admin_view(request):
    """The Base admin view, for frontend urls"""
    user_id = authenticated_userid(request) or Everyone
    if user_id == Everyone:
        raise HTTPUnauthorized()
    context = get_default_context(request)

    session = Discussion.default_db
    preferences = Preferences.get_default_preferences(session)
    user = User.get(user_id)

    if '_LOCALE_' in request.cookies:
        locale = request.cookies['_LOCALE_']
        process_locale(locale, user, session, LanguagePreferenceOrder.Cookie)

    elif '_LOCALE_' in request.params:
        locale = request.params['_LOCALE_']
        process_locale(locale, user, session,
                       LanguagePreferenceOrder.Parameter)
    else:
        locale = request.locale_name
        process_locale(locale, user, session,
                       LanguagePreferenceOrder.OS_Default)

    target_locale = strip_country(locale)
    locale_labels = json.dumps(
        DummyGoogleTranslationService.target_locale_labels_cls(target_locale))
    context['translation_locale_names_json'] = locale_labels

    role_names = [x for (x, ) in session.query(Role.name).all()]
    permission_names = [x for (x, ) in session.query(Permission.name).all()]
    context['role_names'] = json.dumps(role_names)
    context['permission_names'] = json.dumps(permission_names)
    context['discussion'] = PseudoDiscussion()

    response = render_to_response('../../templates/adminIndex.jinja2',
                                  context,
                                  request=request)
    # Prevent caching the home, especially for proper login/logout
    response.cache_control.max_age = 0
    response.cache_control.prevent_auto = True
    return response
示例#6
0
def populate_from_langstring(ls, data, dataPropName):
    langs = index_languages()
    if ls:
        others = []
        for entry in ls.entries:
            if not entry.value:
                continue
            locale_code = strip_country(entry.base_locale)
            if locale_code == 'zh_Hans':
                locale_code = 'zh_CN'
            if locale_code in langs:
                dataPropNameL = "_".join((dataPropName, locale_code))
                # Japanese for example is stored in db with a html entity for
                # each character.
                # unescape to transform html entities back to characters
                data[dataPropNameL] = unescape(entry.value)
            else:
                others.append(unescape(entry.value))
        if others:
            dataPropNameL = dataPropName + "_other"
            data[dataPropNameL] = ' '.join(others)
示例#7
0
文件: utils.py 项目: assembl/assembl
def populate_from_langstring(ls, data, dataPropName):
    langs = index_languages()
    if ls:
        others = []
        for entry in ls.entries:
            if not entry.value:
                continue
            locale_code = strip_country(entry.base_locale)
            if locale_code == 'zh_Hans':
                locale_code = 'zh_CN'
            if locale_code in langs:
                dataPropNameL = "_".join((dataPropName, locale_code))
                # Japanese for example is stored in db with a html entity for
                # each character.
                # unescape to transform html entities back to characters
                data[dataPropNameL] = unescape(entry.value)
            else:
                others.append(unescape(entry.value))
        if others:
            dataPropNameL = dataPropName + "_other"
            data[dataPropNameL] = ' '.join(others)
def upgrade(pyramid_env):
    from assembl import models as m
    db = m.get_session_maker()()
    with transaction.manager:
        for (locales, pref_id, pref) in db.execute(
                """SELECT discussion.preferred_locales, preferences.id, preferences."values"
                FROM discussion
                JOIN preferences
                    ON discussion.preferences_id = preferences.id"""):
            if locales is not None:
                pref = {} if pref is None else json.loads(pref)
                pref["preferred_locales"] = [
                    strip_country(l) for l in locales.split()]
                db.execute(sa.text(
                    'UPDATE preferences SET "values"=:val where id=:pref_id'
                    ).bindparams(
                        val=json.dumps(pref), pref_id=pref_id))
                mark_changed()

    with context.begin_transaction():
        op.drop_column("discussion", "preferred_locales")
示例#9
0
def upgrade(pyramid_env):
    from assembl import models as m
    db = m.get_session_maker()()
    with transaction.manager:
        for (locales, pref_id, pref) in db.execute(
                """SELECT discussion.preferred_locales, preferences.id, preferences."values"
                FROM discussion
                JOIN preferences
                    ON discussion.preferences_id = preferences.id"""):
            if locales is not None:
                pref = {} if pref is None else json.loads(pref)
                pref["preferred_locales"] = [
                    strip_country(l) for l in locales.split()
                ]
                db.execute(
                    sa.text(
                        'UPDATE preferences SET "values"=:val where id=:pref_id'
                    ).bindparams(val=json.dumps(pref), pref_id=pref_id))
                mark_changed()

    with context.begin_transaction():
        op.drop_column("discussion", "preferred_locales")
示例#10
0
def get_opengraph_locale(request):
    """
    If there is a user logged in, returns his preferred locale
    If not, returns the first preferred locale of the discussion
    Otherwise, sets locale to fr
    """
    from ..auth.util import get_user, get_current_discussion
    from assembl.lib.locale import strip_country
    user = get_user(request)
    discussion = get_current_discussion()
    if not user and not discussion:
        locale = "fr"
    elif user:
        try:
            locale = user.language_preference[0].locale.code
            locale = strip_country(locale)
        except:
            if discussion:
                locale = discussion.preferences['preferred_locales'][0]
            else:
                locale = "fr"
    elif discussion and user is None:
        locale = discussion.preferences['preferred_locales'][0]
    return locale
示例#11
0
def get_locale_from_request(request, session=None, user=None):
    if user is None:
        user_id = request.authenticated_userid or Everyone
        if user_id != Everyone:
            user = User.get(user_id)
    session = session or User.default_db
    if user:
        if '_LOCALE_' in request.params:
            locale = request.params['_LOCALE_']
            process_locale(locale, user, session,
                           LanguagePreferenceOrder.Parameter)
        elif '_LOCALE_' in request.cookies:
            locale = request.cookies['_LOCALE_']
            process_locale(locale, user, session,
                           LanguagePreferenceOrder.Cookie)
        else:
            # uses my locale negotiator
            locale = request.locale_name
            process_locale(locale, user, session,
                           LanguagePreferenceOrder.OS_Default)
    else:
        locale = request.localizer.locale_name
    target_locale = Locale.get_or_create(strip_country(locale), session)
    return target_locale
示例#12
0
def get_opengraph_locale(request):
    """
    If there is a user logged in, returns his preferred locale
    If not, returns the first preferred locale of the discussion
    Otherwise, sets locale to fr
    """
    from ..auth.util import get_user, get_current_discussion
    from assembl.lib.locale import strip_country
    user = get_user(request)
    discussion = get_current_discussion()
    if not user and not discussion:
        locale = "fr"
    elif user:
        try:
            locale = user.language_preference[0].locale.code
            locale = strip_country(locale)
        except:
            if discussion:
                locale = discussion.preferences['preferred_locales'][0]
            else:
                locale = "fr"
    elif discussion and user is None:
        locale = discussion.preferences['preferred_locales'][0]
    return locale
示例#13
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}
示例#14
0
文件: views.py 项目: srault95/assembl
def home_view(request):
    """The main view on a discussion"""
    user_id = authenticated_userid(request) or Everyone
    context = get_default_context(request)
    discussion = context["discussion"]
    canRead = user_has_permission(discussion.id, user_id, P_READ)
    if not canRead and user_id == Everyone:
        # User isn't logged-in and discussion isn't public:
        # redirect to login page
        # need to pass the route to go to *after* login as well

        # With regards to a next_view, if explicitly stated, then
        # that is the next view. If not stated, the referer takes
        # precedence. In case of failure, login redirects to the
        # discussion which is its context.
        next_view = request.params.get('next', None)
        if not next_view and discussion:
            # If referred here from a post url, want to be able to
            # send the user back. Usually, Assembl will send the user
            # here to login on private discussions.
            referrer = request.url
            next_view = path_qs(referrer)

        if discussion.preferences['authorization_server_backend']:
            login_url = request.route_url(
                "contextual_social_auth",
                discussion_slug=discussion.slug,
                backend=discussion.preferences['authorization_server_backend'],
                _query={"next": next_view})
        elif next_view:
            login_url = request.route_url("contextual_login",
                                          discussion_slug=discussion.slug,
                                          _query={"next": next_view})
        else:
            login_url = request.route_url('contextual_login',
                                          discussion_slug=discussion.slug)
        return HTTPTemporaryRedirect(login_url)
    elif not canRead:
        # User is logged-in but doesn't have access to the discussion
        # Would use render_to_response, except for the 401
        from pyramid_jinja2 import IJinja2Environment
        jinja_env = request.registry.queryUtility(IJinja2Environment,
                                                  name='.jinja2')
        template = jinja_env.get_template('cannot_read_discussion.jinja2')
        body = template.render(get_default_context(request))
        return Response(body, 401)

    # if the route asks for a post, get post content (because this is needed for meta tags)
    route_name = request.matched_route.name
    if route_name == "purl_posts":
        post_id = FrontendUrls.getRequestedPostId(request)
        if not post_id:
            return HTTPSeeOther(
                request.route_url('home', discussion_slug=discussion.slug))
        post = Post.get_instance(post_id)
        if not post or post.discussion_id != discussion.id:
            return HTTPSeeOther(
                request.route_url('home', discussion_slug=discussion.slug))
        context['post'] = post
    elif route_name == "purl_idea":
        idea_id = FrontendUrls.getRequestedIdeaId(request)
        if not idea_id:
            return HTTPSeeOther(
                request.route_url('home', discussion_slug=discussion.slug))
        idea = Idea.get_instance(idea_id)
        if not idea or idea.discussion_id != discussion.id:
            return HTTPSeeOther(
                request.route_url('home', discussion_slug=discussion.slug))
        context['idea'] = idea

    canAddExtract = user_has_permission(discussion.id, user_id, P_ADD_EXTRACT)
    context['canAddExtract'] = canAddExtract
    context['canDisplayTabs'] = True
    preferences = discussion.preferences
    if user_id != Everyone:
        from assembl.models import UserPreferenceCollection
        user = User.get(user_id)
        preferences = UserPreferenceCollection(user_id, discussion)
        # TODO: user may not exist. Case of session with BD change.
        user.is_visiting_discussion(discussion.id)
        session = Discussion.default_db

        if '_LOCALE_' in request.cookies:
            locale = request.cookies['_LOCALE_']
            process_locale(locale, user, session,
                           LanguagePreferenceOrder.Cookie)

        elif '_LOCALE_' in request.params:
            locale = request.params['_LOCALE_']
            process_locale(locale, user, session,
                           LanguagePreferenceOrder.Parameter)
        else:
            locale = locale_negotiator(request)
            process_locale(locale, user, session,
                           LanguagePreferenceOrder.OS_Default)
    else:
        locale = request.localizer.locale_name

    target_locale = Locale.get_or_create(strip_country(locale), discussion.db)

    translation_service_data = {}
    try:
        service = discussion.translation_service()
        if service:
            translation_service_data = service.serviceData()
    except:
        pass
    context['translation_service_data_json'] = json.dumps(
        translation_service_data)
    locale_labels = json.dumps(
        DummyGoogleTranslationService.target_locale_labels_cls(target_locale))
    context['translation_locale_names_json'] = locale_labels

    context['preferences_json'] = json.dumps(dict(preferences))

    response = render_to_response('../../templates/index.jinja2',
                                  context,
                                  request=request)
    # Prevent caching the home, especially for proper login/logout
    response.cache_control.max_age = 0
    response.cache_control.prevent_auto = True
    return response
示例#15
0
 def target_locale_labels_for_locales(cls, locales, target_locale):
     return LocaleLabel.names_of_locales_in_locale(
         [strip_country(cls.asPosixLocale(loc)) for loc in locales] +
         Locale.SPECIAL_LOCALES,
         target_locale)
示例#16
0
 def target_locale_labels_for_locales(cls, locales, target_locale):
     return LocaleLabel.names_of_locales_in_locale(
         [strip_country(cls.asPosixLocale(loc)) for loc in locales] +
         Locale.SPECIAL_LOCALES,
         target_locale)
示例#17
0
文件: utils.py 项目: assembl/assembl
def get_data(content):
    """Return uid, dict of fields we want to index,
    return None if we don't index."""
    from assembl.models import Idea, Post, SynthesisPost, AgentProfile, LangString, Extract, Question
    if type(content) == Idea:  # only index Idea, not Thematic or Question
        data = {}
        for attr in ('creation_date', 'id', 'discussion_id'):
            data[attr] = getattr(content, attr)
        populate_from_langstring_prop(content, data, 'title')
        populate_from_langstring_prop(content, data, 'synthesis_title')
        populate_from_langstring_prop(content, data, 'description')

        announcement = content.get_applicable_announcement()
        if announcement:
            populate_from_langstring_prop(announcement, data, 'title', 'announcement_title')
            populate_from_langstring_prop(announcement, data, 'body', 'announcement_body')

        phase = content.get_associated_phase()
        if phase:
            data['phase_id'] = phase.id
            data['phase_identifier'] = phase.identifier

        data['message_view_override'] = content.message_view_override
        return get_uid(content), data

    elif isinstance(content, AgentProfile):
        data = {}
        for attr in ('creation_date', 'id', 'name'):
            data[attr] = getattr(content, attr, None)
            # AgentProfile doesn't have creation_date, User does.

        # get all discussions that the user is in via AgentStatusInDiscussion
        data['discussion_id'] = set([s.discussion_id
                                 for s in content.agent_status_in_discussion])
        # get discussion_id for all posts of this agent
        data['discussion_id'] = list(
            data['discussion_id'].union(
                [post.discussion_id for post in content.posts_created]
            )
        )
        return get_uid(content), data

    elif isinstance(content, Post):
        data = {}
        data['_parent'] = 'user:{}'.format(content.creator_id)
        if content.parent_id is not None:
            data['parent_creator_id'] = content.parent.creator_id

        for attr in ('discussion_id', 'creation_date', 'id', 'parent_id',
                     'creator_id', 'sentiment_counts'):
            data[attr] = getattr(content, attr)

        data['creator_display_name'] = AgentProfile.get(content.creator_id).display_name()
        data['sentiment_tags'] = [key for key in data['sentiment_counts']
                                  if data['sentiment_counts'][key] > 0]
        like = data['sentiment_counts']['like']
        disagree = data['sentiment_counts']['disagree']
        dont_understand = data['sentiment_counts']['dont_understand']
        more_info = data['sentiment_counts']['more_info']
        all_sentiments = [like, disagree, dont_understand, more_info]
        data['sentiment_counts']['total'] = sum(all_sentiments)
        data['sentiment_counts']['popularity'] = like - disagree
        data['sentiment_counts']['consensus'] = max(all_sentiments) / ((sum(all_sentiments) / len(all_sentiments)) or 1)
        data['sentiment_counts']['controversy'] = max(like, disagree, 1) / min(like or 1, disagree or 1)
        data['type'] = content.type  # this is the subtype (assembl_post, email...)
#        data['publishes_synthesis_id'] = getattr(
#            content, 'publishes_synthesis_id', None)
        phase = content.get_created_phase()
        if phase:
            data['phase_id'] = phase.id
            data['phase_identifier'] = phase.identifier

        if isinstance(content, SynthesisPost):
            populate_from_langstring_prop(content.publishes_synthesis,
                                          data, 'subject')
            populate_from_langstring_prop(content.publishes_synthesis,
                                          data, 'introduction')
            populate_from_langstring_prop(content.publishes_synthesis,
                                          data, 'conclusion')
            long_titles = [idea.synthesis_title for idea in content.publishes_synthesis.ideas
                           if idea.synthesis_title]
            long_titles_c = defaultdict(list)
            for ls in long_titles:
                for e in ls.entries:
                    if e.value:
                        long_titles_c[strip_country(e.base_locale)].append(e.value)
            ls = LangString()
            for locale, values in long_titles_c.iteritems():
                ls.add_value(' '.join(values), locale)
            populate_from_langstring(ls, data, 'ideas')
        else:
            idea_id = get_idea_id_for_post(content)
            if not idea_id:
                return None, None

            data['idea_id'] = idea_id
            related_idea = Idea.get(idea_id[0])
            data['message_view_override'] = related_idea.message_view_override
            if isinstance(related_idea, Question):
                related_idea = related_idea.parents[0]
            # we take the title of the first idea in the list for now (in v2, posts are attached to only one idea)
            populate_from_langstring_prop(
                related_idea, data, 'title', 'idea_title')

            populate_from_langstring_prop(content, data, 'body')
            populate_from_langstring_prop(content, data, 'subject')

        return get_uid(content), data

    elif isinstance(content, Extract):
        data = {}
        for attr in ('discussion_id', 'body', 'creation_date', 'id', 'creator_id'):
            data[attr] = getattr(content, attr)

        data['post_id'] = content.content_id
        post = Post.get(content.content_id)
        populate_from_langstring_prop(post, data, 'subject')
        phase = post.get_created_phase()
        if phase:
            data['phase_id'] = phase.id
            data['phase_identifier'] = phase.identifier

        idea_id = get_idea_id_for_post(post)
        if not idea_id:
            return None, None

        data['idea_id'] = idea_id
        # we take the title of the first idea in the list for now (in v2, posts are attached to only one idea)
        related_idea = Idea.get(idea_id[0])
        data['message_view_override'] = related_idea.message_view_override
        if isinstance(related_idea, Question):
            related_idea = related_idea.parents[0]
        populate_from_langstring_prop(
            related_idea, data, 'title', 'idea_title')
        data['extract_state'] = 'taxonomy_state.' + content.extract_state
        if content.extract_nature:
            data['extract_nature'] = 'taxonomy_nature.' + content.extract_nature.name

        if content.extract_action:
            data['extract_action'] = 'taxonomy_action.' + content.extract_action.name

        data['creator_display_name'] = AgentProfile.get(content.creator_id).display_name()

        return get_uid(content), data

    return None, None
示例#18
0
def home_view(request):
    user_id = authenticated_userid(request) or Everyone
    context = get_default_context(request)
    discussion = context["discussion"]
    request.session["discussion"] = discussion.slug
    canRead = user_has_permission(discussion.id, user_id, P_READ)
    if not canRead and user_id == Everyone:
        # User isn't logged-in and discussion isn't public:
        # redirect to login page
        # need to pass the route to go to *after* login as well

        # With regards to a next_view, if explicitly stated, then
        # that is the next view. If not stated, the referer takes
        # precedence. In case of failure, login redirects to the
        # discussion which is its context.
        next_view = request.params.get('next_view', None)
        if not next_view and discussion:
            # If referred here from a post url, want to be able to
            # send the user back. Usually, Assembl will send the user
            # here to login on private discussions.
            referrer = request.url
            next_view = path_qs(referrer)

        if next_view:
            login_url = request.route_url("contextual_login",
                                          discussion_slug=discussion.slug,
                                          _query={"next_view": next_view})
        else:
            login_url = request.route_url(
                'contextual_login', discussion_slug=discussion.slug)
        return HTTPSeeOther(login_url)
    elif not canRead:
        # User is logged-in but doesn't have access to the discussion
        # Would use render_to_response, except for the 401
        from pyramid_jinja2 import IJinja2Environment
        jinja_env = request.registry.queryUtility(
            IJinja2Environment, name='.jinja2')
        template = jinja_env.get_template('cannot_read_discussion.jinja2')
        body = template.render(get_default_context(request))
        return Response(body, 401)

    # if the route asks for a post, get post content (because this is needed for meta tags)
    route_name = request.matched_route.name
    if route_name == "purl_posts":
        post_id = FrontendUrls.getRequestedPostId(request)
        if not post_id:
            return HTTPSeeOther(request.route_url(
                'home', discussion_slug=discussion.slug))
        post = Post.get_instance(post_id)
        if not post or post.discussion_id != discussion.id:
            return HTTPSeeOther(request.route_url(
                'home', discussion_slug=discussion.slug))
        context['post'] = post
    elif route_name == "purl_idea":
        idea_id = FrontendUrls.getRequestedIdeaId(request)
        if not idea_id:
            return HTTPSeeOther(request.route_url(
                'home', discussion_slug=discussion.slug))
        idea = Idea.get_instance(idea_id)
        if not idea or idea.discussion_id != discussion.id:
            return HTTPSeeOther(request.route_url(
                'home', discussion_slug=discussion.slug))
        context['idea'] = idea

    canAddExtract = user_has_permission(discussion.id, user_id, P_ADD_EXTRACT)
    context['canAddExtract'] = canAddExtract
    context['canDisplayTabs'] = True
    preferences = discussion.preferences
    if user_id != Everyone:
        from assembl.models import UserPreferenceCollection
        user = User.get(user_id)
        preferences = UserPreferenceCollection(user_id, discussion)
        # TODO: user may not exist. Case of session with BD change.
        user.is_visiting_discussion(discussion.id)
        session = Discussion.default_db

        if '_LOCALE_' in request.cookies:
            locale = request.cookies['_LOCALE_']
            process_locale(locale, user, session,
                           LanguagePreferenceOrder.Cookie)

        elif '_LOCALE_' in request.params:
            locale = request.params['_LOCALE_']
            process_locale(locale, user, session,
                           LanguagePreferenceOrder.Parameter)
        else:
            locale = locale_negotiator(request)
            process_locale(locale, user, session,
                           LanguagePreferenceOrder.OS_Default)
    else:
        locale = request.localizer.locale_name

    target_locale = Locale.get_or_create(
        strip_country(locale), discussion.db)

    translation_service_data = {}
    try:
        service = discussion.translation_service()
        if service:
            translation_service_data = service.serviceData()
    except:
        pass
    context['translation_service_data_json'] = json.dumps(
        translation_service_data)
    locale_labels = json.dumps(
        DummyGoogleTranslationService.target_locale_labels_cls(target_locale))
    context['translation_locale_names_json'] = locale_labels

    context['preferences_json'] = json.dumps(dict(preferences))

    response = render_to_response('../../templates/index.jinja2', context,
                                  request=request)
    # Prevent caching the home, especially for proper login/logout
    response.cache_control.max_age = 0
    response.cache_control.prevent_auto = True
    return response
示例#19
0
def get_data(content):
    """Return uid, dict of fields we want to index,
    return None if we don't index."""
    from assembl.models import Idea, Post, SynthesisPost, AgentProfile, LangString, Extract
    if type(content) == Idea:  # only index Idea, not Thematic or Question
        data = {}
        for attr in ('creation_date', 'id', 'discussion_id'):
            data[attr] = getattr(content, attr)
        populate_from_langstring_prop(content, data, 'title')
        populate_from_langstring_prop(content, data, 'synthesis_title')
        populate_from_langstring_prop(content, data, 'description')

        announcement = content.get_applicable_announcement()
        if announcement:
            populate_from_langstring_prop(announcement, data, 'title',
                                          'announcement_title')
            populate_from_langstring_prop(announcement, data, 'body',
                                          'announcement_body')

        phase = content.get_associated_phase()
        if phase:
            data['phase_id'] = phase.id
            data['phase_identifier'] = phase.identifier

        return get_uid(content), data

    elif isinstance(content, AgentProfile):
        data = {}
        for attr in ('creation_date', 'id', 'name'):
            data[attr] = getattr(content, attr, None)
            # AgentProfile doesn't have creation_date, User does.

        # get all discussions that the user is in via AgentStatusInDiscussion
        data['discussion_id'] = set(
            [s.discussion_id for s in content.agent_status_in_discussion])
        # get discussion_id for all posts of this agent
        data['discussion_id'] = list(data['discussion_id'].union(
            [post.discussion_id for post in content.posts_created]))
        return get_uid(content), data

    elif isinstance(content, Post):
        data = {}
        data['_parent'] = 'user:{}'.format(content.creator_id)
        if content.parent_id is not None:
            data['parent_creator_id'] = content.parent.creator_id

        for attr in ('discussion_id', 'creation_date', 'id', 'parent_id',
                     'creator_id', 'sentiment_counts'):
            data[attr] = getattr(content, attr)

        data['creator_display_name'] = AgentProfile.get(
            content.creator_id).display_name()
        data['sentiment_tags'] = [
            key for key in data['sentiment_counts']
            if data['sentiment_counts'][key] > 0
        ]
        like = data['sentiment_counts']['like']
        disagree = data['sentiment_counts']['disagree']
        dont_understand = data['sentiment_counts']['dont_understand']
        more_info = data['sentiment_counts']['more_info']
        all_sentiments = [like, disagree, dont_understand, more_info]
        data['sentiment_counts']['total'] = sum(all_sentiments)
        data['sentiment_counts']['popularity'] = like - disagree
        data['sentiment_counts']['consensus'] = max(all_sentiments) / (
            (sum(all_sentiments) / len(all_sentiments)) or 1)
        data['sentiment_counts']['controversy'] = max(like, disagree, 1) / min(
            like or 1, disagree or 1)
        data[
            'type'] = content.type  # this is the subtype (assembl_post, email...)
        #        data['publishes_synthesis_id'] = getattr(
        #            content, 'publishes_synthesis_id', None)
        phase = content.get_created_phase()
        if phase:
            data['phase_id'] = phase.id
            data['phase_identifier'] = phase.identifier

        if isinstance(content, SynthesisPost):
            populate_from_langstring_prop(content.publishes_synthesis, data,
                                          'subject')
            populate_from_langstring_prop(content.publishes_synthesis, data,
                                          'introduction')
            populate_from_langstring_prop(content.publishes_synthesis, data,
                                          'conclusion')
            long_titles = [
                idea.synthesis_title
                for idea in content.publishes_synthesis.ideas
                if idea.synthesis_title
            ]
            long_titles_c = defaultdict(list)
            for ls in long_titles:
                for e in ls.entries:
                    if e.value:
                        long_titles_c[strip_country(e.base_locale)].append(
                            e.value)
            ls = LangString()
            for locale, values in long_titles_c.iteritems():
                ls.add_value(' '.join(values), locale)
            populate_from_langstring(ls, data, 'ideas')
        else:
            idea_id = get_idea_id_for_post(content)
            if not idea_id:
                return None, None

            data['idea_id'] = idea_id
            populate_from_langstring_prop(content, data, 'body')
            populate_from_langstring_prop(content, data, 'subject')

        return get_uid(content), data

    elif isinstance(content, Extract):
        data = {}
        for attr in ('discussion_id', 'body', 'creation_date', 'id',
                     'creator_id'):
            data[attr] = getattr(content, attr)

        data['post_id'] = content.content_id
        post = Post.get(content.content_id)
        populate_from_langstring_prop(post, data, 'subject')
        phase = post.get_created_phase()
        if phase:
            data['phase_id'] = phase.id
            data['phase_identifier'] = phase.identifier

        idea_id = get_idea_id_for_post(post)
        if not idea_id:
            return None, None

        data['idea_id'] = idea_id
        data['extract_state'] = 'taxonomy_state.' + content.extract_state
        if content.extract_nature:
            data[
                'extract_nature'] = 'taxonomy_nature.' + content.extract_nature.name

        if content.extract_action:
            data[
                'extract_action'] = 'taxonomy_action.' + content.extract_action.name

        data['creator_display_name'] = AgentProfile.get(
            content.creator_id).display_name()

        return get_uid(content), data

    return None, None
示例#20
0
 def test_strip_country_case1(self):
     # There is only one case for this function since it assumes a posix
     # locale
     locale = "fr_FR"
     assert strip_country(locale) == "fr"