"""Projekte: the API (projects/views.py).""" import json from unittest.mock import patch from django.contrib.auth.models import User from django.core.cache import cache from django.test import TestCase from .models import Project, ProjectItem from .views import doi_of IV = 'a1' * 12 class Base(TestCase): def setUp(self): cache.clear() self.user = User.objects.create_user(username='forscher', password='pw12345678') self.client.force_login(self.user) def post(self, url, body=None): return self.client.post(url, json.dumps(body or {}), content_type='application/json') def make(self, ct='name'): return self.post('/projects/create/', {'preset': 'research', 'data_ct': ct, 'data_iv': IV}).json()['project'] class ProjectTests(Base): def test_create_list_update(self): p = self.make() self.assertEqual(p['preset'], 'research') r = self.client.get('/projects/').json() self.assertEqual([x['id'] for x in r['projects']], [p['id']]) self.assertIn('research', r['presets']) r = self.post(f"/projects/{p['id']}/", {'data_ct': 'neu', 'data_iv': 'b2' * 12, 'base_iv': IV}) self.assertEqual(r.json()['project']['data_ct'], 'neu') # Written from an old state: refused with the current one. r = self.post(f"/projects/{p['id']}/", {'data_ct': 'alt', 'data_iv': 'c3' * 12, 'base_iv': IV}) self.assertEqual((r.status_code, r.json()['project']['data_ct']), (409, 'neu')) def test_bad_input(self): self.assertEqual(self.post('/projects/create/', {'data_ct': 'x', 'data_iv': 'zz'}).status_code, 400) self.assertEqual(self.post('/projects/create/', {'preset': 'nope', 'data_ct': 'x', 'data_iv': IV}).status_code, 400) def test_only_ones_own(self): p = self.make() other = User.objects.create_user(username='andere', password='pw12345678') self.client.force_login(other) self.assertEqual(self.client.get(f"/projects/{p['id']}/").status_code, 404) self.assertEqual(self.post(f"/projects/{p['id']}/items/add/", {'kind': 'note', 'data_ct': 'x', 'data_iv': IV}).status_code, 404) self.assertEqual(self.client.get('/projects/').json()['projects'], []) self.client.logout() self.assertEqual(self.client.get('/projects/').status_code, 401) def test_delete_takes_the_items(self): p = self.make() self.post(f"/projects/{p['id']}/items/add/", {'kind': 'note', 'data_ct': 'x', 'data_iv': IV}) self.post(f"/projects/{p['id']}/delete/") self.assertEqual((Project.objects.count(), ProjectItem.objects.count()), (0, 0)) class ItemTests(Base): def test_links_once_notes_many(self): p = self.make() url = f"/projects/{p['id']}/items/add/" a = self.post(url, {'kind': 'book', 'ref': 12, 'data_ct': 'b', 'data_iv': IV}).json() b = self.post(url, {'kind': 'book', 'ref': 12, 'data_ct': 'b2', 'data_iv': IV}).json() self.assertEqual((a['existing'], b['existing'], a['item']['id']), (False, True, b['item']['id'])) self.post(url, {'kind': 'note', 'data_ct': 'n', 'data_iv': IV}) self.post(url, {'kind': 'note', 'ref': 5, 'data_ct': 'n', 'data_iv': IV}) # a note has no ref self.post(url, {'kind': 'episode', 'ref': 7, 'data_ct': 'e', 'data_iv': IV}) self.assertEqual(self.post(url, {'kind': 'episode', 'data_ct': 'e', 'data_iv': IV}).status_code, 400) got = self.client.get(f"/projects/{p['id']}/").json() self.assertEqual([(i['kind'], i['ref']) for i in got['items']], [('book', 12), ('note', None), ('note', None), ('episode', 7)]) links = self.client.get('/projects/').json()['links'] self.assertEqual(sorted((l['kind'], l['ref']) for l in links), [('book', 12), ('episode', 7)]) def test_update_with_base_and_delete(self): p = self.make() i = self.post(f"/projects/{p['id']}/items/add/", {'kind': 'note', 'data_ct': 'v1', 'data_iv': IV}).json()['item'] r = self.post(f"/projects/items/{i['id']}/", {'data_ct': 'v2', 'data_iv': 'b2' * 12, 'base_iv': IV}) self.assertEqual(r.status_code, 200) r = self.post(f"/projects/items/{i['id']}/", {'data_ct': 'v3', 'data_iv': 'c3' * 12, 'base_iv': IV}) self.assertEqual((r.status_code, r.json()['item']['data_ct']), (409, 'v2')) self.post(f"/projects/items/{i['id']}/delete/") self.assertFalse(ProjectItem.objects.exists()) class DoiTests(Base): def test_recognised(self): self.assertEqual(doi_of('https://doi.org/10.1038/s41586-020-2649-2.'), '10.1038/s41586-020-2649-2') self.assertEqual(doi_of('https://arxiv.org/abs/2401.01234v2'), '10.48550/arXiv.2401.01234') self.assertEqual(doi_of('2401.01234'), '10.48550/arXiv.2401.01234') self.assertIsNone(doi_of('kein doi')) def test_lookup_trimmed_and_cached(self): class R: status_code = 200 def json(self): return {'title': 'Ein Paper', 'DOI': '10.1234/x', 'reference': [1, 2, 3], 'author': [{'family': 'A'}]} with patch('projects.views.requests.get', return_value=R()) as get: a = self.client.get('/projects/doi/', {'q': 'doi:10.1234/x'}).json() self.client.get('/projects/doi/', {'q': '10.1234/X'}) self.assertEqual(get.call_count, 1) self.assertEqual(a['csl']['title'], 'Ein Paper') self.assertNotIn('reference', a['csl']) self.assertEqual(self.client.get('/projects/doi/', {'q': 'nichts'}).status_code, 400)