Пример #1
0
def test_recursive_zip(community, client, req_ctx):
    user = community.test_user
    with client_login(client, user):
        data = {"action": "new", "title": "my folder"}
        folder = community.folder
        url = url_for(
            "documents.folder_post", community_id=community.slug, folder_id=folder.id
        )
        response = client.post(url, data=data)
        assert response.status_code == 302

        my_folder = folder.children[0]

        title = "onepage.pdf"
        content_type = "application/pdf"
        data = {"file": (open_file(title), title, content_type), "action": "upload"}
        url = url_for(
            "documents.folder_post", community_id=community.slug, folder_id=my_folder.id
        )
        response = client.post(url, data=data)
        assert response.status_code == 302

        data = {
            "action": "download",
            "object-selected": ["cmis:folder:%d" % my_folder.id],
        }
        url = url_for(
            "documents.folder_post", community_id=community.slug, folder_id=folder.id
        )
        response = client.post(url, data=data)
        assert response.status_code == 200
        assert response.content_type == "application/zip"

        zipfile = ZipFile(BytesIO(response.data))
        assert zipfile.namelist() == ["my folder/" + title]
Пример #2
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)
Пример #3
0
def test_zip(community, client, req_ctx):
    user = community.test_user
    with client_login(client, user):
        title = "onepage.pdf"
        content_type = "application/pdf"
        data = {
            "file": (open_file(title), title, content_type),
            "action": "upload"
        }
        folder = community.folder
        url = url_for("documents.folder_post",
                      community_id=community.slug,
                      folder_id=folder.id)
        response = client.post(url, data=data)
        assert response.status_code == 302

        doc = folder.children[0]
        data = {
            "action": "download",
            "object-selected": ["cmis:document:%d" % doc.id]
        }
        url = url_for("documents.folder_post",
                      community_id=community.slug,
                      folder_id=folder.id)
        response = client.post(url, data=data)
        assert response.status_code == 200
        assert response.content_type == "application/zip"

        zipfile = ZipFile(BytesIO(response.data))
        assert [zipfile.namelist()[0]] == [title]
Пример #4
0
    def test_zip(self):
        with self.client_login(self.user.email, password='******'):
            title = u"onepage.pdf"
            content_type = "application/pdf"
            data = {
                'file': (self.open_file(title), title, content_type),
                'action': 'upload',
            }
            folder = self.community.folder
            url = url_for(
                "documents.folder_post",
                community_id=self.community.slug,
                folder_id=folder.id)
            response = self.client.post(url, data=data)
            self.assert_302(response)

            doc = folder.children[0]
            data = {
                'action': 'download',
                'object-selected': ["cmis:document:%d" % doc.id]
            }
            url = url_for(
                "documents.folder_post",
                community_id=self.community.slug,
                folder_id=folder.id)
            response = self.client.post(url, data=data)
            self.assert_200(response)
            assert response.content_type == 'application/zip'

            zipfile = ZipFile(BytesIO(response.data))
            assert zipfile.namelist() == [title]
Пример #5
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
Пример #6
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
Пример #7
0
  def get(self):
    # FIXME: use widgets.AjaxMainTableView instead
    datatable_options = {
      'sDom': 'lfFrtip',
      'aaSorting': [
        [0, u'asc'],
      ],
      'aoColumns': [
        dict(asSorting=['asc', 'desc']),
        dict(bSortable=False),
        dict(bSortable=False),
      ],
      'bFilter': True,
      'oLanguage': {
        'sSearch': _("Filter records:"),
        'sPrevious': _("Previous"),
        'sNext': _("Next"),
        'sInfo': _("Showing _START_ to _END_ of _TOTAL_ entries"),
        'sInfoFiltered': _("(filtered from _MAX_ total entries)"),
        'sAddAdvancedFilter': _("Add a filter"),
      },
      'bStateSave': False,
      'bPaginate': True,
      'sPaginationType': "bootstrap",
      'bLengthChange': False,
      'iDisplayLength': 30,
      'bProcessing': True,
      'bServerSide': True,
      'sAjaxSource': url_for('.groups_json_list'),
    }

    return render_template('admin/groups.html',
                           next=next,
                           datatable_options=datatable_options)
Пример #8
0
    def get(self):
        # FIXME: use widgets.AjaxMainTableView instead
        datatable_options = {
            "sDom": "lfFritip",
            "aaSorting": [[1, u"asc"]],
            "aoColumns": [
                dict(bSortable=False),
                dict(asSorting=["asc", "desc"]),
                dict(asSorting=["asc", "desc"]),
                dict(bSortable=False),
                dict(bSortable=False),
                dict(bSortable=False),
                dict(asSorting=["asc", "desc"]),
            ],
            "bFilter": True,
            "oLanguage": {
                "sSearch": _("Filter records:"),
                "sPrevious": _("Previous"),
                "sNext": _("Next"),
                "sInfo": _("Showing _START_ to _END_ of _TOTAL_ entries"),
                "sInfoFiltered": _("(filtered from _MAX_ total entries)"),
                "sAddAdvancedFilter": _("Add a filter"),
            },
            "bStateSave": False,
            "bPaginate": True,
            "sPaginationType": "bootstrap",
            "bLengthChange": False,
            "iDisplayLength": 30,
            "bProcessing": True,
            "bServerSide": True,
            "sAjaxSource": url_for(".users_json_list"),
        }

        return render_template("admin/users.html", next=next, datatable_options=datatable_options)
Пример #9
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)
Пример #10
0
def home():
    """Home page.

    Actually there is no home page, so we redirect to the most
    appropriate place.
    """
    return redirect(url_for("social.home"))
Пример #11
0
    def get(self):
        # FIXME: use widgets.AjaxMainTableView instead
        datatable_options = {
            "sDom":
            "lfFritip",
            "aaSorting": [[1, "asc"]],
            "aoColumns": [
                {
                    "bSortable": False
                },
                {
                    "asSorting": ["asc", "desc"]
                },
                {
                    "asSorting": ["asc", "desc"]
                },
                {
                    "bSortable": False
                },
                {
                    "bSortable": False
                },
                {
                    "bSortable": False
                },
                {
                    "asSorting": ["asc", "desc"]
                },
            ],
            "bFilter":
            True,
            "oLanguage": {
                "sSearch": _("Filter records:"),
                "sPrevious": _("Previous"),
                "sNext": _("Next"),
                "sInfo": _("Showing _START_ to _END_ of _TOTAL_ entries"),
                "sInfoFiltered": _("(filtered from _MAX_ total entries)"),
                "sAddAdvancedFilter": _("Add a filter"),
            },
            "bStateSave":
            False,
            "bPaginate":
            True,
            "sPaginationType":
            "bootstrap",
            "bLengthChange":
            False,
            "iDisplayLength":
            30,
            "bProcessing":
            True,
            "bServerSide":
            True,
            "sAjaxSource":
            url_for(".users_json_list"),
        }

        return render_template("admin/users.html",
                               next=next,
                               datatable_options=datatable_options)
Пример #12
0
    def data(self, *args, **kw) -> Dict:
        security = get_service("security")
        length = int(kw.get("iDisplayLength", 0))
        start = int(kw.get("iDisplayStart", 0))
        sort_dir = kw.get("sSortDir_0", "asc")
        echo = int(kw.get("sEcho", 0))
        search = kw.get("sSearch", "").replace("%", "").strip().lower()

        end = start + length
        # pyre-fixme[16]: `Group` has no attribute `query`.
        query = Group.query.options(sa.orm.noload("*"))
        total_count = query.count()

        if search:
            # TODO: gérer les accents
            query = query.filter(
                func.lower(Group.name).like("%" + search + "%"))

        count = query.count()
        columns = [func.lower(Group.name)]
        direction = asc if sort_dir == "asc" else desc
        order_by = list(map(direction, columns))

        # sqlite does not support 'NULLS FIRST|LAST' in ORDER BY clauses
        # pyre-fixme[16]: `Group` has no attribute `__mapper__`.
        engine = query.session.get_bind(Group.__mapper__)
        if engine.name != "sqlite":
            order_by[0] = nullslast(order_by[0])

        query = query.order_by(*order_by).add_columns(Group.members_count)
        groups = query.slice(start, end).all()
        data = []

        for group, members_count in groups:
            # TODO: this should be done on the browser.
            group_url = url_for(".groups_group", group_id=group.id)
            name = html.escape(group.name or "")
            # pyre-fixme[16]: `Service` has no attribute `get_roles`.
            roles = [r for r in security.get_roles(group) if r.assignable]

            columns = [
                f'<a href="{group_url}">{name}</a>',
                str(members_count or 0),
                render_template_string(
                    """{%- for role in roles %}
                        <span class="badge badge-default">{{ role }}</span>
                        {%- endfor %}""",
                    roles=roles,
                ),
                "\u2713" if group.public else "",
            ]

            data.append(columns)

        return {
            "sEcho": echo,
            "iTotalRecords": total_count,
            "iTotalDisplayRecords": count,
            "aaData": data,
        }
Пример #13
0
    def data(self, *args, **kw):
        security = get_service('security')
        length = int(kw.get("iDisplayLength", 0))
        start = int(kw.get("iDisplayStart", 0))
        sort_dir = kw.get("sSortDir_0", "asc")
        echo = int(kw.get("sEcho", 0))
        search = kw.get("sSearch", "").replace("%", "").strip().lower()

        end = start + length
        query = Group.query \
            .options(sa.orm.noload('*'))
        total_count = query.count()

        if search:
            # TODO: gérer les accents
            query = query.filter(
                func.lower(Group.name).like("%" + search + "%"),
            )

        count = query.count()
        columns = [func.lower(Group.name)]
        direction = asc if sort_dir == 'asc' else desc
        order_by = list(map(direction, columns))

        # sqlite does not support 'NULLS FIRST|LAST' in ORDER BY clauses
        engine = query.session.get_bind(Group.__mapper__)
        if engine.name != 'sqlite':
            order_by[0] = nullslast(order_by[0])

        query = query.order_by(*order_by) \
            .add_columns(Group.members_count)
        groups = query.slice(start, end).all()
        data = []

        for group, members_count in groups:
            # TODO: this should be done on the browser.
            group_url = url_for(".groups_group", group_id=group.id)
            name = escape(getattr(group, "name") or "")
            roles = [r for r in security.get_roles(group) if r.assignable]

            columns = [
                '<a href="{url}">{name}</a>'.format(url=group_url, name=name),
                text_type(members_count or 0),
                render_template_string(
                    '''{%- for role in roles %}
                        <span class="badge badge-default">{{ role }}</span>
                        {%- endfor %}''',
                    roles=roles,
                ),
                '\u2713' if group.public else '',
            ]

            data.append(columns)

        return {
            "sEcho": echo,
            "iTotalRecords": total_count,
            "iTotalDisplayRecords": count,
            "aaData": data,
        }
Пример #14
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))
Пример #15
0
  def render(self):
    render = render_template_string
    e = self.entry

    manager = render(
        u'<img class="avatar" '
        u'src="{{ user_photo_url(user=e.manager, size=16) }}" alt="" />'
        u'<a href="''{{ url_for("social.user", user_id=e.manager.id) }}">'
        u'{{ e.manager.name }}</a>', e=e)

    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)
    else:
      principal = u''

    entity = u''
    if e.object_id:
      entity_url = None
      entity_name = e.object_name
      if e.object:
        entity_name = getattr(e.object, 'path', e.object.name)
        entity_url = url_for(e.object)

      entity = render(
          u'{%- if url %}<a href="{{ url }}">{%- endif %}'
          u'{{ name }}{%- if url %}</a>{%- endif %}',
          url=entity_url,
          name=entity_name)

      if e.op == e.SET_INHERIT:
        msg = _(u'{manager} has activated inheritance on {entity}')
      elif e.op == e.UNSET_INHERIT:
        msg = _(u'{manager} has deactivated inheritance on {entity}')
      elif e.op == e.GRANT:
        msg = _(u'{manager} has given role "{role}" to {principal} '
                'on {entity}')
      elif e.op == e.REVOKE:
        msg = _(u'{manager} has revoked role "{role}" from '
                '{principal} on {entity}')
      else:
        raise Exception("Invalid entity op: {}".format(e.op))
    else:
      if e.op == e.GRANT:
        msg = _(u'{manager} has given role "{role}" to {principal}')
      elif e.op == e.REVOKE:
        msg = _(u'{manager} has revoked role "{role}" from {principal}')
      else:
        raise Exception("Invalid entity op: {}".format(e.op))

    self.msg = Markup(msg.format(manager=manager,
                                 principal=principal,
                                 role=e.role,
                                 entity=entity))
    tmpl = get_template_attribute('admin/_macros.html', 'm_security_entry')
    return tmpl(self)
Пример #16
0
  def data(self, *args, **kw):
    security = current_app.services['security']
    length = int(kw.get("iDisplayLength", 0))
    start = int(kw.get("iDisplayStart", 0))
    sort_dir = kw.get("sSortDir_0", "asc")
    echo = int(kw.get("sEcho", 0))
    search = kw.get("sSearch", "").replace("%", "").strip().lower()

    end = start + length
    q = Group.query \
      .options(sa.orm.noload('*'))
    total_count = q.count()

    if search:
      # TODO: gérer les accents
      q = q.filter(func.lower(Group.name).like("%" + search + "%"))

    count = q.count()
    columns = [func.lower(Group.name)]
    direction = asc if sort_dir == 'asc' else desc
    order_by = map(direction, columns)

    # sqlite does not support 'NULLS FIRST|LAST' in ORDER BY clauses
    engine = q.session.get_bind(Group.__mapper__)
    if engine.name != 'sqlite':
      order_by[0] = nullslast(order_by[0])

    q = q.order_by(*order_by) \
      .add_columns(Group.members_count)
    groups = q.slice(start, end).all()
    data = []

    for group, members_count in groups:
      # TODO: this should be done on the browser.
      group_url = url_for(".groups_group", group_id=group.id)
      name = escape(getattr(group, "name") or "")
      roles = [r for r in security.get_roles(group) if r.assignable]
      columns = []
      columns.append(
        u'<a href="{url}">{name}</a>'.format(url=group_url, name=name)
      )
      columns.append(unicode(members_count or 0))
      columns.append(render_template_string(
        u'''{%- for role in roles %}
            <span class="badge badge-default">{{ role }}</span>
            {%- endfor %}''',
        roles=roles))
      columns.append(u'\u2713' if group.public else u'')
      data.append(columns)

    return {
      "sEcho": echo,
      "iTotalRecords": total_count,
      "iTotalDisplayRecords": count,
      "aaData": data,
    }
Пример #17
0
    def data(self, *args, **kw):
        security = get_service("security")
        length = int(kw.get("iDisplayLength", 0))
        start = int(kw.get("iDisplayStart", 0))
        sort_dir = kw.get("sSortDir_0", "asc")
        echo = int(kw.get("sEcho", 0))
        search = kw.get("sSearch", "").replace("%", "").strip().lower()

        end = start + length
        query = Group.query.options(sa.orm.noload("*"))
        total_count = query.count()

        if search:
            # TODO: gérer les accents
            query = query.filter(func.lower(Group.name).like("%" + search + "%"))

        count = query.count()
        columns = [func.lower(Group.name)]
        direction = asc if sort_dir == "asc" else desc
        order_by = list(map(direction, columns))

        # sqlite does not support 'NULLS FIRST|LAST' in ORDER BY clauses
        engine = query.session.get_bind(Group.__mapper__)
        if engine.name != "sqlite":
            order_by[0] = nullslast(order_by[0])

        query = query.order_by(*order_by).add_columns(Group.members_count)
        groups = query.slice(start, end).all()
        data = []

        for group, members_count in groups:
            # TODO: this should be done on the browser.
            group_url = url_for(".groups_group", group_id=group.id)
            name = html.escape(group.name or "")
            roles = [r for r in security.get_roles(group) if r.assignable]

            columns = [
                f'<a href="{group_url}">{name}</a>',
                str(members_count or 0),
                render_template_string(
                    """{%- for role in roles %}
                        <span class="badge badge-default">{{ role }}</span>
                        {%- endfor %}""",
                    roles=roles,
                ),
                "\u2713" if group.public else "",
            ]

            data.append(columns)

        return {
            "sEcho": echo,
            "iTotalRecords": total_count,
            "iTotalDisplayRecords": count,
            "aaData": data,
        }
Пример #18
0
def page_source():
    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))

    actions.context['object'] = page
    return render_template('wiki/source.html', page=page)
Пример #19
0
 def test_home(self):
     with self.client_login(self.user.email, password='******'):
         response = self.get(
             url_for(
                 'documents.index', community_id=self.community.slug))
         self.assert_status(response, 302)
         self.assertEqual(
             response.headers['Location'],
             u'http://localhost/communities/{}/docs/folder/{}'
             u''.format(self.community.slug, self.folder.id),)
Пример #20
0
def test_home(app, client, db, community, req_ctx):
    folder = community.folder
    user = community.test_user

    with client_login(client, user):
        response = client.get(url_for("documents.index", community_id=community.slug))
        assert response.status_code == 302
        path = path_from_url(response.location)
        expected = f"/communities/{community.slug}/docs/folder/{folder.id}"
        assert path == expected
Пример #21
0
def page_source():
    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)
        )

    actions.context["object"] = page
    return render_template("wiki/source.html", page=page)
Пример #22
0
def get_body_document(object):
    # type: (Document) -> Markup
    body = bleach.clean(object.body_html, tags=[], strip=True)
    body = Markup(body).unescape()
    if len(body) > 400:
        body = body[0:400] + "…"
    body = render_template_string(DOCUMENT_BODY_TEMPLATE,
                                  object_url=url_for(object),
                                  body=body,
                                  post=object)
    return Markup(body)
Пример #23
0
def page_changes():
    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)
    actions.context['object'] = page
    return render_template('wiki/changes.html', page=page, revisions=revisions)
Пример #24
0
def page_changes():
    title = request.args["title"].strip()
    try:
        page = get_page_by_title(title)
    except NoResultFound:
        url = url_for(".page_edit", title=title, community_id=g.community.slug)
        return redirect(url)
    revisions = page.revisions
    revisions = sorted(revisions, key=lambda x: -x.number)
    actions.context["object"] = page
    return render_template("wiki/changes.html", page=page, revisions=revisions)
Пример #25
0
def get_body_thread(object):
    # type: (Thread) -> Markup
    body = bleach.clean(object.posts[0].body_html, tags=[], strip=True)
    body = Markup(body).unescape()
    if len(body) > 400:
        body = body[0:400] + "…"
    body = render_template_string(POST_BODY_TEMPLATE,
                                  object_url=url_for(object),
                                  body=body,
                                  post=object.posts[0])
    return Markup(body)
Пример #26
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(_(u"You must check exactly 2 revisions."), "error")
        return redirect(
            url_for(".page_changes",
                    title=title,
                    community_id=g.community.slug))

    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
    return render_template(
        'wiki/compare.html',
        page=page,
        diff=diff,
        rev1=from_rev,
        rev2=to_rev,
    )
Пример #27
0
def test_home(app, client, db, community, req_ctx):
    folder = community.folder
    user = community.test_user

    with client_login(client, user):
        response = client.get(
            url_for("documents.index", community_id=community.slug))
        assert response.status_code == 302
        path = path_from_url(response.location)
        expected = "/communities/{}/docs/folder/{}".format(
            community.slug, folder.id)
        assert path == expected
Пример #28
0
def page_delete():
    title = request.form['title'].strip()
    try:
        page = get_page_by_title(title)
    except NoResultFound:
        flash(_(u"This page doesn't exist"), "error")
        return redirect(url_for(".index", community_id=g.community.slug))

    db.session.delete(page)

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

    db.session.commit()
    flash(_(u"Page %(title)s deleted.", title=title))
    return redirect(url_for(".index", community_id=g.community.slug))
Пример #29
0
    def init_object(self, args, kwargs):
        args, kwargs = BasePageView.init_object(self, args, kwargs)
        if not self.obj:
            title = kwargs["title"]
            if title == "Home":
                self.obj = create_home_page()
            else:
                url = url_for(".page_edit", title=title, community_id=g.community.slug)
                return redirect(url)

        actions.context["object"] = self.obj
        viewtracker.record_hit(entity=self.obj, user=current_user)
        return args, kwargs
Пример #30
0
    def __html__(self):
        endpoint = self.endpoint
        if callable(endpoint):
            endpoint = endpoint()

        url_args = self.get_url_args()
        if self.url_args_callback is not None:
            url_args = self.url_args_callback(self, url_args)

        return self.template.render(url=url_for(endpoint, **url_args),
                                    width=self.width,
                                    height=self.height,
                                    css=self.css)
Пример #31
0
def _test_upload(
    community,
    client,
    title,
    content_type,
    test_preview=True,
    assert_preview_available=True,
):
    data = {"file": (open_file(title), title, content_type), "action": "upload"}

    folder = community.folder
    url = url_for(
        "documents.folder_post", community_id=community.slug, folder_id=folder.id
    )
    response = client.post(url, data=data)
    assert response.status_code == 302

    doc = folder.children[0]
    assert doc.title == title

    url = url_for("documents.document_view", community_id=community.slug, doc_id=doc.id)
    response = client.get(url)
    assert response.status_code == 200

    url = url_for(
        "documents.document_download", community_id=community.slug, doc_id=doc.id
    )
    response = client.get(url)
    assert response.status_code == 200
    assert response.headers["Content-Type"] == content_type

    content = open_file(title).read()
    assert response.data == content

    if test_preview:
        url = url_for(
            "documents.document_preview_image",
            community_id=community.slug,
            doc_id=doc.id,
            size=500,
        )
        response = client.get(url)
        if assert_preview_available:
            assert response.status_code == 200
            assert response.headers["Content-Type"] == "image/jpeg"
        else:
            # redirect to 'missing image'
            assert response.status_code == 302
            assert response.headers["Cache-Control"] == "no-cache"

    url = url_for(
        "documents.document_delete", community_id=community.slug, doc_id=doc.id
    )
    response = client.post(url)
    assert response.status_code == 302

    url = url_for("documents.document_view", community_id=community.slug, doc_id=doc.id)
    response = client.get(url)
    assert response.status_code == 404
Пример #32
0
  def __html__(self):
    endpoint = self.endpoint
    if callable(endpoint):
      endpoint = endpoint()

    url_args = self.get_url_args()
    if self.url_args_callback is not None:
      url_args = self.url_args_callback(self, url_args)

    return self.template.render(
      url=url_for(endpoint, **url_args),
      width=self.width,
      height=self.height,
      css=self.css)
Пример #33
0
    def init_object(self, args, kwargs):
        args, kwargs = BasePageView.init_object(self, args, kwargs)
        if not self.obj:
            title = kwargs['title']
            if title == u'Home':
                self.obj = create_home_page()
            else:
                return redirect(
                    url_for(".page_edit",
                            title=title,
                            community_id=g.community.slug))

        actions.context['object'] = self.obj
        return args, kwargs
Пример #34
0
    def init_object(self, args, kwargs):
        args, kwargs = BasePageView.init_object(self, args, kwargs)
        if not self.obj:
            title = kwargs["title"]
            if title == "Home":
                self.obj = create_home_page()
            else:
                url = url_for(".page_edit",
                              title=title,
                              community_id=g.community.slug)
                return redirect(url)

        actions.context["object"] = self.obj
        viewtracker.record_hit(entity=self.obj, user=current_user)
        return args, kwargs
Пример #35
0
 def init_object(self, args, kwargs):
     title = kwargs['title'] = request.args['title'].strip()
     if title:
         try:
             self.obj = get_page_by_title(title)
         except NoResultFound:
             if title == u'Home':
                 self.obj = create_home_page()
             else:
                 flash(
                     _(u"This page doesn't exit. You must create it first."
                       ), "warning")
                 self.redirect(
                     url_for(".page_new",
                             title=title,
                             community_id=g.community.slug))
         actions.context['object'] = self.obj
     return args, kwargs
Пример #36
0
def attachment_delete():
    title = request.args['title'].strip()
    attachment_id = int(request.args['attachment'])
    try:
        page = get_page_by_title(title)
    except NoResultFound:
        raise NotFound()

    attachment = WikiPageAttachment.query.get(attachment_id)
    assert attachment is not None
    assert attachment.wikipage is page

    if request.form.get('action') == 'delete':
        name = attachment.name
        db.session.delete(attachment)
        db.session.commit()
        flash(_(u'Attachment "{name}" has been deleted').format(name=name))

    return redirect(url_for(page))
Пример #37
0
def attachment_delete():
    title = request.args["title"].strip()
    attachment_id = int(request.args["attachment"])
    try:
        page = get_page_by_title(title)
    except NoResultFound:
        raise NotFound()

    attachment = WikiPageAttachment.query.get(attachment_id)
    assert attachment is not None
    assert attachment.wikipage is page

    if request.form.get("action") == "delete":
        name = attachment.name
        db.session.delete(attachment)
        db.session.commit()
        flash(_('Attachment "{name}" has been deleted').format(name=name))

    return redirect(url_for(page))
Пример #38
0
 def init_object(self, args, kwargs):
     title = kwargs["title"] = request.args["title"].strip()
     if title:
         try:
             self.obj = get_page_by_title(title)
         except NoResultFound:
             if title == "Home":
                 self.obj = create_home_page()
             else:
                 flash(
                     _("This page doesn't exit. You must create it first."),
                     "warning",
                 )
                 url = url_for(
                     ".page_new", title=title, community_id=g.community.slug
                 )
                 self.redirect(url)
         actions.context["object"] = self.obj
     return args, kwargs
Пример #39
0
def login_required():
    """Before request handler to ensure login is required on any view."""
    if current_app.config.get("NO_LOGIN"):
        return

    if request.path.startswith(current_app.static_url_path):
        return

    if request.url_rule and request.url_rule.endpoint == "geodata.static":
        # geodata blueprint assets
        return

    if request.blueprint in ("login", "first_login", "projects",
                             "notifications"):
        return

    if request.blueprint == "_debug_toolbar" and current_app.debug:
        return

    if not current_user.is_authenticated:
        return redirect(url_for("login.login_form", next=request.url))
Пример #40
0
def attachment_upload():
    title = request.args["title"].strip()
    try:
        page = get_page_by_title(title)
    except NoResultFound:
        raise NotFound()

    files = request.files.getlist("attachments")
    saved_count = 0

    for f in files:
        name = f.filename
        if not isinstance(name, text_type):
            name = text_type(f.filename, encoding="utf-8", errors="ignore")

        # FIXME: do something instead of just skipping the attachement
        if not name:
            continue

        attachment = WikiPageAttachment(name=name)
        attachment.wikipage = page
        attachment.set_content(f.read(), f.content_type)
        db.session.add(attachment)
        saved_count += 1

    if saved_count:
        db.session.commit()
        flash(
            _n(
                "One new document successfully uploaded",
                "%(num)d new documents successfully uploaded",
                count=saved_count,
                num=len(files),
            ),
            "success",
        )
    else:
        flash(_("No file uploaded."))

    return redirect(url_for(page))
Пример #41
0
def attachment_upload():
    title = request.args["title"].strip()
    try:
        page = get_page_by_title(title)
    except NoResultFound:
        raise NotFound()

    files = request.files.getlist("attachments")
    saved_count = 0

    for f in files:
        name = f.filename
        if not isinstance(name, str):
            name = str(f.filename, encoding="utf-8", errors="ignore")

        # FIXME: do something instead of just skipping the attachement
        if not name:
            continue

        attachment = WikiPageAttachment(name=name)
        attachment.wikipage = page
        attachment.set_content(f.read(), f.content_type)
        db.session.add(attachment)
        saved_count += 1

    if saved_count:
        db.session.commit()
        flash(
            _n(
                "One new document successfully uploaded",
                "%(num)d new documents successfully uploaded",
                count=saved_count,
                num=len(files),
            ),
            "success",
        )
    else:
        flash(_("No file uploaded."))

    return redirect(url_for(page))
Пример #42
0
    def test_zip_upload_uncompress(self):
        folder = Folder(title=u'folder 1', parent=self.community.folder)
        self.session.add(folder)
        self.session.flush()
        folder = self.community.folder
        files = []
        files.append((BytesIO(b'A document'), u'existing-doc', 'text/plain'))
        files.append((self.open_file('content.zip'), u'content.zip',
                      'application/zip'))
        data = {'file': files, 'action': 'upload', 'uncompress_files': True}
        url = url_for(
            "documents.folder_post",
            community_id=self.community.slug,
            folder_id=folder.id)
        with self.client_login(self.user.email, password='******'):
            response = self.client.post(url, data=data)

        expected = {u'existing-doc', u'folder 1', u'existing-doc-1'}
        self.assert_status(response, 302)
        assert expected == {f.title for f in folder.children}
        expected = {u'folder 1', u'existing-doc-1'}
        assert expected == {f.title for f in folder.subfolders}
Пример #43
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(
                        '<a href="{{ url }}">{{ entity.path or entity.name }}</a>',
                        url=entity_url,
                        entity=e.entity,
                    ), )

        if e.type == 0:
            msg = _('{user} created {entity_type} {entity_id} "{entity}"')
        elif e.related or e.op == 1:
            msg = _(
                '{user} made changes on {entity_type} {entity_id} "{entity}"')
        elif e.op == 2:
            msg = _('{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)
Пример #44
0
def test_zip_upload_uncompress(community, db, client, req_ctx):
    subfolder = Folder(title="folder 1", parent=community.folder)
    db.session.add(subfolder)
    db.session.flush()

    folder = community.folder
    files = []
    files.append((BytesIO(b"A document"), "existing-doc", "text/plain"))
    files.append((open_file("content.zip"), "content.zip", "application/zip"))
    data = {"file": files, "action": "upload", "uncompress_files": True}
    url = url_for("documents.folder_post",
                  community_id=community.slug,
                  folder_id=folder.id)
    user = community.test_user
    with client_login(client, user):
        response = client.post(url, data=data)

    assert response.status_code == 302
    expected = {"existing-doc", "folder 1", "existing-doc-1"}
    assert expected == {f.title for f in folder.children}
    expected = {"folder 1", "existing-doc-1"}
    assert expected == {f.title for f in folder.subfolders}
Пример #45
0
def test_zip_upload_uncompress(community, db, client, req_ctx):
    subfolder = Folder(title="folder 1", parent=community.folder)
    db.session.add(subfolder)
    db.session.flush()

    folder = community.folder
    files = []
    files.append((BytesIO(b"A document"), "existing-doc", "text/plain"))
    files.append((open_file("content.zip"), "content.zip", "application/zip"))
    data = {"file": files, "action": "upload", "uncompress_files": True}
    url = url_for(
        "documents.folder_post", community_id=community.slug, folder_id=folder.id
    )
    user = community.test_user
    with client_login(client, user):
        response = client.post(url, data=data)

    assert response.status_code == 302
    expected = {"existing-doc", "folder 1", "existing-doc-1"}
    assert expected == {f.title for f in folder.children}
    expected = {"folder 1", "existing-doc-1"}
    assert expected == {f.title for f in folder.subfolders}
Пример #46
0
 def index_url(self):
   return url_for('.users')
Пример #47
0
 def view_url(self):
   return url_for('.groups_group', group_id=self.obj.id)
Пример #48
0
 def index_url(self):
   return url_for('.groups')
Пример #49
0
def index():
    return redirect(url_for(".page", title="Home", community_id=g.community.slug))
Пример #50
0
 def index_url(self):
     return url_for(".index", community_id=g.community.slug)
Пример #51
0
 def __unicode__(self):
   return unicode(url_for(self.name, *self.args, **self.get_kwargs()))
Пример #52
0
 def object_url(self):
     return url_for(self._model.object)
Пример #53
0
 def redirect_if_no_change(self):
     form = self.form
     if all(f.data == f.object_data for f in (form.title, form.body_src)):
         flash(_("You didn't make any change to this page."))
         return self.redirect(url_for(self.obj))
Пример #54
0
 def index_url(self):
     return url_for('.groups')
Пример #55
0
 def view_url(self):
     return url_for(
         self.view_endpoint, community_id=g.community.slug, title=self.obj.title
     )
Пример #56
0
def home():
    """
    Home page. Actually there is no home page, so for this demo
    we redirect to the most appropriate place.
    """
    return redirect(url_for("admin.settings"))
Пример #57
0
def test_document_send_by_mail(app, community, client, req_ctx):
    mail = app.extensions["mail"]
    folder = community.folder
    user = community.test_user
    with client_login(client, user):
        # upload files
        for filename in ("ascii title.txt", "utf-8 est arrivé!.txt"):
            content_type = "text/plain"
            data = {
                "file": (BytesIO(b"file content"), filename, content_type),
                "action": "upload",
            }
            url = url_for(
                "documents.folder_post",
                community_id=community.slug,
                folder_id=folder.id,
            )
            client.post(url, data=data)

        ascii_doc = folder.children[0]
        unicode_doc = folder.children[1]

        def get_send_url(doc_id):
            return url_for(
                "documents.document_send", community_id=community.slug, doc_id=doc_id
            )

        # mail ascii filename
        with mail.record_messages() as outbox:
            url = get_send_url(ascii_doc.id)
            response = client.post(
                url,
                data={"recipient": "*****@*****.**", "message": "Voilà un fichier"},
            )
            assert response.status_code == 302
            assert len(outbox) == 1

            msg = outbox[0]
            assert msg.subject == "[Abilian Test] Unknown sent you a file"
            assert msg.recipients == ["*****@*****.**"]

            assert len(msg.attachments) == 1

            attachment = first(msg.attachments)
            assert isinstance(attachment, flask_mail.Attachment)
            assert attachment.filename == "ascii title.txt"

        # mail unicode filename
        with mail.record_messages() as outbox:
            url = get_send_url(unicode_doc.id)
            response = client.post(
                url,
                data={"recipient": "*****@*****.**", "message": "Voilà un fichier"},
            )
            assert response.status_code == 302
            assert len(outbox) == 1

            msg = outbox[0]
            assert isinstance(msg, flask_mail.Message)
            assert msg.subject == "[Abilian Test] Unknown sent you a file"
            assert msg.recipients == ["*****@*****.**"]
            assert len(msg.attachments) == 1

            attachment = first(msg.attachments)
            assert isinstance(attachment, flask_mail.Attachment)
            assert attachment.filename == "utf-8 est arrivé!.txt"
Пример #58
0
  def data(self, *args, **kw):
    security = current_app.services['security']
    length = int(kw.get("iDisplayLength", 0))
    start = int(kw.get("iDisplayStart", 0))
    sort_col = int(kw.get("iSortCol_0", 1))
    sort_dir = kw.get("sSortDir_0", "asc")
    echo = int(kw.get("sEcho", 0))
    search = kw.get("sSearch", "").replace("%", "").strip().lower()

    end = start + length
    q = User.query \
      .options(sa.orm.subqueryload('groups'),
               sa.orm.undefer('photo'), ) \
      .filter(User.id != 0)
    total_count = q.count()

    if search:
      # TODO: gérer les accents
      filter = or_(func.lower(User.first_name).like("%" + search + "%"),
                   func.lower(User.last_name).like("%" + search + "%"),
                   func.lower(User.email).like("%" + search + "%"))
      q = q.filter(filter)

    count = q.count()
    SORT_COLS = {
      1: [],  # [User.last_name, User.first_name] will be added anyway
      2: [func.lower(User.email)],
      5: [User.last_active],
    }
    columns = list(SORT_COLS.get(sort_col, []))
    columns.extend([func.lower(User.last_name), func.lower(User.first_name)])

    direction = asc if sort_dir == 'asc' else desc
    order_by = map(direction, columns)

    # sqlite does not support 'NULLS FIRST|LAST' in ORDER BY clauses
    engine = q.session.get_bind(User.__mapper__)
    if engine.name != 'sqlite':
      order_by[0] = nullslast(order_by[0])

    q = q.order_by(*order_by)

    users = q.slice(start, end).all()

    data = []
    MUGSHOT_SIZE = 45
    for user in users:
      # TODO: this should be done on the browser.
      user_url = url_for(".users_user", user_id=user.id)
      mugshot = user_photo_url(user, size=MUGSHOT_SIZE)
      name = escape(getattr(user, "name") or "")
      email = escape(getattr(user, "email") or "")
      roles = [r for r in security.get_roles(user, no_group_roles=True)
               if r.assignable]
      columns = []
      columns.append(
        u'<a href="{url}"><img src="{src}" width="{size}" height="{size}">'
        u'</a>'.format(url=user_url, src=mugshot, size=MUGSHOT_SIZE)
      )
      columns.append(
        u'<a href="{url}">{name}</a>'.format(url=user_url, name=name))
      columns.append(
        u'<a href="{url}"><em>{email}</em></a>'.format(url=user_url,
                                                       email=email))
      columns.append(u'\u2713' if user.can_login else u'')
      columns.append(render_template_string(
        u'''{%- for g in groups %}
            <span class="badge badge-default">{{ g.name }}</span>
            {%- endfor %}''',
        groups=sorted(user.groups)))
      columns.append(render_template_string(
        u'''{%- for role in roles %}
            <span class="badge badge-default">{{ role }}</span>
            {%- endfor %}''',
        roles=roles))

      if user.last_active:
        last_active = format_datetime(user.last_active)
      else:
        last_active = _(u'Never logged in')
      columns.append(last_active)

      data.append(columns)

    return {
      "sEcho": echo,
      "iTotalRecords": total_count,
      "iTotalDisplayRecords": count,
      "aaData": data,
    }
Пример #59
0
 def get_send_url(doc_id):
     return url_for(
         "documents.document_send", community_id=community.slug, doc_id=doc_id
     )