Пример #1
0
 def get_private_graphs_cif(self):
     graphs = [x for x in self.get_user_graph_cif() if x]
     return {
         "@context": [
             "http://purl.org/catalyst/jsonld",
             {"local": get_global_base_url() + '/data/'}],
         "@graph": graphs
     }
Пример #2
0
def send_change_password_email(
        request, profile, email=None, subject=None,
        text_body=None, html_body=None, discussion=None,
        sender_name=None, welcome=False, immediate=False):
    mailer = get_mailer(request)
    localizer = request.localizer
    route_maker = create_get_route(request, discussion)
    data = dict(
        assembl="Assembl", name=profile.name,
        confirm_url=get_global_base_url() + route_maker(
            'welcome' if welcome else 'do_password_change',
            token=password_change_token(profile)))
    sender_email = config.get('assembl.admin_email')
    if discussion:
        data.update(dict(
            discussion_topic=discussion.topic,
            discussion_url=discussion.get_url()))
        sender_name = sender_name or discussion.topic
    if sender_name:
        sender_name = normalize_email_name(sender_name)
        sender = '"%s" <%s>' % (sender_name, sender_email)
        sender_name = Header(sender_name, 'utf-8').encode()
        if len(sender) > 255:
            sender = sender_email
    else:
        sender = sender_email
    subject = (subject or localizer.translate(
        _("Request for password change"))).format(**data)
    #subject = Header(subject, 'utf-8').encode()  # Fails in some cases???
    if text_body is None or html_body is not None:
        # if text_body and no html_body, html_body remains None.
        html_body = html_body or localizer.translate(_(u"""<p>Hello, {name}!</p>
<p>We have received a request to change the password on your {assembl} account.
Please <a href="{confirm_url}">click here to confirm your password change</a>.</p>
<p>If you did not ask to reset your password please disregard this email.</p>
<p>Best regards,<br />The {assembl} Team</p>
"""))
    text_body = text_body or localizer.translate(_(u"""Hello, {name}!
We have received a request to change the password on your {assembl} account.
To confirm your password change please click on the link below.
<{confirm_url}>

If you did not ask to reset your password please disregard this email.

Best regards,
The {assembl} Team
"""))
    message = Message(
        subject=subject,
        sender=sender,
        recipients=["%s <%s>" % (
            profile.name, email or profile.get_preferred_email())],
        body=text_body.format(**data), html=html_body.format(**data))
    if immediate:
        mailer.send_immediately(message)
    else:
        mailer.send(message)
Пример #3
0
    def get_base_url(self):
        """Get the base URL of this server

        Tied to discussion so that we can support virtual hosts or
        communities in the future and access the urls when we can't rely
        on pyramid's current request (such as when celery generates
        notifications)
        Temporarily equivalent to get_global_base_url
        """
        return get_global_base_url()
Пример #4
0
def login_view(request):
    if request.scheme == "http"\
            and asbool(config.get("accept_secure_connection")):
        return HTTPFound(get_global_base_url(True) + request.path_qs)
    force_providers = request.matched_route.name.endswith('_forceproviders')
    if request.matched_route.name == 'contextual_login':
        contextual_login = get_social_autologin(request)
        if contextual_login:
            return HTTPFound(contextual_login)
    return get_login_context(request, force_providers)
Пример #5
0
def get_discussion_url():
    from ..auth.util import get_current_discussion
    from assembl.lib.frontend_urls import FrontendUrls
    from assembl.lib.utils import get_global_base_url
    discussion = get_current_discussion()
    if discussion:
        front_end_urls = FrontendUrls(discussion)
        return front_end_urls.get_discussion_url()
    else:
        return get_global_base_url()
Пример #6
0
    def get_base_url(self, require_secure=None):
        """Get the base URL of this server

        Tied to discussion so that we can support virtual hosts or
        communities in the future and access the urls when we can't rely
        on pyramid's current request (such as when celery generates
        notifications)
        Temporarily equivalent to get_global_base_url
        """
        return get_global_base_url(require_secure)
Пример #7
0
def get_discussion_url():
    from ..auth.util import get_current_discussion
    from assembl.lib.frontend_urls import FrontendUrls
    from assembl.lib.utils import get_global_base_url
    discussion = get_current_discussion()
    if discussion:
        front_end_urls = FrontendUrls(discussion)
        return front_end_urls.get_discussion_url()
    else:
        return get_global_base_url()
Пример #8
0
def login_view(request):
    if request.scheme == "http"\
            and asbool(config.get("accept_secure_connection")):
        return HTTPFound(get_global_base_url(True) + request.path_qs)
    force_providers = request.matched_route.name.endswith('_forceproviders')
    if request.matched_route.name == 'contextual_login':
        contextual_login = get_social_autologin(request)
        if contextual_login:
            return HTTPFound(contextual_login)
    return get_login_context(request, force_providers)
Пример #9
0
 def get_public_graphs_cif(self):
     graphs = [x for x in self.get_extract_graphs_cif() if x]
     graphs.append({
         "@id": "assembl:discussion_%d_data" % (self.id),
         "@graph": [x for x in self.get_discussion_graph_cif() if x]
     })
     return {
         "@context": [
             "http://purl.org/catalyst/jsonld",
             {"local": get_global_base_url() + '/data/'}],
         "@graph": graphs
     }
Пример #10
0
def assembl_register_view(request):
    slug = request.matchdict.get('discussion_slug', "")
    next_view = handle_next_view(request)
    if not request.params.get('email'):
        if request.scheme == "http"\
                and asbool(config.get("accept_secure_connection")):
            return HTTPFound(get_global_base_url(True) + request.path_qs)
        response = get_login_context(request)
        return response
    forget(request)
    session = AgentProfile.default_db
    localizer = request.localizer
    name = request.params.get('name', '').strip()
    if not name or len(name) < 3:
        return dict(get_default_context(request),
            error=localizer.translate(_(
                "Please use a name of at least 3 characters")))
    password = request.params.get('password', '').strip()
    password2 = request.params.get('password2', '').strip()
    email = request.params.get('email', '').strip()
    if not is_email(email):
        return dict(get_default_context(request),
                    error=localizer.translate(_(
                        "This is not a valid email")))
    email = EmailString.normalize_email_case(email)
    # Find agent account to avoid duplicates!
    if session.query(AbstractAgentAccount).filter_by(
            email_ci=email, verified=True).count():
        return dict(get_default_context(request),
                    error=localizer.translate(_(
                        "We already have a user with this email.")))
    if password != password2:
        return dict(get_default_context(request),
                    error=localizer.translate(_(
                        "The passwords should be identical")))

    # TODO: Validate password quality
    # otherwise create.
    validate_registration = asbool(config.get(
        'assembl.validate_registration_emails'))

    user = User(
        name=name,
        password=password,
        verified=not validate_registration,
        creation_date=datetime.utcnow()
    )
    email_account = EmailAccount(
        email=email,
        verified=not validate_registration,
        profile=user
    )
    session.add(user)
    session.add(email_account)
    discussion = discussion_from_request(request)
    if discussion:
        permissions = get_permissions(Everyone, discussion.id)
        if not (P_SELF_REGISTER in permissions or
                P_SELF_REGISTER_REQUEST in permissions):
            discussion = None
    if discussion:
        _now = datetime.utcnow()
        agent_status = AgentStatusInDiscussion(
            agent_profile=user, discussion=discussion,
            first_visit=_now, last_visit=_now,
            user_created_on_this_discussion=True)
        session.add(agent_status)
    session.flush()
    if not validate_registration:
        if asbool(config.get('pyramid.debug_authorization')):
            # for debugging purposes
            from assembl.auth.password import email_token
            print "email token:", request.route_url(
                'user_confirm_email', token=email_token(email_account))
        headers = remember(request, user.id)
        user.last_login = datetime.utcnow()
        request.response.headerlist.extend(headers)
        if discussion:
            maybe_auto_subscribe(user, discussion)
        # TODO: Tell them to expect an email.
        return HTTPFound(location=next_view)
    return HTTPFound(location=maybe_contextual_route(
        request, 'confirm_emailid_sent', email_account_id=email_account.id))
Пример #11
0
def get_default_context(request, **kwargs):
    kwargs.update(default_context)
    from ..auth.util import get_user, get_current_discussion
    if request.scheme == "http"\
            and asbool(config.get("require_secure_connection")):
        raise HTTPFound(get_global_base_url(True) + request.path_qs)
    react_url = '/static2'
    use_webpack_server = asbool(config.get('use_webpack_server'))
    if use_webpack_server:
        # Allow to specify a distinct webpack_host in configuration.
        # Useful for development tests of social auth through a reverse tunnel.
        # Otherwise fallback on public_hostname, then localhost.
        webpack_host = config.get(
            'webpack_host',
            config.get('public_hostname',
                       'localhost'))
        react_url = 'http://%s:%d' % (
            webpack_host,
            int(config.get('webpack_port', 8000)))
    socket_proxied = asbool(config.get('changes_websocket_proxied'))
    websocket_port = None if socket_proxied \
        else config.get('changes_websocket_port')
    secure_socket = socket_proxied and (
        asbool(config.get("require_secure_connection")) or (asbool(config.get("accept_secure_connection")) and request.url.startswith('https:')))
    application_url = get_global_base_url()
    socket_url = get_global_base_url(
        secure_socket, websocket_port) + config.get('changes_prefix')

    localizer = request.localizer
    _ = TranslationStringFactory('assembl')
    user = get_user(request)
    if user and user.username:
        user_profile_edit_url = request.route_url(
            'profile_user', type='u', identifier=user.username.username)
    elif user:
        user_profile_edit_url = request.route_url(
            'profile_user', type='id', identifier=user.id)
    else:
        user_profile_edit_url = None

    web_analytics_piwik_script = config.get(
        'web_analytics_piwik_script') or False
    discussion = get_current_discussion()
    if (web_analytics_piwik_script and discussion and discussion.web_analytics_piwik_id_site):
        web_analytics_piwik_script = web_analytics_piwik_script % (
            discussion.web_analytics_piwik_id_site,
            discussion.web_analytics_piwik_id_site)
    else:
        web_analytics_piwik_script = False

    web_analytics_piwik_custom_variable_size = config.get('web_analytics_piwik_custom_variable_size')
    if not web_analytics_piwik_custom_variable_size:
        web_analytics_piwik_custom_variable_size = 5

    help_url = config.get('help_url') or ''
    if discussion and discussion.help_url:
        help_url = discussion.help_url
    if help_url and "%s" in help_url:
        help_url = help_url % localizer.locale_name

    first_login_after_auto_subscribe_to_notifications = False
    if (user and discussion and discussion.id and user.is_first_visit and
        discussion.subscribe_to_notifications_on_signup and
            user.is_participant(discussion.id)):
        first_login_after_auto_subscribe_to_notifications = True
    locales = config.get('available_languages').split()
    countries_for_locales = defaultdict(set)
    for locale in locales:
        countries_for_locales[get_language(locale)].add(get_country(locale))
    show_locale_country = {
        locale: (len(countries_for_locales[get_language(locale)]) > 1)
        for locale in locales}
    jedfilename = os.path.join(
        os.path.dirname(__file__), '..', 'locale',
        localizer.locale_name, 'LC_MESSAGES', 'assembl.jed.json')
    if not os.path.exists(jedfilename) and '_' in localizer.locale_name:
        jedfilename = os.path.join(
            os.path.dirname(__file__), '..', 'locale',
            get_language(localizer.locale_name), 'LC_MESSAGES',
            'assembl.jed.json')
    assert os.path.exists(jedfilename)

    from ..models.facebook_integration import language_sdk_existance
    fb_lang_exists, fb_locale = language_sdk_existance(
        get_language(localizer.locale_name), countries_for_locales)

    def process_export_list(ls):
        return map(lambda s: s.strip(), ls.split(","))

    social_settings = {
        'fb_export_permissions': config.get('facebook.export_permissions'),
        'fb_debug': asbool(config.get('facebook.debug_mode')),
        'fb_app_id': config.get('facebook.consumer_key'),
        'fb_api_version': config.get('facebook.api_version') or '2.2',
        'supported_exports': process_export_list(
            config.get('supported_exports_list'))
    }

    # A container for all analytics related settings. All future
    # analytics based settings that will be exposed to the templates
    # should be included in this dictionary
    analytics_settings = {
        'enabled': True if web_analytics_piwik_script else False,
    }

    if analytics_settings.get('enabled', False):
        analytics_settings['piwik'] = {
            'script': web_analytics_piwik_script,
            'host': config.get('piwik_host')
        }

    analytics_url = config.get('web_analytics_piwik_url', None)

    get_route = create_get_route(request, discussion)
    providers = get_provider_data(get_route)

    errors = request.session.pop_flash()
    if kwargs.get('error', None):
        errors.append(kwargs['error'])
    if errors:
        kwargs['error'] = '<br />'.join(errors)
    messages = request.session.pop_flash('message')
    if messages:
        kwargs['messages'] = '<br />'.join(messages)

    admin_email = config.get('assembl.admin_email', None)
    # If an admin_email is improperly configured, raise an error
    if admin_email is None or admin_email is '':
        raise HTTPInternalServerError(explanation="Assembl MUST have an admin_email configured in order to operate.")

    theme_name, theme_relative_path = get_theme_info(discussion)
    node_env = os.getenv('NODE_ENV', 'production')
    under_test = bool(config.get('under_test') or False)
    base = dict(
        kwargs,
        request=request,
        application_url=application_url,
        get_route=get_route,
        user=user,
        templates=get_template_views(),
        discussion=discussion or {},  # Templates won't load without a discussion object
        preferences=discussion.preferences if discussion else {},
        user_profile_edit_url=user_profile_edit_url,
        locale=localizer.locale_name,
        locales=locales,
        fb_lang_exists=fb_lang_exists,
        fb_locale=fb_locale,
        social_settings=social_settings,
        show_locale_country=show_locale_country,
        NODE_ENV=node_env,
        theme_name=theme_name,
        theme_relative_path=theme_relative_path,
        minified_js=config.get('minified_js') or False,
        web_analytics=analytics_settings,
        analytics_url=analytics_url,
        help_url=help_url,
        socket_url=socket_url,
        REACT_URL=react_url,
        elasticsearch_lang_indexes=config.get('elasticsearch_lang_indexes', 'en fr'),
        first_login_after_auto_subscribe_to_notifications=first_login_after_auto_subscribe_to_notifications,
        sentry_dsn=config.get('sentry_dsn', ''),
        activate_tour=str(config.get('activate_tour') or False).lower(),
        providers=providers,
        providers_json=json.dumps(providers),
        translations=io.open(jedfilename, encoding='utf-8').read(),
        admin_email=admin_email,
        under_test=under_test
    )

    base.update({
        "opengraph_locale": get_opengraph_locale(request),
        "get_description": get_description(request),
        "get_landing_page_image": get_landing_page_image(),
        "private_social_sharing": private_social_sharing(),
        "get_topic": get_topic(request),
        "get_discussion_url": get_discussion_url(),
        "discussion_title": discussion_title(),
    })
    base.update(get_v1_resources_hash())
    return base
Пример #12
0
 def get_url(self, *args):
     return get_global_base_url(True)
Пример #13
0
def get_default_context(request, **kwargs):
    kwargs.update(default_context)
    from ..auth.util import get_user, get_current_discussion
    if request.scheme == "http"\
            and asbool(config.get("require_secure_connection")):
        raise HTTPFound(get_global_base_url(True) + request.path_qs)
    react_url = '/static2'
    use_webpack_server = asbool(config.get('use_webpack_server'))
    if use_webpack_server:
        # Allow to specify a distinct webpack_host in configuration.
        # Useful for development tests of social auth through a reverse tunnel.
        # Otherwise fallback on public_hostname, then localhost.
        webpack_host = config.get('webpack_host',
                                  config.get('public_hostname', 'localhost'))
        react_url = 'http://%s:%d' % (webpack_host,
                                      int(config.get('webpack_port', 8000)))
    socket_proxied = asbool(config.get('changes_websocket_proxied'))
    websocket_port = None if socket_proxied \
        else config.get('changes_websocket_port')
    secure_socket = socket_proxied and (
        asbool(config.get("require_secure_connection")) or
        (asbool(config.get("accept_secure_connection"))
         and request.url.startswith('https:')))
    application_url = get_global_base_url()
    socket_url = get_global_base_url(
        secure_socket, websocket_port) + config.get('changes_prefix')

    localizer = request.localizer
    _ = TranslationStringFactory('assembl')
    user = get_user(request)
    if user and user.username:
        user_profile_edit_url = request.route_url(
            'profile_user', type='u', identifier=user.username.username)
    elif user:
        user_profile_edit_url = request.route_url('profile_user',
                                                  type='id',
                                                  identifier=user.id)
    else:
        user_profile_edit_url = None

    web_analytics_piwik_script = config.get(
        'web_analytics_piwik_script') or False
    discussion = get_current_discussion()
    if (web_analytics_piwik_script and discussion
            and discussion.web_analytics_piwik_id_site):
        web_analytics_piwik_script = web_analytics_piwik_script % (
            discussion.web_analytics_piwik_id_site,
            discussion.web_analytics_piwik_id_site)
    else:
        web_analytics_piwik_script = False

    web_analytics_piwik_custom_variable_size = config.get(
        'web_analytics_piwik_custom_variable_size')
    if not web_analytics_piwik_custom_variable_size:
        web_analytics_piwik_custom_variable_size = 5

    help_url = config.get('help_url') or ''
    if discussion and discussion.help_url:
        help_url = discussion.help_url
    if help_url and "%s" in help_url:
        help_url = help_url % localizer.locale_name

    first_login_after_auto_subscribe_to_notifications = False
    if (user and discussion and discussion.id and user.is_first_visit
            and discussion.subscribe_to_notifications_on_signup
            and user.is_participant(discussion.id)):
        first_login_after_auto_subscribe_to_notifications = True
    locales = config.get('available_languages').split()
    countries_for_locales = defaultdict(set)
    for locale in locales:
        countries_for_locales[get_language(locale)].add(get_country(locale))
    show_locale_country = {
        locale: (len(countries_for_locales[get_language(locale)]) > 1)
        for locale in locales
    }
    jedfilename = os.path.join(os.path.dirname(__file__), '..', 'locale',
                               localizer.locale_name, 'LC_MESSAGES',
                               'assembl.jed.json')
    if not os.path.exists(jedfilename) and '_' in localizer.locale_name:
        jedfilename = os.path.join(os.path.dirname(__file__), '..', 'locale',
                                   get_language(localizer.locale_name),
                                   'LC_MESSAGES', 'assembl.jed.json')
    assert os.path.exists(jedfilename)

    from ..models.facebook_integration import language_sdk_existance
    fb_lang_exists, fb_locale = language_sdk_existance(
        get_language(localizer.locale_name), countries_for_locales)

    def process_export_list(ls):
        return map(lambda s: s.strip(), ls.split(","))

    social_settings = {
        'fb_export_permissions':
        config.get('facebook.export_permissions'),
        'fb_debug':
        asbool(config.get('facebook.debug_mode')),
        'fb_app_id':
        config.get('facebook.consumer_key'),
        'fb_api_version':
        config.get('facebook.api_version') or '2.2',
        'supported_exports':
        process_export_list(config.get('supported_exports_list'))
    }

    # A container for all analytics related settings. All future
    # analytics based settings that will be exposed to the templates
    # should be included in this dictionary
    analytics_settings = {
        'enabled': True if web_analytics_piwik_script else False,
    }

    if analytics_settings.get('enabled', False):
        analytics_settings['piwik'] = {
            'script': web_analytics_piwik_script,
            'host': config.get('piwik_host')
        }

    analytics_url = config.get('web_analytics_piwik_url', None)

    get_route = create_get_route(request, discussion)
    providers = get_provider_data(get_route)

    errors = request.session.pop_flash()
    if kwargs.get('error', None):
        errors.append(kwargs['error'])
    if errors:
        kwargs['error'] = '<br />'.join(errors)
    messages = request.session.pop_flash('message')
    if messages:
        kwargs['messages'] = '<br />'.join(messages)

    admin_email = config.get('assembl.admin_email', None)
    # If an admin_email is improperly configured, raise an error
    if admin_email is None or admin_email is '':
        raise HTTPInternalServerError(
            explanation=
            "Assembl MUST have an admin_email configured in order to operate.")

    theme_name, theme_relative_path = get_theme_info(discussion)
    node_env = os.getenv('NODE_ENV', 'production')
    under_test = bool(config.get('under_test') or False)
    base = dict(
        kwargs,
        request=request,
        application_url=application_url,
        get_route=get_route,
        user=user,
        templates=get_template_views(),
        discussion=discussion
        or {},  # Templates won't load without a discussion object
        preferences=discussion.preferences if discussion else {},
        user_profile_edit_url=user_profile_edit_url,
        locale=localizer.locale_name,
        locales=locales,
        fb_lang_exists=fb_lang_exists,
        fb_locale=fb_locale,
        social_settings=social_settings,
        show_locale_country=show_locale_country,
        NODE_ENV=node_env,
        theme_name=theme_name,
        theme_relative_path=theme_relative_path,
        minified_js=config.get('minified_js') or False,
        web_analytics=analytics_settings,
        analytics_url=analytics_url,
        help_url=help_url,
        socket_url=socket_url,
        REACT_URL=react_url,
        elasticsearch_lang_indexes=config.get('elasticsearch_lang_indexes',
                                              'en fr'),
        first_login_after_auto_subscribe_to_notifications=
        first_login_after_auto_subscribe_to_notifications,
        sentry_dsn=config.get('sentry_dsn', ''),
        activate_tour=str(config.get('activate_tour') or False).lower(),
        providers=providers,
        providers_json=json.dumps(providers),
        translations=io.open(jedfilename, encoding='utf-8').read(),
        admin_email=admin_email,
        under_test=under_test)

    base.update({
        "opengraph_locale": get_opengraph_locale(request),
        "get_description": get_description(request),
        "get_landing_page_image": get_landing_page_image(),
        "private_social_sharing": private_social_sharing(),
        "get_topic": get_topic(request),
        "get_discussion_url": get_discussion_url(),
        "discussion_title": discussion_title(),
    })

    return base
Пример #14
0
def assembl_register_view(request):
    slug = request.matchdict.get('discussion_slug', "")
    next_view = handle_next_view(request)
    if not request.params.get('email'):
        if request.scheme == "http"\
                and asbool(config.get("accept_secure_connection")):
            return HTTPFound(get_global_base_url(True) + request.path_qs)
        response = get_login_context(request)
        return response
    forget(request)
    session = AgentProfile.default_db
    localizer = request.localizer
    name = request.params.get('name', '').strip()
    if not name or len(name) < 3:
        return dict(get_default_context(request),
            error=localizer.translate(_(
                "Please use a name of at least 3 characters")))
    password = request.params.get('password', '').strip()
    password2 = request.params.get('password2', '').strip()
    email = request.params.get('email', '').strip()
    if not is_email(email):
        return dict(get_default_context(request),
                    error=localizer.translate(_(
                        "This is not a valid email")))
    email = EmailString.normalize_email_case(email)
    # Find agent account to avoid duplicates!
    if session.query(AbstractAgentAccount).filter_by(
            email_ci=email, verified=True).count():
        return dict(get_default_context(request),
                    error=localizer.translate(_(
                        "We already have a user with this email.")))
    if password != password2:
        return dict(get_default_context(request),
                    error=localizer.translate(_(
                        "The passwords should be identical")))

    # TODO: Validate password quality
    # otherwise create.
    validate_registration = asbool(config.get(
        'assembl.validate_registration_emails'))

    user = User(
        name=name,
        password=password,
        verified=not validate_registration,
        creation_date=datetime.utcnow()
    )
    email_account = EmailAccount(
        email=email,
        verified=not validate_registration,
        profile=user
    )
    session.add(user)
    session.add(email_account)
    discussion = discussion_from_request(request)
    if discussion:
        permissions = get_permissions(Everyone, discussion.id)
        if not (P_SELF_REGISTER in permissions or
                P_SELF_REGISTER_REQUEST in permissions):
            discussion = None
    if discussion:
        _now = datetime.utcnow()
        agent_status = AgentStatusInDiscussion(
            agent_profile=user, discussion=discussion,
            first_visit=_now, last_visit=_now,
            user_created_on_this_discussion=True)
        session.add(agent_status)
    session.flush()
    if not validate_registration:
        if asbool(config.get('pyramid.debug_authorization')):
            # for debugging purposes
            from assembl.auth.password import email_token
            print "email token:", request.route_url(
                'user_confirm_email', token=email_token(email_account))
        headers = remember(request, user.id)
        user.successful_login()
        request.response.headerlist.extend(headers)
        if discussion:
            maybe_auto_subscribe(user, discussion)
        # TODO: Tell them to expect an email.
        return HTTPFound(location=next_view)
    return HTTPFound(location=maybe_contextual_route(
        request, 'confirm_emailid_sent', email_account_id=email_account.id))