Example #1
0
def test_change_api_key(auth_user, auth_client, client, mailoutbox):
    # Check/store original API key as visible to user
    original_token = auth_user.get_api_key()
    response = auth_client.get(reverse('user-details'))
    check_response(response)
    content = re.sub(r'\s+', ' ', response.content.decode()).strip()
    assert original_token in content

    # Make sure warning/confirmation template is rendered on get request
    response = auth_client.get(reverse('reset-api-key'))
    check_response(response)
    content = re.sub(r'\s+', ' ', response.content.decode()).strip()
    assert "This change takes place immediately and cannot be undone." in content

    # Change API key through web request
    response = auth_client.post(reverse('reset-api-key'))
    assert response.status_code == 302
    assert response.url.endswith('/user/details')

    # Make sure new API key is in place and immediately visible to user
    auth_user.refresh_from_db()
    response = auth_client.get(reverse('user-details'))
    check_response(response)
    content = re.sub(r'\s+', ' ', response.content.decode()).strip()
    assert auth_user.get_api_key() in content
    assert original_token not in content

    # Make sure mail is sent and contains the correct new and old API keys
    message = mailoutbox[0].body
    assert "Your Case.law API key reset is complete" in message

    # Make sure auth is in place
    unauth_response = client.post(reverse('reset-api-key'))
    assert unauth_response.status_code == 302
    assert "/user/login/" in unauth_response.url
Example #2
0
def test_timeline_update(client, auth_client):
    tl = Timeline.objects.create(created_by=auth_client.auth_user,
                                 timeline=timeline)
    response = auth_client.get(retrieve_url + str(tl.id))
    check_response(response, content_type="application/json")
    assert response.json()["timeline"]["title"] == timeline["title"]

    new_title = "My second timeline attempt"
    timeline["title"] = new_title
    update_url = reverse('labs:chronolawgic-api-update', args=[str(tl.id)])
    response = auth_client.post(update_url, {"timeline": timeline},
                                format='json')
    check_response(response, content_type="application/json")
    assert response.json()["timeline"]["title"] == new_title

    new_title = "My third timeline attempt"
    timeline["title"] = new_title

    update_url = reverse('labs:chronolawgic-api-update', args=[str(tl.id)])

    # don't allow unauthenticated users
    response = client.post(update_url, {"timeline": timeline}, format='json')
    check_response(response, status_code=403, content_type="application/json")

    response = auth_client.get(retrieve_url + str(tl.id))
    assert response.json()["timeline"]["title"] != timeline["title"]
Example #3
0
def test_case_citation_redirect(client, case_factory, elasticsearch):
    """Should allow various forms of citation, should redirect to normalized_cite"""
    case = case_factory(citations__cite='123 Mass. App. 456')
    citation = case.citations.first()
    url = api_reverse("cases-detail", args=[citation.normalized_cite])

    # should have received a redirect
    response = client.get(url)
    check_response(response, status_code=302)

    response = client.get(url, follow=True)
    check_response(response)
    content = response.json()['results']
    case = citation.case

    # should only have one case returned
    assert len(content) == 1
    assert content[0]['id'] == case.id
    # should only have one citation for this case
    citations_result = content[0]['citations']
    assert len(citations_result) == 1
    assert citations_result[0]['cite'] == citation.cite

    # allow user to enter real citation (not normalized)
    url = api_reverse("case-get-cite", args=[citation.cite])
    response = client.get(url, follow=True)

    check_response(response)
    content = response.json()['results']
    case = citation.case
    assert len(content) == 1
    assert content[0]['id'] == case.id
Example #4
0
def test_unauthenticated_full_case(unrestricted_case, restricted_case, client,
                                   elasticsearch):
    """
    we should allow users to get full case without authentication
    if case is whitelisted
    we should allow users to see why they couldn't get full case
    if case is blacklisted
    """
    case_url = api_reverse("cases-detail", args=[unrestricted_case.id])

    response = client.get(case_url, {"full_case": "true"})
    check_response(response)
    content = response.json()
    assert "casebody" in content
    assert type(content['casebody']['data']) is dict

    case_url = api_reverse("cases-detail", args=[restricted_case.id])
    response = client.get(case_url, {"full_case": "true"})
    check_response(response)
    content = response.json()
    casebody = content['casebody']
    assert 'error_' in casebody['status']
    assert not casebody['data']
Example #5
0
def test_case_editor(reset_sequences, admin_client, auth_client, unrestricted_case_factory):
    unrestricted_case = unrestricted_case_factory(first_page_order=1, last_page_order=3)
    url = reverse('case_editor', args=[unrestricted_case.pk], host='cite')
    response = admin_client.get(url)
    check_response(response)
    response = auth_client.get(url)
    check_response(response, status_code=302)

    # make an edit
    unrestricted_case.sync_case_body_cache()
    body_cache = unrestricted_case.body_cache
    old_html = body_cache.html
    old_first_page = unrestricted_case.first_page
    description = "Made some edits"
    page = unrestricted_case.structure.pages.first()
    response = admin_client.post(
        url,
        json.dumps({
            'metadata': {
                'name': [unrestricted_case.name, 'new name'],
                'decision_date_original': [unrestricted_case.decision_date_original, '2020-01-01'],
                'first_page': [old_first_page, 'ignore this'],
                'human_corrected': [False, True],
            },
            'description': description,
            'edit_list': {
                page.id: {
                    'BL_81.3': {
                        3: ["Case text 0", "Replacement text"],
                    }
                }
            }
        }),
        content_type="application/json")
    check_response(response)

    # check OCR edit
    body_cache.refresh_from_db()
    new_html = body_cache.html
    assert list(unified_diff(old_html.splitlines(), new_html.splitlines(), n=0))[3:] == [
        '-    <h4 class="parties" id="b81-4">Case text 0</h4>',
        '+    <h4 class="parties" id="b81-4">Replacement text</h4>',
    ]

    # check metadata
    unrestricted_case.refresh_from_db()
    assert unrestricted_case.name == 'new name'
    assert unrestricted_case.decision_date_original == '2020-01-01'
    assert unrestricted_case.decision_date == datetime.date(year=2020, month=1, day=1)
    assert unrestricted_case.human_corrected is True
    assert unrestricted_case.first_page == old_first_page  # change ignored

    # check log
    log_entry = unrestricted_case.correction_logs.first()
    assert log_entry.description == description
    assert log_entry.user_id == admin_client.auth_user.id
Example #6
0
def test_case_series_name_redirect(client, unrestricted_case, elasticsearch):
    """ Test /series/volume/case/ with series redirect when not slugified"""
    cite = unrestricted_case.citations.first()
    cite_parts = re.match(r'(\S+)\s+(.*?)\s+(\S+)$', cite.cite).groups()

    # series is not slugified, expect redirect
    response = client.get(
        reverse('citation', args=[cite_parts[1], cite_parts[0], cite_parts[2]], host='cite'))
    check_response(response, status_code=302)

    response = client.get(
        reverse('citation', args=[cite_parts[1], cite_parts[0], cite_parts[2]], host='cite'), follow=True)
    check_response(response)

    # series redirect works with case_id
    response = client.get(
        reverse('citation', args=[cite_parts[1], cite_parts[0], cite_parts[2], unrestricted_case.id], host='cite'))
    check_response(response, status_code=302)

    response = client.get(
        reverse('citation', args=[cite_parts[1], cite_parts[0], cite_parts[2]], host='cite'), follow=True)
    check_response(response)
Example #7
0
def test_registration_after_login(auth_user, auth_client):
    response = auth_client.get(reverse('user-details'))
    check_response(response)

    # try going to the registration page
    # get directed to the details page instead
    response = auth_client.get(reverse('register'))
    check_response(response, status_code=302)
    assert response.url == reverse('user-details')

    # make sure registration is still reachable after logging out
    auth_client.logout()
    response = auth_client.get(reverse('register'))
    check_response(response, status_code=200)
    assert "<title>Register | Caselaw Access Project</title>" in response.content.decode()
Example #8
0
def test_series(client, django_assert_num_queries, volume_metadata_factory):
    """ Test /series/ """

    # make sure we correctly handle multiple reporters with same slug
    volume_1, volume_2 = [volume_metadata_factory(
        reporter__short_name='Mass.',
        reporter__short_name_slug='mass',
    ) for _ in range(2)]
    response = client.get(reverse('series', args=['mass'], host='cite'))
    check_response(response)
    content = response.content.decode()
    for vol in (volume_1, volume_2):
        assert vol.volume_number in content
        assert vol.reporter.full_name in content

    # make sure we redirect if series is not slugified
    response = client.get(reverse('series', args=['Mass.'], host='cite'))
    check_response(response, status_code=302)
    response = client.get(reverse('series', args=['mass'], host='cite'), follow=True)
    check_response(response, status_code=200)
    
    # make sure we get 404 if bad series input
    response = client.get(reverse('series', args=['*'], host='cite'))
    check_response(response, status_code=404)
Example #9
0
def test_robots(client, case):
    case_string = "Disallow: %s" % case.frontend_url

    # default version is empty:
    url = reverse('robots', host='cite')
    response = client.get(url)
    check_response(response, content_type="text/plain", content_includes='User-agent: *', content_excludes=case_string)

    # case with robots_txt_until in future is included:
    case.no_index = True
    case.robots_txt_until = timezone.now() + timedelta(days=1)
    case.save()
    check_response(client.get(url), content_type="text/plain", content_includes=case_string)

    # case with robots_txt_until in past is excluded:
    case.robots_txt_until = timezone.now() - timedelta(days=1)
    case.save()
    response = client.get(url)
    check_response(response, content_type="text/plain", content_includes='User-agent: *', content_excludes=case_string)
Example #10
0
def test_flow(client, unrestricted_case, elasticsearch):
    """user should be able to click through to get to different tables"""
    # start with case
    response = client.get(
        api_reverse("cases-detail", args=[unrestricted_case.id]))
    check_response(response)
    content = response.json()
    # onwards to court
    court_url = content.get("court")["url"]
    assert court_url
    response = client.get(court_url)
    check_response(response)
    # onwards to jurisdiction
    jurisdiction_url = content.get("jurisdiction")["url"]
    assert jurisdiction_url
    response = client.get(jurisdiction_url)
    check_response(response)
    content = response.json()
    assert content.get("name") == unrestricted_case.jurisdiction.name
Example #11
0
def test_timeline_delete(client, auth_client):
    tl = Timeline.objects.create(created_by=auth_client.auth_user,
                                 timeline=timeline)

    response = auth_client.get(retrieve_url + str(tl.id))
    check_response(response, content_type="application/json")
    assert response.json()["timeline"]["title"] == timeline["title"]

    delete_url = reverse('labs:chronolawgic-api-delete', args=[str(tl.id)])

    # don't allow unauthenticated users
    response = client.delete(delete_url)
    check_response(response, status_code=403, content_type="application/json")
    assert Timeline.objects.filter(
        created_by=auth_client.auth_user).count() == 1

    # allow authenticated creators of timeline
    response = auth_client.delete(delete_url)
    check_response(response, content_type="application/json")
    assert Timeline.objects.filter(
        created_by=auth_client.auth_user).count() == 0
Example #12
0
def test_harvard_access(request, restricted_case, client_fixture_name,
                        elasticsearch):
    ### user with harvard access can download from harvard IPs, even without case allowance
    client = request.getfixturevalue(client_fixture_name)
    user = client.auth_user
    user.harvard_access = True
    user.case_allowance_remaining = 1
    user.save()
    case_url = api_reverse("cases-detail", args=[restricted_case.id])

    # request works when IP address provided
    response = client.get(case_url, {"full_case": "true"},
                          HTTP_CF_CONNECTING_IP='128.103.1.1')
    check_response(response)
    result = response.json()
    assert result['casebody']['status'] == 'ok'

    # no case allowance used
    user.refresh_from_db()
    assert user.case_allowance_remaining == 1

    # request succeeds when IP address is wrong, using case allowance
    response = client.get(case_url, {"full_case": "true"},
                          HTTP_CF_CONNECTING_IP='1.1.1.1')
    check_response(response)
    result = response.json()
    assert result['casebody']['status'] == 'ok'

    # case allowance used
    user.refresh_from_db()
    assert user.case_allowance_remaining == 0

    # request fails when case allowance exhausted
    response = client.get(case_url, {"full_case": "true"},
                          HTTP_CF_CONNECTING_IP='1.1.1.1')
    check_response(response)
    result = response.json()
    assert result['casebody']['status'] != 'ok'
Example #13
0
def test_volume(client, django_assert_num_queries, case_factory, elasticsearch):
    """ Test /series/volume/ """
    cases = [case_factory(
        volume__reporter__full_name='Massachusetts%s' % i,
        volume__reporter__short_name='Mass.',
        volume__reporter__short_name_slug='mass',
        volume__volume_number='1',
        volume__volume_number_slug='1',
    ) for i in range(3)]

    with django_assert_num_queries(select=1):
        response = client.get(reverse('volume', args=['mass', '1'], host='cite'))
    check_response(response)

    content = response.content.decode()
    for case in cases:
        assert case.reporter.full_name in content
        assert case.citations.first().cite in content

    # make sure we redirect if reporter name / series is not slugified
    response = client.get(reverse('volume', args=['Mass.', '1'], host='cite'))
    check_response(response, status_code=302)
    response = client.get(reverse('volume', args=['Mass.', '1'], host='cite'), follow=True)
    check_response(response, status_code=200)
Example #14
0
def test_unlimited_access(auth_user, auth_client, restricted_case,
                          elasticsearch):
    ### user with unlimited access should not have blacklisted cases count against them
    auth_user.total_case_allowance = settings.API_CASE_DAILY_ALLOWANCE
    auth_user.unlimited_access = True
    auth_user.unlimited_access_until = timedelta(hours=24) + timezone.now()
    auth_user.save()
    case_url = api_reverse("cases-detail", args=[restricted_case.id])

    response = auth_client.get(case_url, {"full_case": "true"})
    check_response(response)
    auth_user.refresh_from_db()
    assert auth_user.case_allowance_remaining == auth_user.total_case_allowance

    # total_case_allowance shouldn't matter if unlimited access is in effect
    auth_user.total_case_allowance = 0
    auth_user.case_allowance_remaining = 0
    auth_user.unlimited_access_until = None
    auth_user.save()
    response = auth_client.get(case_url, {"full_case": "true"})
    check_response(response)
    result = response.json()
    casebody = result['casebody']
    assert casebody['status'] == 'ok'
    assert type(casebody['data']) is dict

    # don't allow user to download blacklisted case if unlimited access has expired
    # and they don't have enough case allowance
    auth_user.total_case_allowance = 0
    auth_user.case_allowance_remaining = 0
    auth_user.unlimited_access_until = timezone.now() - timedelta(hours=1)
    auth_user.save()
    response = auth_client.get(case_url, {"full_case": "true"})
    check_response(response)
    result = response.json()
    assert result['casebody']['status'] != 'ok'
Example #15
0
def test_docs(client, elasticsearch, three_cases):
    response = client.get(reverse('docs', args=['site_features/registration']))
    check_response(response)
Example #16
0
def test_affiliated_research_access_request(auth_client, contract_approver_auth_client, mailoutbox):
    user = auth_client.auth_user

    # can view form
    response = auth_client.get(reverse('affiliated-research-request'))
    check_response(response)

    # can submit form
    values = {
        'name': 'First Last',
        'email': '*****@*****.**',
        'institution': 'Foo Institution',
        'title': 'Foo Title',
        'area_of_interest': 'Foo Area of Interest'
    }
    response = auth_client.post(reverse('affiliated-research-request'), values)
    check_response(response, status_code=302)
    assert response.url == reverse('affiliated-research-request-success')
    contract = user.research_contracts.first()
    assert contract

    # can review contract
    message = mailoutbox[0].body
    approve_url = message.split("deny this application at ")[1].split()[0]
    response = contract_approver_auth_client.get(approve_url)
    check_response(response, content_includes=values['name'])

    # can deny contract
    response = contract_approver_auth_client.post(approve_url, {
        'contract_id': contract.id,
        'deny': 'true'
    })
    check_response(response, content_includes="%s denied" % values['name'])
    contract.refresh_from_db()
    assert contract.status == 'denied'
    user.refresh_from_db()
    assert not user.unlimited_access_in_effect()
    message = mailoutbox[1].body
    assert "has been denied" in message

    # can approve contract
    contract.status = 'pending'
    contract.save()
    response = contract_approver_auth_client.post(approve_url, {
        'contract_id': contract.id,
        'approve': 'true'
    })
    check_response(response, content_includes="%s approved" % values['name'])
    contract.refresh_from_db()
    assert contract.status == 'approved'
    assert contract.approver_signature_date
    assert contract.approver == contract_approver_auth_client.auth_user
    user.refresh_from_db()
    assert user.unlimited_access_in_effect()

    # check created contract and email message
    message = mailoutbox[2].body
    values['email'] = user.email
    for k, v in values.items():
        assert getattr(contract, k) == v
        assert v in message
        assert v in contract.contract_html
Example #17
0
import pytest
from PIL import Image

from django.conf import settings

from capapi.tests.helpers import check_response
from capweb.helpers import reverse, page_image_url


@pytest.mark.django_db
def test_nav(client, case, reporter):
    """
    All our navigation links lead to somewhere 200 Ok
    """
    response = client.get(reverse('home'))
    check_response(response)
    soup = BeautifulSoup(response.content.decode(), 'html.parser')

    dropdown_item = soup.find_all('a', {'class': 'dropdown-item'})
    for a in dropdown_item:
        res = client.get(a.get('href'))
        check_response(res)

    nav_links = soup.find_all('a', {'class': 'nav-link'})
    for a in nav_links:
        res = client.get(a.get('href'))
        try:
            check_response(res)
        except AssertionError:
            check_response(res, status_code=302)
            assert "/docs/" in res.url
Example #18
0
def test_show_timelines(client, auth_client):
    response = client.get(reverse('labs:chronolawgic-dashboard'))
    # check to see it includes api urls since everything else is rendered in Vue
    check_response(response, content_includes="chronolawgic_api_create")
Example #19
0
def test_labs_page(client):
    response = client.get(reverse('labs:labs'))
    check_response(response, content_includes="CAP LABS")
Example #20
0
import re
import pytest
from capapi.tests.helpers import check_response
from django.conf import settings


@pytest.mark.django_db
def test_get_docs_urls(client, jurisdiction, case, reporter):
    """
    Test that every url in docs.html is functional
    """
    settings.API_DOCS_CASE_ID = case.id

    response = client.get('/')
    html = response.content.decode()
    tmp_html = re.sub(";", "", html)
    possible_lines = tmp_html.split("&#39")
    for line in possible_lines:
        if line[0:4] == "http":
            response = client.get(line)
            check_response(response)



Example #21
0
def test_timeline_update_validation(client, auth_client):
    tl = Timeline.objects.create(created_by=auth_client.auth_user,
                                 timeline=timeline)
    update_url = reverse('labs:chronolawgic-api-update', args=[str(tl.id)])
    response = auth_client.post(
        update_url, {"timeline": {
            "description": "And my very best one"
        }},
        format='json')
    check_response(response,
                   status_code=400,
                   content_type="application/json",
                   content_includes="Timeline Missing")

    # missing timeline value
    response = auth_client.post(update_url, {"timeline": {
        "title": []
    }},
                                format='json')
    check_response(response,
                   status_code=400,
                   content_type="application/json",
                   content_includes="Wrong Data Type for title")

    # wrong timeline value data type
    response = auth_client.post(update_url, {"timeline": {
        "title": []
    }},
                                format='json')
    check_response(response,
                   status_code=400,
                   content_type="application/json",
                   content_includes="Wrong Data Type for title")

    # missing required case value
    response = auth_client.post(
        update_url,
        {"timeline": {
            "title": "Rad",
            "cases": [{
                'What even is': 'this?'
            }]
        }},
        format='json')
    check_response(response,
                   status_code=400,
                   content_type="application/json",
                   content_includes="Case Missing: name")

    # wrong case data type
    response = auth_client.post(update_url, {
        "timeline": {
            "title": "Rad",
            "cases": [{
                'name': ['what', 'crazy', 'data', 'you', 'have']
            }]
        }
    },
                                format='json')
    check_response(response,
                   status_code=400,
                   content_type="application/json",
                   content_includes="Case Has Wrong Data Type for name")

    # missing require event value
    response = auth_client.post(update_url, {
        "timeline": {
            "title": "Rad",
            "events": [{
                'name': 'wow',
                'start_date': '1975-12-16'
            }]
        }
    },
                                format='json')
    check_response(response,
                   status_code=400,
                   content_type="application/json",
                   content_includes="Event Missing: end_date")

    # wrong event data type
    response = auth_client.post(update_url, {
        "timeline": {
            "title":
            "Rad",
            "events": [{
                'name': 'wow',
                'start_date': '1975-12-16',
                'end_date': '1975-12-16',
                'short_description': {
                    'guess': 'who'
                }
            }]
        }
    },
                                format='json')
    check_response(
        response,
        status_code=400,
        content_type="application/json",
        content_includes="Event Has Wrong Data Type for short_description")

    # extraneous timeline field
    response = auth_client.post(
        update_url,
        {"timeline": {
            "title": "Rad",
            "events": [],
            "helloooooo": "badata"
        }},
        format='json')
    check_response(response,
                   status_code=400,
                   content_type="application/json",
                   content_includes="Unexpected timeline field(s)")

    # extraneous event field
    response = auth_client.post(update_url, {
        "timeline": {
            "title":
            "Rad",
            "events": [{
                'name': 'wow',
                'start_date': '1975-12-16',
                'end_date': '1975-12-16',
                'DOESNOTBELONG': 'here'
            }],
        }
    },
                                format='json')
    check_response(response,
                   status_code=400,
                   content_type="application/json",
                   content_includes="Unexpected event field(s)")

    # extraneous case field
    response = auth_client.post(update_url, {
        "timeline": {
            "title": "Rad",
            "cases": [{
                'name': 'joe v volcano',
                "herring_color": 'purple'
            }],
        }
    },
                                format='json')
    check_response(response,
                   status_code=400,
                   content_type="application/json",
                   content_includes="Unexpected case field(s)")
Example #22
0
def test_single_case(client, auth_client, token_auth_client, case_factory, elasticsearch, response_type, django_assert_num_queries, settings):
    """ Test /series/volume/case/ with one matching case """

    # set up for viewing html or pdf
    case_text = "Case HTML"
    unrestricted_case = case_factory(jurisdiction__whitelisted=True, body_cache__html=case_text, first_page_order=2, last_page_order=2)
    restricted_case = case_factory(jurisdiction__whitelisted=False, body_cache__html=case_text, first_page_order=2, last_page_order=2)
    if response_type == 'pdf':
        case_text = "REMEMBERED"
        unrestricted_url = unrestricted_case.get_pdf_url()
        url = restricted_case.get_pdf_url()
        content_type = 'application/pdf'
    else:
        unrestricted_url = full_url(unrestricted_case)
        url = full_url(restricted_case)
        content_type = None

    ### can load whitelisted case
    with django_assert_num_queries(select=2):
        check_response(client.get(unrestricted_url), content_includes=case_text, content_type=content_type)

    ### can load blacklisted case while logged out, via redirect

    # first we get redirect to JS page
    check_response(client.get(url, follow=True), content_includes="Click here to continue")

    # POSTing will set our cookies and let the case load
    response = client.post(reverse('set_cookie'), {'not_a_bot': 'yes', 'next': url}, follow=True)
    check_response(response, content_includes=case_text, content_type=content_type)
    session = client.session
    assert session['case_allowance_remaining'] == settings.API_CASE_DAILY_ALLOWANCE - 1

    # we can now load directly
    response = client.get(url)
    check_response(response, content_includes=case_text, content_type=content_type)
    session = client.session
    assert session['case_allowance_remaining'] == settings.API_CASE_DAILY_ALLOWANCE - 2

    # can no longer load if quota used up
    session['case_allowance_remaining'] = 0
    session.save()
    response = client.get(url)
    if response_type == 'pdf':
        assert response.status_code == 302  # PDFs redirect back to HTML version if quota exhausted
    else:
        check_response(response)
        assert case_text not in response.content.decode()
    session = client.session
    assert session['case_allowance_remaining'] == 0

    # check daily quota reset
    session['case_allowance_last_updated'] -= 60 * 60 * 24 + 1
    session.save()
    response = client.get(url)
    check_response(response, content_includes=case_text, content_type=content_type)
    session = client.session
    assert session['case_allowance_remaining'] == settings.API_CASE_DAILY_ALLOWANCE - 1

    ### can load normally as logged-in user

    for c in [auth_client, token_auth_client]:
        response = c.get(url)
        check_response(response, content_includes=case_text, content_type=content_type)
        previous_case_allowance = c.auth_user.case_allowance_remaining
        c.auth_user.refresh_from_db()
        assert c.auth_user.case_allowance_remaining == previous_case_allowance - 1
Example #23
0
def test_download_area(client, auth_client, unlimited_auth_client, tmp_path, monkeypatch):
    overlay_path = Path(settings.BASE_DIR, 'downloads')
    underlay_path = tmp_path
    monkeypatch.setattr("capweb.views.download_files_storage", DownloadOverlayStorage(location=str(underlay_path)))

    # listing should include files from BASE_DIR/downloads as well as from donload_files_storage location
    underlay_path.joinpath('underlay.txt').write_text("contents")
    response = client.get(reverse('download-files', args=['']))
    check_response(response, content_type="application/json")
    response_json = response.json()
    assert set(f['name'] for f in response_json['files']) == (set(p.name for p in overlay_path.glob('*')) | {'underlay.txt'}) - {'README.md', '.DS_Store'}

    # can fetch contents from both overlay and underlay, with or without auth
    for c in (client, unlimited_auth_client):
        for read_from, path, content_type in ((overlay_path, 'README.md', 'text/markdown'), (underlay_path, 'underlay.txt', 'text/plain')):
            response = c.get(reverse('download-files', args=[path]))
            check_response(response, content_type=content_type, content_includes=read_from.joinpath(path).read_text())
            assert is_cached(response)

    # can list overlay folders
    response = c.get(reverse('download-files', args=['scdb/']))
    check_response(response, content_type="application/json")

    # restricted folder
    underlay_path.joinpath('restricted').mkdir()
    underlay_path.joinpath('restricted/file.txt').write_text('contents')
    for test_client, allow_downloads, token in (
            (client, False, 'none'),
            (auth_client, False, auth_client.auth_user.get_api_key()),
            (unlimited_auth_client, True, unlimited_auth_client.auth_user.get_api_key())
    ):
        token_client = CapClient()
        token_client.credentials(HTTP_AUTHORIZATION='Token ' + token)

        for c in (test_client, token_client):
            # restricted directory
            response = c.get(reverse('download-files', args=['restricted/']))
            check_response(response, content_type="application/json")
            cacheable = c == client  # we can only cache for an anonymous user who didn't supply an auth header
            assert is_cached(response) is cacheable
            response_json = response.json()
            assert response_json['allow_downloads'] == allow_downloads
            assert set(f['name'] for f in response_json['files']) == {'file.txt'}

            # restricted file
            response = c.get(reverse('download-files', args=['restricted/file.txt']))
            assert not is_cached(response)
            if allow_downloads:
                check_response(response, content_type="text/plain", content_includes="contents")
            else:
                check_response(response, content_type="application/json", status_code=403)

    # symlinks
    underlay_path.joinpath('folder_link').symlink_to('restricted')
    underlay_path.joinpath('file_link.txt').symlink_to('restricted/file.txt')
    for p1, p2 in (('folder_link/', 'restricted/'), ('folder_link/file.txt', 'restricted/file.txt'), ('file_link.txt', 'restricted/file.txt')):
        response = c.get(reverse('download-files', args=[p1]))
        check_response(response, status_code=302)
        assert response.url == reverse('download-files', args=[p2])
Example #24
0
def test_home(client, django_assert_num_queries, reporter):
    """ Test / """
    with django_assert_num_queries(select=2):
        response = client.get(reverse('cite_home', host='cite'))
    check_response(response, content_includes=reporter.full_name)
Example #25
0
def test_swagger(client, url, content_type):
    response = client.get(url)
    check_response(response, content_type=content_type)
Example #26
0
def test_case_not_found(client, django_assert_num_queries, elasticsearch):
    """ Test /series/volume/case/ not found """
    with django_assert_num_queries(select=1):
        response = client.get(reverse('citation', args=['fake', '123', '456'], host='cite'))
    check_response(response, content_includes='Search for "123 Fake 456" in other databases')
Example #27
0
def test_redoc(client):
    response = client.get(api_reverse("schema-redoc"))
    check_response(response, content_type="text/html")
Example #28
0
def test_docs_default(client, elasticsearch, three_cases):
    response = client.get(reverse('docs', args=['']))
    check_response(response, content_includes="Welcome to the Caselaw Access Project Documentation")
Example #29
0
def test_site_limits(client, auth_client, restricted_case, mailoutbox,
                     elasticsearch):

    ### registration limit ###

    # set signups per day to zero, downloads per day to one
    site_limits = SiteLimits.get()
    site_limits.daily_signup_limit = 0
    site_limits.daily_download_limit = 1
    site_limits.save()

    # register
    email = '*****@*****.**'
    response = client.post(
        reverse('register'), {
            'email': email,
            'first_name': 'First',
            'last_name': 'Last',
            'password1': 'Password2',
            'password2': 'Password2',
            'agreed_to_tos': 'on',
        })
    user = CapUser.objects.get(email=email)

    # verify email address
    verify_email = mail.outbox[0].body
    verify_url = re.findall(r'https://\S+', verify_email)[0]
    response = client.get(verify_url)
    check_response(response,
                   content_includes="We've verified your email address.")
    user.refresh_from_db()
    assert user.email_verified
    assert user.auth_token

    # verified user still has 0 limit
    assert user.total_case_allowance == 0

    ### case download limit ###

    # can fetch one case
    response = auth_client.get(
        api_reverse('cases-detail', args=[restricted_case.id]),
        {'full_case': 'true'})
    result = response.json()
    assert result['casebody']['status'] == 'ok'

    # cannot fetch second case
    response = auth_client.get(
        api_reverse('cases-detail', args=[restricted_case.id]),
        {'full_case': 'true'})
    result = response.json()
    assert result['casebody']['status'] == 'error_sitewide_limit_exceeded'

    ### tracking ###

    # site_limits updated
    site_limits.refresh_from_db()
    assert site_limits.daily_signups == 1
    assert site_limits.daily_downloads == 1

    ### reporting ###

    daily_site_limit_reset_and_report.apply()
    site_limits.refresh_from_db()
    assert site_limits.daily_signups == 0
    assert site_limits.daily_downloads == 0
    last_mail = mailoutbox[-1]
    assert last_mail.subject == 'CAP daily usage: 1 registered users, 1 blacklisted downloads'
Example #30
0
def test_legacy_redirect(client):
    response = client.get(reverse('api'))
    check_response(response, 302)
    assert "/docs/" in response.url