import tempfile
import uuid
import zipfile

from django.contrib.auth.models import Group, User
from django.utils import translation

import pytest
from webtest import Upload

from docbow_project.docbow.models import (
    AttachedFile,
    DeletedDocument,
    Document,
    FileType,
    MailingList,
    FileTypeAttachedFileKind,
)
from utils import assert_can_see_doc, assert_cannot_see_doc, send_file

MEDIA_ROOT = tempfile.mkdtemp()


def assert_field_not_in_form(field, form):
    with pytest.raises(AssertionError):
        form[field]


def delete_doc(app, user):
    app.login(user.username)
    resp = app.get('/inbox/')
    assert resp.status_code == 200
    delete_form = resp.forms[1]
    resp = delete_form.submit()
    assert resp.status_code == 302
    app.logout()


def find_delegate_form(forms):
    for form in forms.values():
        if 'delegate-create' in form.fields:
            return form


def create_delegate(app, user, delegate):
    app.login(username=user.username)
    resp = app.get('/profile/')
    assert resp.status_code == 200
    delegate_form = find_delegate_form(resp.forms)
    delegate_form['delegate-existing_user'] = '%s' % delegate.pk
    resp = delegate_form.submit('delegate-create')
    assert resp.status_code == 302
    delegate = User.objects.get(pk=delegate.pk)
    assert not delegate.docbowprofile.is_guest
    assert delegate.delegations_by.count() == 1
    assert delegate.delegations_by.first().by == user
    app.logout()
    return delegate


def create_guest_delegate(app, user, first_name, last_name, email):
    app.login(username=user.username)
    resp = app.get('/profile/')
    assert resp.status_code == 200
    delegate_form = find_delegate_form(resp.forms)
    delegate_form['delegate-first_name'] = first_name
    delegate_form['delegate-last_name'] = last_name
    delegate_form['delegate-email'] = email
    resp = delegate_form.submit('delegate-create')
    assert resp.status_code == 302
    delegate = User.objects.get(email=email)
    assert delegate.docbowprofile.is_guest
    assert delegate.delegations_by.count() == 1
    assert delegate.delegations_by.first().by == user
    app.logout()
    delegate.set_password('password')
    delegate.save()
    return delegate


def test_login_logout(app, users):
    resp = app.get('/')
    assert resp.status_code == 302
    assert resp.url.endswith('/accounts/login/?next=/')

    resp = app.login()
    assert resp.location.endswith('/inbox')
    resp = app.get('/')
    assert resp.status_code == 302
    assert resp.url.endswith('/inbox/')

    resp = app.get('/inbox/')
    assert resp.status_code == 200

    resp = app.logout()
    assert resp.url.endswith('/inbox/')


def test_sendfile_selector(app, filetypes, users):
    app.login()
    resp = app.get('/send_file/')
    for ft in FileType.objects.all():
        assert ft.name in resp.text
        assert u'<a href="/send_file/%s/?">' % ft.pk in resp.text


def test_sendfile(app, filetypes, users, settings):
    settings.DEBUG = True
    settings.MEDIA_ROOT = MEDIA_ROOT
    sender = User.objects.get(username='user-1')
    recipient1, recipient2 = User.objects.get(username='user-2'), User.objects.get(username='user-3')
    app.login()
    ft = FileType.objects.first()
    resp = app.get('/send_file/%s/' % ft.pk)
    form = resp.form
    form['content_1'] = Upload('readme.rst', b'data')
    form['recipients'] = ['user-%s' % recipient1.pk, 'user-%s' % recipient2.pk]
    resp = form.submit('send')

    assert resp.status_code == 302
    assert resp.location.endswith('/outbox/')

    doc = Document.objects.first()
    assert len(doc.delivered_to()) == 2
    assert recipient1 in doc.delivered_to()
    assert recipient2 in doc.delivered_to()
    assert doc.filenames() == 'readme.rst'
    assert doc.sender == sender


def test_sendfile_extra_senders(app, filetypes, users, settings):
    settings.MEDIA_ROOT = MEDIA_ROOT
    settings.EXTRA_SENDERS = True
    sender = User.objects.get(username='user-1')
    recipient1, recipient2 = User.objects.get(username='user-2'), User.objects.get(username='user-3')
    extra_sender1, extra_sender2 = User.objects.get(username='user-4'), User.objects.get(username='user-5')
    app.login()
    ft = FileType.objects.first()
    ft.extra_senders = 4
    ft.save()
    resp = app.get('/send_file/%s/' % ft.pk)
    form = resp.form
    form['content_1'] = Upload('readme.rst', b'data')
    form['recipients'] = ['user-%s' % recipient1.pk, 'user-%s' % recipient2.pk]
    form['extra_senders'] = ['%s' % extra_sender1.pk, '%s' % extra_sender2.pk]
    resp = form.submit('send')

    assert resp.status_code == 302
    assert resp.location.endswith('/outbox/')

    doc = Document.objects.first()
    assert len(doc.delivered_to()) == 2
    assert recipient1 in doc.delivered_to()
    assert recipient2 in doc.delivered_to()
    assert doc.filenames() == 'readme.rst'
    assert doc.sender == sender
    assert doc.extra_senders.count() == 2
    assert doc.extra_senders.filter(pk=extra_sender1.pk).exists()
    assert doc.extra_senders.filter(pk=extra_sender2.pk).exists()

    # extra senders in outbox column
    resp = app.get('/outbox/')
    assert extra_sender1.username in resp.text
    assert extra_sender2.username in resp.text

    # extra senders in outbox message title
    resp = app.get('/outbox/%s/' % doc.pk)
    assert extra_sender1.username in resp.text
    assert extra_sender2.username in resp.text

    # delete doc
    resp = app.get('/outbox/')
    assert resp.status_code == 200
    delete_form = resp.forms[2]
    delete_form['selection'] = doc.pk
    resp = delete_form.submit('delete')
    assert resp.status_code == 302
    assert resp.location.endswith('/outbox/')

    # extra senders in trash outbox column
    resp = app.get('/outbox/trash/')
    assert extra_sender1.username in resp.text
    assert extra_sender2.username in resp.text

    # doc show up in extra sender outbox
    assert_can_see_doc(app, doc, extra_sender1, inbox=False)
    assert_can_see_doc(app, doc, extra_sender2, inbox=False)

    # extra senders in inbox column
    app.login(recipient1.username)
    resp = app.get('/inbox/')
    assert extra_sender1.username in resp.text
    assert extra_sender2.username in resp.text

    # extra senders in inbox message title
    resp = app.get('/inbox/%s/' % doc.pk)
    assert extra_sender1.username in resp.text
    assert extra_sender2.username in resp.text

    # delete doc
    resp = app.get('/inbox/')
    assert resp.status_code == 200
    delete_form = resp.forms[2]
    delete_form['selection'] = doc.pk
    resp = delete_form.submit('delete')
    assert resp.status_code == 302
    assert resp.location.endswith('/inbox/')

    # extra senders in trash inbox column
    resp = app.get('/inbox/trash/')
    assert extra_sender1.username in resp.text
    assert extra_sender2.username in resp.text


def test_extra_senders_disabled(app, filetypes, users, settings):
    settings.MEDIA_ROOT = MEDIA_ROOT
    recipient = User.objects.get(username='user-2')
    app.login()
    ft = FileType.objects.first()
    resp = app.get('/send_file/%s/' % ft.pk)
    form = resp.form
    assert 'extra_senders' not in form.fields
    form['content_1'] = Upload('readme.rst', b'data')
    form['recipients'] = ['user-%s' % recipient.pk]
    resp = form.submit('send')

    assert resp.status_code == 302
    assert resp.location.endswith('/outbox/')
    resp = app.get('/outbox/')
    assert 'Additional senders' not in resp.text
    resp = app.get('/outbox/trash/')
    assert 'Additional senders' not in resp.text
    resp = app.get('/inbox/')
    assert 'Additional senders' not in resp.text
    resp = app.get('/inbox/trash/')
    assert 'Additional senders' not in resp.text

    # even if global option enabled, can be disabled by file type
    settings.EXTRA_SENDERS = True
    assert ft.extra_senders == 0
    resp = app.get('/send_file/%s/' % ft.pk)
    form = resp.form
    assert 'extra_senders' not in form.fields
    form['content_1'] = Upload('readme.rst', b'data')
    form['recipients'] = ['user-%s' % recipient.pk]
    resp = form.submit('send')

    assert resp.status_code == 302
    assert resp.location.endswith('/outbox/')


def test_sendfile_reply_to(app, filetypes, users, settings):
    settings.MEDIA_ROOT = MEDIA_ROOT
    sender = User.objects.get(username='user-1')
    recipient = User.objects.get(username='user-2')
    app.login()
    ft = FileType.objects.first()
    resp = app.get('/send_file/%s/' % ft.pk)
    form = resp.form
    form['content_1'] = Upload('readme.rst', b'data')
    form['recipients'] = ['user-%s' % recipient.pk]
    resp = form.submit('send')

    assert resp.status_code == 302
    assert resp.location.endswith('/outbox/')

    doc = Document.objects.first()
    assert len(doc.delivered_to()) == 1
    assert recipient in doc.delivered_to()
    assert doc.filenames() == 'readme.rst'
    assert doc.sender == sender

    app.login(recipient.username)
    resp = app.get('/inbox/%s/' % doc.pk)
    assert resp.status_code == 200

    # reply
    resp = resp.forms[0].submit()
    assert resp.status_code == 200
    resp = resp.click(filetypes[0].name)
    form = resp.form
    form['content_1'] = Upload('readme.rst', b'data')
    resp = form.submit('send')
    assert resp.status_code == 302
    assert resp.location.endswith('/outbox/')
    doc = Document.objects.exclude(pk=doc.pk).first()
    assert len(doc.delivered_to()) == 1
    assert sender in doc.delivered_to()
    assert doc.filenames() == 'readme.rst'
    assert doc.sender == recipient

    assert_can_see_doc(app, doc, recipient, inbox=False)
    assert_can_see_doc(app, doc, sender, inbox=True)


def test_sendfile_reply_to_extra_senders(app, filetypes, users, settings):
    settings.MEDIA_ROOT = MEDIA_ROOT
    settings.EXTRA_SENDERS = True
    sender = User.objects.get(username='user-1')
    recipient = User.objects.get(username='user-2')
    extra_sender1, extra_sender2 = User.objects.get(username='user-4'), User.objects.get(username='user-5')
    app.login()
    ft = FileType.objects.first()
    ft.extra_senders = 4
    ft.save()
    resp = app.get('/send_file/%s/' % ft.pk)
    form = resp.form
    form['content_1'] = Upload('readme.rst', b'data')
    form['recipients'] = ['user-%s' % recipient.pk]
    form['extra_senders'] = ['%s' % extra_sender1.pk, '%s' % extra_sender2.pk]
    resp = form.submit('send')

    assert resp.status_code == 302
    assert resp.location.endswith('/outbox/')

    doc = Document.objects.first()
    assert len(doc.delivered_to()) == 1
    assert recipient in doc.delivered_to()
    assert doc.filenames() == 'readme.rst'
    assert doc.sender == sender

    app.login(recipient.username)
    resp = app.get('/inbox/%s/' % doc.pk)
    assert resp.status_code == 200

    # reply
    resp = resp.forms[0].submit()
    assert resp.status_code == 200
    resp = resp.click(filetypes[0].name)
    form = resp.form
    form['content_1'] = Upload('readme.rst', b'data')
    # no extra sender on reply
    assert 'extra_senders' not in form.fields
    resp = form.submit('send')
    assert resp.status_code == 302
    assert resp.location.endswith('/outbox/')
    doc = Document.objects.exclude(pk=doc.pk).first()
    assert len(doc.delivered_to()) == 3
    assert sender in doc.delivered_to()
    assert extra_sender1 in doc.delivered_to()
    assert extra_sender2 in doc.delivered_to()
    assert doc.filenames() == 'readme.rst'
    assert doc.sender == recipient

    assert_can_see_doc(app, doc, sender, inbox=True)
    assert_can_see_doc(app, doc, extra_sender1, inbox=True)
    assert_can_see_doc(app, doc, extra_sender2, inbox=True)


def test_sendfile_extra_senders_limit(app, filetypes, users, settings):
    settings.MEDIA_ROOT = MEDIA_ROOT
    settings.EXTRA_SENDERS = True
    sender = User.objects.get(username='user-1')
    recipient1, recipient2 = User.objects.get(username='user-2'), User.objects.get(username='user-3')
    extra_sender1, extra_sender2, extra_sender3 = (
        User.objects.get(username='user-4'),
        User.objects.get(username='user-5'),
        User.objects.get(username='user-6'),
    )
    app.login()
    ft = FileType.objects.first()
    ft.extra_senders = 3
    ft.save()

    resp = app.get('/send_file/%s/' % ft.pk)
    form = resp.form
    form['content_1'] = Upload('readme.rst', b'data')
    form['recipients'] = ['user-%s' % recipient1.pk, 'user-%s' % recipient2.pk]
    form['extra_senders'] = ['%s' % extra_sender1.pk, '%s' % extra_sender2.pk, '%s' % extra_sender3.pk]
    resp = form.submit('send')

    assert resp.status_code == 302
    assert resp.location.endswith('/outbox/')

    doc = Document.objects.first()
    assert len(doc.delivered_to()) == 2
    assert recipient1 in doc.delivered_to()
    assert recipient2 in doc.delivered_to()
    assert doc.filenames() == 'readme.rst'
    assert doc.sender == sender
    assert doc.extra_senders.count() == 3
    assert doc.extra_senders.filter(pk=extra_sender1.pk).exists()
    assert doc.extra_senders.filter(pk=extra_sender2.pk).exists()
    assert doc.extra_senders.filter(pk=extra_sender3.pk).exists()

    # limit extra senders
    ft.extra_senders = 2
    ft.save()
    resp = app.get('/send_file/%s/' % ft.pk)
    form = resp.form
    form['content_1'] = Upload('readme.rst', b'data')
    form['recipients'] = ['user-%s' % recipient1.pk, 'user-%s' % recipient2.pk]
    form['extra_senders'] = ['%s' % extra_sender1.pk, '%s' % extra_sender2.pk, '%s' % extra_sender3.pk]
    resp = form.submit('send')
    assert resp.status_code == 200
    assert 'No more than 2 additional senders allowed' in resp.text


def test_sendfile_mailing_list(app, filetypes, users, settings):
    settings.MEDIA_ROOT = MEDIA_ROOT
    sender = User.objects.get(username='user-1')
    ml = MailingList.objects.create(name='test')
    recipient1, recipient2 = User.objects.get(username='user-2'), User.objects.get(username='user-3')
    ml.members.add(recipient1, recipient2)
    ft = FileType.objects.first()

    app.login()
    resp = app.get('/send_file/%s/' % ft.pk)
    form = resp.form
    form['content_1'] = Upload('readme.rst', b'data')
    form['recipients'] = ['list-%s' % ml.pk]
    resp = form.submit('send')

    assert resp.status_code == 302
    assert resp.location.endswith('/outbox/')
    doc = Document.objects.first()
    assert len(doc.delivered_to()) == 2
    assert recipient1 in doc.delivered_to()
    assert recipient2 in doc.delivered_to()
    assert doc.filenames() == 'readme.rst'
    assert doc.sender == sender


def test_outbox_doc(app, filetypes, users, settings):
    sender = User.objects.get(username='user-1')
    recipient = User.objects.get(username='user-2')
    send_file(app, settings, sender, recipient)

    doc = Document.objects.get(sender=sender)
    af = AttachedFile.objects.first()
    app.login(sender.username)
    resp = app.get('/outbox/%s/' % doc.pk)
    assert resp.status_code == 200
    assert '%s/readme.rst' % af.pk in resp.text

    # download doc
    resp = app.get('/outbox/%s/%s/readme.rst' % (doc.pk, af.pk))
    assert resp.status_code == 200
    assert resp.content_type == 'application/octet-stream'
    assert resp.content == b'data'

    # delete doc
    resp = app.get('/outbox/')
    assert resp.status_code == 200
    delete_form = resp.forms[2]
    delete_form['selection'] = doc.pk
    resp = delete_form.submit('delete')
    assert resp.status_code == 302
    assert resp.location.endswith('/outbox/')

    assert DeletedDocument.objects.get(user=sender, document=doc, soft_delete=True)
    assert_can_see_doc(app, doc, sender, inbox=False, trash=True)

    # go to trash and restore
    app.login(sender.username)
    resp = app.get('/outbox/trash/')
    assert '/outbox/%s/restore' % doc.pk in resp.text
    restore_form = resp.forms[0]
    resp = restore_form.submit()
    assert resp.location.endswith('/outbox/trash/')
    assert_can_see_doc(app, doc, sender, inbox=False)


def test_outbox_trash_link(app, filetypes, users, settings):
    settings.LANGUAGE_CODE = 'en-us'
    sender = User.objects.get(username='user-1')
    recipient = User.objects.get(username='user-2')
    send_file(app, settings, sender, recipient)
    Document.objects.get(sender=sender)
    AttachedFile.objects.first()
    app.login(sender.username)

    # trash disabled by default, no link
    resp = app.get('/outbox/')
    assert 'Trash' not in resp.text

    # enable trash
    settings.TRASH_DURATION = 1
    resp = app.get('/outbox/')
    assert 'Trash' in resp.text


def test_inbox_doc(app, filetypes, users, settings):
    sender = User.objects.get(username='user-1')
    recipient = User.objects.get(username='user-2')
    send_file(app, settings, sender, recipient)

    doc = Document.objects.get(sender=sender)
    af = AttachedFile.objects.first()
    app.login(recipient.username)
    resp = app.get('/inbox/%s/' % doc.pk)
    assert resp.status_code == 200
    doc = Document.objects.first()
    assert '%s/readme.rst' % af.pk in resp.text

    # download doc
    resp = app.get('/inbox/%s/%s/readme.rst' % (doc.pk, af.pk))
    assert resp.status_code == 200
    assert resp.content_type == 'application/octet-stream'
    assert resp.content == b'data'

    # delete doc
    resp = app.get('/inbox/')
    assert resp.status_code == 200
    delete_form = resp.forms[1]
    resp = delete_form.submit()
    assert resp.status_code == 302
    assert resp.location.endswith('/inbox/?page=1')

    assert DeletedDocument.objects.get(user=recipient, document=doc)
    assert_can_see_doc(app, doc, recipient, inbox=True, trash=True)

    # go to trash and restore
    app.login(recipient.username)
    resp = app.get('/inbox/trash/')
    assert '/inbox/%s/restore' % doc.pk in resp.text
    restore_form = resp.forms[0]
    resp = restore_form.submit()
    assert resp.location.endswith('/inbox/trash/')
    assert_can_see_doc(app, doc, recipient)


def test_inbox_trash_link(app, filetypes, users, settings):
    settings.LANGUAGE_CODE = 'en-us'
    sender = User.objects.get(username='user-1')
    recipient = User.objects.get(username='user-2')
    send_file(app, settings, sender, recipient)
    Document.objects.get(sender=sender)
    AttachedFile.objects.first()
    app.login(recipient.username)

    # trash disabled by default, no link
    resp = app.get('/inbox/')
    assert 'Trash' not in resp.text

    # enable trash
    settings.TRASH_DURATION = 1
    resp = app.get('/inbox/')
    assert 'Trash' in resp.text


def test_inbox_unseen_doc(app, filetypes, users, settings):
    sender = User.objects.get(username='user-1')
    recipient = User.objects.get(username='user-2')
    stranger = User.objects.get(username='user-3')
    send_file(app, settings, sender, recipient)
    doc = Document.objects.first()
    af = AttachedFile.objects.first()
    send_file(app, settings, sender, recipient)
    send_file(app, settings, sender, stranger)

    app.login(recipient.username)
    with translation.override('en'):
        resp = app.get('/inbox/')
        assert 'inbox_menu (2)' in resp.text
        resp = app.get('/inbox/%s/%s/readme.rst' % (doc.pk, af.pk))
        resp = app.get('/inbox/')
        assert 'inbox_menu (1)' in resp.text


def test_delete_doc(app, filetypes, users, settings):
    sender = User.objects.get(username='user-1')
    recipient = User.objects.get(username='user-2')
    send_file(app, settings, sender, recipient)

    doc = Document.objects.get(sender=sender)
    assert DeletedDocument.objects.count() == 0
    app.login(recipient.username)
    resp = app.get('/inbox/')
    assert 'data-id="%s"' % doc.pk in resp.text
    resp = app.get('/inbox/%s/delete/' % doc.pk)
    assert resp.status_code == 200
    resp = resp.form.submit()
    assert resp.status_code == 302
    assert resp.location.endswith('/inbox/?page=1')
    # soft delete, doc still available
    resp = app.get('/inbox/%s/' % doc.pk)
    assert resp.status_code == 200
    # not showing up in inbox
    resp = app.get('/inbox/')
    assert 'data-id="%s"' % doc.pk not in resp.text
    # showing up in trash
    resp = app.get('/inbox/trash/')
    assert 'data-id="%s"' % doc.pk in resp.text

    deleted_document = DeletedDocument.objects.get(document=doc, user=recipient)
    assert deleted_document.soft_delete
    assert deleted_document.soft_delete_date


def test_delete_doc_through_inbox(app, filetypes, users, settings):
    sender = User.objects.get(username='user-1')
    recipient = User.objects.get(username='user-2')
    send_file(app, settings, sender, recipient)

    doc = Document.objects.get(sender=sender)
    assert DeletedDocument.objects.count() == 0
    app.login(recipient.username)
    resp = app.get('/inbox/')
    delete_form = resp.forms[2]
    delete_form['selection'] = doc.pk
    resp = delete_form.submit('delete')
    assert resp.status_code == 302

    # soft delete
    deleted_document = DeletedDocument.objects.get(document=doc, user=recipient)
    assert deleted_document.soft_delete
    assert deleted_document.soft_delete_date


def test_forward_doc(app, filetypes, users, settings):
    sender = User.objects.get(username='user-1')
    recipient1 = User.objects.get(username='user-2')
    recipient2 = User.objects.get(username='user-3')
    send_file(app, settings, sender, recipient1)

    doc = Document.objects.get(sender=sender)
    app.login(recipient1.username)
    resp = app.get('/inbox/%s/' % doc.pk)
    assert resp.status_code == 200
    form = resp.forms[1]
    form['recipients'] = ['user-%s' % recipient2.pk]
    resp = form.submit('forward')
    assert resp.status_code == 302
    assert resp.location.endswith('/inbox/%s/' % doc.pk)
    app.logout()

    doc = Document.objects.get(sender=recipient1)
    app.login(recipient2.username)
    resp = app.get('/inbox/%s/' % doc.pk)
    assert resp.status_code == 200


def test_upload_file(app, users, settings):
    settings.MEDIA_ROOT = MEDIA_ROOT
    app.login(username='user-1')
    upload_id = str(uuid.uuid4())
    resp = app.post(
        '/upload/%s/' % upload_id,
        headers={'Accept': 'application/json'},
        upload_files=[('file', 'readme.rst', b'data')],
    )
    assert resp.status_code == 200
    json = resp.json
    assert len(json) == 1
    data = json[0]
    assert data['name'] == 'readme.rst'
    url = '/upload/%s/readme.rst' % upload_id
    assert data['url'] == url

    resp = app.get(url)
    assert resp.status_code == 200
    assert resp.content_type == 'application/octet-stream'
    assert resp.content == b'data'


def test_zip_download(app, filetypes, users, settings, tmp_path):
    settings.MEDIA_ROOT = MEDIA_ROOT
    settings.ZIP_DOWNLOAD = True

    sender = User.objects.get(username='user-1')
    recipient = User.objects.get(username='user-2')

    settings.MEDIA_ROOT = MEDIA_ROOT
    ft = FileType.objects.first()
    kind0 = FileTypeAttachedFileKind.objects.create(name='kind0', file_type=ft, position=0)
    kind1 = FileTypeAttachedFileKind.objects.create(name='kind1', file_type=ft, position=1)
    app.login(username=sender.username)
    resp = app.get('/send_file/%s/' % ft.pk)
    form = resp.form
    form['content-%s_1' % kind0.pk] = Upload('readme.rst', b'data')
    form['content-%s_1' % kind1.pk] = Upload('another.rst', b'otherdata')
    form['recipients'] = ['user-%s' % recipient.pk]
    form['private'] = False
    resp = form.submit('send')
    assert resp.status_code == 302
    assert resp.location.endswith('/outbox/')
    app.logout()

    doc = Document.objects.get(sender=sender)
    app.login(recipient.username)
    resp = app.get('/inbox/%s/' % doc.pk)
    assert resp.status_code == 200
    assert 'allfiles/' in resp.text

    # download zip
    resp = app.get('/inbox/%s/allfiles/' % doc.pk)
    assert resp.status_code == 200
    assert resp.content_type == 'application/octet-stream'
    zip_path = tmp_path / 'zipfile'
    zip_path.write_bytes(resp.content)

    # check zip
    zip_ = zipfile.ZipFile(zip_path.as_posix(), 'r')
    namelist = zip_.namelist()
    assert len(namelist) == 2
    assert 'readme.rst' in namelist
    assert 'another.rst' in namelist
    assert zip_.open('readme.rst', 'r').read() == b'data'
    assert zip_.open('another.rst', 'r').read() == b'otherdata'


def test_document_acces(app, filetypes, settings, users):
    user = users[0]
    delegate = create_delegate(app, user, users[1])
    guest_delegate = create_guest_delegate(app, user, 'john', 'doe', 'john@localhost')
    sender = users[2]
    stranger = users[3]

    # Doc recieved by user and delegates
    send_file(app, settings, sender, user)
    doc = Document.objects.get(sender=sender)

    assert_can_see_doc(app, doc, user)
    assert_can_see_doc(app, doc, delegate)
    assert_can_see_doc(app, doc, guest_delegate)
    assert_cannot_see_doc(app, doc, stranger)
    assert_can_see_doc(app, doc, sender, inbox=False)

    # Visibility after deletion by user
    delete_doc(app, user)
    assert_can_see_doc(app, doc, user, trash=True)
    assert_can_see_doc(app, doc, delegate)  # yes it's strange
    assert_can_see_doc(app, doc, guest_delegate, trash=True)
    assert_cannot_see_doc(app, doc, stranger)
    assert_can_see_doc(app, doc, sender, inbox=False)

    # reset
    doc.delete()

    # Visibility after deletion by delegate
    send_file(app, settings, sender, user)
    doc = Document.objects.get(sender=sender)
    delete_doc(app, delegate)
    assert_can_see_doc(app, doc, user)
    assert_can_see_doc(app, doc, delegate, trash=True)
    assert_can_see_doc(app, doc, guest_delegate)
    assert_can_see_doc(app, doc, sender, inbox=False)

    # reset
    doc.delete()

    # Visibility after deletion by guest delegate
    send_file(app, settings, sender, user)
    doc = Document.objects.get(sender=sender)
    delete_doc(app, guest_delegate)
    assert_can_see_doc(app, doc, user, trash=True)
    assert_can_see_doc(app, doc, delegate)
    assert_can_see_doc(app, doc, guest_delegate, trash=True)
    assert_can_see_doc(app, doc, sender, inbox=False)


def test_private_document_access(app, filetypes, settings, users):
    user = users[0]
    delegate = create_delegate(app, user, users[1])
    guest_delegate = create_guest_delegate(app, user, 'john', 'doe', 'john@localhost')
    sender = users[2]
    stranger = users[3]

    # Doc recieved by user and delegates
    send_file(app, settings, sender, user, private=True)
    doc = Document.objects.get(sender=sender)

    assert_can_see_doc(app, doc, user)
    assert_cannot_see_doc(app, doc, delegate)
    assert_cannot_see_doc(app, doc, guest_delegate)
    assert_cannot_see_doc(app, doc, stranger)
    assert_can_see_doc(app, doc, sender, inbox=False)

    # Visibility after deletion by user
    delete_doc(app, user)
    assert_can_see_doc(app, doc, user, trash=True)
    assert_cannot_see_doc(app, doc, delegate)
    assert_cannot_see_doc(app, doc, guest_delegate)
    assert_cannot_see_doc(app, doc, stranger)
    assert_can_see_doc(app, doc, sender, inbox=False)


def test_document_seen(app, filetypes, settings, users):
    user = users[0]
    sender = users[1]
    send_file(app, settings, sender, user)

    doc = Document.objects.get(sender=sender)
    app.login(user.username)
    box_url = '/inbox/'
    doc_url = box_url + '%s/' % doc.pk

    # not seen
    resp = app.get(box_url)
    assert '<span class="false">' in resp.text

    # get file
    attached_file = doc.attached_files.first()
    file_url = doc_url + '%s/%s' % (attached_file.pk, attached_file.name)
    resp = app.get(file_url)
    assert resp.status_code == 200

    # seen
    resp = app.get(box_url)
    assert '<span class="true">' in resp.text


def test_contact_no_contact(app, users):
    app.login(username='user-1')
    resp = app.get('/contact/')
    assert resp.status_code == 302
    assert resp.location.endswith('/inbox/')


def test_contact(app, settings, users):
    settings.CONTACT_GROUPS = ('Contact',)
    contact_group = Group.objects.create(name='Contact')
    user_1 = User.objects.get(username='user-1')
    user_1.groups.add(contact_group)
    user_1.save()

    app.login(username='user-2')
    resp = app.get('/contact/')
    form = resp.form
    form['subject'] = 'help'
    form['message'] = 'help message'
    resp = form.submit('send')
    assert resp.status_code == 302
    assert resp.location.endswith('/inbox/')


def test_send_file_no_private(app, settings, users, filetypes):
    settings.MEDIA_ROOT = MEDIA_ROOT
    settings.DOCBOW_PRIVATE_DOCUMENTS = False
    ft = FileType.objects.first()
    sender = users[0]
    recipient = users[1]
    app.login(username=sender.username)
    resp = app.get('/send_file/%s/' % ft.pk)
    form = resp.form
    form['content_1'] = Upload('readme.rst', b'data')
    form['recipients'] = ['user-%s' % recipient.pk]
    assert_field_not_in_form('private', form)
    resp = form.submit('send')
    assert resp.status_code == 302
    assert resp.location.endswith('/outbox/')
    app.logout()


def test_is_staff_kept_on_superuser(app, settings, admin):
    staffuser = User.objects.create(username='staffuser', is_staff=True, is_superuser=True)
    app.login(username=admin.username)
    resp = app.get('/admin/auth/user/%s/' % staffuser.pk)
    if resp.status_code == 302:
        resp = resp.follow()  # django 1.11 redirects to /admin/auth/user/%s/change/

    form = resp.forms[0]
    form['email'] = 'newmail@localhost'
    resp = form.submit()
    assert resp.status_code == 302

    staffuser = User.objects.get(username='staffuser')
    assert staffuser.is_staff


def test_mailbox_pagination(app, filetypes, users, settings):
    settings.LANGUAGE_CODE = 'en-us'
    sender = User.objects.get(username='user-1')
    recipient = User.objects.get(username='user-2')
    for i in range(40):
        send_file(app, settings, sender, recipient)

    app.login(username='user-1')
    resp = app.get('/outbox/')
    assert 'Page 1 of 2' in resp.text
    assert '20 de 40 documents' in resp.text

    app.login(username='user-2')
    resp = app.get('/inbox/')
    assert 'Page 1 of 2' in resp.text
    assert '20 de 40 documents' in resp.text
