test_repository.py 51 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894
  1. import io
  2. import pathlib
  3. import pytest
  4. import zipfile
  5. from datetime import datetime, timedelta
  6. from werkzeug.datastructures import FileStorage
  7. from stor import db
  8. from stor.auth.models import User
  9. from stor.repository.definitions import (
  10. Dsi, EcResourceStatus, EcSharingLevel, LanguageDataType,
  11. LicenceType, LicenceConditionType, LocalResourceStatus, LocalSharingLevel, Theme
  12. )
  13. from stor.repository.models import Resource
  14. @pytest.mark.parametrize(
  15. ( "resource_id", "expected_monolingual", "expected_bilingual", "expected_other"),
  16. (
  17. (1, 0, 0, 2),
  18. (2, 222, 0, 0),
  19. (3, 0, 0, 0),
  20. (4, 44444, 0, 0),
  21. (5, 6420, 55555, 0),
  22. (6, 0, 246, 2),
  23. ),
  24. )
  25. def test_aggregate_data_sizes(app, resource_id, expected_monolingual, expected_bilingual, expected_other):
  26. with app.app_context():
  27. resource = Resource.query.filter_by(id=resource_id).first()
  28. sizes = resource.aggregate_data_sizes()
  29. assert sizes[LanguageDataType.MONOLINGUAL_WORD] == expected_monolingual
  30. assert sizes[LanguageDataType.BILINGUAL_TU] == expected_bilingual
  31. assert sizes[LanguageDataType.OTHER_FILE] == expected_other
  32. @pytest.mark.parametrize(
  33. ("username", "message"),
  34. (
  35. ("", "Access Denied"),
  36. ("una", "Access Denied"),
  37. ("vera", "Email not verified"),
  38. ("ina", "Account not activated"),
  39. ("maya", "Access Denied"),
  40. ),
  41. )
  42. def test_get_invalid(client, auth, username, message):
  43. if username:
  44. auth.login(username)
  45. endpoints = [
  46. "",
  47. "/contribute",
  48. "/browse",
  49. "/1",
  50. "/1/download",
  51. "/1/download-licence",
  52. ]
  53. for endpoint in endpoints:
  54. assert bytes(message, "utf8") in client.get("/repository{0}".format(endpoint), follow_redirects=True).data
  55. def test_default_authorized(client, auth):
  56. auth.login("stan")
  57. response = client.get("/repository", follow_redirects=True)
  58. assert response.history[0].status_code == 308
  59. assert response.status_code == 200
  60. @pytest.mark.parametrize(
  61. ("username"),
  62. (
  63. (""),
  64. ("una"),
  65. ),
  66. )
  67. def test_contribute_post_unauthenticated_and_unauthorized(client, auth, username):
  68. auth.login(username)
  69. data = {
  70. "resource_title" : "Cooking with Garlic",
  71. "resource_description" : "How to cook with garlic",
  72. "licence_type" : "CC-BY-4.0",
  73. "resource_files" : [],
  74. "local_sharing_level" : "ALL",
  75. "ec_sharing_level" : "INTERNAL",
  76. "accept_tos" : True,
  77. }
  78. response = client.post("/repository/contribute", data=data)
  79. assert len(response.history) == 0
  80. assert b"Access Denied" in response.data
  81. def test_contribute_get_valid(client, auth):
  82. auth.login("stan")
  83. response = client.get("/repository/contribute")
  84. assert response.status_code == 200
  85. assert b"<h1>Contribute New Resource</h1>" in response.data
  86. assert b"I agree with the Language Resource upload Terms of Service for Data Holders" in response.data
  87. @pytest.mark.parametrize(
  88. ("licence_type", "expected_licence_filename", "ec_sharing_level", "expected_ec_status",
  89. "ipr_holder", "licence_conditions"),
  90. (
  91. (LicenceType.PUBLIC_DOMAIN, "", EcSharingLevel.INTERNAL,
  92. EcResourceStatus.NOT_RELAYED, "", []),
  93. (LicenceType.CC_BY_40, LicenceType.CC_BY_40.value.standard_filename, EcSharingLevel.INTERNAL,
  94. EcResourceStatus.NOT_RELAYED, "Dept of Thunderstorms", [LicenceConditionType.ATTRIBUTION]),
  95. (LicenceType.CC_BY_40, LicenceType.CC_BY_40.value.standard_filename, EcSharingLevel.INTERNAL,
  96. EcResourceStatus.NOT_RELAYED, "Dept of Thunderstorms", [LicenceConditionType.ATTRIBUTION]),
  97. (LicenceType.OTHER, "licence.pdf", EcSharingLevel.INTERNAL,
  98. EcResourceStatus.NOT_RELAYED, "", []),
  99. (LicenceType.OTHER, "licence.pdf", EcSharingLevel.NONE,
  100. EcResourceStatus.NOT_APPLICABLE, "", []),
  101. (LicenceType.CC_BY_NC_SA_40, LicenceType.CC_BY_NC_SA_40.value.standard_filename, EcSharingLevel.INTERNAL,
  102. EcResourceStatus.NOT_RELAYED, "Dept of Thunderstorms", [LicenceConditionType.ATTRIBUTION, LicenceConditionType.NON_COMMERCIAL, LicenceConditionType.SHARE_ALIKE]),
  103. ),
  104. )
  105. def test_contribute_post_valid(app, client, auth, licence_type, expected_licence_filename,
  106. ec_sharing_level, expected_ec_status, ipr_holder, licence_conditions):
  107. username = "stan"
  108. auth.login(username)
  109. previous_seen = datetime.utcnow()
  110. with app.app_context():
  111. previous_seen = User.query.filter_by(username=username).first().seen
  112. expected_id = 11 # 10 resources pre-populated
  113. resource_title = "Cooking with Garlic"
  114. licence_file = FileStorage(stream=io.BytesIO(b"licence information"), filename="licence.pdf") if licence_type.value.user_provided else None
  115. resource_files = [FileStorage(stream=io.BytesIO(b"a cookery book"), filename="garlic.txt")]
  116. data = {
  117. "resource_title" : resource_title,
  118. "resource_description" : "How to cook with garlic",
  119. "themes" : [Theme.AGRICULTURE.name],
  120. "licence_type" : licence_type.name,
  121. "licence_file" : licence_file,
  122. "resource_files" : resource_files,
  123. "local_sharing_level" : "ALL",
  124. "ec_sharing_level" : ec_sharing_level.name,
  125. "ipr_holder" : ipr_holder,
  126. "attribution" : "Licensed",
  127. "accept_tos" : True,
  128. }
  129. response = client.post("/repository/contribute", data=data, follow_redirects=True)
  130. assert response.status_code == 200
  131. assert response.history[0].status_code == 302
  132. assert response.history[0].headers["Location"] == "/index"
  133. with app.test_request_context():
  134. resource = Resource.query.filter_by(id=expected_id).first()
  135. standard_user = User.query.filter_by(username=username).first()
  136. assert (standard_user.seen - previous_seen) > timedelta()
  137. assert resource is not None
  138. assert len(resource.titles) == 1
  139. assert resource.titles[0].language == "en"
  140. assert resource.titles[0].content == resource_title
  141. assert len(resource.descriptions) == 1
  142. assert resource.descriptions[0].language == "en"
  143. assert resource.descriptions[0].content == "How to cook with garlic"
  144. assert resource.owner_id == 3
  145. assert resource.owner == standard_user
  146. assert resource.contact_id == 3
  147. assert resource.contact == standard_user
  148. assert len(resource.dsis) == 0
  149. assert len(resource.themes) == 1
  150. assert resource.themes[0].theme == Theme.AGRICULTURE
  151. assert resource.licence.type == licence_type
  152. assert resource.licence.name == licence_type.value.default_name
  153. if licence_type.value.default_text:
  154. assert resource.licence.texts[0].language == "en"
  155. assert resource.licence.texts[0].content == licence_type.value.default_text
  156. else:
  157. assert len(resource.licence.texts) == 0
  158. assert resource.licence.url == None
  159. assert resource.local_sharing_level == LocalSharingLevel.ALL
  160. assert resource.ec_sharing_level == ec_sharing_level
  161. assert resource.local_status == LocalResourceStatus.RAW
  162. assert resource.ec_status == expected_ec_status
  163. if ipr_holder:
  164. assert len(resource.ipr_holders) == 1
  165. assert resource.ipr_holders[0].organization_name == ipr_holder
  166. else:
  167. assert len(resource.ipr_holders) == 0
  168. assert len(resource.attributions) == 1
  169. assert resource.attributions[0].language == "en"
  170. assert resource.attributions[0].content == "Licensed"
  171. assert resource.funding_project == None
  172. assert((datetime.utcnow() - resource.created) < timedelta(seconds=2))
  173. assert resource.updated == None
  174. location = pathlib.Path(app.config["UPLOAD_FOLDER"]).resolve().joinpath(resource.uuid)
  175. assert location.exists()
  176. resource_path = location.joinpath("input", "garlic.txt")
  177. assert resource_path.exists()
  178. assert resource_path.stat().st_size > 0
  179. licence_dir = location.joinpath("output", "licence")
  180. assert licence_dir.exists()
  181. if licence_type.value.file_required:
  182. licence_path = licence_dir.joinpath(expected_licence_filename)
  183. assert licence_path.exists()
  184. assert licence_path.stat().st_size > 0
  185. else:
  186. licence_path = licence_dir.joinpath("licence_{0}.txt".format(licence_type.value.export_name))
  187. assert licence_path.exists()
  188. assert licence_path.stat().st_size > 0
  189. with open(licence_path) as licence_file:
  190. licence_lines = licence_file.read().splitlines()
  191. assert licence_lines[0] == licence_type.value.display_name
  192. assert licence_lines[1] == licence_type.value.default_text
  193. assert len(resource.licence.conditions) == len(licence_conditions)
  194. for condition in licence_conditions:
  195. assert any(lc.condition == condition for lc in resource.licence.conditions)
  196. assert len(standard_user.resources) == 1
  197. assert standard_user.resources[0] == resource
  198. assert len(standard_user.contact_for) == 1
  199. assert standard_user.contact_for[0] == resource
  200. outbox = app.extensions["mailman"].outbox
  201. assert len(outbox) == 1
  202. assert outbox[0].subject == "New resource contributed | Acmhainn nua curtha ar fáil"
  203. assert outbox[0].body.startswith("A new resource has been contributed.\n\nUploader: stan\nResource title: Cooking with Garlic")
  204. assert outbox[0].from_email == "no-reply@localhost"
  205. assert set(outbox[0].to) == {"reeve@test.com", "ada@test.com"}
  206. expected_document = {
  207. "get_titles_en": resource_title,
  208. "get_descriptions_en": "How to cook with garlic",
  209. "local_status": "RAW",
  210. "local_sharing_level": "ALL",
  211. "owner_id": standard_user.id,
  212. "funding_project_id": None,
  213. "get_licence_0": licence_type.name,
  214. "get_themes_0": Theme.AGRICULTURE.name
  215. }
  216. app.elasticsearch.index.assert_any_call(index="resources", id=expected_id, document=expected_document)
  217. def test_contribute_post_compressed(app, client, auth):
  218. auth.login("stan")
  219. expected_id = 11 # 10 resources pre-populated
  220. resource_file_info = [
  221. ("a.txt", io.BytesIO(b"aaaaa")),
  222. ("b.sh", io.BytesIO(b"bbbbb")),
  223. ("c.tmx", io.BytesIO(b"ccccc")),
  224. ("d.zip", io.BytesIO(b"ddddd")),
  225. ("nested/e.odt", io.BytesIO(b"eeeee")),
  226. ("much/further/nested/f.doc", io.BytesIO(b"fffff")),
  227. ("nested/g.exe", io.BytesIO(b"ggggg")),
  228. ]
  229. zip_bytes = io.BytesIO()
  230. with zipfile.ZipFile(zip_bytes, mode="a") as zip:
  231. for name, data in resource_file_info:
  232. zip.writestr(name, data.getvalue())
  233. zip_bytes.seek(0)
  234. resource_files = [FileStorage(stream=zip_bytes, filename="files.zip")]
  235. data = {
  236. "resource_title" : "Cooking with Garlic",
  237. "resource_description" : "How to cook with garlic",
  238. "licence_type" : LicenceType.CC0_10.name,
  239. "licence_file" : None,
  240. "resource_files" : resource_files,
  241. "local_sharing_level" : "ALL",
  242. "ec_sharing_level" : "INTERNAL",
  243. "accept_tos" : True,
  244. }
  245. response = client.post("/repository/contribute", data=data, follow_redirects=True)
  246. assert response.status_code == 200
  247. assert response.history[0].status_code == 302
  248. assert response.history[0].headers["Location"] == "/index"
  249. with app.app_context():
  250. resource = Resource.query.filter_by(id=expected_id).first()
  251. standard_user = User.query.filter_by(username="stan").first()
  252. assert resource is not None
  253. assert len(resource.titles) == 1
  254. assert resource.titles[0].language == "en"
  255. assert resource.titles[0].content == "Cooking with Garlic"
  256. assert len(resource.descriptions) == 1
  257. assert resource.descriptions[0].language == "en"
  258. assert resource.descriptions[0].content == "How to cook with garlic"
  259. assert resource.owner_id == 3
  260. assert resource.owner == standard_user
  261. assert resource.licence.type == LicenceType.CC0_10
  262. assert resource.licence.name == ""
  263. assert len(resource.licence.texts) == 0
  264. assert resource.licence.url == None
  265. assert resource.local_sharing_level == LocalSharingLevel.ALL
  266. assert resource.ec_sharing_level == EcSharingLevel.INTERNAL
  267. assert resource.local_status == LocalResourceStatus.RAW
  268. assert resource.ec_status == EcResourceStatus.NOT_RELAYED
  269. assert((datetime.utcnow() - resource.created) < timedelta(seconds=2))
  270. assert resource.updated == None
  271. location = pathlib.Path(app.config["UPLOAD_FOLDER"]).resolve().joinpath(resource.uuid)
  272. assert location.exists()
  273. resource_path = location.joinpath("input", "files.zip")
  274. assert resource_path.exists()
  275. assert resource_path.stat().st_size > 0
  276. assert location.joinpath("input", "a.txt").exists()
  277. assert location.joinpath("input", "c.tmx").exists()
  278. assert location.joinpath("input", "nested_e.odt").exists()
  279. assert location.joinpath("input", "much_further_nested_f.doc").exists()
  280. assert not location.joinpath("input", "b.sh").exists()
  281. assert not location.joinpath("input", "d.zip").exists()
  282. assert not location.joinpath("input", "nested_g.exe").exists()
  283. assert not location.joinpath("input", "nested").exists()
  284. assert not location.joinpath("input", "much", "further", "nested").exists()
  285. licence_dir = location.joinpath("output", "licence")
  286. assert licence_dir.exists()
  287. assert len(standard_user.resources) == 1
  288. assert standard_user.resources[0] == resource
  289. def test_contribute_post_multiple(app, client, auth):
  290. auth.login("stan")
  291. expected_id = 11 # 10 resources pre-populated
  292. zip_resource_file_info = [
  293. ("a.txt", io.BytesIO(b"aaaaa")),
  294. ("b.sh", io.BytesIO(b"bbbbb")),
  295. ("c.tmx", io.BytesIO(b"ccccc")),
  296. ("d.zip", io.BytesIO(b"ddddd")),
  297. ]
  298. zip_bytes = io.BytesIO()
  299. with zipfile.ZipFile(zip_bytes, mode="a") as zip:
  300. for name, data in zip_resource_file_info:
  301. zip.writestr(name, data.getvalue())
  302. zip_bytes.seek(0)
  303. resource_files = [
  304. FileStorage(stream=io.BytesIO(b"aniseed cookery book"), filename="aniseed.txt"),
  305. FileStorage(stream=io.BytesIO(b"basil cookery book"), filename="basil.tmx"),
  306. FileStorage(stream=zip_bytes, filename="files.zip"),
  307. ]
  308. data = {
  309. "resource_title" : "Cooking",
  310. "resource_description" : "How to cook",
  311. "licence_type" : LicenceType.CC0_10.name,
  312. "licence_file" : None,
  313. "resource_files" : resource_files,
  314. "local_sharing_level" : "ALL",
  315. "ec_sharing_level" : "INTERNAL",
  316. "accept_tos" : True,
  317. }
  318. response = client.post("/repository/contribute", data=data, follow_redirects=True)
  319. assert response.status_code == 200
  320. assert response.history[0].status_code == 302
  321. assert response.history[0].headers["Location"] == "/index"
  322. with app.app_context():
  323. resource = Resource.query.filter_by(id=expected_id).first()
  324. standard_user = User.query.filter_by(username="stan").first()
  325. assert resource is not None
  326. assert len(resource.titles) == 1
  327. assert resource.titles[0].language == "en"
  328. assert resource.titles[0].content == "Cooking"
  329. assert len(resource.descriptions) == 1
  330. assert resource.descriptions[0].language == "en"
  331. assert resource.descriptions[0].content == "How to cook"
  332. assert resource.owner_id == 3
  333. assert resource.owner == standard_user
  334. assert resource.licence.type == LicenceType.CC0_10
  335. assert resource.licence.name == ""
  336. assert len(resource.licence.texts) == 0
  337. assert resource.licence.url == None
  338. assert resource.local_sharing_level == LocalSharingLevel.ALL
  339. assert resource.ec_sharing_level == EcSharingLevel.INTERNAL
  340. assert resource.local_status == LocalResourceStatus.RAW
  341. assert resource.ec_status == EcResourceStatus.NOT_RELAYED
  342. assert((datetime.utcnow() - resource.created) < timedelta(seconds=2))
  343. assert resource.updated == None
  344. location = pathlib.Path(app.config["UPLOAD_FOLDER"]).resolve().joinpath(resource.uuid)
  345. assert location.exists()
  346. resource_path = location.joinpath("input", "files.zip")
  347. assert resource_path.exists()
  348. assert resource_path.stat().st_size > 0
  349. assert location.joinpath("input", "aniseed.txt").exists()
  350. assert location.joinpath("input", "basil.tmx").exists()
  351. assert location.joinpath("input", "a.txt").exists()
  352. assert location.joinpath("input", "c.tmx").exists()
  353. assert not location.joinpath("input", "b.sh").exists()
  354. assert not location.joinpath("input", "d.zip").exists()
  355. licence_dir = location.joinpath("output", "licence")
  356. assert licence_dir.exists()
  357. assert len(standard_user.resources) == 1
  358. assert standard_user.resources[0] == resource
  359. @pytest.mark.parametrize(
  360. ( "name", "description", "licence_type", "resource_filename", "local_sl", "ec_sl", "ipr_holder", "attribution", "accept", "message"),
  361. (
  362. ("", "res desc", "CC_BY_40", "resource.txt", "ALL", "INTERNAL", "I.P.R. Holder", "Licensed", True, b"Please fill in this field."),
  363. ("res name", "", "CC_BY_40", "resource.txt", "ALL", "INTERNAL", "I.P.R. Holder", "Licensed", True, b"Please fill in this field."),
  364. ("res name", "res desc", "ABC_80", "resource.txt", "ALL", "INTERNAL", "I.P.R. Holder", "Licensed", True, b"Not a valid choice."),
  365. ("res name", "res desc", "CC_BY_40", "resource.txt", "NONE", "INTERNAL", "I.P.R. Holder", "Licensed", True, b"Not a valid choice."),
  366. ("res name", "res desc", "CC_BY_40", "resource.txt", "ALL", "UNKNOWN", "I.P.R. Holder", "Licensed", True, b"Not a valid choice."),
  367. ("res name", "res desc", "CC_BY_40", "resource.txt", "ALL", "INTERNAL", "I.P.R. Holder", "Licensed", "", b"This box must be checked in order to continue."),
  368. ("res name", "res desc", "CC_BY_40", "resource.sh", "ALL", "INTERNAL", "I.P.R. Holder", "Licensed", True, b"Only the following formats are allowed:"),
  369. ("res-01", "res desc", "CC_BY_40", "resource.txt", "ALL", "INTERNAL", "I.P.R. Holder", "Licensed", True, b"You have previously uploaded a resource with this title."),
  370. ("res name", "res desc", "CC_BY_40", "resource.txt", "ALL", "INTERNAL", "", "Licensed", True, b"An IPR holder must be named for the type of licence selected."),
  371. ("res name", "res desc", "CC_BY_40", "resource.txt", "ALL", "INTERNAL", "I.P.R. Holder", "", True, b"Attribution text must be entered for the type of licence selected."),
  372. ),
  373. )
  374. def test_contribute_post_invalid(client, app, auth, name, description, licence_type, resource_filename,
  375. local_sl, ec_sl, ipr_holder, attribution, accept, message):
  376. username = "gobnait"
  377. auth.login(username)
  378. expected_id = 11 # 10 resources pre-populated
  379. expected_resources = 5
  380. resource_files = FileStorage(stream=io.BytesIO(b"a cookery book"), filename=resource_filename)
  381. data = {
  382. "resource_title" : name,
  383. "resource_description" : description,
  384. "licence_type" : licence_type,
  385. "resource_files" : resource_files,
  386. "local_sharing_level" : local_sl,
  387. "ec_sharing_level" : ec_sl,
  388. "ipr_holder" : ipr_holder,
  389. "attribution" : attribution,
  390. "accept_tos" : accept,
  391. }
  392. response = client.post("/repository/contribute", data=data, follow_redirects=True)
  393. assert response.status_code == 200
  394. assert len(response.history) == 0
  395. assert message in response.data
  396. with app.app_context():
  397. assert Resource.query.filter_by(id=expected_id).first() is None
  398. assert len(User.query.filter_by(username=username).first().resources) == expected_resources
  399. @pytest.mark.parametrize(
  400. ( "licence_type", "licence_file", "message"),
  401. (
  402. (LicenceType.OTHER, None, "A licence file must be provided for the selected licence type."),
  403. (LicenceType.OTHER, FileStorage(stream=io.BytesIO(b"licence info"), filename="licence.sh"), "Only the following formats are allowed:"),
  404. (LicenceType.CC_BY_40, FileStorage(stream=io.BytesIO(b"licence info"), filename="licence.pdf"), "No licence file is required for a standard licence type"),
  405. ),
  406. )
  407. def test_contribute_post_invalid_licence(client, app, auth, licence_type, licence_file, message):
  408. auth.login("stan")
  409. expected_id = 11 # 10 resources pre-populated
  410. resource_files = FileStorage(stream=io.BytesIO(b"a cookery book"), filename="resource.txt")
  411. data = {
  412. "resource_title" : "res name",
  413. "resource_description" : "res desc",
  414. "licence_type" : licence_type.name,
  415. "licence_file" : licence_file,
  416. "resource_files" : resource_files,
  417. "local_sharing_level" : LocalSharingLevel.ALL,
  418. "ec_sharing_level" : EcSharingLevel.NONE,
  419. "ipr_holder" : "I.P.R. Holder",
  420. "attribution" : "Licensed",
  421. "accept_tos" : True,
  422. }
  423. response = client.post("/repository/contribute", data=data, follow_redirects=True)
  424. assert response.status_code == 200
  425. assert len(response.history) == 0
  426. assert bytes(message, "utf8") in response.data
  427. with app.app_context():
  428. assert Resource.query.filter_by(id=expected_id).first() is None
  429. standard_user = User.query.filter_by(username="stan").first()
  430. assert len(standard_user.resources) == 0
  431. ALL_TITLES = ["res-01", "res-02", "ac-02", "cinnamon", "ac-04", "elderflower", "fennel", "fearn", "res-07", "res-08", "res-09", "res-10"]
  432. @pytest.mark.parametrize(
  433. ("username", "primary_metadata_language", "request_args", "result_count", "visible_total", "expected_titles", "expected_texts"),
  434. (
  435. ("stan", "en", "?page=1", 5, 5, ["elderflower", "res-07", "res-08"], []),
  436. ("stan", "en", "?page=2", 5, 5, ["res-09", "res-10"], []),
  437. ("stan", "en", "?page=3", 5, 5, [], []),
  438. ("gobnait", "en", "?page=1", 6, 6, ["elderflower", "fennel", "res-07"], []),
  439. ("gobnait", "en", "?page=2", 6, 6, ["res-08", "res-09", "res-10"], []),
  440. ("gobnait", "ga", "?page=1", 6, 6, ["elderflower", "fearn", "res-07"], []),
  441. ("gobnait", "ga", "?page=2", 6, 6, ["res-08", "res-09", "res-10"], []),
  442. ("leo", "en", "?page=1", 6, 6, ["ac-04", "elderflower", "res-07"], []),
  443. ("leo", "en", "?page=2", 6, 6, ["res-08", "res-09", "res-10"], []),
  444. ("steph", "en", "", 7, 7, ["ac-04", "elderflower", "fennel"], ["href=\"/repository/browse?page=2\""]),
  445. ("steph", "en", "?page=1", 7, 7, ["ac-04", "elderflower", "fennel"], ["href=\"/repository/browse?page=2\""]),
  446. ("steph", "en", "?page=2", 7, 7, ["res-07", "res-08", "res-09"], ["href=\"/repository/browse?page=3\""]),
  447. ("steph", "en", "?page=3", 7, 7, ["res-10"], ["href=\"/repository/browse?page=2\""]),
  448. ("steph", "en", "?page=4", 7, 7, [], ["href=\"/repository/browse?page=3\""]),
  449. ("reeve", "en", "?page=1", 7, 7, ["ac-04", "elderflower", "fennel"], []),
  450. ("reeve", "en", "?page=2", 7, 7, ["res-07", "res-08", "res-09"], []),
  451. ("reeve", "en", "?page=3", 7, 7, ["res-10"], []),
  452. ("steph", "en", "?licence=UNKNOWN", 0, 7, [], []),
  453. ("steph", "en", "?licence=CC_BY_40", 0, 7, [], []),
  454. ("steph", "en", "?licence=PUBLIC_DOMAIN", 1, 7, ["elderflower"], []),
  455. ("steph", "en", "?licence=CC0_10", 2, 7, ["res-07", "res-10"], []),
  456. ("steph", "en", "?licence=OTHER", 4, 7, ["ac-04", "fennel", "res-08"], ["href=\"/repository/browse?page=2&amp;licence=OTHER\""]),
  457. ("steph", "en", "?licence=OTHER&page=2", 4, 7, ["res-09"], ["href=\"/repository/browse?page=1&amp;licence=OTHER\""]),
  458. ("steph", "ga", "?licence=OTHER", 4, 7, ["ac-04", "fearn", "res-08"], ["href=\"/repository/browse?page=2&amp;licence=OTHER\""]),
  459. ("steph", "ga", "?licence=OTHER&page=2", 4, 7, ["res-09"], ["href=\"/repository/browse?page=1&amp;licence=OTHER\""]),
  460. ("gobnait", "en", "?licence=OTHER", 3, 6, ["fennel", "res-08", "res-09"], []),
  461. ("stan", "en", "?licence=OTHER", 2, 5, ["res-08", "res-09"], []),
  462. ("steph", "en", "?theme=UNKNOWN", 0, 7, [], []),
  463. ("steph", "en", "?theme=ECONOMY", 0, 7, [], []),
  464. ("steph", "en", "?theme=HEALTH", 1, 7, ["ac-04"], []),
  465. ("steph", "en", "?theme=ENERGY", 1, 7, ["elderflower"], []),
  466. ("steph", "en", "?theme=ENVIRONMENT", 2, 7, ["elderflower", "res-09"], []),
  467. ("steph", "en", "?theme=REGIONS", 3, 7, ["fennel", "res-07", "res-09"], []),
  468. ("gobnait", "en", "?theme=HEALTH", 0, 6, [], []),
  469. ("gobnait", "en", "?theme=REGIONS", 3, 6, ["fennel", "res-07", "res-09"], []),
  470. ("stan", "en", "?theme=HEALTH", 0, 5, [], []),
  471. ("stan", "en", "?theme=REGIONS", 2, 5, ["res-07", "res-09"], []),
  472. ("steph", "en", "?licence=PUBLIC_DOMAIN&theme=ENVIRONMENT", 1, 7, ["elderflower"], []),
  473. ("steph", "en", "?licence=OTHER&theme=REGIONS", 2, 7, ["fennel", "res-09"], []),
  474. ("steph", "en", "?licence=CC0_10&theme=REGIONS", 1, 7, ["res-07"], []),
  475. ("gobnait", "en", "?licence=OTHER&theme=REGIONS", 2, 6, ["fennel", "res-09"], []),
  476. ("gobnait", "en", "?licence=CC0_10&theme=REGIONS", 1, 6, ["res-07"], []),
  477. ("stan", "en", "?licence=OTHER&theme=REGIONS", 1, 5, ["res-09"], []),
  478. ("stan", "en", "?licence=CC0_10&theme=REGIONS", 1, 5, ["res-07"], []),
  479. ("steph", "en", "?dsi=UNKNOWN", 0, 7, [], []),
  480. ("steph", "en", "?dsi=EESSI", 0, 7, [], []),
  481. ("steph", "en", "?dsi=EH", 1, 7, ["ac-04"], []),
  482. ("steph", "en", "?dsi=EURO", 1, 7, ["elderflower"], []),
  483. ("steph", "en", "?dsi=ODR", 2, 7, ["fennel", "res-10"], []),
  484. ("steph", "en", "?dsi=EJ", 3, 7, ["elderflower", "res-08", "res-10"], []),
  485. ("gobnait", "en", "?dsi=EH", 0, 6, [], []),
  486. ("gobnait", "en", "?dsi=EURO", 1, 6, ["elderflower"], []),
  487. ("gobnait", "en", "?dsi=ODR", 2, 6, ["fennel", "res-10"], []),
  488. ("gobnait", "en", "?dsi=EJ", 3, 6, ["elderflower", "res-08", "res-10"], []),
  489. ("stan", "en", "?dsi=EH", 0, 5, [], []),
  490. ("stan", "en", "?dsi=EURO", 1, 5, ["elderflower"], []),
  491. ("stan", "en", "?dsi=ODR", 1, 5, ["res-10"], []),
  492. ("stan", "en", "?dsi=EJ", 3, 5, ["elderflower", "res-08", "res-10"], []),
  493. ("steph", "en", "?licence=OTHER&dsi=ODR", 1, 7, ["fennel"], []),
  494. ("steph", "en", "?licence=OTHER&dsi=CS", 2, 7, ["fennel", "res-09"], []),
  495. ("steph", "en", "?licence=OTHER&dsi=EJ", 1, 7, ["res-08"], []),
  496. ("gobnait", "en", "?licence=OTHER&dsi=ODR", 1, 6, ["fennel"], []),
  497. ("gobnait", "en", "?licence=OTHER&dsi=CS", 2, 6, ["fennel", "res-09"], []),
  498. ("gobnait", "en", "?licence=OTHER&dsi=EJ", 1, 6, ["res-08"], []),
  499. ("stan", "en", "?licence=OTHER&dsi=ODR", 0, 5, [], []),
  500. ("stan", "en", "?licence=OTHER&dsi=CS", 1, 5, ["res-09"], []),
  501. ("stan", "en", "?licence=OTHER&dsi=EJ", 1, 5, ["res-08"], []),
  502. ("steph", "en", "?theme=HEALTH&dsi=EH", 1, 7, ["ac-04"], []),
  503. ("steph", "en", "?theme=HOUSING&dsi=ODR", 1, 7, ["fennel"], []),
  504. ("steph", "en", "?theme=JUSTICE&dsi=EJ", 1, 7, ["res-10"], []),
  505. ("gobnait", "en", "?theme=HEALTH&dsi=EH", 0, 6, [], []),
  506. ("gobnait", "en", "?theme=HOUSING&dsi=ODR", 1, 6, ["fennel"], []),
  507. ("gobnait", "en", "?theme=JUSTICE&dsi=EJ", 1, 6, ["res-10"], []),
  508. ("stan", "en", "?theme=HEALTH&dsi=EH", 0, 5, [], []),
  509. ("stan", "en", "?theme=HOUSING&dsi=ODR", 0, 5, [], []),
  510. ("stan", "en", "?theme=JUSTICE&dsi=EJ", 1, 5, ["res-10"], []),
  511. ("steph", "en", "?licence=CC0_10&theme=JUSTICE&dsi=SI", 1, 7, ["res-10"], []),
  512. ("steph", "en", "?licence=OTHER&theme=REGIONS&dsi=CS", 2, 7, ["fennel", "res-09"], []),
  513. ("gobnait", "en", "?licence=CC0_10&theme=JUSTICE&dsi=SI", 1, 6, ["res-10"], []),
  514. ("gobnait", "en", "?licence=OTHER&theme=REGIONS&dsi=CS", 2, 6, ["fennel", "res-09"], []),
  515. ("stan", "en", "?licence=CC0_10&theme=JUSTICE&dsi=SI", 1, 5, ["res-10"], []),
  516. ("stan", "en", "?licence=OTHER&theme=REGIONS&dsi=CS", 1, 5, ["res-09"], []),
  517. ("steph", "en", "?project=4", 0, 7, [], []),
  518. ("steph", "en", "?project=2", 1, 7, ["res-07"], []),
  519. ("steph", "en", "?project=3", 2, 7, ["ac-04", "res-09"], []),
  520. ("steph", "en", "?project=1", 4, 7, ["elderflower", "fennel", "res-08"], ["href=\"/repository/browse?page=2&amp;project=1\""]),
  521. ("steph", "en", "?project=1&page=2", 4, 7, ["res-10"], ["href=\"/repository/browse?page=1&amp;project=1\""]),
  522. ("gobnait", "en", "?project=1", 4, 6, ["elderflower", "fennel", "res-08"], []),
  523. ("gobnait", "en", "?project=1&page=2", 4, 6, ["res-10"], []),
  524. ("stan", "en", "?project=1", 3, 5, ["elderflower", "res-08", "res-10"], []),
  525. ("stan", "en", "?project=1&page=2", 3, 5, [], []),
  526. ("steph", "en", "?licence=CC0_10&project=1", 1, 7, ["res-10"], []),
  527. ("steph", "en", "?licence=OTHER&project=3", 2, 7, ["ac-04", "res-09"], []),
  528. ("gobnait", "en", "?licence=OTHER&project=3", 1, 6, ["res-09"], []),
  529. ("steph", "en", "?theme=HEALTH&project=1", 0, 7, [], []),
  530. ("steph", "en", "?theme=HOUSING&project=1", 1, 7, ["fennel"], []),
  531. ("stan", "en", "?theme=HOUSING&project=1", 0, 5, [], []),
  532. ("steph", "en", "?dsi=ODR&project=1", 2, 7, ["fennel", "res-10"], []),
  533. ("gobnait", "en", "?dsi=ODR&project=1", 2, 6, ["fennel", "res-10"], []),
  534. ("stan", "en", "?dsi=ODR&project=1", 1, 5, ["res-10"], []),
  535. ("steph", "en", "?dsi=EJ&project=1", 3, 7, ["elderflower", "res-08", "res-10"], []),
  536. ("steph", "en", "?licence=OTHER&theme=REGIONS&dsi=CS&project=1", 1, 7, ["fennel"], []),
  537. ("gobnait", "en", "?licence=OTHER&theme=REGIONS&dsi=CS&project=1", 1, 6, ["fennel"], []),
  538. ("stan", "en", "?licence=OTHER&theme=REGIONS&dsi=CS&project=1", 0, 5, [], []),
  539. ("steph", "en", "?licence=OTHER&theme=REGIONS&dsi=CS&project=3", 1, 7, ["res-09"], []),
  540. ("stan", "en", "?licence=OTHER&theme=REGIONS&dsi=CS&project=3", 1, 5, ["res-09"], []),
  541. ("steph", "en", "?licence=PUBLIC_DOMAIN&theme=ENERGY&dsi=EURO&project=2", 0, 7, [], []),
  542. ("steph", "en", "?licence=PUBLIC_DOMAIN&theme=ENERGY&dsi=EURO&project=1", 1, 7, ["elderflower"], []),
  543. ("gobnait", "en", "?licence=PUBLIC_DOMAIN&theme=ENERGY&dsi=EURO&project=1", 1, 6, ["elderflower"], []),
  544. ("stan", "en", "?licence=PUBLIC_DOMAIN&theme=ENERGY&dsi=EURO&project=1", 1, 5, ["elderflower"], []),
  545. ),
  546. )
  547. def test_browse_get_valid(app, client, auth, username, primary_metadata_language, request_args, result_count,
  548. visible_total, expected_titles, expected_texts):
  549. app.config["PRIMARY_METADATA_LANGUAGE"] = primary_metadata_language
  550. auth.login(username)
  551. response = client.get("/repository/browse{0}".format(request_args))
  552. assert response.status_code == 200
  553. for title in ALL_TITLES:
  554. assert (bytes(title, "utf8") in response.data) == (title in expected_titles)
  555. for text in expected_texts:
  556. assert (bytes(text, "utf8") in response.data)
  557. if result_count == visible_total:
  558. assert bytes("Total resources: {0}".format(visible_total), "utf8") in response.data
  559. else:
  560. assert bytes("Approximately {0} resource(s) found (<a href=/repository/browse>of {1} total</a>)".format(result_count, visible_total), "utf8") in response.data
  561. @pytest.mark.parametrize(
  562. ("username", "user_id", "is_staff", "request_args", "es_query", "es_total", "visible_total", "es_results", "page_no", "expected_titles", "additional_filters"),
  563. (
  564. ("steph", 7, True, "zzzzz", "zzzzz", 0, 7, [], 1, [], []),
  565. ("steph", 7, True, "elderflower", "elderflower", 1, 7, [5], 1, ["elderflower"], []),
  566. ("steph", 7, True, "dill", "dill", 1, 7, [2], 1, [], []),
  567. ("steph", 7, True, "aniseed", "aniseed", 2, 7, [1, 7], 1, ["res-07"], []),
  568. ("steph", 7, True, "fennel", "fennel", 3, 7, [2, 3, 6], 1, ["fennel"], []),
  569. ("steph", 7, True, "ginger", "ginger", 4, 7, [3, 4, 6], 1, ["ac-04", "fennel"], []),
  570. ("gobnait", 4, False, "ginger", "ginger", 4, 6, [3, 4, 6], 1, ["fennel"], []),
  571. ("steph", 7, True, "ginger&page=2", "ginger", 4, 7, [7], 2, ["res-07"], []),
  572. ("gobnait", 4, False, "ginger&page=2", "ginger", 4, 6, [7], 2, ["res-07"], []),
  573. ("steph", 7, True, "res", "res", 6, 7, [1, 2, 7], 1, ["res-07"], []),
  574. ("steph", 7, True, "res&page=1", "res", 6, 7, [1, 2, 7], 1, ["res-07"], []),
  575. ("steph", 7, True, "res&page=2", "res", 6, 7, [8, 9, 10], 2, ["res-08", "res-09", "res-10"], []),
  576. ("steph", 7, True, "ginger&theme=REGIONS", "ginger", 4, 7, [3, 4, 6], 1, ["fennel"], [{"multi_match": {"query": "REGIONS","fields": ["get_themes_*"]}}]),
  577. ("gobnait", 4, False, "ginger&theme=REGIONS", "ginger", 4, 6, [3, 4, 6], 1, ["fennel"], [{"multi_match": {"query": "REGIONS","fields": ["get_themes_*"]}}]),
  578. ("steph", 7, True, "ginger&theme=REGIONS&page=2", "ginger", 4, 7, [7], 2, ["res-07"], [{"multi_match": {"query": "REGIONS","fields": ["get_themes_*"]}}]),
  579. ("gobnait", 4, False, "ginger&theme=REGIONS&page=2", "ginger", 4, 6, [7], 2, ["res-07"], [{"multi_match": {"query": "REGIONS","fields": ["get_themes_*"]}}]),
  580. ("steph", 7, True, "ginger&licence=OTHER", "ginger", 4, 7, [3, 4, 6], 1, ["ac-04", "fennel"], [{"match": {"get_licence_0": "OTHER"}}]),
  581. ("gobnait", 4, False, "ginger&licence=OTHER", "ginger", 4, 6, [3, 4, 6], 1, ["fennel"], [{"match": {"get_licence_0": "OTHER"}}]),
  582. ("steph", 7, True, "ginger&licence=OTHER&page=2", "ginger", 4, 7, [7], 2, [], [{"match": {"get_licence_0": "OTHER"}}]),
  583. ("gobnait", 4, False, "ginger&licence=OTHER&page=2", "ginger", 4, 6, [7], 2, [], [{"match": {"get_licence_0": "OTHER"}}]),
  584. ("steph", 7, True, "ginger&project=1", "ginger", 4, 7, [3, 4, 6], 1, ["fennel"], [{"term" : {"funding_project_id": 1}}]),
  585. ("steph", 7, True, "ginger&dsi=EH", "ginger", 4, 7, [3, 4, 6], 1, ["ac-04"], [{"multi_match" : {"query" : "EH", "fields" : ["get_dsis_*"]}}]),
  586. ),
  587. )
  588. def test_search_resources_repository(app, client, auth, username, user_id, is_staff, request_args, es_query, es_total,
  589. visible_total, es_results, page_no, expected_titles, additional_filters):
  590. auth.login(username)
  591. app.elasticsearch.search.return_value = {
  592. "hits": {
  593. "total": {"value": es_total},
  594. "hits": [{"_id" : r} for r in es_results]
  595. }
  596. }
  597. response = client.get("/repository/browse/search?q={0}".format(request_args))
  598. assert response.status_code == 200
  599. for title in ALL_TITLES:
  600. assert (bytes(title, "utf8") in response.data) == (title in expected_titles)
  601. assert bytes("Approximately {0} resource(s) found (<a href=/repository/browse>of {1} total</a>)".format(es_total, visible_total), "utf8") in response.data
  602. expected_search_query = {
  603. "bool": {
  604. "must": {
  605. "multi_match": {
  606. "query": es_query,
  607. "fields": ["get_titles_*", "get_descriptions_*"]
  608. }
  609. },
  610. "filter": [
  611. {
  612. "match": {
  613. "local_status": "PUBLISHED"
  614. }
  615. }
  616. ]
  617. }
  618. }
  619. for additional_filter in additional_filters:
  620. expected_search_query["bool"]["filter"].append(additional_filter)
  621. if not is_staff:
  622. expected_search_query["bool"]["filter"].append({
  623. "bool": {
  624. "should": [
  625. {
  626. "term": {
  627. "owner_id": user_id
  628. }
  629. },
  630. {
  631. "match": {
  632. "local_sharing_level": "ALL"
  633. }
  634. }
  635. ]
  636. }
  637. })
  638. page_size = app.config["RESOURCES_PER_PAGE_REPOSITORY"]
  639. from_ = (page_no - 1) * page_size
  640. app.elasticsearch.search.assert_called_once_with(index="resources", query=expected_search_query, from_=from_, size=page_size)
  641. @pytest.mark.parametrize(
  642. ("username", "resource_id", "visible", "resource_title", "expected_view_count", "contact_email", "dsis", "themes", "linguality_type", "languages", "format", "encoding", "size"),
  643. (
  644. ("una", 1, False, "res-01", 0, "gobnait@test.com", [], [], "Monolingual", ["ga"], "text/plain", "utf8", "0 Unknown"),
  645. ("una", 5, False, "elderflower", 0, "leo@test.com", [Dsi.EJ.value, Dsi.EURO.value], [Theme.ENERGY, Theme.ENVIRONMENT], "Bilingual", ["en", "ga"], "application/x-tmx+xml", "utf16", "55555 Translation Units"),
  646. ("gobnait", 1, False, "res-01", 0, "gobnait@test.com", [], [], "Monolingual", ["ga"], "text/plain", "utf8", "0 Unknown"),
  647. ("gobnait", 2, False, "res-02", 0, "gobnait@test.com", [], [], "Monolingual", ["ga"], "text/plain", "utf8", "0 Unknown"),
  648. ("gobnait", 3, False, "cinnamon", 0, "gobnait@test.com", [], [], "Monolingual", ["ga"], "text/plain", "utf8", "0 Unknown"),
  649. ("gobnait", 4, False, "ac-04", 2, "leo@test.com", [Dsi.EH.value], [Theme.HEALTH], "Monolingual", ["zz"], "text/plain", "ascii", "44444 Words"),
  650. ("gobnait", 5, True, "elderflower", 1, "leo@test.com", [Dsi.EJ.value, Dsi.EURO.value], [Theme.ENERGY, Theme.ENVIRONMENT], "Bilingual", ["en", "ga"], "application/x-tmx+xml", "utf16", "55555 Translation Units"),
  651. ("gobnait", 6, True, "fennel", 7, "gobnait@test.com", [], [Theme.HOUSING, Theme.REGIONS], "Multilingual", ["ga", "en", "de"], "text/csv", "utf8", "66666 Terms"),
  652. ("leo", 4, True, "ac-04", 3, "leo@test.com", [Dsi.EH.value], [Theme.HEALTH], "Monolingual", ["zz"], "text/plain", "ascii", "44444 Words"),
  653. ("leo", 5, True, "elderflower", 1, "leo@test.com", [Dsi.EJ.value, Dsi.EURO.value], [Theme.ENERGY, Theme.ENVIRONMENT], "Bilingual", ["en", "ga"], "application/x-tmx+xml", "utf16", "55555 Translation Units"),
  654. ("leo", 6, False, "fennel", 7, "gobnait@test.com", [], [Theme.HOUSING, Theme.REGIONS], "Multilingual", ["ga", "en", "de"], "text/csv", "utf8", "66666 Terms"),
  655. ("steph", 4, True, "ac-04", 2, "leo@test.com", [Dsi.EH.value], [Theme.HEALTH], "Monolingual", ["zz"], "text/plain", "ascii", "44444 Words"),
  656. ("steph", 5, True, "elderflower", 1, "leo@test.com", [Dsi.EJ.value, Dsi.EURO.value], [Theme.ENERGY, Theme.ENVIRONMENT], "Bilingual", ["en", "ga"], "application/x-tmx+xml", "utf16", "55555 Translation Units"),
  657. ("steph", 6, True, "fennel", 7, "gobnait@test.com", [], [Theme.HOUSING, Theme.REGIONS], "Multilingual", ["ga", "en", "de"], "text/csv", "utf8", "66666 Terms"),
  658. ("reeve", 0, False, "res-00", 0, "unknown@test.com", [], [], "Unknown", [], "OTHER", "", "0 Unknown"),
  659. ("reeve", 4, True, "ac-04", 3, "leo@test.com", [Dsi.EH.value], [Theme.HEALTH], "Monolingual", ["zz"], "text/plain", "ascii", "44444 Words"),
  660. ),
  661. )
  662. def test_detail_get_authenticated(client, app, auth, username, resource_id, visible, resource_title,
  663. expected_view_count, contact_email, dsis, themes, linguality_type, languages, format, encoding, size):
  664. auth.login(username)
  665. response = client.get("/repository/{0}".format(resource_id))
  666. assert response.status_code == 200
  667. assert (bytes(resource_title, "utf8") in response.data) == visible
  668. assert (bytes(contact_email, "utf8") in response.data) == visible
  669. assert (bytes(linguality_type, "utf8") in response.data) == visible
  670. for language in languages:
  671. assert (bytes("<li>{0}</li>".format(language), "utf8") in response.data) == visible
  672. assert (bytes(format, "utf8") in response.data) == visible
  673. if encoding:
  674. assert (bytes(encoding, "utf8") in response.data) == visible
  675. assert (bytes(size, "utf8") in response.data) == visible
  676. for dsi in dsis:
  677. assert (bytes(str(dsi.display_name), "utf8") in response.data) == visible
  678. for theme in themes:
  679. assert (bytes(str(theme.value.display_name), "utf8") in response.data) == visible
  680. if resource_id > 0:
  681. with app.app_context():
  682. assert Resource.query.filter_by(id=resource_id).first().get_view_count() == expected_view_count
  683. @pytest.mark.parametrize(
  684. ("username", "resource_id", "resource_filename", "expected_download_count"),
  685. (
  686. ("leo", 4, "resource/processed_resource4.txt", 1),
  687. ("leo", 5, "resource/processed_resource5.txt", 2),
  688. ("gobnait", 5, "resource/processed_resource5.txt", 2),
  689. ("gobnait", 6, "resource/processed_resource6.txt", 4),
  690. ("steph", 4, "resource/processed_resource4.txt", 1),
  691. ("steph", 5, "resource/processed_resource5.txt", 2),
  692. ("steph", 6, "resource/processed_resource6.txt", 4),
  693. ("reeve", 4, "resource/processed_resource4.txt", 1),
  694. ("reeve", 5, "resource/processed_resource5.txt", 1),
  695. ("reeve", 6, "resource/processed_resource6.txt", 5),
  696. ),
  697. )
  698. def test_download_valid(client, app, auth, username, resource_id, resource_filename, expected_download_count):
  699. auth.login(username)
  700. app.config["UPLOAD_FOLDER"] = "test-res/repository"
  701. response = client.post("/repository/{0}/download".format(resource_id), data={"accept_licence": True}, follow_redirects=True)
  702. assert response.status_code == 200
  703. with zipfile.ZipFile(io.BytesIO(response.data)) as archive:
  704. assert resource_filename in archive.namelist()
  705. with app.app_context():
  706. assert Resource.query.filter_by(id=resource_id).first().get_download_count() == expected_download_count
  707. @pytest.mark.parametrize(
  708. ("username", "resource_id", "expected_text"),
  709. (
  710. ("una", 1, "Access Denied"),
  711. ("gobnait", 1, "Access Denied"),
  712. ("gobnait", 2, "Access Denied"),
  713. ("gobnait", 3, "Access Denied"),
  714. ("gobnait", 4, "Access Denied"),
  715. ("reeve", 0, "Not Found"),
  716. ),
  717. )
  718. def test_download_invalid(client, app, auth, username, resource_id, expected_text):
  719. auth.login(username)
  720. response = client.post("/repository/{0}/download".format(resource_id), data={"accept_licence": True}, follow_redirects=True)
  721. assert response.status_code == 200
  722. assert bytes(expected_text, "utf8") in response.data
  723. with pytest.raises(zipfile.BadZipFile):
  724. with zipfile.ZipFile(io.BytesIO(response.data)) as archive:
  725. pass
  726. if resource_id > 0:
  727. with app.app_context():
  728. assert Resource.query.filter_by(id=resource_id).first().get_download_count() == 0
  729. @pytest.mark.parametrize(
  730. ("username", "resource_id"),
  731. (
  732. ("leo", 4),
  733. ("leo", 5),
  734. ("gobnait", 5),
  735. ("gobnait", 6),
  736. ("steph", 4),
  737. ("steph", 5),
  738. ("steph", 6),
  739. ("reeve", 4),
  740. ("reeve", 5),
  741. ("reeve", 6),
  742. ),
  743. )
  744. def test_download_licence_valid(client, app, auth, username, resource_id):
  745. auth.login(username)
  746. app.config["UPLOAD_FOLDER"] = "test-res/repository"
  747. response = client.get("/repository/{0}/download-licence".format(resource_id))
  748. assert response.status_code == 200
  749. assert response.data == bytes("Licence for resource #{0}\n".format(resource_id), "utf8")
  750. @pytest.mark.parametrize(
  751. ("username", "resource_id", "expected_text"),
  752. (
  753. ("una", 1, "Access Denied"),
  754. ("gobnait", 1, "Access Denied"),
  755. ("gobnait", 2, "Access Denied"),
  756. ("gobnait", 3, "Access Denied"),
  757. ("gobnait", 4, "Access Denied"),
  758. ("reeve", 0, "Not Found"),
  759. ),
  760. )
  761. def test_download_licence_invalid(client, app, auth, username, resource_id, expected_text):
  762. auth.login(username)
  763. response = client.get("/repository/{0}/download-licence".format(resource_id))
  764. assert response.status_code == 200
  765. assert bytes(expected_text, "utf8") in response.data
  766. def test_detail_view_counts(client, auth, app):
  767. resource_id = 6
  768. with app.app_context():
  769. resource = Resource.query.filter_by(id=resource_id).first()
  770. for stat in resource.stats:
  771. db.session.delete(stat)
  772. db.session.commit()
  773. views = [
  774. ("gobnait", 1),
  775. ("gobnait", 1), # Previously viewed
  776. ("steph", 2),
  777. ("reeve", 3),
  778. ("stan", 3), # Not authorized
  779. ("gobnait", 3), # Previously viewed
  780. ("ada", 4),
  781. ]
  782. for username, expected_view_count in views:
  783. auth.login(username)
  784. client.get("/repository/{0}".format(resource_id))
  785. with app.app_context():
  786. assert Resource.query.filter_by(id=resource_id).first().get_view_count() == expected_view_count
  787. def test_download_counts(client, auth, app):
  788. app.config["UPLOAD_FOLDER"] = "test-res/repository"
  789. resource_id = 6
  790. with app.app_context():
  791. resource = Resource.query.filter_by(id=resource_id).first()
  792. for stat in resource.stats:
  793. db.session.delete(stat)
  794. db.session.commit()
  795. downloads = [
  796. ("stan", 0), # Not authorized
  797. ("gobnait", 1),
  798. ("steph", 2),
  799. ("ada", 3),
  800. ("reeve", 4),
  801. ("steph", 4), # Previously downloaded
  802. ]
  803. for username, expected_download_count in downloads:
  804. auth.login(username)
  805. client.get("/repository/{0}/download".format(resource_id))
  806. with app.app_context():
  807. assert Resource.query.filter_by(id=resource_id).first().get_download_count() == expected_download_count