Esempio n. 1
0
def test_harvard_research_access_request(auth_client, mailoutbox):
    user = auth_client.auth_user

    # viewing form with non-harvard email doesn't work
    response = auth_client.get(reverse('harvard-research-request-intro'), follow=True)
    check_response(response, content_includes="You are not currently using a harvard.edu email address")
    response = auth_client.get(reverse('harvard-research-request'), follow=True)
    check_response(response, content_includes="You are not currently using a harvard.edu email address")

    # viewing as harvard email does work
    user.email = '*****@*****.**'
    user.save()
    response = auth_client.get(reverse('harvard-research-request'))
    check_response(response, content_includes="Sign Agreement")

    # can submit form
    values = {
        'name': 'First Last',
        'title': 'Title',
        'area_of_interest': 'Area of Interest'
    }
    response = auth_client.post(reverse('harvard-research-request'), values)
    check_response(response, status_code=302)
    assert response.url == reverse('harvard-research-request-success')

    # check created contract and email message
    research_request = user.harvard_contracts.first()
    message = mailoutbox[0].body
    for k, v in values.items():
        assert getattr(research_request, k) == v
        assert v in message
    user.refresh_from_db()
    assert user.harvard_access is True
Esempio n. 2
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
Esempio n. 3
0
def test_fetch(client, auth_client, elasticsearch, case_factory):
    cases = [
        case_factory(jurisdiction__whitelisted=True, first_page_order=1, last_page_order=2),
        case_factory(jurisdiction__whitelisted=False, first_page_order=1, last_page_order=2),
        case_factory(jurisdiction__whitelisted=False, first_page_order=1, last_page_order=2),
    ]
    cites = [c.citations.first() for c in cases]
    text = f"""
{cites[0].cite}
{"A"*50} {cites[1].cite} {"A"*50}
123 {cites[2].cite} 123
    """
    response = client.post(reverse('fetch'), {'q': text})
    check_response(response, content_includes=[
        cites[0].cite, cases[0].full_cite(),
        f'... {"A"*39}', cites[1].cite, cases[1].full_cite(), f'{"A"*29} ...',
        '    123', cites[2].cite, cases[2].full_cite(), ' 123\n',
    ])

    # can't download zip when logged out
    check_response(client.post(reverse('fetch'), {'download': '1', 'case_ids': [c.pk for c in cases]}), status_code=403)

    # can download zip of valid PDFs
    response = auth_client.post(reverse('fetch'), {'download': '1', 'case_ids': [c.pk for c in cases]})
    zip = ZipFile(BytesIO(b''.join(response)))
    for case in cases:
        path = 'cases/' + case.get_pdf_name()
        doc = fitz.open(stream=zip.open(path).read(), filetype='pdf')
        assert len(list(doc.pages())) == 2

    # quota is tracked
    auth_client.auth_user.refresh_from_db()
    assert auth_client.auth_user.case_allowance_remaining == 498
Esempio n. 4
0
def test_contact(client, auth_client, mailoutbox):
    # email field is empty if logged out
    response = client.get(reverse('contact'))
    soup = BeautifulSoup(response.content.decode(), 'html.parser')
    assert not soup.find('input', {'id': 'id_email'}).get('value')

    # email field is filled if logged in
    response = auth_client.get(reverse('contact'))
    soup = BeautifulSoup(response.content.decode(), 'html.parser')
    assert soup.find('input', {
        'id': 'id_email'
    }).get('value') == auth_client.auth_user.email

    # submitting form will send an email
    post_vals = {
        'subject': 'subject',
        'box2': 'body',
        'email': '*****@*****.**'
    }
    response = client.post(reverse('contact'), post_vals)
    check_response(response, status_code=302)
    assert len(mailoutbox) == 1

    # submitting box1 will not send an email
    post_vals = {
        'subject': 'subject',
        'box1': 'body',
        'box2': 'body',
        'email': '*****@*****.**'
    }
    response = client.post(reverse('contact'), post_vals)
    check_response(response, status_code=302)  # form pretends to succeed
    assert len(mailoutbox) == 1
Esempio n. 5
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"]
Esempio n. 6
0
def test_retrieve_page_image(admin_client, auth_client, volume_metadata):
    volume_metadata.pdf_file = "fake_volume.pdf"
    volume_metadata.save()
    response = admin_client.get(reverse('page_image', args=[volume_metadata.pk, '2'], host='cite'))
    check_response(response, content_type="image/png")
    assert b'\x89PNG' in response.content

    response = auth_client.get(reverse('page_image', args=[volume_metadata.pk, '2'], host='cite'))
    check_response(response, status_code=302)
Esempio n. 7
0
def test_redirect_following_login(auth_user, auth_client):
    """if ?next=url is not set, user gets directed to '/' after login"""
    auth_client.logout()
    response = auth_client.get(reverse('login'))
    check_response(response)
    password = '******'
    assert auth_user.check_password(password)

    response = auth_client.post(reverse('login'), {
        'username': auth_user.email,
        'password': password})

    check_response(response, status_code=302)
    assert response.url == '/'
Esempio n. 8
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()
Esempio n. 9
0
def test_cache_headers_with_bad_auth(client, case):
    # visiting homepage when logged out is cached ...
    response = client.get(reverse('home'))
    assert is_cached(response)

    # ... but visiting with a bad Authorization header is not cached
    client.credentials(HTTP_AUTHORIZATION='Token fake')
    response = client.get(reverse('home'))
    assert not is_cached(response)

    # ... and visiting with a bad session cookie is not cached
    client.credentials()
    client.cookies = SimpleCookie({settings.SESSION_COOKIE_NAME: 'fake'})
    response = client.get(reverse('home'))
    assert not is_cached(response)
Esempio n. 10
0
def test_login_wrong_password(auth_user, client):
    response = client.post(reverse('login'), {
        'username': auth_user.email,
        'password': '******'
    })
    check_response(response)
    assert "Please enter a correct email and password." in response.content.decode()
Esempio n. 11
0
def test_delete_account(auth_user, auth_client):
    assert auth_user.deactivated_by_user is False
    response = auth_client.post(reverse('delete_account'))
    check_response(response, status_code=302)
    assert response.url == reverse('home')

    response = auth_client.post(reverse('login'), {
        'username': auth_user.email,
        'password': '******'
    })
    check_response(response)
    assert "Please enter a correct email and password." in response.content.decode()

    auth_user.refresh_from_db()
    assert auth_user.deactivated_by_user is True
    assert auth_user.deactivated_date
Esempio n. 12
0
def citation(request, series_slug, volume_number_slug, page_number, case_id=None, pdf=False, db_case=None):
    """
        /<series_slug>/<volume_number>/<page_number>/                       -- show requested case (or list of cases, or case not found page).
        /<series_slug>/<volume_number>/<page_number>/<case_id>/             -- show requested case, using case_id to find one of multiple cases at this cite
    """

    # redirect if series slug or volume number slug is in the wrong format
    if not pdf and (slugify(series_slug) != series_slug or slugify(volume_number_slug) != volume_number_slug):
        return HttpResponseRedirect(reverse(
            'citation',
            args=[slugify(series_slug), slugify(volume_number_slug), page_number] + ([case_id] if case_id else []),
            host='cite'))

    ### try to look up citation

    case = None
    resolved_case = None
    if case_id:
        try:
            case = CaseDocument.get(id=case_id)
            resolved_cases = ResolveDocument.search().query("match", source='cap').query("match", source_id=case_id).execute()
            if resolved_cases:
                resolved_case = resolved_cases[0]
        except NotFoundError:
            raise Http404
Esempio n. 13
0
def contact(request):
    form = form_for_request(request, ContactForm)

    if request.method == 'POST' and form.is_valid():
        data = form.data
        # Only send email if box2 is filled out and box1 is not.
        # box1 is display: none, so should never be filled out except by spam bots.
        if data.get('box2') and not data.get('box1'):
            send_contact_email(data.get('subject'), data.get('box2'),
                               data.get('email'))
            logger.info("sent contact email: %s" % data)
        else:
            logger.info("suppressing invalid contact email: %s" % data)
        return HttpResponseRedirect(reverse('contact-success'))

    email_from = request.user.email if request.user.is_authenticated else ""
    form.initial = {"email": email_from}

    return render(
        request, 'contact.html', {
            "form":
            form,
            "email":
            settings.DEFAULT_FROM_EMAIL,
            'page_image':
            'img/og_image/contact.png',
            'meta_description':
            'Email us at %s or fill out this form. ' %
            settings.DEFAULT_FROM_EMAIL,
        })
Esempio n. 14
0
def test_screenshot__parallel(client, live_server, settings, ngrammed_cases):
    # set up conditions for /screenshot/ route to work
    settings.SCREENSHOT_FEATURE = True
    settings.DEBUG = True  # so view runs browser unsandboxed for docker
    live_server_port = live_server.url.rsplit(':', 1)[1]
    with mock.patch('capweb.views.safe_domains',
                    ['case.test:%s' % live_server_port]):

        # url we want a screenshot of -- .graph-container in /trends/?q=the
        target_url = reverse('trends', port=live_server_port).replace(
            ':8000', '') + '?q=the'
        target_selector = '.graph-container'

        # check screenshot
        screenshot_url = page_image_url(target_url,
                                        targets=[target_selector],
                                        timeout=30)
        response = client.get(screenshot_url)
        check_response(response, content_type="image/png")
        # screenshot size doesn't seem to be consistent across host environments?
        # width, height = Image.open(BytesIO(response.content)).size
        # assert width == 664
        # assert height == 400

        # check fallback screenshot
        screenshot_url = page_image_url(target_url,
                                        targets=['.does_not_exist'],
                                        timeout=30)
        response = client.get(screenshot_url)
        check_response(response, content_type="image/jpeg")
        # check that we got the default fallback image, api.jpg
        width, height = Image.open(BytesIO(response.content)).size
        assert width == 1200
        assert height == 630
Esempio n. 15
0
def test_schema_in_case(client, restricted_case, unrestricted_case, elasticsearch):

    ### whitelisted case

    response = client.get(full_url(unrestricted_case))
    check_response(response, content_includes=unrestricted_case.body_cache.html)

    schema = get_schema(response)
    assert schema["headline"] == unrestricted_case.name_abbreviation
    assert schema["author"]["name"] == unrestricted_case.court.name

    # if case is whitelisted, extra info about inaccessibility is not needed
    # https://developers.google.com/search/docs/data-types/paywalled-content
    assert "hasPart" not in schema

    ### blacklisted case

    response = client.post(reverse('set_cookie'), {'not_a_bot': 'yes', 'next': full_url(restricted_case)}, follow=True)
    check_response(response, content_includes=restricted_case.body_cache.html)
    schema = get_schema(response)
    assert schema["headline"] == restricted_case.name_abbreviation
    assert schema["author"]["name"] == restricted_case.court.name

    # if case is blacklisted, we include more data
    assert "hasPart" in schema
    assert schema["hasPart"]["isAccessibleForFree"] == 'False'
Esempio n. 16
0
def verify_user(request, user_id, activation_nonce):
    """ Verify email and assign api token """
    user = get_object_or_404(CapUser, pk=user_id)

    # This leaks a little info -- we reveal whether a user ID exists or not and whether it is verified or deactivated.
    # This seems acceptable to provide better messages to legitimate users.
    if user.email_verified:
        return render(request, 'registration/verified.html')
    if not user.is_active:
        return render(
            request, 'registration/verified.html',
            {'error': 'This account is not active and cannot be verified.'})

    error = None
    mailing_list_message = "We have not signed you up for our newsletter, Lawvocado. Sign up any time from our homepage."
    try:
        user.authenticate_user(activation_nonce=activation_nonce)
    except PermissionDenied:
        error = mark_safe(
            "This verification code is invalid or expired. <a href='%s'>Resend verification</a>?"
            % reverse('resend-verification'))
    else:
        # user authenticated successfully

        # update API limits for first X users per day
        # users after this limit will have approved accounts, but we will have to go back manually to increase limits
        site_limits = SiteLimits.add_values(daily_signups=1)
        if site_limits.daily_signups < site_limits.daily_signup_limit:
            user.total_case_allowance = user.case_allowance_remaining = settings.API_CASE_DAILY_ALLOWANCE
            user.save()

        # sign them up for the mailing list if they selected the mailing_list checkbox.
        if settings.MAILCHIMP['api_key'] and user.mailing_list:
            try:
                mc_client = MailChimp(mc_api=settings.MAILCHIMP['api_key'],
                                      mc_user=settings.MAILCHIMP['api_user'])
                mc_client.lists.members.create(
                    settings.MAILCHIMP['id'], {
                        'email_address': user.email,
                        'merge_fields': {
                            'LNAME': user.first_name,
                            'FNAME': user.last_name
                        },
                        'status': 'subscribed'
                    })
                mailing_list_message = "Also, thanks for signing up for our newsletter, Lawvocado."
            except MailChimpError as e:
                if e.args[0]['status'] == 400 and e.args[0][
                        'title'] == 'Member Exists':
                    mailing_list_message = "Also, thanks for your continued interest in our newsletter, " \
                                           "Lawvocado. We'll keep you on our list."
                else:
                    logger.exception(
                        "Error adding user email %s to mailing list" %
                        user.email)

    return render(request, 'registration/verified.html', {
        'error': error,
        'mailing_list_message': mailing_list_message,
    })
Esempio n. 17
0
def request_unaffiliated_research_access(request):
    """ Submit request for unaffiliated research access """
    name = "%s %s" % (request.user.first_name, request.user.last_name)
    form = form_for_request(request,
                            UnaffiliatedResearchRequestForm,
                            initial={
                                'name': name,
                                'email': request.user.email
                            })

    if request.method == 'POST' and form.is_valid():
        # save request object
        form.instance.user = request.user
        form.save()

        # send notice emails
        message = loader.get_template(
            'research_request/emails/unaffiliated_request_email.txt').render({
                'data':
                form.cleaned_data,
            })
        subject = 'CAP independent research scholar application for {}'.format(
            name)
        send_contact_email(subject, message, request.user.email)

        return HttpResponseRedirect(
            reverse('unaffiliated-research-request-success'))

    return render(request,
                  'research_request/unaffiliated_research_request.html',
                  {'form': form})
Esempio n. 18
0
def volume(request, series_slug, volume_number_slug):
    """ /<series_slug>/<volume_number>/ -- list all cases for given volumes (typically only one). """

    # redirect if series slug or volume number slug is in the wrong format

    if slugify(series_slug) != series_slug or slugify(volume_number_slug) != volume_number_slug:
        return HttpResponseRedirect(reverse('volume', args=[slugify(series_slug), slugify(volume_number_slug)], host='cite'))

    vols = list(VolumeMetadata.objects
        .select_related('reporter')
        .filter(volume_number_slug=volume_number_slug, reporter__short_name_slug=series_slug, out_of_scope=False)
        .order_by('-second_part_of'))
    if not vols:
        raise Http404

    cases_query = CaseDocument.search()\
        .filter("term", volume__volume_number_slug=volume_number_slug)\
        .filter("term", reporter__short_name_slug__raw=series_slug)\
        .sort('first_page')\
        .extra(size=10000)\
        .source({"excludes": "casebody_data.*"})
    cases = cases_query.execute()
    cases = natsorted(cases, key=lambda c: c.first_page)

    volumes = [(volume, [c for c in cases if c.volume.barcode == volume.barcode]) for volume in vols]

    return render(request, 'cite/volume.html', {
        "volumes": volumes,
    })
Esempio n. 19
0
def test_view_user_details(auth_user, auth_client):
    """ User can see their API token """
    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 "Unlimited access:" not in content
    assert str(auth_user.total_case_allowance) in content

    # user can't see limit if they have unlimited access
    auth_user.unlimited_access = True
    auth_user.unlimited_access_until = timedelta(hours=24) + timezone.now()
    auth_user.save()
    response = auth_client.get(reverse('user-details'))
    check_response(response)
    content = re.sub(r'\s+', ' ', response.content.decode()).strip()
    assert "Unmetered access" in content
Esempio n. 20
0
def delete_account(request):
    if request.method == 'POST':
        request.user.is_active = False
        request.user.deactivated_by_user = True
        request.user.save()
        return HttpResponseRedirect(reverse('home'))

    return render(request, 'registration/delete_account.html')
Esempio n. 21
0
def docs_url(doc_link):
    """
        Link to a documentation page. This can either be the value of the `doc_link:` key in the markdown file,
        if there is one, or else the text part of the filename ('example' from '01_example.md').

        This allows us to consistently link to docs pages when they are moved or reordered.
    """
    return reverse('docs', args=[doc_links[doc_link]])
Esempio n. 22
0
def send_new_signup_email(request, user):
    token_url = reverse('verify-user', kwargs={'user_id':user.pk, 'activation_nonce': user.get_activation_nonce()}, scheme="https")
    send_mail(
        'Caselaw Access Project: Verify your email address',
        "Please click here to verify your email address: \n\n%s \n\nIf you received this message in error, please ignore it." % token_url,
        settings.DEFAULT_FROM_EMAIL,
        [user.email],
        fail_silently=False, )
    logger.info("sent new_signup email for %s" % user.email)
Esempio n. 23
0
 def __init__(self, *args, **kwargs):
     super().__init__(*args, **kwargs)
     # set label here because reverse() isn't ready when defining the class
     self.fields['mailing_list'].label = mark_safe(
         "<small>(optional)</small> Sign me up for the CAP newsletter: Lawvocado."
     )
     self.fields['agreed_to_tos'].label = mark_safe(
         "I have read and agree to the <a href='%s' target='_blank'>Terms of Use</a>."
         % reverse('terms'))
Esempio n. 24
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])
Esempio n. 25
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
Esempio n. 26
0
 def confirm_login_allowed(self, user):
     """ Override AuthenticationForm to block login with unverified email address. """
     if not user.email_verified:
         raise forms.ValidationError(
             mark_safe(
                 "This email is registered but not yet verified. <a href='%s'>Resend verification</a>?"
                 % reverse('resend-verification')),
             code='unverified',
         )
     return super().confirm_login_allowed(user)
Esempio n. 27
0
def test_cases_multiple(client, django_assert_num_queries, case_factory, elasticsearch):
    """ Test /series/volume/case/ with multiple matching cases """
    three_cases = [case_factory(
        jurisdiction__whitelisted=True,
        citations__type='official',
        citations__cite='23 Ill. App. 19',
        citations__normalized_cite='23illapp19'
    ) for i in range(3)]
    first_case = three_cases[0]

    response = client.get(reverse('citation', args=['ill-app', '23', '19'], host='cite'), follow=True)

    check_response(response, content_includes='Multiple cases match')
    content = response.content.decode()
    for case in three_cases:
        assert case.name_abbreviation in content

    # load one of the results
    response = client.get(reverse('citation', args=['ill-app', '23', '19', first_case.id], host='cite'))
    check_response(response)
Esempio n. 28
0
def test_resend_verification(client, mailoutbox):
    # create new user
    response = client.post(reverse('register'), {
        'email': '*****@*****.**',
        'first_name': 'First',
        'last_name': 'Last',
        'password1': 'Password2',
        'password2': 'Password2',
        'agreed_to_tos': 'on',
    })
    check_response(response)
    assert len(mailoutbox) == 1

    # resend verification
    response = client.post(reverse('resend-verification'), {
        'email': '*****@*****.**',
    })
    check_response(response)

    # same verification email sent
    assert mailoutbox[0].body == mailoutbox[1].body
Esempio n. 29
0
def test_unaffiliated_research_access_request(auth_client, mailoutbox):
    # can view form
    response = auth_client.get(reverse('unaffiliated-research-request'))
    check_response(response)

    # can submit form
    values = {
        'name': 'First Last',
        'email': '*****@*****.**',
        'area_of_interest': 'Foo Area of Interest'
    }
    response = auth_client.post(reverse('unaffiliated-research-request'), values)
    check_response(response, status_code=302)
    assert response.url == reverse('unaffiliated-research-request-success')

    # check created request and email message
    research_request = auth_client.auth_user.research_requests.first()
    message = mailoutbox[0].body
    for k, v in values.items():
        assert getattr(research_request, k) == v
        assert v in message
Esempio n. 30
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)