Пример #1
0
def document_send(doc_id):
    doc = get_document(doc_id)

    recipient = request.form.get("recipient")
    user_msg = request.form.get("message")

    site_name = "[{}] ".format(current_app.config["SITE_NAME"])
    sender_name = current_user.name
    subject = site_name + _("{sender} sent you a file").format(
        sender=sender_name)
    msg = Message(subject)
    msg.sender = current_user.email
    msg.recipients = [recipient]
    msg.body = render_template_i18n(
        "documents/mail_file_sent.txt",
        sender_name=sender_name,
        message=user_msg,
        document_url=url_for(doc),
        filename=doc.title,
    )

    filename = doc.title
    msg.attach(filename, doc.content_type, doc.content)

    mail.send(msg)
    flash(_("Email successfully sent"), "success")

    return redirect(url_for(doc))
Пример #2
0
def do_login(form):
  email = form.get('email', "").lower()
  password = form.get('password')
  next_url = form.get('next', u'')
  res = dict(username=email, email=email, next_url=next_url)

  if not email or not password:
    res['error'] = _(u"You must provide your email and password.")
    res['code'] = 401
    return res

  try:
    user = User.query\
        .filter(sql.func.lower(User.email) == email,
                User.can_login == True)\
        .one()
  except NoResultFound:
    res['error'] = _(u"Sorry, we couldn't find an account for "
                     u"email '{email}'.").format(email=email)
    res['code'] = 401
    return res

  if user and not user.authenticate(password):
    res['error'] = _(u"Sorry, wrong password.")
    res['code'] = 401
    return res

  # Login successful
  login_user(user)
  res['user'] = user
  res['email'] = user.email
  return res
Пример #3
0
    def do_delete(self):
        data = request.form
        confirm = data.get("confirm_delete", False, type=bool)

        if not confirm:
            flash(_("Please fix the error(s) below"), "error")
            self.form_errors["confirm_delete"] = _(
                "Must be checked to ensure you "
                "intent to delete these tags")
            return self.get(self.ns)

        session = db.session()
        tags = self._get_selected_tags()

        if not tags:
            flash(_("No action performed: no tags selected"), "warning")
            return self.redirect_to_view()

        count = len(tags)
        entities_to_reindex = get_entities_for_reindex(tags)
        success_message = _n(
            "%(tag)s deleted",
            "%(num)d tags deleted:\n%(tags)s",
            count,
            tag=tags[0].label,
            tags=", ".join(t.label for t in tags),
        )
        for tag in tags:
            session.delete(tag)
        session.commit()
        flash(success_message)
        schedule_entities_reindex(entities_to_reindex)
        return self.redirect_to_view()
Пример #4
0
    def validate_photo(self, field):
        data = request.form.get(field.name)
        if not data:
            return

        data = field.data
        filename = data.filename
        valid = any(filename.lower().endswith(ext)
                    for ext in ('.png', '.jpg', '.jpeg'))

        if not valid:
            raise ValidationError(
                _(u'Only PNG or JPG image files are accepted'))

        img_type = imghdr.what('ignored', data.read())

        if img_type not in ('png', 'jpeg'):
            raise ValidationError(
                _(u'Only PNG or JPG image files are accepted'))

        data.seek(0)
        try:
            # check this is actually an image file
            im = PIL.Image.open(data)
            im.load()
        except:
            raise ValidationError(_(u'Could not decode image file'))

        # convert to jpeg
        # FIXME: better do this at model level?
        jpeg = BytesIO()
        im.convert('RGBA').save(jpeg, 'JPEG')
        field.data = jpeg.getvalue()
Пример #5
0
        def __init__(self, e):
            render = render_template_string
            self.entry = e
            self.date = e.happened_at.strftime('%Y-%m-%d %H:%M')
            self.manager = render(
                '<img src="{{ user_photo_url(e.manager, size=16) }}" alt="" />'
                '<a href="{{ url_for("social.user", user_id=e.manager_id) }}">'
                '{{ e.manager.name }}</a>',
                e=e)

            if e.op == e.SET_INHERIT:
                msg = _('On {date}, {manager} has activated inheritance')
            elif e.op == e.UNSET_INHERIT:
                msg = _('On {date}, {manager} has deactivated inheritance')
            elif e.op == e.GRANT:
                msg = _(
                    'On {date}, {manager} has given role "{role}" to {principal}'
                )
            elif e.op == e.REVOKE:
                msg = _('On {date}, {manager} has revoked role "{role}" from '
                        '{principal}')
            else:
                raise Exception("Unknown audit entry type %s" % e.op)

            principal = ''
            if self.entry.user:
                principal = render(self._USER_FMT, user=self.entry.user)
            elif self.entry.group:
                principal = render(self._GROUP_FMT, group=self.entry.group)

            self.msg = Markup(
                msg.format(date=self.date,
                           manager=self.manager,
                           role=self.entry.role,
                           principal=principal))
Пример #6
0
  def validate_photo(self, field):
    data = request.files.get(field.name)
    if not data:
      return

    filename = data.filename
    valid = any(filename.lower().endswith(ext)
                for ext in ('.png', '.jpg', '.jpeg'))

    if not valid:
      raise ValidationError(_(u'Only PNG or JPG image files are accepted'))

    img_type = imghdr.what('ignored', data.read())

    if not img_type in ('png', 'jpeg'):
      raise ValidationError(_(u'Only PNG or JPG image files are accepted'))

    data.stream.seek(0)
    try:
      # check this is actually an image file
      im = PIL.Image.open(data.stream)
      im.load()
    except:
      raise ValidationError(_(u'Could not decode image file'))

    # convert to jpeg
    #FIXME: better do this at model level?
    jpeg = StringIO()
    im.save(jpeg, 'JPEG')
    field.data = jpeg.getvalue()
Пример #7
0
def document_send(doc_id):
    doc = get_document(doc_id)

    recipient = request.form.get("recipient")
    user_msg = request.form.get("message")

    site_name = "[{}] ".format(current_app.config["SITE_NAME"])
    sender_name = current_user.name
    subject = site_name + _("{sender} sent you a file").format(sender=sender_name)
    msg = Message(subject)
    msg.sender = current_user.email
    msg.recipients = [recipient]
    msg.body = render_template_i18n(
        "documents/mail_file_sent.txt",
        sender_name=sender_name,
        message=user_msg,
        document_url=url_for(doc),
        filename=doc.title,
    )

    filename = doc.title
    msg.attach(filename, doc.content_type, doc.content)

    mail.send(msg)
    flash(_("Email successfully sent"), "success")

    return redirect(url_for(doc))
Пример #8
0
    def post(self):
        # Manual security check, should be done by the framework instead.
        if not self.is_accessible():
            raise InternalServerError()

        if request.form['_action'] == 'cancel':
            return redirect(url_for('.user'))

        form = UserPreferencesForm(request.form, prefix=self.id)

        if form.validate():
            if request.csrf_failed:
                current_app.extensions[
                    'csrf-handler'].flash_csrf_failed_message()
                return render_template('preferences/user.html', form=form)

            del form.confirm_password
            if form.password.data:
                g.user.set_password(form.password.data)
                flash(_(u'Password changed'), 'success')
            del form.password

            form.populate_obj(g.user)

            current_app.db.session.commit()
            flash(_(u"Preferences saved."), "info")
            return redirect(url_for(".user"))
        else:
            return render_template('preferences/user.html', form=form)
Пример #9
0
    def do_delete(self):
        data = request.form
        confirm = data.get('confirm_delete', False, type=bool)

        if not confirm:
            flash(_(u'Please fix the error(s) below'), 'error')
            self.form_errors['confirm_delete'] = _(
                u'Must be checked to ensure you '
                u'intent to delete these tags')
            return self.get(self.ns)

        session = current_app.db.session()
        tags = self._get_selected_tags()

        if not tags:
            flash(_(u'No action performed: no tags selected'), 'warning')
            return self.redirect_to_view()

        count = len(tags)
        entities_to_reindex = get_entities_for_reindex(tags)
        success_message = _n(u'%(tag)s deleted',
                             u'%(num)d tags deleted:\n%(tags)s',
                             count,
                             tag=tags[0].label,
                             tags=u', '.join(t.label for t in tags))
        map(session.delete, tags)
        session.commit()
        flash(success_message)
        schedule_entities_reindex(entities_to_reindex)
        return self.redirect_to_view()
Пример #10
0
def check_valid_name():
    """Check if name is valid for content creation in this folder."""

    object_id = int(request.args.get("object_id"))
    action = request.args.get("action")
    title = request.args.get("title")

    get_object = get_document if action == "document-edit" else get_folder
    obj = get_object(object_id)
    check_read_access(obj)

    if action == "new":
        parent = obj
        help_text = _('An element named "{name}" is already present in folder')
    elif action in ("folder-edit", "document-edit"):
        parent = obj.parent
        help_text = _('Cannot rename: "{name}" is already present in parent '
                      "folder")
    else:
        raise InternalServerError()

    existing = {e.title for e in parent.children}

    if action in ("folder-edit", "document-edit"):
        try:
            existing.remove(obj.title)
        except KeyError:
            pass

    result = {}
    valid = result["valid"] = title not in existing
    if not valid:
        result["help_text"] = help_text.format(name=title)

    return jsonify(result)
Пример #11
0
def check_valid_name():
    """Check if name is valid for content creation in this folder."""

    object_id = int(request.args.get('object_id'))
    action = request.args.get('action')
    title = request.args.get('title')

    get_object = get_document if action == 'document-edit' else get_folder
    obj = get_object(object_id)
    check_read_access(obj)

    if action == 'new':
        parent = obj
        help_text = _('An element named "{name}" is already present in folder')
    elif action in ('folder-edit', 'document-edit'):
        parent = obj.parent
        help_text = _('Cannot rename: "{name}" is already present in parent '
                      'folder')
    else:
        raise InternalServerError()

    existing = set((e.title for e in parent.children))

    if action in ('folder-edit', 'document-edit'):
        try:
            existing.remove(obj.title)
        except KeyError:
            pass

    result = {}
    valid = result['valid'] = title not in existing
    if not valid:
        result['help_text'] = help_text.format(name=title)

    return jsonify(result)
Пример #12
0
  def do_delete(self):
    data = request.form
    confirm = data.get('confirm_delete', False, type=bool)

    if not confirm:
      flash(_(u'Please fix the error(s) below'), 'error')
      self.form_errors['confirm_delete'] = _(u'Must be checked to ensure you '
                                             u'intent to delete these tags')
      return self.get(self.ns)

    session = current_app.db.session()
    tags = self._get_selected_tags()

    if not tags:
      flash(_(u'No action performed: no tags selected'), 'warning')
      return self.redirect_to_view()

    count = len(tags)
    entities_to_reindex = get_entities_for_reindex(tags)
    success_message = _n(u'%(tag)s deleted',
                         u'%(num)d tags deleted:\n%(tags)s',
                         count,
                         tag=tags[0].label,
                         tags=u', '.join(t.label for t in tags))
    map(session.delete, tags)
    session.commit()
    flash(success_message)
    schedule_entities_reindex(entities_to_reindex)
    return self.redirect_to_view()
Пример #13
0
def forgotten_pw(new_user=False):
    """Reset password for users who have already activated their accounts."""
    email = request.form.get("email", "").lower()

    action = request.form.get("action")
    if action == "cancel":
        return redirect(url_for("login.login_form"))

    if not email:
        flash(_("You must provide your email address."), "error")
        return render_template("login/forgotten_password.html")

    try:
        user = User.query.filter(
            sql.func.lower(User.email) == email, User.can_login == True
        ).one()
    except NoResultFound:
        flash(
            _("Sorry, we couldn't find an account for " "email '{email}'.").format(
                email=email
            ),
            "error",
        )
        return render_template("login/forgotten_password.html"), 401

    if user.can_login and not user.password:
        user.set_password(random_password())
        db.session.commit()

    send_reset_password_instructions(user)
    flash(
        _("Password reset instructions have been sent to your email address."), "info"
    )

    return redirect(url_for("login.login_form"))
Пример #14
0
def do_login(form):
    email = form.get("email", "").lower()
    password = form.get("password")
    next_url = form.get("next", "")
    res = dict(username=email, email=email, next_url=next_url)

    if not email or not password:
        res["error"] = _("You must provide your email and password.")
        res["code"] = 401
        return res

    try:
        user = User.query.filter(
            sql.func.lower(User.email) == email, User.can_login == True
        ).one()
    except NoResultFound:
        auth_failed.send(unwrap(current_app), email=email)
        res["error"] = _(
            "Sorry, we couldn't find an account for " "email '{email}'."
        ).format(email=email)
        res["code"] = 401
        return res

    if user and not user.authenticate(password):
        auth_failed.send(unwrap(current_app), email=email)
        res["error"] = _("Sorry, wrong password.")
        res["code"] = 401
        return res

    # Login successful
    login_user(user)
    res["user"] = user
    res["email"] = user.email
    return res
Пример #15
0
    def post(self):
        # Manual security check, should be done by the framework instead.
        if not self.is_accessible():
            raise InternalServerError()

        if request.form["_action"] == "cancel":
            return redirect(url_for(".user"))

        form = UserPreferencesForm(request.form, prefix=self.id)

        if form.validate():
            if request.csrf_failed:
                current_app.extensions["csrf-handler"].flash_csrf_failed_message()
                return render_template("preferences/user.html", form=form)

            del form.confirm_password
            if form.password.data:
                g.user.set_password(form.password.data)
                flash(_("Password changed"), "success")
            del form.password

            form.populate_obj(g.user)

            db.session.commit()
            flash(_("Preferences saved."), "info")
            return redirect(url_for(".user"))
        else:
            return render_template("preferences/user.html", form=form)
Пример #16
0
    def do_delete(self):
        data = request.form
        confirm = data.get("confirm_delete", False, type=bool)

        if not confirm:
            flash(_("Please fix the error(s) below"), "error")
            self.form_errors["confirm_delete"] = _(
                "Must be checked to ensure you " "intent to delete these tags"
            )
            return self.get(self.ns)

        session = db.session()
        tags = self._get_selected_tags()

        if not tags:
            flash(_("No action performed: no tags selected"), "warning")
            return self.redirect_to_view()

        count = len(tags)
        entities_to_reindex = get_entities_for_reindex(tags)
        success_message = _n(
            "%(tag)s deleted",
            "%(num)d tags deleted:\n%(tags)s",
            count,
            tag=tags[0].label,
            tags=", ".join(t.label for t in tags),
        )
        for tag in tags:
            session.delete(tag)
        session.commit()
        flash(success_message)
        schedule_entities_reindex(entities_to_reindex)
        return self.redirect_to_view()
Пример #17
0
  def render(self):
    render = render_template_string
    e = self.entry
    user = render(self._USER_FMT, user=e.user)
    self.entity_deleted = e.entity is None
    entity_html = e.entity_name

    if not self.entity_deleted:
      try:
        entity_url = url_for(e.entity)
      except (BuildError, ValueError):
        pass
      else:
        entity_html = Markup(render(
          u'<a href="{{ url }}">{{ entity.path or entity.name }}</a>',
          url=entity_url,
          entity=e.entity))

    if e.type == 0:
      msg = _(u'{user} created {entity_type} {entity_id} "{entity}"')
    elif e.related or e.op == 1:
      msg = _(u'{user} made changes on {entity_type} {entity_id} "{entity}"')
    elif e.op == 2:
      msg = _(u'{user} has deleted {entity_type}: {entity_id} "{entity}"')
    else:
      raise Exception("Bad entry type: {}".format(e.type))

    self.msg = Markup(msg.format(user=user, entity=entity_html,
                                 entity_type=e.entity_type.rsplit('.', 1)[-1],
                                 entity_id=e.entity_id,))
    tmpl = get_template_attribute('admin/_macros.html', 'm_audit_entry')
    return tmpl(self)
Пример #18
0
def check_valid_name():
    """Check if name is valid for content creation in this folder."""

    object_id = int(request.args.get("object_id"))
    action = request.args.get("action")
    title = request.args.get("title")

    get_object = get_document if action == "document-edit" else get_folder
    obj = get_object(object_id)
    check_read_access(obj)

    if action == "new":
        parent = obj
        help_text = _('An element named "{name}" is already present in folder')
    elif action in ("folder-edit", "document-edit"):
        parent = obj.parent
        help_text = _('Cannot rename: "{name}" is already present in parent ' "folder")
    else:
        raise InternalServerError()

    existing = {e.title for e in parent.children}

    if action in ("folder-edit", "document-edit"):
        try:
            existing.remove(obj.title)
        except KeyError:
            pass

    result = {}
    valid = result["valid"] = title not in existing
    if not valid:
        result["help_text"] = help_text.format(name=title)

    return jsonify(result)
Пример #19
0
def forgotten_pw(new_user=False):
    """Reset password for users who have already activated their accounts."""
    email = request.form.get("email", "").lower()

    action = request.form.get("action")
    if action == "cancel":
        return redirect(url_for("login.login_form"))

    if not email:
        flash(_("You must provide your email address."), "error")
        return render_template("login/forgotten_password.html")

    try:
        user = User.query.filter(
            sql.func.lower(User.email) == email, User.can_login == True
        ).one()
    except NoResultFound:
        flash(
            _("Sorry, we couldn't find an account for " "email '{email}'.").format(
                email=email
            ),
            "error",
        )
        return render_template("login/forgotten_password.html"), 401

    if user.can_login and not user.password:
        user.set_password(random_password())
        db.session.commit()

    send_reset_password_instructions(user)
    flash(
        _("Password reset instructions have been sent to your email address."), "info"
    )

    return redirect(url_for("login.login_form"))
Пример #20
0
def do_login(form):
    email = form.get('email', "").lower()
    password = form.get('password')
    next_url = form.get('next', u'')
    res = dict(username=email, email=email, next_url=next_url)

    if not email or not password:
        res['error'] = _(u"You must provide your email and password.")
        res['code'] = 401
        return res

    try:
        user = User.query \
            .filter(sql.func.lower(User.email) == email,
                    User.can_login == True) \
            .one()
    except NoResultFound:
        res['error'] = _(u"Sorry, we couldn't find an account for "
                         u"email '{email}'.").format(email=email)
        res['code'] = 401
        return res

    if user and not user.authenticate(password):
        res['error'] = _(u"Sorry, wrong password.")
        res['code'] = 401
        return res

    # Login successful
    login_user(user)
    res['user'] = user
    res['email'] = user.email
    return res
Пример #21
0
  def __call__(self, field, **kwargs):
    kwargs.setdefault('id', field.id)
    kwargs['name'] = field.name
    kwargs['type'] = 'file'
    kwargs['disabled'] = 'disabled' # JS widget will activate it
    input_elem = u'<input {}>'.format(html_params(**kwargs))
    button_label = _(u'Add file') if 'multiple' in kwargs else _(u'Select file')

    existing = self.build_exisiting_files_list(field)
    uploads = self.build_uploads_list(field)

    if not field.multiple and uploads:
      # single file field: exising file replaced by new upload, don't show
      # existing
      existing = []
    else:
      for data in existing:
        # this might be a very big bytes object: in any case it will not be used
        # in widget's template, and during development it makes very large pages
        # due to debugtoolbar capturing template parameters
        del data['file']

    return Markup(
      render_template(self.template,
                      id=field.id,
                      field=field,
                      widget=self,
                      input=input_elem,
                      button_label=button_label,
                      existing=existing,
                      uploaded=uploads,)
    )
Пример #22
0
    def _validate_siret(form, field, siret=""):
        """SIRET validator.

        A WTForm validator wants a form and a field as parameters. We
        also want to give directly a siret, for a scripting use.
        """
        if field is not None:
            siret = (field.data or "").strip()

        if len(siret) != 14:
            msg = _("SIRET must have exactly 14 characters ({count})").format(
                count=len(siret)
            )
            raise validators.ValidationError(msg)

        if not all(("0" <= c <= "9") for c in siret):
            if not siret[-3:] in SIRET_CODES:
                msg = _(
                    "SIRET looks like special SIRET but geographical "
                    "code seems invalid (%(code)s)",
                    code=siret[-3:],
                )
                raise validators.ValidationError(msg)

        elif not luhn(siret):
            msg = _("SIRET number is invalid (length is ok: verify numbers)")
            raise validators.ValidationError(msg)
Пример #23
0
def do_login(form):
    email = form.get("email", "").lower()
    password = form.get("password")
    next_url = form.get("next", "")
    res = {"username": email, "email": email, "next_url": next_url}

    if not email or not password:
        res["error"] = _("You must provide your email and password.")
        res["code"] = 401
        return res

    try:
        user = User.query.filter(
            sql.func.lower(User.email) == email, User.can_login == True
        ).one()
    except NoResultFound:
        auth_failed.send(unwrap(current_app), email=email)
        res["error"] = _(
            "Sorry, we couldn't find an account for " "email '{email}'."
        ).format(email=email)
        res["code"] = 401
        return res

    if user and not user.authenticate(password):
        auth_failed.send(unwrap(current_app), email=email)
        res["error"] = _("Sorry, wrong password.")
        res["code"] = 401
        return res

    # Login successful
    login_user(user)
    res["user"] = user
    res["email"] = user.email
    return res
Пример #24
0
    def validate_photo(self, field):
        data = request.form.get(field.name)
        if not data:
            return

        data = field.data
        filename = data.filename
        valid = any(filename.lower().endswith(ext) for ext in (".png", ".jpg", ".jpeg"))

        if not valid:
            raise ValidationError(_("Only PNG or JPG image files are accepted"))

        img_type = imghdr.what("ignored", data.read())

        if img_type not in ("png", "jpeg"):
            raise ValidationError(_("Only PNG or JPG image files are accepted"))

        data.seek(0)
        try:
            # check this is actually an image file
            im = PIL.Image.open(data)
            im.load()
        except Exception:
            raise ValidationError(_("Could not decode image file"))

        # convert to jpeg
        # FIXME: better do this at model level?
        jpeg = BytesIO()
        im.convert("RGB").save(jpeg, "JPEG")
        field.data = jpeg.getvalue()
Пример #25
0
    def _validate_siret(form: Form, field: Field, siret: str = "") -> None:
        """SIRET validator.

        A WTForm validator wants a form and a field as parameters. We
        also want to give directly a siret, for a scripting use.
        """
        if field is not None:
            # pyre-fixme[16]: `Field` has no attribute `data`.
            siret = (field.data or "").strip()

        if len(siret) != 14:
            msg = _("SIRET must have exactly 14 characters ({count})").format(
                count=len(siret))
            raise validators.ValidationError(msg)

        if not all(("0" <= c <= "9") for c in siret):
            if not siret[-3:] in SIRET_CODES:
                msg = _(
                    "SIRET looks like special SIRET but geographical "
                    "code seems invalid (%(code)s)",
                    code=siret[-3:],
                )
                raise validators.ValidationError(msg)

        elif not luhn(siret):
            msg = _("SIRET number is invalid (length is ok: verify numbers)")
            raise validators.ValidationError(msg)
Пример #26
0
    def _validate_siret(form, field, siret=""):
        """SIRET validator.

        A WTForm validator wants a form and a field as parameters. We
        also want to give directly a siret, for a scripting use.
        """
        if field is not None:
            siret = (field.data or '').strip()

        if len(siret) != 14:
            msg = _('SIRET must have exactly 14 characters ({count})').format(
                count=len(siret), )
            raise validators.ValidationError(msg)

        if not all(('0' <= c <= '9') for c in siret):
            if not siret[-3:] in SIRET_CODES:
                msg = _(
                    'SIRET looks like special SIRET but geographical '
                    'code seems invalid (%s)',
                    code=siret[-3:],
                )
                raise validators.ValidationError(msg)

        elif not luhn(siret):
            msg = _('SIRET number is invalid (length is ok: verify numbers)')
            raise validators.ValidationError(msg)
Пример #27
0
    def validate_photo(self, field: FileField) -> None:
        data = request.form.get(field.name)
        if not data:
            return

        data = field.data
        filename = data.filename
        valid = any(filename.lower().endswith(ext)
                    for ext in (".png", ".jpg", ".jpeg"))

        if not valid:
            raise ValidationError(
                _("Only PNG or JPG image files are accepted"))

        img_type = imghdr.what("ignored", data.read())

        if img_type not in ("png", "jpeg"):
            raise ValidationError(
                _("Only PNG or JPG image files are accepted"))

        data.seek(0)
        try:
            # check this is actually an image file
            im = PIL.Image.open(data)
            im.load()
        except Exception:
            raise ValidationError(_("Could not decode image file"))

        # convert to jpeg
        # FIXME: better do this at model level?
        jpeg = BytesIO()
        im.convert("RGB").save(jpeg, "JPEG")
        field.data = jpeg.getvalue()
Пример #28
0
def reset_password(token):
    expired, invalid, user = reset_password_token_status(token)
    if invalid:
        flash(_("Invalid reset password token."), "error")
    elif expired:
        flash(_("Password reset expired"), "error")
    if invalid or expired:
        return redirect(url_for("login.forgotten_pw"))

    return render_template_i18n("login/password_reset.html")
Пример #29
0
def reset_password(token):
    expired, invalid, user = reset_password_token_status(token)
    if invalid:
        flash(_("Invalid reset password token."), "error")
    elif expired:
        flash(_("Password reset expired"), "error")
    if invalid or expired:
        return redirect(url_for("login.forgotten_pw"))

    return render_template_i18n("login/password_reset.html")
Пример #30
0
def folder_edit(folder):
    check_write_access(folder)

    changed = edit_object(folder)

    if changed:
        db.session.commit()
        flash(_("Folder properties successfully edited."), "success")
    else:
        flash(_("You didn't change any property."), "success")
    return redirect(url_for(folder))
Пример #31
0
    def get(self):
        login_entries = LoginSession.query \
            .order_by(LoginSession.started_at.asc()) \
            .all()
        # .options(sa.orm.joinedload(LoginSession.user))
        daily, weekly, monthly = uniquelogins(login_entries)
        new_logins, total_users = newlogins(login_entries)

        stats = {
            'today': stats_since(timedelta(days=1)),
            'this_week': stats_since(timedelta(days=7)),
            'this_month': stats_since(timedelta(days=30)),
        }

        # let's format the data into NVD3 datastructures
        connections = [
            {
                'key': _('Daily'),
                'color': '#7777ff',
                'values': daily
            },
            {
                'key': _('Weekly'),
                'color': '#2ca02c',
                'values': weekly,
                'disabled': True,
            },
            {
                'key': _('Monthly'),
                'color': '#ff7f0e',
                'values': monthly,
                'disabled': True,
            },
        ]
        new_logins = [
            {
                'key': _('New'),
                'color': '#ff7f0e',
                "bar": True,
                'values': new_logins,
            },
            {
                'key': _('Total'),
                'color': '#2ca02c',
                'values': total_users
            },
        ]

        return render_template(
            "admin/dashboard.html",
            stats=stats,
            connections=connections,
            new_logins=new_logins,
        )
Пример #32
0
def folder_edit(folder):
    check_write_access(folder)

    changed = edit_object(folder)

    if changed:
        db.session.commit()
        flash(_("Folder properties successfully edited."), "success")
    else:
        flash(_("You didn't change any property."), "success")
    return redirect(url_for(folder))
Пример #33
0
    def get(self) -> str:
        login_entries = LoginSession.query.order_by(
            LoginSession.started_at.asc()).all()
        # .options(sa.orm.joinedload(LoginSession.user))
        daily, weekly, monthly = uniquelogins(login_entries)
        new_logins, total_users = newlogins(login_entries)

        stats = {
            "today": stats_since(timedelta(days=1)),
            "this_week": stats_since(timedelta(days=7)),
            "this_month": stats_since(timedelta(days=30)),
        }

        # let's format the data into NVD3 datastructures
        connections = [
            {
                "key": _("Daily"),
                "color": "#7777ff",
                "values": daily
            },
            {
                "key": _("Weekly"),
                "color": "#2ca02c",
                "values": weekly,
                "disabled": True,
            },
            {
                "key": _("Monthly"),
                "color": "#ff7f0e",
                "values": monthly,
                "disabled": True,
            },
        ]
        new_logins = [
            {
                "key": _("New"),
                "color": "#ff7f0e",
                "bar": True,
                "values": new_logins
            },
            {
                "key": _("Total"),
                "color": "#2ca02c",
                "values": total_users
            },
        ]

        return render_template(
            "admin/dashboard.html",
            stats=stats,
            connections=connections,
            new_logins=new_logins,
        )
Пример #34
0
  def render(self):
    aoColumns = [{'asSorting': []}] if self.show_controls else []
    aoColumns += [{'asSorting': col['sorting'], 'bSortable': col['sortable']}
                  for col in self.columns]
    datatable_options = {
      'sDom': 'fFriltip',
      'aoColumns': aoColumns,
      'bFilter': True,
      'oLanguage': {
        'sSearch': self.options.get('search_label', _(u'Filter records:')),
        'oPaginate': {
          'sPrevious': _(u'Previous'),
          'sNext': _(u'Next'),
        },
        'sLengthMenu': _(u'Entries per page: _MENU_'),
        'sInfo': _(u'Showing _START_ to _END_ of _TOTAL_ entries'),
        'sInfoEmpty': _(u'Showing _START_ to _END_ of _TOTAL_ entries'),
        'sInfoFiltered': _(u'(filtered from _MAX_ total entries)'),
        'sAddAdvancedFilter': _(u'Add a filter'),
        'sZeroRecords': _(u'No matching records found'),
        'sEmptyTable': _(u'No matching records found'),
      },
      'bPaginate': self.paginate,
      'sPaginationType': "bootstrap",
      'bLengthChange': True,
      'iDisplayLength': 25,
      'bStateSave': self.save_state,
      'bProcessing': True,
      'bServerSide': True,
      'sAjaxSource': self.ajax_source,
    }

    advanced_search_filters = []
    for c in self.search_criterions:
      if not c.has_form_filter:
        continue
      d = dict(name=c.name,
               label=unicode(c.label),
               type=c.form_filter_type,
               args=c.form_filter_args,
               unset=c.form_unset_value,)
      if c.has_form_default_value:
        d['defaultValue'] = c.form_default_value

      advanced_search_filters.append(d)

    if advanced_search_filters:
      datatable_options['aoAdvancedSearchFilters'] = advanced_search_filters

    return Markup(render_template('widgets/render_ajax_table.html',
                                  datatable_options=datatable_options,
                                  view=self))
Пример #35
0
def make_tabs(user):
    return [
        dict(id='profile',
             label=_(u'Profile'),
             link=url_for(user, tab='profile')),
        # dict(id='conversations', label=_(u'Conversations'), link=url_for(user), is_online=True),
        dict(id='documents',
             label=_(u'Documents'),
             link=url_for(user, tab='documents')),
        dict(id='images', label=_(u'Images'), link=url_for(user,
                                                           tab='images')),
        dict(id='audit', label=_(u'Audit'), link=url_for(user, tab='audit')),
    ]
Пример #36
0
def document_edit(doc_id):
    doc = get_document(doc_id)
    check_write_access(doc)

    changed = edit_object(doc)

    if changed:
        db.session.commit()
        flash(_(u"Document properties successfully edited."), "success")
    else:
        flash(_(u"You didn't change any property."), "success")

    return redirect(url_for(doc))
Пример #37
0
def wizard_check_data():
    """Filter and detect existing members, existing accounts and new emails."""
    if request.method == "GET":
        return redirect(url_for(".members", community_id=g.community.slug))

    g.breadcrumb.append(
        BreadcrumbItem(
            label=_("Members"),
            url=Endpoint("communities.members", community_id=g.community.slug),
        )
    )

    is_csv = False
    if request.form.get("wizard-emails"):
        wizard_emails = request.form.get("wizard-emails").split(",")
        existing_accounts_object, existing_members_objects, final_email_list = wizard_extract_data(
            wizard_emails
        )
        final_email_list_json = json.dumps(final_email_list)
    else:
        is_csv = True
        accounts_data = wizard_read_csv(request.files["csv_file"])
        if not accounts_data:
            flash(_("To add new members, please follow the CSV file model."), "warning")
            return redirect(
                url_for(".wizard_data_insertion", community_id=g.community.slug)
            )

        existing_accounts, existing_members_objects, final_email_list = wizard_extract_data(
            accounts_data, is_csv=True
        )
        existing_accounts_object = existing_accounts["account_objects"]
        existing_accounts_csv_roles = existing_accounts["csv_roles"]
        final_email_list_json = json.dumps(final_email_list)

    if not final_email_list:
        flash(_("No new members were found"), "warning")
        return redirect(
            url_for(".wizard_data_insertion", community_id=g.community.slug)
        )

    ctx = {
        "existing_accounts_object": existing_accounts_object,
        "csv_roles": existing_accounts_csv_roles if is_csv else False,
        "wizard_emails": final_email_list_json,
        "existing_members_objects": existing_members_objects,
    }
    return render_template("community/wizard_check_members.html", **ctx)
Пример #38
0
def wizard_check_data():
    """Filter and detect existing members, existing accounts and new emails."""
    if request.method == "GET":
        return redirect(url_for(".members", community_id=g.community.slug))

    g.breadcrumb.append(
        BreadcrumbItem(
            label=_("Members"),
            url=Endpoint("communities.members", community_id=g.community.slug),
        )
    )

    is_csv = False
    if request.form.get("wizard-emails"):
        wizard_emails = request.form.get("wizard-emails").split(",")
        existing_accounts_object, existing_members_objects, final_email_list = wizard_extract_data(
            wizard_emails
        )
        final_email_list_json = json.dumps(final_email_list)
    else:
        is_csv = True
        accounts_data = wizard_read_csv(request.files["csv_file"])
        if not accounts_data:
            flash(_("To add new members, please follow the CSV file model."), "warning")
            return redirect(
                url_for(".wizard_data_insertion", community_id=g.community.slug)
            )

        existing_accounts, existing_members_objects, final_email_list = wizard_extract_data(
            accounts_data, is_csv=True
        )
        existing_accounts_object = existing_accounts["account_objects"]
        existing_accounts_csv_roles = existing_accounts["csv_roles"]
        final_email_list_json = json.dumps(final_email_list)

    if not final_email_list:
        flash(_("No new members were found"), "warning")
        return redirect(
            url_for(".wizard_data_insertion", community_id=g.community.slug)
        )

    ctx = {
        "existing_accounts_object": existing_accounts_object,
        "csv_roles": existing_accounts_csv_roles if is_csv else False,
        "wizard_emails": final_email_list_json,
        "existing_members_objects": existing_members_objects,
    }
    return render_template("community/wizard_check_members.html", **ctx)
Пример #39
0
    def message(self, ignore_community=False):
        try:
            # another quick&dirty approach for now. FIXME later.
            entry = self._model
            object_class = entry.object_type.split(".")[-1]
            object_class_localized = _(object_class)

            ctx = {}
            ctx["verb"] = entry.verb

            ctx["object_name"] = entry.object.name or getattr(
                entry.object, "title", "???")
            ctx["object_url"] = url_for(entry.object)
            ctx["object_type"] = object_class_localized
            ctx["object"] = OBJ_TEMPLATE.render(**ctx)

            if entry.target:
                ctx["target_name"] = entry.target.name
                ctx["target_url"] = url_for(entry.target)
                ctx["target"] = OBJ_TEMPLATE.render(
                    object_name=ctx["target_name"],
                    object_url=ctx["target_url"])

            msg = MESSAGES.get((entry.verb, entry.object.__class__))
            if msg:
                msg = msg.format(**ctx)
                if entry.target and not ignore_community:
                    msg += " " + _("in the community {target}.").format(**ctx)
                else:
                    msg += "."

            elif entry.verb == "post":
                msg = _("has posted an object of type {object_type} "
                        'called "{object}"').format(**ctx)

                if entry.target and not ignore_community:
                    msg += " " + _("in the community {target}.").format(**ctx)
                else:
                    msg += "."

            elif entry.verb == "join":
                msg = _("has joined the community {object}.").format(**ctx)

            elif entry.verb == "leave":
                msg = _("has left the community {object}.").format(**ctx)

            elif entry.verb == "update":
                msg = _("has updated {object_type} {object}.").format(**ctx)

            else:
                msg = _('has done action "{verb}" on object "{object}".'
                        ).format(**ctx)

            return Markup(msg)

        except BaseException:
            logger.exception("Exception while presenting activity message")
            raise
Пример #40
0
    def message(self, ignore_community=False):
        try:
            # another quick&dirty approach for now. FIXME later.
            entry = self._model
            object_class = entry.object_type.split('.')[-1]
            object_class_localized = _(object_class)

            ctx = {}
            ctx['verb'] = entry.verb

            ctx['object_name'] = entry.object.name or getattr(
                entry.object, 'title', "???")
            ctx['object_url'] = url_for(entry.object)
            ctx['object_type'] = object_class_localized
            ctx['object'] = OBJ_TEMPLATE.render(**ctx)

            if entry.target:
                ctx['target_name'] = entry.target.name
                ctx['target_url'] = url_for(entry.target)
                ctx['target'] = OBJ_TEMPLATE.render(
                    object_name=ctx['target_name'],
                    object_url=ctx['target_url'])

            msg = MESSAGES.get((entry.verb, entry.object.__class__))
            if msg:
                msg = msg.format(**ctx)
                if entry.target and not ignore_community:
                    msg += " " + _('in the community {target}.').format(**ctx)
                else:
                    msg += "."

            elif entry.verb == 'post':
                msg = _('has posted an object of type {object_type} '
                        'called "{object}"').format(**ctx)

                if entry.target and not ignore_community:
                    msg += " " + _('in the community {target}.').format(**ctx)
                else:
                    msg += "."

            elif entry.verb == 'join':
                msg = _('has joined the community {object}.').format(**ctx)

            elif entry.verb == 'leave':
                msg = _('has left the community {object}.').format(**ctx)

            elif entry.verb == 'update':
                msg = _('has updated {object_type} {object}.').format(**ctx)

            else:
                msg = _('has done action "{verb}" on object "{object}".'
                        ).format(**ctx)

            return Markup(msg)

        except:
            logger.exception('Exception while presenting activity message')
            raise
Пример #41
0
    def __call__(self, form, field):
        l = field.data and len(field.data) or 0

        if l < self.min or self.max != -1 and l > self.max:
            message = self.message
            if message is None:
                if self.max == -1:
                    message = _n(
                        u'Field must be at least %(min)d character long.',
                        u'Field must be at least %(min)d characters long.',
                        self.min,
                        min=self.min)
                elif self.min == -1:
                    message = _n(
                        u'Field cannot be longer than %(max)d character.',
                        u'Field cannot be longer than %(max)d characters.',
                        self.max,
                        max=self.max)
                else:
                    message = _(
                        u'Field must be between %(min)d and %(max)d characters long.',
                        min=self.min,
                        max=self.max)
            raise ValidationError(message %
                                  dict(min=self.min, max=self.max, length=l))
Пример #42
0
def folder_post(folder_id):
    """A POST on a folder can result on several different actions (depending on
    the `action` parameter)."""
    folder = get_folder(folder_id)
    action = request.form.get("action")

    if action == "edit":
        return folder_edit(folder)

    elif action == "upload":
        return upload_new(folder)

    elif action == "download":
        return download_multiple(folder)

    elif action == "delete":
        return delete_multiple(folder)

    elif action == "new":
        return create_subfolder(folder)

    elif action == "move":
        return move_multiple(folder)

    elif action == "change-owner":
        return change_owner(folder)

    else:
        # Probably an error or a hack attempt.
        # Logger will inform sentry if enabled
        logger = logging.getLogger(__name__)
        logger.error("Unknown folder action.", extra={"stack": True})
        flash(_("Unknown action."), "error")
        return redirect(url_for(folder))
Пример #43
0
def folder_post(folder_id):
    """A POST on a folder can result on several different actions (depending on
    the `action` parameter)."""
    folder = get_folder(folder_id)
    action = request.form.get("action")

    if action == "edit":
        return folder_edit(folder)

    elif action == "upload":
        return upload_new(folder)

    elif action == "download":
        return download_multiple(folder)

    elif action == "delete":
        return delete_multiple(folder)

    elif action == "new":
        return create_subfolder(folder)

    elif action == "move":
        return move_multiple(folder)

    elif action == "change-owner":
        return change_owner(folder)

    else:
        # Probably an error or a hack attempt.
        # Logger will inform sentry if enabled
        logger = logging.getLogger(__name__)
        logger.error("Unknown folder action.", extra={"stack": True})
        flash(_("Unknown action."), "error")
        return redirect(url_for(folder))
Пример #44
0
    def url_value_preprocess(self, endpoint, view_args):
        Model = view_args.pop('Model', None)
        group = view_args.pop('group', _MARKER)

        if group == u'_':
            # "General" group
            group = None

        if group is not _MARKER:
            view_args['group'] = group

        if Model is not None:
            svc = self.svc
            Model = svc.get_vocabulary(name=Model, group=group)
            g.breadcrumb.append(
                BreadcrumbItem(
                    label=Model.Meta.group if group else _('Global'),
                    url=url_for('.vocabularies_group', group=group or u'_'),
                ))
            g.breadcrumb.append(
                BreadcrumbItem(
                    label=Model.Meta.label,
                    url=url_for('.vocabularies_model',
                                group=group or u'_',
                                Model=Model.Meta.name),
                ))
            view_args['Model'] = Model
Пример #45
0
    def get(self):
        geoips = []
        for filename in DATA_FILES:
            try:
                geoips.append(pygeoip.GeoIP(filename))
            except (pygeoip.GeoIPError, IOError):
                pass

        sessions = LoginSession.query.order_by(
            LoginSession.id.desc()).limit(50).all()
        unknown_country = _(u'Country unknown')

        for session in sessions:
            country = unknown_country

            if geoips and session.ip_address:
                ip_address = session.ip_address
                multiple = ip_address.split(',')
                if multiple:
                    # only use last ip in the list, most likely the public address
                    ip_address = multiple[-1]
                for g in geoips:
                    try:
                        country = g.country_name_by_addr(ip_address)
                    except:  # noqa
                        continue

                    if country:
                        break
                    else:
                        country = unknown_country

                session.country = country

        return render_template("admin/login_sessions.html", **locals())
Пример #46
0
  def url_value_preprocess(self, endpoint, view_args):
    Model = view_args.pop('Model', None)
    group = view_args.pop('group', _MARKER)

    if group == u'_':
      # "General" group
      group = None

    if group is not _MARKER:
      view_args['group'] = group

    if Model is not None:
      svc = self.svc
      Model = svc.get_vocabulary(name=Model, group=group)
      g.breadcrumb.append(BreadcrumbItem(
          label=Model.Meta.group if group else _('Global'),
          url=url_for('.vocabularies_group', group=group or u'_'),
      ))
      g.breadcrumb.append(BreadcrumbItem(
          label=Model.Meta.label,
          url=url_for('.vocabularies_model',
                      group=group or u'_',
                      Model=Model.Meta.name),
      ))
      view_args['Model'] = Model
Пример #47
0
    def __call__(self, form, field):
        field_data_length = field.data and len(field.data) or 0

        if (field_data_length < self.min
                or self.max != -1 and field_data_length > self.max):
            message = self.message
            if message is None:
                if self.max == -1:
                    message = _n(
                        "Field must be at least %(min)d character long.",
                        "Field must be at least %(min)d characters long.",
                        self.min,
                        min=self.min,
                    )
                elif self.min == -1:
                    message = _n(
                        "Field cannot be longer than %(max)d character.",
                        "Field cannot be longer than %(max)d characters.",
                        self.max,
                        max=self.max,
                    )
                else:
                    message = _(
                        "Field must be between %(min)d and %(max)d characters long.",
                        min=self.min,
                        max=self.max,
                    )
            raise validators.ValidationError(message % {
                "min": self.min,
                "max": self.max,
                "length": field_data_length
            })
Пример #48
0
def wizard_new_accounts():
    """Complete new emails information."""
    if request.method == "GET":
        return redirect(url_for(".members", community_id=g.community.slug))

    g.breadcrumb.append(
        BreadcrumbItem(
            label=_("Members"),
            url=Endpoint("communities.members", community_id=g.community.slug),
        )
    )

    wizard_emails = request.form.get("wizard-emails")
    wizard_accounts = json.loads(wizard_emails)

    wizard_existing_account = {}
    new_accounts = []

    for user in wizard_accounts:
        if user["status"] == "existing":
            wizard_existing_account[user["email"]] = user["role"]

        elif user["status"] == "new":
            new_accounts.append(user)

    existing_account = json.dumps(wizard_existing_account)

    return render_template(
        "community/wizard_new_accounts.html",
        existing_account=existing_account,
        new_accounts=new_accounts,
    )
Пример #49
0
def page_compare():
    title = request.args["title"].strip()
    try:
        page = get_page_by_title(title)
    except NoResultFound:
        return redirect(
            url_for(".page_edit", title=title, community_id=g.community.slug)
        )
    revisions = page.revisions
    revisions = sorted(revisions, key=lambda x: x.number)
    revs_to_compare = []
    for arg in request.args:
        if arg.startswith("rev"):
            revs_to_compare.append(int(arg[3:]))
    if len(revs_to_compare) != 2:
        flash(_("You must check exactly 2 revisions."), "error")
        url = url_for(".page_changes", title=title, community_id=g.community.slug)
        return redirect(url)

    revs_to_compare.sort()
    from_rev = revisions[revs_to_compare[0]]
    to_rev = revisions[revs_to_compare[1]]
    assert from_rev.number == revs_to_compare[0]
    assert to_rev.number == revs_to_compare[1]

    from_lines = from_rev.body_src.splitlines(1)
    to_lines = to_rev.body_src.splitlines(1)

    differ = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK)
    diff = differ.compare(from_lines, to_lines)
    diff = [line for line in diff if not line.startswith("?")]

    actions.context["object"] = page
    ctx = {"page": page, "diff": diff, "rev1": from_rev, "rev2": to_rev}
    return render_template("wiki/compare.html", **ctx)
Пример #50
0
 def delete(self):
     session = db.session()
     session.delete(self.obj)
     activity.send(
         self,
         actor=g.user,
         verb="delete",
         object=self.obj,
         target=self.activity_target,
     )
     try:
         session.commit()
     except sa.exc.IntegrityError as e:
         rv = self.handle_commit_exception(e)
         if rv is not None:
             return rv
         session.rollback()
         logger.error(e)
         flash(
             _("This entity is referenced by another object and cannot be deleted."
               ),
             "error",
         )
         return self.redirect_to_view()
     else:
         flash(self.message_success(), "success")
         # FIXME: for DELETE verb response in case of success should be 200, 202
         # (accepted) or 204 (no content)
         return self.redirect_to_index()
Пример #51
0
    def data(self, *args, **kwargs):
        task_id = request.args.get("task_id")
        task = celery.result.AsyncResult(task_id)
        result = dict(state=task.state, exported=0, total=0)

        if task.state in ("REVOKED", "PENDING", "STARTED"):
            return result

        if task.state == "PROGRESS":
            result.update(task.result)
            return result

        if task.state == "FAILURE":
            result["message"] = _("An error happened during generation of file.")
            return result

        if task.state == "SUCCESS":
            result.update(task.result)
            handle = result["handle"]
            uploads = current_app.extensions["uploads"]
            filemeta = uploads.get_metadata(current_user, handle)
            result["filename"] = filemeta.get("filename", "export.xlsx")
            result["downloadUrl"] = url_for(
                "uploads.handle", handle=handle, _external=True
            )
            return result

        # unattended state, return data anyway
        # FIXME: log at error level for sentry?
        return result
Пример #52
0
    def url_value_preprocess(self, endpoint, view_args):
        model_name = view_args.pop("Model", None)
        group = view_args.pop("group", _MARKER)

        if group == "_":
            # "General" group
            group = ""

        if group is not _MARKER:
            view_args["group"] = group

        if model_name is not None:
            svc = get_service("vocabularies")
            Model = svc.get_vocabulary(name=model_name, group=group)
            g.breadcrumb.append(
                BreadcrumbItem(
                    label=Model.Meta.group if group else _("Global"),
                    url=url_for(".vocabularies_group", group=group or "_"),
                ))
            g.breadcrumb.append(
                BreadcrumbItem(
                    label=Model.Meta.label,
                    url=url_for(".vocabularies_model",
                                group=group or "_",
                                Model=Model.Meta.name),
                ))
            view_args["Model"] = Model
Пример #53
0
 def delete(self):
     session = db.session()
     session.delete(self.obj)
     activity.send(
         self,
         actor=g.user,
         verb="delete",
         object=self.obj,
         target=self.activity_target,
     )
     try:
         session.commit()
     except sa.exc.IntegrityError as e:
         rv = self.handle_commit_exception(e)
         if rv is not None:
             return rv
         session.rollback()
         logger.error(e)
         flash(
             _("This entity is referenced by another object and cannot be deleted."),
             "error",
         )
         return self.redirect_to_view()
     else:
         flash(self.message_success(), "success")
         # FIXME: for DELETE verb response in case of success should be 200, 202
         # (accepted) or 204 (no content)
         return self.redirect_to_index()
Пример #54
0
    def __call__(self, form, field):
        field_data_length = field.data and len(field.data) or 0

        if (
            field_data_length < self.min
            or self.max != -1
            and field_data_length > self.max
        ):
            message = self.message
            if message is None:
                if self.max == -1:
                    message = _n(
                        "Field must be at least %(min)d character long.",
                        "Field must be at least %(min)d characters long.",
                        self.min,
                        min=self.min,
                    )
                elif self.min == -1:
                    message = _n(
                        "Field cannot be longer than %(max)d character.",
                        "Field cannot be longer than %(max)d characters.",
                        self.max,
                        max=self.max,
                    )
                else:
                    message = _(
                        "Field must be between %(min)d and %(max)d characters long.",
                        min=self.min,
                        max=self.max,
                    )
            raise validators.ValidationError(
                message
                % {"min": self.min, "max": self.max, "length": field_data_length}
            )
Пример #55
0
def wizard_saving():
    """Automatically add existing accounts to the current community.

    Create accounts for new emails, add them to the community and send
    them a password reset email.
    """
    community = g.community._model
    existing_accounts = request.form.get("existing_account")
    existing_accounts = json.loads(existing_accounts)
    new_accounts = request.form.get("new_accounts")
    new_accounts = json.loads(new_accounts)

    if not (existing_accounts or new_accounts):
        flash(_("No new members were found"), "warning")
        return redirect(url_for(".members", community_id=g.community.slug))

    if existing_accounts:
        for email, role in existing_accounts.items():
            user = User.query.filter(User.email == email).first()
            community.set_membership(user, role)

            app = unwrap(current_app)
            activity.send(app, actor=user, verb="join", object=community)

            db.session.commit()

    if new_accounts:
        for account in new_accounts:
            email = account["email"]
            first_name = account["first_name"]
            last_name = account["last_name"]
            role = account["role"]

            user = User(
                email=email, last_name=last_name, first_name=first_name, can_login=True
            )
            db.session.add(user)

            community.set_membership(user, role)
            app = unwrap(current_app)
            activity.send(app, actor=user, verb="join", object=community)
            db.session.commit()

            send_reset_password_instructions(user)

    flash(_("New members added successfully"), "success")
    return redirect(url_for(".members", community_id=community.slug))
Пример #56
0
    def do_merge(self):
        target_id = request.form.get("merge_to", type=int)

        if not target_id:
            flash(_("You must select a target tag to merge to"), "error")
            return self.get(self.ns)

        target = Tag.query.filter(Tag.ns == self.ns, Tag.id == target_id).scalar()

        if not target:
            flash(_("Target tag not found, no action performed"), "error")
            return self.get(self.ns)

        merge_from = set(self._get_selected_tags())

        if target in merge_from:
            merge_from.remove(target)

        if not merge_from:
            flash(_("No tag selected for merging"), "warning")
            return self.get(self.ns)

        session = db.session()
        merge_from_ids = [t.id for t in merge_from]
        tbl = entity_tag_tbl
        entities_to_reindex = get_entities_for_reindex(merge_from)
        already_tagged = sa.sql.select([tbl.c.entity_id]).where(
            tbl.c.tag_id == target.id
        )
        del_dup = tbl.delete().where(
            sa.sql.and_(
                tbl.c.tag_id.in_(merge_from_ids), tbl.c.entity_id.in_(already_tagged)
            )
        )
        session.execute(del_dup)
        update = (
            tbl.update()
            .where(tbl.c.tag_id.in_(merge_from_ids))
            .values(tag_id=target.id)
        )
        session.execute(update)
        for merged in merge_from:
            session.delete(merged)
        session.commit()
        schedule_entities_reindex(entities_to_reindex)
        return self.redirect_to_view()
Пример #57
0
  def __call__(self, form, field):
    svc = get_service('antivirus')
    if not svc:
      return

    res = svc.scan(field.data)
    if res is False:
      raise ValidationError(_(u'Virus detected!'))
Пример #58
0
  def validate_password(self, field):
    pwd = field.data
    confirmed = self['confirm_password'].data

    if pwd != confirmed:
      raise ValidationError(
        _(u'Passwords differ. Ensure you have typed same password in both'
          u' "password" field and "confirm password" field.'))
Пример #59
0
  def __init__(self, *args, **kwargs):
    if len(args) == 0:
      kwargs.setdefault('name', 'tags')

    if len(args) < 2:
      kwargs.setdefault('label', _(u'Tags'))

    super(TagCriterion, self).__init__(*args, **kwargs)
Пример #60
0
def page_delete():
    title = request.form["title"].strip()
    try:
        page = get_page_by_title(title)
    except NoResultFound:
        flash(_("This page doesn't exist"), "error")
        return redirect(url_for(".index", community_id=g.community.slug))

    db.session.delete(page)

    app = unwrap(current_app)
    community = g.community._model
    activity.send(app, actor=current_user, verb="delete", object=page, target=community)

    db.session.commit()
    flash(_("Page %(title)s deleted.", title=title))
    return redirect(url_for(".index", community_id=g.community.slug))