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]
Example #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)
Example #3
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)
Example #4
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)
Example #5
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)
Example #6
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))
Example #7
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)
Example #8
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,
    }
Example #9
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,
        }
Example #10
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
Example #11
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)
Example #12
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)
Example #13
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
Example #14
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
Example #15
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)
Example #16
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))
Example #17
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
Example #18
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))
Example #19
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}
Example #20
0
def index():
    return redirect(url_for(".page", title="Home", community_id=g.community.slug))
Example #21
0
 def __unicode__(self):
   return unicode(url_for(self.name, *self.args, **self.get_kwargs()))
Example #22
0
 def index_url(self):
   return url_for('.users')
Example #23
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": "dest@example.com", "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 == ["dest@example.com"]

            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": "dest@example.com", "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 == ["dest@example.com"]
            assert len(msg.attachments) == 1

            attachment = first(msg.attachments)
            assert isinstance(attachment, flask_mail.Attachment)
            assert attachment.filename == "utf-8 est arrivé!.txt"
Example #24
0
 def view_url(self):
     return url_for(
         self.view_endpoint, community_id=g.community.slug, title=self.obj.title
     )
Example #25
0
 def get_send_url(doc_id):
     return url_for(
         "documents.document_send", community_id=community.slug, doc_id=doc_id
     )
Example #26
0
 def index_url(self):
   return url_for('.groups')
Example #27
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))
Example #28
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,
    }
Example #29
0
 def view_url(self):
   return url_for('.groups_group', group_id=self.obj.id)
Example #30
0
 def index_url(self):
     return url_for(".index", community_id=g.community.slug)