Exemple #1
0
def on_auth_sign_up(user: auth.AbstractUser):
    # Set session notification
    router.session().add_success_message(
        lang.t('auth_ui@registration_form_success'))

    # Send a confirmation email to the user
    if auth.is_sign_up_confirmation_required():
        msg = tpl.render(
            'auth_ui@mail/{}/sign-up'.format(lang.get_current()), {
                'user':
                user,
                'confirm_url':
                router.rule_url('auth_ui@sign_up_confirm',
                                {'code': user.confirmation_hash})
                if not user.is_confirmed else None
            })
        mail.Message(user.login, lang.t('auth_ui@confirm_registration'),
                     msg).send()

    # Send a notification emails to admins
    if auth.is_sign_up_admins_notification_enabled():
        for admin in auth.get_admin_users():
            msg = tpl.render(
                'auth_ui@mail/{}/sign-up-admin-notify'.format(
                    lang.get_current()), {
                        'admin': admin,
                        'user': user,
                    })
            mail.Message(admin.login,
                         lang.t('auth_ui@registration_admin_notify'),
                         msg).send()
Exemple #2
0
    def odm_ui_widget_select_search_entities(self, f: odm.MultiModelFinder,
                                             args: dict):
        f.eq('language', args.get('language', lang.get_current()))

        query = args.get('q')
        if query:
            f.regex('title', '{}'.format(query), True)
Exemple #3
0
    def exec(self):
        reporter = auth.get_current_user()
        if reporter.is_anonymous:
            raise self.forbidden()

        model = self.arg('model')

        try:
            entity = _api.dispense(model, self.arg('uid'))
        except odm.error.EntityNotFound:
            raise self.not_found()

        tpl_name = 'content@mail/{}/abuse'.format(lang.get_current())
        subject = lang.t('content@mail_subject_abuse')
        for recipient in auth.find_users(
                query.Query(query.Eq('status', 'active'))):
            if not entity.odm_auth_check_entity_permissions(
                [PERM_MODIFY, PERM_DELETE], recipient):
                continue

            body = tpl.render(tpl_name, {
                'reporter': reporter,
                'recipient': recipient,
                'entity': entity
            })
            mail.Message(entity.author.login, subject, body).send()

        return {'message': lang.t('content@abuse_receipt_confirm')}
    def _on_submit(self):
        try:
            user = auth.get_user(self.val('login'))
            if user.status != auth.USER_STATUS_ACTIVE:
                return

            token = util.random_password(64, True)
            _RESET_TOKENS_POOL.put(token, user.login, _RESET_TOKEN_TTL)
            reset_url = router.rule_url('auth_ui_password@reset',
                                        {'token': token})
            msg_body = tpl.render(
                'auth_ui_password@mail/{}/reset-password'.format(
                    lang.get_current()), {
                        'user': user,
                        'reset_url': reset_url
                    })
            mail.Message(
                user.login,
                lang.t('auth_ui_password@reset_password_mail_subject'),
                msg_body).send()

            router.session().add_info_message(
                lang.t('auth_ui_password@check_email_for_instructions'))

        except auth.error.UserNotFound:
            pass
Exemple #5
0
    def odm_ui_m_form_setup(self, frm: form.Form):
        """Hook
        """
        if not self.is_new and self.has_field('language') and self.language != lang.get_current():
            raise errors.NotFound('Entity for this language does not exist')

        frm.css += ' content-m-form'
Exemple #6
0
def find(model: str, **kwargs) -> odm.SingleModelFinder:
    """Instantiate content entities finder
    """
    check_publish_time = kwargs.get('check_publish_time', True)
    language = kwargs.get('language', lang.get_current())
    status = kwargs.get('status', [CONTENT_STATUS_PUBLISHED])

    if not is_model_registered(model):
        raise KeyError(f"Model '{model}' is not registered as content model")

    f = odm.find(model)
    mock = f.mock  # type: Content

    # Publish time
    if mock.has_field('publish_time'):
        f.sort([('publish_time', odm.I_DESC)])
        if check_publish_time:
            f.lte('publish_time', datetime.now()).no_cache('publish_time')
    else:
        f.sort([('_modified', odm.I_DESC)])

    # Language
    if language != '*' and mock.has_field('language'):
        f.eq('language', language)

    # Status
    if status != '*' and mock.has_field('status'):
        if isinstance(status, str):
            status = [status]
        elif not isinstance(status, (list, tuple)):
            raise TypeError(f"'status' must be a string, list or tuple, not {type(status)}")

        f.inc('status', status)

    return f
Exemple #7
0
def on_auth_user_status_change(user: auth.AbstractUser, status: str):
    if auth.is_user_status_change_notification_enabled():
        msg = tpl.render(
            'auth_ui@mail/{}/user-status-change'.format(lang.get_current()), {
                'user': user,
                'status': status,
            })
        mail.Message(user.login, lang.t('auth_ui@user_status_change_notify'),
                     msg).send()
Exemple #8
0
 def odm_http_api_get_entities(cls, finder: odm.SingleModelFinder, args: routing.ControllerArgs):
     """Called by 'odm_http_api@get_entities' route
     """
     if 'search' in args:
         query = args['search']
         if args.get('search_by') == 'title' and finder.mock.has_field('title'):
             finder.regex('title', query)
         else:
             finder.text(query, lang.get_current())
Exemple #9
0
def dispense(model: str,
             title: str,
             alias: str = None,
             language: str = None,
             parent: Term = None) -> Term:
    """Dispense a new term or raise exception if term with specified alias already exists
    """
    if alias and get(model, alias=alias, language=language):
        raise _error.TermExists(model, alias, language or lang.get_current())

    term = odm.dispense(model)  # type: Term
    term.title = title.strip()
    term.parent = parent
    if term.has_field('language'):
        term.language = language or lang.get_current()
    if term.has_field('alias') and alias:
        term.alias = alias or util.transform_str_2(title, language)

    return term
Exemple #10
0
def find(content_language: str = None) -> _odm.Finder:
    """Get ODM finder for 'content_import' model.
    """
    f = _odm.find('content_import')

    if content_language is None:
        f.eq('content_language', _lang.get_current())
    elif content_language != '*':
        f.eq('content_language', content_language)

    return f
Exemple #11
0
 def _setup_fields(self):
     """Hook
     """
     self.define_field(odm.field.String('title', is_required=True))
     self.define_field(odm.field.String('alias', is_required=True))
     self.define_field(
         odm.field.String('language',
                          is_required=True,
                          default=lang.get_current()))
     self.define_field(odm.field.Integer('weight'))
     self.define_field(odm.field.Integer('order'))
     self.define_field(file_storage_odm.field.Image('image'))
Exemple #12
0
    def _content_notify_author_status_change(self):
        """Notify content author about status change by another user
        """
        if auth.get_current_user() == self.author:
            return

        m_subject = lang.t('content@content_status_change_mail_subject')
        m_body = tpl.render('content@mail/{}/content-status-change'.format(lang.get_current()), {
            'entity': self,
            'status': self.t('content_status_{}_{}'.format(self.model, self.status)),
        })
        mail.Message(self.author.login, m_subject, m_body).send()
    def __init__(self):
        super().__init__()

        self.define_option(console.option.Bool('short'))
        self.define_option(console.option.Bool('no-html'))
        self.define_option(console.option.Bool('no-tags'))
        self.define_option(console.option.Bool('no-sections'))
        self.define_option(console.option.Str('author'))
        self.define_option(console.option.Str('lang', default=lang.get_current()))
        self.define_option(console.option.PositiveInt('num', default=10))
        self.define_option(console.option.PositiveInt('title-len', default=7))
        self.define_option(console.option.PositiveInt('description-len', default=28))
        self.define_option(console.option.PositiveInt('images', default=1))
Exemple #14
0
    def _content_notify_admins_waiting_status(self):
        """Notify administrators about waiting content
        """
        if auth.get_current_user().is_admin or self.status != CONTENT_STATUS_WAITING:
            return

        for u in auth.get_admin_users():
            m_subject = lang.t('content@content_waiting_mail_subject')
            m_body = tpl.render('content@mail/{}/waiting-content'.format(lang.get_current()), {
                'user': u,
                'entity': self,
            })
            mail.Message(u.login, m_subject, m_body).send()
Exemple #15
0
def on_comments_create_comment(comment: comments.model.AbstractComment):
    """comments.create_comment
    """
    entity = _api.find_by_url(comment.thread_uid)
    if comment.is_reply or not entity or comment.author == entity.author:
        return

    tpl_name = 'content@mail/{}/comment'.format(lang.get_current())
    subject = lang.t('content@mail_subject_new_comment')
    body = tpl.render(tpl_name, {'comment': comment, 'entity': entity})
    m_from = '{} <{}>'.format(comment.author.first_last_name,
                              mail.mail_from()[1])
    mail.Message(entity.author.login, subject, body, m_from).send()
Exemple #16
0
    def _render_sidebar(sidebar: admin.SideBar) -> htmler.Aside:
        """Render admin's sidebar
        """
        aside = htmler.Aside(css='main-sidebar')
        sidebar_section_em = htmler.Section(css='sidebar')
        aside.append_child(sidebar_section_em)

        root_menu_ul = htmler.Ul(css='sidebar-menu')
        sidebar_section_em.append_child(root_menu_ul)

        sections, menus = sidebar.items

        # Do actual rendering
        for section in sections:
            li = htmler.Li(lang.t(section['title']),
                           css='header',
                           data_section_weight=section['weight'])
            root_menu_ul.append_child(li)

            # Building top level menu item
            for menu in menus[section['sid']]:
                # Link
                a = htmler.A(
                    href=router.url(menu['path'], lang=lang.get_current()))

                # Icon
                if menu['icon']:
                    a.append_child(htmler.I(css=menu['icon']))

                # Title
                a.append_child(htmler.Span(lang.t(menu['title'])))

                # Label
                if menu['label']:
                    label_class = 'label pull-right label-' + menu[
                        'label_class']
                    a.append_child(
                        htmler.Span(lang.t(menu['label']), css=label_class))

                # List element
                li = htmler.Li(data_menu_weight=menu['weight'])

                # Active state
                if menu['active']:
                    li.set_attr('css', 'active')

                li.append_child(a)
                root_menu_ul.append_child(li)

        return aside
Exemple #17
0
def comments_report_comment(uid: str):
    try:
        comment = comments.get_comment(uid, 'pytsite')
    except comments.error.CommentNotExist:
        return

    tpl_name = 'comments_odm@mail/{}/report'.format(lang.get_current())
    m_subject = lang.t('comments_odm@mail_subject_report_comment')

    for user in auth.find_users(query.Query(query.Eq('status', 'active'))):
        if not user.has_permission('*****@*****.**'):
            continue

        m_body = tpl.render(tpl_name, {'comment': comment, 'recipient': user})
        mail.Message(user.login, m_subject, m_body).send()
Exemple #18
0
    def odm_auth_permissions(self) -> List[str]:
        """Hook
        """
        r = [PERM_CREATE, CONTENT_PERM_VIEW, PERM_MODIFY, PERM_DELETE,
             CONTENT_PERM_VIEW_OWN, PERM_MODIFY_OWN, PERM_DELETE_OWN]

        if self.has_field('status') and CONTENT_STATUS_WAITING in self.content_statuses():
            r.append(CONTENT_PERM_BYPASS_MODERATION)

        if self.has_field('localization_' + lang.get_current()):
            r.append(CONTENT_PERM_SET_LOCALIZATION)

        if self.has_field('publish_time'):
            r.append(CONTENT_PERM_SET_PUBLISH_TIME)

        return r
 def odm_ui_browser_setup(cls, browser):
     """Hook.
     :type browser: odm_ui._browser.Browser
     """
     browser.default_sort_field = 'driver'
     browser.finder_adjust = lambda f: f.eq('content_language', _lang.get_current())
     browser.data_fields = [
         ('content_model', 'content_import@content_model'),
         ('driver', 'content_import@driver'),
         ('driver_opts', 'content_import@driver_opts'),
         ('content_section', 'content_import@content_section'),
         ('content_author', 'content_import@content_author'),
         ('enabled', 'content_import@enabled'),
         ('errors', 'content_import@errors'),
         ('paused_till', 'content_import@paused_till'),
     ]
Exemple #20
0
def create_comment(thread_id: str,
                   body: str,
                   author: auth.model.AbstractUser,
                   status: str = 'published',
                   parent_uid: str = None,
                   driver_name: str = None) -> _model.AbstractComment:
    """Create a new comment
    """
    # Check min length
    if len(body) < get_comment_min_body_length():
        raise _error.CommentTooShort(lang.t('comments@error_body_too_short'))

    # Check max length
    if len(body) > get_comment_max_body_length():
        raise _error.CommentTooLong(lang.t('comments@error_body_too_long'))

    # Check status
    if status not in get_comment_statuses():
        raise _error.InvalidCommentStatus(
            "'{}' is not a valid comment's status.".format(status))

    # Load driver
    driver = get_driver(driver_name)

    # Create comment
    comment = driver.create_comment(thread_id, body, author, status,
                                    parent_uid)
    events.fire('comments@create_comment', comment=comment)

    # Send email notification about reply
    if reg.get('comments.email_notify', True) and comment.is_reply:
        parent_comment = get_comment(comment.parent_uid)
        if comment.author != parent_comment.author:
            tpl_name = 'comments@mail/{}/reply'.format(lang.get_current())
            m_subject = lang.t('comments@mail_subject_new_reply')
            m_body = tpl.render(
                tpl_name, {
                    'reply': comment,
                    'comment': get_comment(comment.parent_uid, driver_name)
                })
            m_from = '{} <{}>'.format(author.first_last_name,
                                      mail.mail_from()[1])

            mail.Message(parent_comment.author.login, m_subject, m_body,
                         m_from).send()

    return comment
Exemple #21
0
def on_dispatch():
    settings = reg.get('app')

    # Add meta tags for home page
    if settings and router.is_base_url():
        lng = lang.get_current()
        for s_key in ['title', 'description', 'keywords']:
            s_full_key = 'home_{}_{}'.format(s_key, lng)
            if s_full_key in settings:
                s_val = settings[s_full_key]
                if isinstance(s_val, list):
                    s_val = ','.join(s_val)
                metatag.t_set(s_key, s_val)

                if s_key in ['title', 'description']:
                    metatag.t_set('og:' + s_key, s_val)
                    metatag.t_set('twitter:' + s_key, s_val)
Exemple #22
0
    def _on_pre_save(self, **kwargs):
        """Hook
        """
        super()._on_pre_save(**kwargs)

        c_user = auth.get_current_user()

        # Content must be reviewed by moderator
        if self.has_field('status'):
            sts = self.content_statuses()
            if CONTENT_STATUS_WAITING in sts and CONTENT_STATUS_PUBLISHED in sts \
                    and self.status == CONTENT_STATUS_PUBLISHED \
                    and not self.odm_auth_check_entity_permissions(CONTENT_PERM_BYPASS_MODERATION):
                self.f_set('status', CONTENT_STATUS_WAITING)

        # Language is required
        if not self.language or not self.f_get('language_db'):
            self.f_set('language', lang.get_current())

        # Author is required
        if self.has_field('author') and self.get_field('author').is_required and not self.author:
            if not c_user.is_anonymous:
                self.f_set('author', c_user)
            else:
                raise RuntimeError('Cannot assign author, because current user is anonymous')

        # Extract inline images from the body
        if self.has_field('body') and self.has_field('images'):
            body, images = _extract_images(self)

            # If new images has been extracted
            if images:
                self.f_set('body', body)
                self.f_set('images', list(self.images) + images)

        # Extract inline videos from the body
        if self.has_field('body') and self.has_field('video_links'):
            body, video_links = _extract_video_links(self)

            # If new video links has been extracted
            if video_links:
                self.f_set('body', body)
                self.f_set('video_links', list(self.video_links) + video_links)

        events.fire('[email protected]_save', entity=self)
        events.fire('content@entity.{}.pre_save.'.format(self.model), entity=self)
Exemple #23
0
    def _sanitize_nickname(self, s: str) -> str:
        """Generate unique nickname.
        """
        cnt = 0
        s = util.transform_str_2(s[:32], lang.get_current())
        nickname = s
        while True:
            try:
                user = auth.get_user(nickname=nickname)

                # If nickname of THIS user was not changed
                if user.nickname == self.f_get('nickname'):
                    return s

            except auth.error.UserNotFound:
                return nickname

            cnt += 1
            nickname = s + '-' + str(cnt)
    def exec(self) -> dict:
        if not auth.get_current_user().is_admin:
            raise self.forbidden()

        e_type = self.arg('e_type')
        sort_order = -1 if self.arg('order') == 'desc' else 1

        q = None
        total = 0
        limit = self.arg('limit', 10)
        skip = self.arg('offset', 0)
        rows = []

        if self.arg('search'):
            q = query.Query(query.Text(self.arg('search'), lang.get_current()))

        if e_type == 'role':
            total = auth.count_roles() - 2  # Minus admin and dev

            f = auth.find_roles(q,
                                sort=[(self.arg('sort', 'name'), sort_order)],
                                limit=limit,
                                skip=skip)
            for role in f:
                if role.name in ('admin', 'dev'):
                    continue

                rows.append(self._get_role_row(role))

        elif e_type == 'user':
            total = auth.count_users()

            for user in auth.find_users(q,
                                        sort=[(self.arg('sort',
                                                        'login'), sort_order)],
                                        limit=limit,
                                        skip=skip):
                rows.append(self._get_user_row(user))

        return {
            'rows': rows,
            'total': total,
        }
Exemple #25
0
def find(model: str, language: str = None):
    """Get finder for the taxonomy model
    """
    if not is_model_registered(model):
        raise RuntimeError(
            "Model '{}' is not registered as taxonomy model.".format(model))

    f = odm.find(model)

    if f.mock.has_field('weight'):
        f.sort([('weight', odm.I_DESC)])
    elif f.mock.has_field('order'):
        f.sort([('order', odm.I_ASC)])

    if not language:
        f.eq('language', lang.get_current())
    elif language != '*':
        f.eq('language', language)

    return f
Exemple #26
0
    def exec(self) -> dict:
        lng = _lang.get_current()
        email = _validation.rule.Email(value=self.arg('email')).validate()

        # Search for subscriber
        s = _odm.find('content_digest_subscriber').eq('email', email).eq(
            'language', lng).first()

        # Create new subscriber
        if not s:
            s = _odm.dispense('content_digest_subscriber').f_set(
                'email', email).f_set('language', lng).save()

        # Enable subscriber
        s.f_set('enabled', True).save()

        return {
            '__alert': _lang.t('content_digest@digest_subscription_success'),
            '__reset': True,
        }
Exemple #27
0
def get(model: str,
        title: str = None,
        alias: str = None,
        language: str = None,
        exceptions: bool = False) -> Optional[Term]:
    """Find a term by title
    """
    if not (title or alias):
        raise ValueError('At least title or alias argument must be specified')

    f = find(model, language)
    if title:
        f.regex('title', '^{}$'.format(title), True)
    if alias:
        f.eq('alias', alias)

    term = f.first()

    if not term and exceptions:
        raise _error.TermNotExist(model, alias, language or lang.get_current())

    return term
Exemple #28
0
    def __init__(self, uid: str, **kwargs):
        """Init
        """
        self._uid = uid
        self._inherit_cid = kwargs.get('inherit_cid', True)
        self._wrap_em = kwargs.get('wrap_em',
                                   htmler.Div())  # type: htmler.Element
        self._name = kwargs.get('name', uid)
        self._language = kwargs.get('language', lang.get_current())
        self._weight = kwargs.get('weight', 0)
        self._default = kwargs.get('default')
        self._value = None  # Wil be set later
        self._label = kwargs.get('label')
        self._title = kwargs.get('title')
        self._label_hidden = kwargs.get('label_hidden', False)
        self._label_disabled = kwargs.get('label_disabled', False)
        self._placeholder = kwargs.get('placeholder')
        self._css = kwargs.get('css', '')
        self._data = kwargs.get('data', {})
        self._has_messages = kwargs.get('has_messages', True)
        self._has_success = kwargs.get('has_success', False)
        self._has_warning = kwargs.get('has_warning', False)
        self._has_error = kwargs.get('has_error', False)
        self._help = kwargs.get('help')
        self._h_size = kwargs.get('h_size')
        self._h_size_label = kwargs.get('h_size_label', False)
        self._h_size_row_css = kwargs.get('h_size_row_css', '')
        self._hidden = kwargs.get('hidden', False)
        self._rules = kwargs.get('rules',
                                 [])  # type: List[validation.rule.Rule]
        self._form_area = kwargs.get('form_area', 'body')
        self._replaces = kwargs.get('replaces')
        self._required = kwargs.get('required', False)
        self._enabled = kwargs.get('enabled', True)
        self._parent = kwargs.get('parent')
        self._children = []  # type: List[Abstract]
        self._children_uids = []  # type: List[str]
        self._children_sep = kwargs.get('children_sep', '')
        self._last_children_weight = 0
        self._form_group = kwargs.get('form_group', True)

        # Check validation rules
        if not isinstance(self._rules, (list, tuple)):
            self._rules = [self._rules]
        if isinstance(self._rules, tuple):
            self._rules = list(self._rules)
        for rule in self._rules:
            if not isinstance(rule, validation.rule.Rule):
                raise TypeError(
                    'Instance of pytsite.validation.rule.Base expected.')

        # Required
        if self.required:
            self.add_rule(validation.rule.NonEmpty())

        # It is important to filter value through the setter-method
        if 'value' in kwargs:
            self.set_val(kwargs.get('value'))
        else:
            self.set_val(deepcopy(self._default))

        # Process data-attributes
        for k, v in kwargs.items():
            if k.startswith('data_'):
                self._data[k.replace('data_', '')] = v
Exemple #29
0
    def odm_ui_m_form_setup_widgets(self, frm: form.Form):
        """Hook
        """
        # Parent
        from ._widget import TermSelect
        frm.add_widget(
            TermSelect(
                uid='_parent',
                model=self.model,
                exclude=self if not self.is_new else None,
                exclude_descendants=True,
                label=self.t('parent'),
                append_none_item=not self.get_field('_parent').is_required,
                value=self.parent,
            ))

        # Title
        if self.has_field('title'):
            frm.add_widget(
                widget.input.Text(
                    uid='title',
                    label=lang.t('taxonomy@title'),
                    value=self.title,
                    required=self.get_field('title').is_required,
                ))

        # Alias
        if self.has_field('alias'):
            frm.add_widget(
                widget.input.Text(
                    uid='alias',
                    label=lang.t('taxonomy@alias'),
                    value=self.f_get('alias'),
                ))

        # Weight
        if self.has_field('weight'):
            frm.add_widget(
                widget.input.Integer(uid='weight',
                                     label=lang.t('taxonomy@weight'),
                                     value=self.weight,
                                     h_size='col-sm-3 col-md-2 col-lg-1'))

        # Image
        if self.has_field('image'):
            frm.add_widget(
                file_ui.widget.ImagesUpload(
                    uid='image',
                    label=lang.t('taxonomy@image'),
                    required=self.get_field('image').is_required,
                    value=self.image,
                ))

        # Language
        if self.has_field('language'):
            lng = lang.get_current() if self.is_new else self.language
            frm.add_widget(
                widget.static.Text(
                    uid='language',
                    label=lang.t('taxonomy@language'),
                    text=lang.lang_title(lng),
                    value=lng,
                    hidden=len(lang.langs()) == 1,
                ))
Exemple #30
0
    def odm_ui_browser_setup_finder(self, finder: odm.SingleModelFinder,
                                    args: routing.ControllerArgs):
        super().odm_ui_browser_setup_finder(finder, args)

        finder.eq('language', lang.get_current())