udata 8.0.2.dev29304__py2.py3-none-any.whl → 9.1.0__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of udata might be problematic. Click here for more details.
- udata/__init__.py +1 -1
- udata/api/__init__.py +2 -0
- udata/api/commands.py +0 -2
- udata/api_fields.py +41 -3
- udata/commands/db.py +88 -48
- udata/core/dataservices/factories.py +33 -0
- udata/core/dataservices/models.py +42 -4
- udata/core/dataservices/rdf.py +106 -0
- udata/core/dataset/csv.py +8 -1
- udata/core/dataset/models.py +1 -2
- udata/core/dataset/rdf.py +37 -128
- udata/core/discussions/models.py +20 -0
- udata/core/organization/csv.py +5 -3
- udata/core/reports/__init__.py +0 -0
- udata/core/reports/api.py +44 -0
- udata/core/reports/constants.py +30 -0
- udata/core/reports/models.py +58 -0
- udata/core/reuse/csv.py +3 -0
- udata/core/site/api.py +33 -2
- udata/core/site/rdf.py +6 -1
- udata/core/spam/models.py +6 -0
- udata/core/topic/models.py +3 -2
- udata/core/topic/parsers.py +3 -2
- udata/core/user/apiv2.py +28 -0
- udata/db/__init__.py +0 -0
- udata/db/tasks.py +6 -0
- udata/features/notifications/__init__.py +0 -1
- udata/forms/fields.py +2 -2
- udata/harvest/api.py +19 -1
- udata/harvest/backends/base.py +118 -10
- udata/harvest/backends/dcat.py +28 -7
- udata/harvest/models.py +6 -0
- udata/harvest/tests/dcat/bnodes.xml +13 -2
- udata/harvest/tests/test_dcat_backend.py +21 -0
- udata/migrations/2024-06-11-fix-reuse-datasets-references.py +35 -0
- udata/models/__init__.py +1 -0
- udata/rdf.py +113 -2
- udata/routing.py +1 -1
- udata/settings.py +3 -1
- udata/static/admin.js +17 -17
- udata/static/admin.js.map +1 -1
- udata/static/chunks/{18.ad41fb75ac4226e1f3ce.js → 18.1922fd0b2b7fad122991.js} +3 -3
- udata/static/chunks/18.1922fd0b2b7fad122991.js.map +1 -0
- udata/static/chunks/{7.11ac4de064ae59691d49.js → 7.e2106342e94ee09393b1.js} +2 -2
- udata/static/chunks/7.e2106342e94ee09393b1.js.map +1 -0
- udata/static/common.js +1 -1
- udata/static/common.js.map +1 -1
- udata/storage/s3.py +3 -3
- udata/tasks.py +1 -0
- udata/tests/api/test_dataservices_api.py +26 -2
- udata/tests/api/test_datasets_api.py +1 -1
- udata/tests/api/test_reports_api.py +87 -0
- udata/tests/apiv2/test_me_api.py +40 -0
- udata/tests/dataset/test_dataset_rdf.py +19 -1
- udata/tests/frontend/test_auth.py +1 -4
- udata/tests/organization/test_csv_adapter.py +0 -1
- udata/tests/plugin.py +2 -0
- udata/tests/site/test_site_api.py +0 -1
- udata/tests/site/test_site_rdf.py +66 -0
- udata/tests/test_discussions.py +24 -34
- udata/tests/test_model.py +3 -2
- udata/tests/test_utils.py +1 -1
- udata/translations/ar/LC_MESSAGES/udata.mo +0 -0
- udata/translations/ar/LC_MESSAGES/udata.po +128 -64
- udata/translations/de/LC_MESSAGES/udata.mo +0 -0
- udata/translations/de/LC_MESSAGES/udata.po +128 -64
- udata/translations/es/LC_MESSAGES/udata.mo +0 -0
- udata/translations/es/LC_MESSAGES/udata.po +128 -64
- udata/translations/fr/LC_MESSAGES/udata.mo +0 -0
- udata/translations/fr/LC_MESSAGES/udata.po +128 -64
- udata/translations/it/LC_MESSAGES/udata.mo +0 -0
- udata/translations/it/LC_MESSAGES/udata.po +128 -64
- udata/translations/pt/LC_MESSAGES/udata.mo +0 -0
- udata/translations/pt/LC_MESSAGES/udata.po +128 -64
- udata/translations/sr/LC_MESSAGES/udata.mo +0 -0
- udata/translations/sr/LC_MESSAGES/udata.po +128 -64
- udata/translations/udata.pot +129 -65
- udata/uris.py +14 -13
- {udata-8.0.2.dev29304.dist-info → udata-9.1.0.dist-info}/METADATA +26 -7
- {udata-8.0.2.dev29304.dist-info → udata-9.1.0.dist-info}/RECORD +84 -72
- udata/static/chunks/18.ad41fb75ac4226e1f3ce.js.map +0 -1
- udata/static/chunks/7.11ac4de064ae59691d49.js.map +0 -1
- {udata-8.0.2.dev29304.dist-info → udata-9.1.0.dist-info}/LICENSE +0 -0
- {udata-8.0.2.dev29304.dist-info → udata-9.1.0.dist-info}/WHEEL +0 -0
- {udata-8.0.2.dev29304.dist-info → udata-9.1.0.dist-info}/entry_points.txt +0 -0
- {udata-8.0.2.dev29304.dist-info → udata-9.1.0.dist-info}/top_level.txt +0 -0
udata/static/common.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
!function(e){function __webpack_require__(a){if(c[a])return c[a].exports;var f=c[a]={exports:{},id:a,loaded:!1};return e[a].call(f.exports,f,f.exports,__webpack_require__),f.loaded=!0,f.exports}var a=window.webpackJsonp;window.webpackJsonp=function(b,r){for(var t,_,n=0,d=[];n<b.length;n++)_=b[n],f[_]&&d.push.apply(d,f[_]),f[_]=0;for(t in r){var i=r[t];switch(typeof i){case"object":e[t]=function(a){var c=a.slice(1),f=a[0];return function(a,b,r){e[f].apply(this,[a,b,r].concat(c))}}(i);break;case"function":e[t]=i;break;default:e[t]=e[i]}}for(a&&a(b,r);d.length;)d.shift().call(null,__webpack_require__);if(r[0])return c[0]=0,__webpack_require__(0)};var c={},f={31:0};__webpack_require__.e=function(e,a){if(0===f[e])return a.call(null,__webpack_require__);if(void 0!==f[e])f[e].push(a);else{f[e]=[a];var c=document.getElementsByTagName("head")[0],b=document.createElement("script");b.type="text/javascript",b.charset="utf-8",b.async=!0,b.src=__webpack_require__.p+"chunks/"+e+"."+{0:"93c3ae13b5b94753ee80",1:"ff8196d42cab0f031d3f",2:"614b3e73b072982fd9b1",3:"1ca609753b5a02de0ca3",4:"95e6a070a0eb2ed08fdd",5:"cc2e7bf65ef32f9c8604",6:"cad898a38692eda28965",7:"
|
|
1
|
+
!function(e){function __webpack_require__(a){if(c[a])return c[a].exports;var f=c[a]={exports:{},id:a,loaded:!1};return e[a].call(f.exports,f,f.exports,__webpack_require__),f.loaded=!0,f.exports}var a=window.webpackJsonp;window.webpackJsonp=function(b,r){for(var t,_,n=0,d=[];n<b.length;n++)_=b[n],f[_]&&d.push.apply(d,f[_]),f[_]=0;for(t in r){var i=r[t];switch(typeof i){case"object":e[t]=function(a){var c=a.slice(1),f=a[0];return function(a,b,r){e[f].apply(this,[a,b,r].concat(c))}}(i);break;case"function":e[t]=i;break;default:e[t]=e[i]}}for(a&&a(b,r);d.length;)d.shift().call(null,__webpack_require__);if(r[0])return c[0]=0,__webpack_require__(0)};var c={},f={31:0};__webpack_require__.e=function(e,a){if(0===f[e])return a.call(null,__webpack_require__);if(void 0!==f[e])f[e].push(a);else{f[e]=[a];var c=document.getElementsByTagName("head")[0],b=document.createElement("script");b.type="text/javascript",b.charset="utf-8",b.async=!0,b.src=__webpack_require__.p+"chunks/"+e+"."+{0:"93c3ae13b5b94753ee80",1:"ff8196d42cab0f031d3f",2:"614b3e73b072982fd9b1",3:"1ca609753b5a02de0ca3",4:"95e6a070a0eb2ed08fdd",5:"cc2e7bf65ef32f9c8604",6:"cad898a38692eda28965",7:"e2106342e94ee09393b1",8:"17d1afb591ad1495bd03",9:"d5b992e9ef51921aeb57",10:"e97ea231893dc435d6b5",11:"ae54612e36c6d46f85db",12:"59f035a9438e2baf5126",13:"d8ccb992a49875966313",14:"e64890872b31c55fcdf7",15:"92b2cef3032ea35da04a",16:"4565605e68bab129a471",17:"15ecbcf8f0b2968689e8",18:"1922fd0b2b7fad122991",19:"f993a75d5bfe2382548d",20:"14a92e5c503f74ff40df",21:"ccbfce6680a2b11a5284",22:"bc79367e5f4c8ad00038",23:"5486b3fc83b194d55191",24:"e905e3f6ba089a34b07c",25:"e20b4daac9fb2bdceee6",26:"c8f33e73b9117b70aef8",27:"6779f92692327013b446",28:"280c392f19bc9e908abf",29:"daadfa33135efe4e5534",30:"b2464d08ccbeb40ec74e",32:"12df4e65a3476781ee9a",33:"70f8e7b1964892a24e67"}[e]+".js",c.appendChild(b)}},__webpack_require__.m=e,__webpack_require__.c=c,__webpack_require__.p="/static/"}(function(e){for(var a in e)if(Object.prototype.hasOwnProperty.call(e,a))switch(typeof e[a]){case"function":break;case"object":e[a]=function(a){var c=a.slice(1),f=e[a[0]];return function(e,a,b){f.apply(this,[e,a,b].concat(c))}}(e[a]);break;default:e[a]=e[e[a]]}return e}([]));
|
|
2
2
|
//# sourceMappingURL=common.js.map
|
udata/static/common.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["webpack:///common.js","webpack:///webpack/bootstrap e110b7df1b5fdbca3a9e"],"names":["modules","__webpack_require__","moduleId","installedModules","exports","module","id","loaded","call","parentJsonpFunction","window","chunkIds","moreModules","chunkId","i","callbacks","length","installedChunks","push","apply","_m","args","slice","templateId","a","b","c","this","concat","shift","31","e","callback","undefined","head","document","getElementsByTagName","script","createElement","type","charset","async","src","p","0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24","25","26","27","28","29","30","32","33","appendChild","m","Object","prototype","hasOwnProperty","fn"],"mappings":"CAAS,SAAUA,GCwDnB,QAAAC,qBAAAC,GAGA,GAAAC,EAAAD,GACA,MAAAC,GAAAD,GAAAE,OAGA,IAAAC,GAAAF,EAAAD,IACAE,WACAE,GAAAJ,EACAK,QAAA,EAUA,OANAP,GAAAE,GAAAM,KAAAH,EAAAD,QAAAC,IAAAD,QAAAH,qBAGAI,EAAAE,QAAA,EAGAF,EAAAD,QA3EA,GAAAK,GAAAC,OAAA,YACAA,QAAA,sBAAAC,EAAAC,GAIA,IADA,GAAAV,GAAAW,EAAAC,EAAA,EAAAC,KACQD,EAAAH,EAAAK,OAAoBF,IAC5BD,EAAAF,EAAAG,GACAG,EAAAJ,IACAE,EAAAG,KAAAC,MAAAJ,EAAAE,EAAAJ,IACAI,EAAAJ,GAAA,CAEA,KAAAX,IAAAU,GAAA,CACA,GAAAQ,GAAAR,EAAAV,EAGA,cAAAkB,IACA,aAEApB,EAAAE,GAAA,SAAAkB,GACA,GAAAC,GAAAD,EAAAE,MAAA,GAAAC,EAAAH,EAAA,EACA,iBAAAI,EAAAC,EAAAC,GACA1B,EAAAuB,GAAAJ,MAAAQ,MAAAH,EAAAC,EAAAC,GAAAE,OAAAP,MAEMD,EACN,MACA,gBAEApB,EAAAE,GAAAkB,CACA,MACA,SAEApB,EAAAE,GAAAF,EAAAoB,IAKA,IADAX,KAAAE,EAAAC,GACAG,EAAAC,QACAD,EAAAc,QAAArB,KAAA,KAAAP,oBACA,IAAAW,EAAA,GAEA,MADAT,GAAA,KACAF,oBAAA,GAKA,IAAAE,MAKAc,GACAa,GAAA,EA6BA7B,qBAAA8B,EAAA,SAAAlB,EAAAmB,GAEA,OAAAf,EAAAJ,GACA,MAAAmB,GAAAxB,KAAA,KAAAP,oBAGA,IAAAgC,SAAAhB,EAAAJ,GACAI,EAAAJ,GAAAK,KAAAc,OACI,CAEJf,EAAAJ,IAAAmB,EACA,IAAAE,GAAAC,SAAAC,qBAAA,WACAC,EAAAF,SAAAG,cAAA,SACAD,GAAAE,KAAA,kBACAF,EAAAG,QAAA,QACAH,EAAAI,OAAA,EAEAJ,EAAAK,IAAAzC,oBAAA0C,EAAA,UAAA9B,EAAA,KAAsE+B,EAAA,uBAAAC,EAAA,uBAAAC,EAAA,uBAAAC,EAAA,uBAAAC,EAAA,uBAAAC,EAAA,uBAAAC,EAAA,uBAAAC,EAAA,uBAAAC,EAAA,uBAAAC,EAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,wBAAk5B/D,GAAA,MACx9BqB,EAAA2C,YAAAxC,KAKApC,oBAAA6E,EAAA9E,EAGAC,oBAAAyB,EAAAvB,EAGAF,oBAAA0C,EAAA,YDIW,SAAS3C,GAEnB,IAAI,GAAIc,KAAKd,GACZ,GAAG+E,OAAOC,UAAUC,eAAezE,KAAKR,EAASc,GAChD,aAAcd,GAAQc,IACtB,IAAK,WAAY,KACjB,KAAK,SAEJd,EAAQc,GAAM,SAASM,GACtB,GAAIC,GAAOD,EAAGE,MAAM,GAAI4D,EAAKlF,EAAQoB,EAAG,GACxC,OAAO,UAAUI,EAAEC,EAAEC,GACpBwD,EAAG/D,MAAMQ,MAAOH,EAAEC,EAAEC,GAAGE,OAAOP,MAE9BrB,EAAQc,GACV,MACD,SAECd,EAAQc,GAAKd,EAAQA,EAAQc,IAKhC,MAAOd","file":"common.js","sourcesContent":["/******/ (function(modules) { // webpackBootstrap\n/******/ \t// install a JSONP callback for chunk loading\n/******/ \tvar parentJsonpFunction = window[\"webpackJsonp\"];\n/******/ \twindow[\"webpackJsonp\"] = function webpackJsonpCallback(chunkIds, moreModules) {\n/******/ \t\t// add \"moreModules\" to the modules object,\n/******/ \t\t// then flag all \"chunkIds\" as loaded and fire callback\n/******/ \t\tvar moduleId, chunkId, i = 0, callbacks = [];\n/******/ \t\tfor(;i < chunkIds.length; i++) {\n/******/ \t\t\tchunkId = chunkIds[i];\n/******/ \t\t\tif(installedChunks[chunkId])\n/******/ \t\t\t\tcallbacks.push.apply(callbacks, installedChunks[chunkId]);\n/******/ \t\t\tinstalledChunks[chunkId] = 0;\n/******/ \t\t}\n/******/ \t\tfor(moduleId in moreModules) {\n/******/ \t\t\tvar _m = moreModules[moduleId];\n/******/\n/******/ \t\t\t// Check if module is deduplicated\n/******/ \t\t\tswitch(typeof _m) {\n/******/ \t\t\tcase \"object\":\n/******/ \t\t\t\t// Module can be created from a template\n/******/ \t\t\t\tmodules[moduleId] = (function(_m) {\n/******/ \t\t\t\t\tvar args = _m.slice(1), templateId = _m[0];\n/******/ \t\t\t\t\treturn function (a,b,c) {\n/******/ \t\t\t\t\t\tmodules[templateId].apply(this, [a,b,c].concat(args));\n/******/ \t\t\t\t\t};\n/******/ \t\t\t\t}(_m));\n/******/ \t\t\t\tbreak;\n/******/ \t\t\tcase \"function\":\n/******/ \t\t\t\t// Normal module\n/******/ \t\t\t\tmodules[moduleId] = _m;\n/******/ \t\t\t\tbreak;\n/******/ \t\t\tdefault:\n/******/ \t\t\t\t// Module is a copy of another module\n/******/ \t\t\t\tmodules[moduleId] = modules[_m];\n/******/ \t\t\t\tbreak;\n/******/ \t\t\t}\n/******/ \t\t}\n/******/ \t\tif(parentJsonpFunction) parentJsonpFunction(chunkIds, moreModules);\n/******/ \t\twhile(callbacks.length)\n/******/ \t\t\tcallbacks.shift().call(null, __webpack_require__);\n/******/ \t\tif(moreModules[0]) {\n/******/ \t\t\tinstalledModules[0] = 0;\n/******/ \t\t\treturn __webpack_require__(0);\n/******/ \t\t}\n/******/ \t};\n/******/\n/******/ \t// The module cache\n/******/ \tvar installedModules = {};\n/******/\n/******/ \t// object to store loaded and loading chunks\n/******/ \t// \"0\" means \"already loaded\"\n/******/ \t// Array means \"loading\", array contains callbacks\n/******/ \tvar installedChunks = {\n/******/ \t\t31:0\n/******/ \t};\n/******/\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(installedModules[moduleId])\n/******/ \t\t\treturn installedModules[moduleId].exports;\n/******/\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = installedModules[moduleId] = {\n/******/ \t\t\texports: {},\n/******/ \t\t\tid: moduleId,\n/******/ \t\t\tloaded: false\n/******/ \t\t};\n/******/\n/******/ \t\t// Execute the module function\n/******/ \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n/******/\n/******/ \t\t// Flag the module as loaded\n/******/ \t\tmodule.loaded = true;\n/******/\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/\n/******/ \t// This file contains only the entry chunk.\n/******/ \t// The chunk loading function for additional chunks\n/******/ \t__webpack_require__.e = function requireEnsure(chunkId, callback) {\n/******/ \t\t// \"0\" is the signal for \"already loaded\"\n/******/ \t\tif(installedChunks[chunkId] === 0)\n/******/ \t\t\treturn callback.call(null, __webpack_require__);\n/******/\n/******/ \t\t// an array means \"currently loading\".\n/******/ \t\tif(installedChunks[chunkId] !== undefined) {\n/******/ \t\t\tinstalledChunks[chunkId].push(callback);\n/******/ \t\t} else {\n/******/ \t\t\t// start chunk loading\n/******/ \t\t\tinstalledChunks[chunkId] = [callback];\n/******/ \t\t\tvar head = document.getElementsByTagName('head')[0];\n/******/ \t\t\tvar script = document.createElement('script');\n/******/ \t\t\tscript.type = 'text/javascript';\n/******/ \t\t\tscript.charset = 'utf-8';\n/******/ \t\t\tscript.async = true;\n/******/\n/******/ \t\t\tscript.src = __webpack_require__.p + \"chunks/\" + chunkId + \".\" + {\"0\":\"93c3ae13b5b94753ee80\",\"1\":\"ff8196d42cab0f031d3f\",\"2\":\"614b3e73b072982fd9b1\",\"3\":\"1ca609753b5a02de0ca3\",\"4\":\"95e6a070a0eb2ed08fdd\",\"5\":\"cc2e7bf65ef32f9c8604\",\"6\":\"cad898a38692eda28965\",\"7\":\"11ac4de064ae59691d49\",\"8\":\"17d1afb591ad1495bd03\",\"9\":\"d5b992e9ef51921aeb57\",\"10\":\"e97ea231893dc435d6b5\",\"11\":\"ae54612e36c6d46f85db\",\"12\":\"59f035a9438e2baf5126\",\"13\":\"d8ccb992a49875966313\",\"14\":\"e64890872b31c55fcdf7\",\"15\":\"92b2cef3032ea35da04a\",\"16\":\"4565605e68bab129a471\",\"17\":\"15ecbcf8f0b2968689e8\",\"18\":\"ad41fb75ac4226e1f3ce\",\"19\":\"f993a75d5bfe2382548d\",\"20\":\"14a92e5c503f74ff40df\",\"21\":\"ccbfce6680a2b11a5284\",\"22\":\"bc79367e5f4c8ad00038\",\"23\":\"5486b3fc83b194d55191\",\"24\":\"e905e3f6ba089a34b07c\",\"25\":\"e20b4daac9fb2bdceee6\",\"26\":\"c8f33e73b9117b70aef8\",\"27\":\"6779f92692327013b446\",\"28\":\"280c392f19bc9e908abf\",\"29\":\"daadfa33135efe4e5534\",\"30\":\"b2464d08ccbeb40ec74e\",\"32\":\"fa73a4eb8875b89f452f\",\"33\":\"70f8e7b1964892a24e67\"}[chunkId] + \".js\";\n/******/ \t\t\thead.appendChild(script);\n/******/ \t\t}\n/******/ \t};\n/******/\n/******/ \t// expose the modules object (__webpack_modules__)\n/******/ \t__webpack_require__.m = modules;\n/******/\n/******/ \t// expose the module cache\n/******/ \t__webpack_require__.c = installedModules;\n/******/\n/******/ \t// __webpack_public_path__\n/******/ \t__webpack_require__.p = \"/static/\";\n/******/ })\n/************************************************************************/\n/******/ ((function(modules) {\n\t// Check all modules for deduplicated modules\n\tfor(var i in modules) {\n\t\tif(Object.prototype.hasOwnProperty.call(modules, i)) {\n\t\t\tswitch(typeof modules[i]) {\n\t\t\tcase \"function\": break;\n\t\t\tcase \"object\":\n\t\t\t\t// Module can be created from a template\n\t\t\t\tmodules[i] = (function(_m) {\n\t\t\t\t\tvar args = _m.slice(1), fn = modules[_m[0]];\n\t\t\t\t\treturn function (a,b,c) {\n\t\t\t\t\t\tfn.apply(this, [a,b,c].concat(args));\n\t\t\t\t\t};\n\t\t\t\t}(modules[i]));\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\t// Module is a copy of another module\n\t\t\t\tmodules[i] = modules[modules[i]];\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\treturn modules;\n}([])));\n\n\n/** WEBPACK FOOTER **\n ** common.js\n **/"," \t// install a JSONP callback for chunk loading\n \tvar parentJsonpFunction = window[\"webpackJsonp\"];\n \twindow[\"webpackJsonp\"] = function webpackJsonpCallback(chunkIds, moreModules) {\n \t\t// add \"moreModules\" to the modules object,\n \t\t// then flag all \"chunkIds\" as loaded and fire callback\n \t\tvar moduleId, chunkId, i = 0, callbacks = [];\n \t\tfor(;i < chunkIds.length; i++) {\n \t\t\tchunkId = chunkIds[i];\n \t\t\tif(installedChunks[chunkId])\n \t\t\t\tcallbacks.push.apply(callbacks, installedChunks[chunkId]);\n \t\t\tinstalledChunks[chunkId] = 0;\n \t\t}\n \t\tfor(moduleId in moreModules) {\n \t\t\tvar _m = moreModules[moduleId];\n\n \t\t\t// Check if module is deduplicated\n \t\t\tswitch(typeof _m) {\n \t\t\tcase \"object\":\n \t\t\t\t// Module can be created from a template\n \t\t\t\tmodules[moduleId] = (function(_m) {\n \t\t\t\t\tvar args = _m.slice(1), templateId = _m[0];\n \t\t\t\t\treturn function (a,b,c) {\n \t\t\t\t\t\tmodules[templateId].apply(this, [a,b,c].concat(args));\n \t\t\t\t\t};\n \t\t\t\t}(_m));\n \t\t\t\tbreak;\n \t\t\tcase \"function\":\n \t\t\t\t// Normal module\n \t\t\t\tmodules[moduleId] = _m;\n \t\t\t\tbreak;\n \t\t\tdefault:\n \t\t\t\t// Module is a copy of another module\n \t\t\t\tmodules[moduleId] = modules[_m];\n \t\t\t\tbreak;\n \t\t\t}\n \t\t}\n \t\tif(parentJsonpFunction) parentJsonpFunction(chunkIds, moreModules);\n \t\twhile(callbacks.length)\n \t\t\tcallbacks.shift().call(null, __webpack_require__);\n \t\tif(moreModules[0]) {\n \t\t\tinstalledModules[0] = 0;\n \t\t\treturn __webpack_require__(0);\n \t\t}\n \t};\n\n \t// The module cache\n \tvar installedModules = {};\n\n \t// object to store loaded and loading chunks\n \t// \"0\" means \"already loaded\"\n \t// Array means \"loading\", array contains callbacks\n \tvar installedChunks = {\n \t\t31:0\n \t};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId])\n \t\t\treturn installedModules[moduleId].exports;\n\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\texports: {},\n \t\t\tid: moduleId,\n \t\t\tloaded: false\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.loaded = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n \t// This file contains only the entry chunk.\n \t// The chunk loading function for additional chunks\n \t__webpack_require__.e = function requireEnsure(chunkId, callback) {\n \t\t// \"0\" is the signal for \"already loaded\"\n \t\tif(installedChunks[chunkId] === 0)\n \t\t\treturn callback.call(null, __webpack_require__);\n\n \t\t// an array means \"currently loading\".\n \t\tif(installedChunks[chunkId] !== undefined) {\n \t\t\tinstalledChunks[chunkId].push(callback);\n \t\t} else {\n \t\t\t// start chunk loading\n \t\t\tinstalledChunks[chunkId] = [callback];\n \t\t\tvar head = document.getElementsByTagName('head')[0];\n \t\t\tvar script = document.createElement('script');\n \t\t\tscript.type = 'text/javascript';\n \t\t\tscript.charset = 'utf-8';\n \t\t\tscript.async = true;\n\n \t\t\tscript.src = __webpack_require__.p + \"chunks/\" + chunkId + \".\" + {\"0\":\"93c3ae13b5b94753ee80\",\"1\":\"ff8196d42cab0f031d3f\",\"2\":\"614b3e73b072982fd9b1\",\"3\":\"1ca609753b5a02de0ca3\",\"4\":\"95e6a070a0eb2ed08fdd\",\"5\":\"cc2e7bf65ef32f9c8604\",\"6\":\"cad898a38692eda28965\",\"7\":\"11ac4de064ae59691d49\",\"8\":\"17d1afb591ad1495bd03\",\"9\":\"d5b992e9ef51921aeb57\",\"10\":\"e97ea231893dc435d6b5\",\"11\":\"ae54612e36c6d46f85db\",\"12\":\"59f035a9438e2baf5126\",\"13\":\"d8ccb992a49875966313\",\"14\":\"e64890872b31c55fcdf7\",\"15\":\"92b2cef3032ea35da04a\",\"16\":\"4565605e68bab129a471\",\"17\":\"15ecbcf8f0b2968689e8\",\"18\":\"ad41fb75ac4226e1f3ce\",\"19\":\"f993a75d5bfe2382548d\",\"20\":\"14a92e5c503f74ff40df\",\"21\":\"ccbfce6680a2b11a5284\",\"22\":\"bc79367e5f4c8ad00038\",\"23\":\"5486b3fc83b194d55191\",\"24\":\"e905e3f6ba089a34b07c\",\"25\":\"e20b4daac9fb2bdceee6\",\"26\":\"c8f33e73b9117b70aef8\",\"27\":\"6779f92692327013b446\",\"28\":\"280c392f19bc9e908abf\",\"29\":\"daadfa33135efe4e5534\",\"30\":\"b2464d08ccbeb40ec74e\",\"32\":\"fa73a4eb8875b89f452f\",\"33\":\"70f8e7b1964892a24e67\"}[chunkId] + \".js\";\n \t\t\thead.appendChild(script);\n \t\t}\n \t};\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"/static/\";\n\n\n\n/** WEBPACK FOOTER **\n ** webpack/bootstrap e110b7df1b5fdbca3a9e\n **/"],"sourceRoot":""}
|
|
1
|
+
{"version":3,"sources":["webpack:///common.js","webpack:///webpack/bootstrap e7dc5561085d000a9a79"],"names":["modules","__webpack_require__","moduleId","installedModules","exports","module","id","loaded","call","parentJsonpFunction","window","chunkIds","moreModules","chunkId","i","callbacks","length","installedChunks","push","apply","_m","args","slice","templateId","a","b","c","this","concat","shift","31","e","callback","undefined","head","document","getElementsByTagName","script","createElement","type","charset","async","src","p","0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24","25","26","27","28","29","30","32","33","appendChild","m","Object","prototype","hasOwnProperty","fn"],"mappings":"CAAS,SAAUA,GCwDnB,QAAAC,qBAAAC,GAGA,GAAAC,EAAAD,GACA,MAAAC,GAAAD,GAAAE,OAGA,IAAAC,GAAAF,EAAAD,IACAE,WACAE,GAAAJ,EACAK,QAAA,EAUA,OANAP,GAAAE,GAAAM,KAAAH,EAAAD,QAAAC,IAAAD,QAAAH,qBAGAI,EAAAE,QAAA,EAGAF,EAAAD,QA3EA,GAAAK,GAAAC,OAAA,YACAA,QAAA,sBAAAC,EAAAC,GAIA,IADA,GAAAV,GAAAW,EAAAC,EAAA,EAAAC,KACQD,EAAAH,EAAAK,OAAoBF,IAC5BD,EAAAF,EAAAG,GACAG,EAAAJ,IACAE,EAAAG,KAAAC,MAAAJ,EAAAE,EAAAJ,IACAI,EAAAJ,GAAA,CAEA,KAAAX,IAAAU,GAAA,CACA,GAAAQ,GAAAR,EAAAV,EAGA,cAAAkB,IACA,aAEApB,EAAAE,GAAA,SAAAkB,GACA,GAAAC,GAAAD,EAAAE,MAAA,GAAAC,EAAAH,EAAA,EACA,iBAAAI,EAAAC,EAAAC,GACA1B,EAAAuB,GAAAJ,MAAAQ,MAAAH,EAAAC,EAAAC,GAAAE,OAAAP,MAEMD,EACN,MACA,gBAEApB,EAAAE,GAAAkB,CACA,MACA,SAEApB,EAAAE,GAAAF,EAAAoB,IAKA,IADAX,KAAAE,EAAAC,GACAG,EAAAC,QACAD,EAAAc,QAAArB,KAAA,KAAAP,oBACA,IAAAW,EAAA,GAEA,MADAT,GAAA,KACAF,oBAAA,GAKA,IAAAE,MAKAc,GACAa,GAAA,EA6BA7B,qBAAA8B,EAAA,SAAAlB,EAAAmB,GAEA,OAAAf,EAAAJ,GACA,MAAAmB,GAAAxB,KAAA,KAAAP,oBAGA,IAAAgC,SAAAhB,EAAAJ,GACAI,EAAAJ,GAAAK,KAAAc,OACI,CAEJf,EAAAJ,IAAAmB,EACA,IAAAE,GAAAC,SAAAC,qBAAA,WACAC,EAAAF,SAAAG,cAAA,SACAD,GAAAE,KAAA,kBACAF,EAAAG,QAAA,QACAH,EAAAI,OAAA,EAEAJ,EAAAK,IAAAzC,oBAAA0C,EAAA,UAAA9B,EAAA,KAAsE+B,EAAA,uBAAAC,EAAA,uBAAAC,EAAA,uBAAAC,EAAA,uBAAAC,EAAA,uBAAAC,EAAA,uBAAAC,EAAA,uBAAAC,EAAA,uBAAAC,EAAA,uBAAAC,EAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,uBAAAC,GAAA,wBAAk5B/D,GAAA,MACx9BqB,EAAA2C,YAAAxC,KAKApC,oBAAA6E,EAAA9E,EAGAC,oBAAAyB,EAAAvB,EAGAF,oBAAA0C,EAAA,YDIW,SAAS3C,GAEnB,IAAI,GAAIc,KAAKd,GACZ,GAAG+E,OAAOC,UAAUC,eAAezE,KAAKR,EAASc,GAChD,aAAcd,GAAQc,IACtB,IAAK,WAAY,KACjB,KAAK,SAEJd,EAAQc,GAAM,SAASM,GACtB,GAAIC,GAAOD,EAAGE,MAAM,GAAI4D,EAAKlF,EAAQoB,EAAG,GACxC,OAAO,UAAUI,EAAEC,EAAEC,GACpBwD,EAAG/D,MAAMQ,MAAOH,EAAEC,EAAEC,GAAGE,OAAOP,MAE9BrB,EAAQc,GACV,MACD,SAECd,EAAQc,GAAKd,EAAQA,EAAQc,IAKhC,MAAOd","file":"common.js","sourcesContent":["/******/ (function(modules) { // webpackBootstrap\n/******/ \t// install a JSONP callback for chunk loading\n/******/ \tvar parentJsonpFunction = window[\"webpackJsonp\"];\n/******/ \twindow[\"webpackJsonp\"] = function webpackJsonpCallback(chunkIds, moreModules) {\n/******/ \t\t// add \"moreModules\" to the modules object,\n/******/ \t\t// then flag all \"chunkIds\" as loaded and fire callback\n/******/ \t\tvar moduleId, chunkId, i = 0, callbacks = [];\n/******/ \t\tfor(;i < chunkIds.length; i++) {\n/******/ \t\t\tchunkId = chunkIds[i];\n/******/ \t\t\tif(installedChunks[chunkId])\n/******/ \t\t\t\tcallbacks.push.apply(callbacks, installedChunks[chunkId]);\n/******/ \t\t\tinstalledChunks[chunkId] = 0;\n/******/ \t\t}\n/******/ \t\tfor(moduleId in moreModules) {\n/******/ \t\t\tvar _m = moreModules[moduleId];\n/******/\n/******/ \t\t\t// Check if module is deduplicated\n/******/ \t\t\tswitch(typeof _m) {\n/******/ \t\t\tcase \"object\":\n/******/ \t\t\t\t// Module can be created from a template\n/******/ \t\t\t\tmodules[moduleId] = (function(_m) {\n/******/ \t\t\t\t\tvar args = _m.slice(1), templateId = _m[0];\n/******/ \t\t\t\t\treturn function (a,b,c) {\n/******/ \t\t\t\t\t\tmodules[templateId].apply(this, [a,b,c].concat(args));\n/******/ \t\t\t\t\t};\n/******/ \t\t\t\t}(_m));\n/******/ \t\t\t\tbreak;\n/******/ \t\t\tcase \"function\":\n/******/ \t\t\t\t// Normal module\n/******/ \t\t\t\tmodules[moduleId] = _m;\n/******/ \t\t\t\tbreak;\n/******/ \t\t\tdefault:\n/******/ \t\t\t\t// Module is a copy of another module\n/******/ \t\t\t\tmodules[moduleId] = modules[_m];\n/******/ \t\t\t\tbreak;\n/******/ \t\t\t}\n/******/ \t\t}\n/******/ \t\tif(parentJsonpFunction) parentJsonpFunction(chunkIds, moreModules);\n/******/ \t\twhile(callbacks.length)\n/******/ \t\t\tcallbacks.shift().call(null, __webpack_require__);\n/******/ \t\tif(moreModules[0]) {\n/******/ \t\t\tinstalledModules[0] = 0;\n/******/ \t\t\treturn __webpack_require__(0);\n/******/ \t\t}\n/******/ \t};\n/******/\n/******/ \t// The module cache\n/******/ \tvar installedModules = {};\n/******/\n/******/ \t// object to store loaded and loading chunks\n/******/ \t// \"0\" means \"already loaded\"\n/******/ \t// Array means \"loading\", array contains callbacks\n/******/ \tvar installedChunks = {\n/******/ \t\t31:0\n/******/ \t};\n/******/\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(installedModules[moduleId])\n/******/ \t\t\treturn installedModules[moduleId].exports;\n/******/\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = installedModules[moduleId] = {\n/******/ \t\t\texports: {},\n/******/ \t\t\tid: moduleId,\n/******/ \t\t\tloaded: false\n/******/ \t\t};\n/******/\n/******/ \t\t// Execute the module function\n/******/ \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n/******/\n/******/ \t\t// Flag the module as loaded\n/******/ \t\tmodule.loaded = true;\n/******/\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/\n/******/ \t// This file contains only the entry chunk.\n/******/ \t// The chunk loading function for additional chunks\n/******/ \t__webpack_require__.e = function requireEnsure(chunkId, callback) {\n/******/ \t\t// \"0\" is the signal for \"already loaded\"\n/******/ \t\tif(installedChunks[chunkId] === 0)\n/******/ \t\t\treturn callback.call(null, __webpack_require__);\n/******/\n/******/ \t\t// an array means \"currently loading\".\n/******/ \t\tif(installedChunks[chunkId] !== undefined) {\n/******/ \t\t\tinstalledChunks[chunkId].push(callback);\n/******/ \t\t} else {\n/******/ \t\t\t// start chunk loading\n/******/ \t\t\tinstalledChunks[chunkId] = [callback];\n/******/ \t\t\tvar head = document.getElementsByTagName('head')[0];\n/******/ \t\t\tvar script = document.createElement('script');\n/******/ \t\t\tscript.type = 'text/javascript';\n/******/ \t\t\tscript.charset = 'utf-8';\n/******/ \t\t\tscript.async = true;\n/******/\n/******/ \t\t\tscript.src = __webpack_require__.p + \"chunks/\" + chunkId + \".\" + {\"0\":\"93c3ae13b5b94753ee80\",\"1\":\"ff8196d42cab0f031d3f\",\"2\":\"614b3e73b072982fd9b1\",\"3\":\"1ca609753b5a02de0ca3\",\"4\":\"95e6a070a0eb2ed08fdd\",\"5\":\"cc2e7bf65ef32f9c8604\",\"6\":\"cad898a38692eda28965\",\"7\":\"e2106342e94ee09393b1\",\"8\":\"17d1afb591ad1495bd03\",\"9\":\"d5b992e9ef51921aeb57\",\"10\":\"e97ea231893dc435d6b5\",\"11\":\"ae54612e36c6d46f85db\",\"12\":\"59f035a9438e2baf5126\",\"13\":\"d8ccb992a49875966313\",\"14\":\"e64890872b31c55fcdf7\",\"15\":\"92b2cef3032ea35da04a\",\"16\":\"4565605e68bab129a471\",\"17\":\"15ecbcf8f0b2968689e8\",\"18\":\"1922fd0b2b7fad122991\",\"19\":\"f993a75d5bfe2382548d\",\"20\":\"14a92e5c503f74ff40df\",\"21\":\"ccbfce6680a2b11a5284\",\"22\":\"bc79367e5f4c8ad00038\",\"23\":\"5486b3fc83b194d55191\",\"24\":\"e905e3f6ba089a34b07c\",\"25\":\"e20b4daac9fb2bdceee6\",\"26\":\"c8f33e73b9117b70aef8\",\"27\":\"6779f92692327013b446\",\"28\":\"280c392f19bc9e908abf\",\"29\":\"daadfa33135efe4e5534\",\"30\":\"b2464d08ccbeb40ec74e\",\"32\":\"12df4e65a3476781ee9a\",\"33\":\"70f8e7b1964892a24e67\"}[chunkId] + \".js\";\n/******/ \t\t\thead.appendChild(script);\n/******/ \t\t}\n/******/ \t};\n/******/\n/******/ \t// expose the modules object (__webpack_modules__)\n/******/ \t__webpack_require__.m = modules;\n/******/\n/******/ \t// expose the module cache\n/******/ \t__webpack_require__.c = installedModules;\n/******/\n/******/ \t// __webpack_public_path__\n/******/ \t__webpack_require__.p = \"/static/\";\n/******/ })\n/************************************************************************/\n/******/ ((function(modules) {\n\t// Check all modules for deduplicated modules\n\tfor(var i in modules) {\n\t\tif(Object.prototype.hasOwnProperty.call(modules, i)) {\n\t\t\tswitch(typeof modules[i]) {\n\t\t\tcase \"function\": break;\n\t\t\tcase \"object\":\n\t\t\t\t// Module can be created from a template\n\t\t\t\tmodules[i] = (function(_m) {\n\t\t\t\t\tvar args = _m.slice(1), fn = modules[_m[0]];\n\t\t\t\t\treturn function (a,b,c) {\n\t\t\t\t\t\tfn.apply(this, [a,b,c].concat(args));\n\t\t\t\t\t};\n\t\t\t\t}(modules[i]));\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\t// Module is a copy of another module\n\t\t\t\tmodules[i] = modules[modules[i]];\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\treturn modules;\n}([])));\n\n\n/** WEBPACK FOOTER **\n ** common.js\n **/"," \t// install a JSONP callback for chunk loading\n \tvar parentJsonpFunction = window[\"webpackJsonp\"];\n \twindow[\"webpackJsonp\"] = function webpackJsonpCallback(chunkIds, moreModules) {\n \t\t// add \"moreModules\" to the modules object,\n \t\t// then flag all \"chunkIds\" as loaded and fire callback\n \t\tvar moduleId, chunkId, i = 0, callbacks = [];\n \t\tfor(;i < chunkIds.length; i++) {\n \t\t\tchunkId = chunkIds[i];\n \t\t\tif(installedChunks[chunkId])\n \t\t\t\tcallbacks.push.apply(callbacks, installedChunks[chunkId]);\n \t\t\tinstalledChunks[chunkId] = 0;\n \t\t}\n \t\tfor(moduleId in moreModules) {\n \t\t\tvar _m = moreModules[moduleId];\n\n \t\t\t// Check if module is deduplicated\n \t\t\tswitch(typeof _m) {\n \t\t\tcase \"object\":\n \t\t\t\t// Module can be created from a template\n \t\t\t\tmodules[moduleId] = (function(_m) {\n \t\t\t\t\tvar args = _m.slice(1), templateId = _m[0];\n \t\t\t\t\treturn function (a,b,c) {\n \t\t\t\t\t\tmodules[templateId].apply(this, [a,b,c].concat(args));\n \t\t\t\t\t};\n \t\t\t\t}(_m));\n \t\t\t\tbreak;\n \t\t\tcase \"function\":\n \t\t\t\t// Normal module\n \t\t\t\tmodules[moduleId] = _m;\n \t\t\t\tbreak;\n \t\t\tdefault:\n \t\t\t\t// Module is a copy of another module\n \t\t\t\tmodules[moduleId] = modules[_m];\n \t\t\t\tbreak;\n \t\t\t}\n \t\t}\n \t\tif(parentJsonpFunction) parentJsonpFunction(chunkIds, moreModules);\n \t\twhile(callbacks.length)\n \t\t\tcallbacks.shift().call(null, __webpack_require__);\n \t\tif(moreModules[0]) {\n \t\t\tinstalledModules[0] = 0;\n \t\t\treturn __webpack_require__(0);\n \t\t}\n \t};\n\n \t// The module cache\n \tvar installedModules = {};\n\n \t// object to store loaded and loading chunks\n \t// \"0\" means \"already loaded\"\n \t// Array means \"loading\", array contains callbacks\n \tvar installedChunks = {\n \t\t31:0\n \t};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId])\n \t\t\treturn installedModules[moduleId].exports;\n\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\texports: {},\n \t\t\tid: moduleId,\n \t\t\tloaded: false\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.loaded = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n \t// This file contains only the entry chunk.\n \t// The chunk loading function for additional chunks\n \t__webpack_require__.e = function requireEnsure(chunkId, callback) {\n \t\t// \"0\" is the signal for \"already loaded\"\n \t\tif(installedChunks[chunkId] === 0)\n \t\t\treturn callback.call(null, __webpack_require__);\n\n \t\t// an array means \"currently loading\".\n \t\tif(installedChunks[chunkId] !== undefined) {\n \t\t\tinstalledChunks[chunkId].push(callback);\n \t\t} else {\n \t\t\t// start chunk loading\n \t\t\tinstalledChunks[chunkId] = [callback];\n \t\t\tvar head = document.getElementsByTagName('head')[0];\n \t\t\tvar script = document.createElement('script');\n \t\t\tscript.type = 'text/javascript';\n \t\t\tscript.charset = 'utf-8';\n \t\t\tscript.async = true;\n\n \t\t\tscript.src = __webpack_require__.p + \"chunks/\" + chunkId + \".\" + {\"0\":\"93c3ae13b5b94753ee80\",\"1\":\"ff8196d42cab0f031d3f\",\"2\":\"614b3e73b072982fd9b1\",\"3\":\"1ca609753b5a02de0ca3\",\"4\":\"95e6a070a0eb2ed08fdd\",\"5\":\"cc2e7bf65ef32f9c8604\",\"6\":\"cad898a38692eda28965\",\"7\":\"e2106342e94ee09393b1\",\"8\":\"17d1afb591ad1495bd03\",\"9\":\"d5b992e9ef51921aeb57\",\"10\":\"e97ea231893dc435d6b5\",\"11\":\"ae54612e36c6d46f85db\",\"12\":\"59f035a9438e2baf5126\",\"13\":\"d8ccb992a49875966313\",\"14\":\"e64890872b31c55fcdf7\",\"15\":\"92b2cef3032ea35da04a\",\"16\":\"4565605e68bab129a471\",\"17\":\"15ecbcf8f0b2968689e8\",\"18\":\"1922fd0b2b7fad122991\",\"19\":\"f993a75d5bfe2382548d\",\"20\":\"14a92e5c503f74ff40df\",\"21\":\"ccbfce6680a2b11a5284\",\"22\":\"bc79367e5f4c8ad00038\",\"23\":\"5486b3fc83b194d55191\",\"24\":\"e905e3f6ba089a34b07c\",\"25\":\"e20b4daac9fb2bdceee6\",\"26\":\"c8f33e73b9117b70aef8\",\"27\":\"6779f92692327013b446\",\"28\":\"280c392f19bc9e908abf\",\"29\":\"daadfa33135efe4e5534\",\"30\":\"b2464d08ccbeb40ec74e\",\"32\":\"12df4e65a3476781ee9a\",\"33\":\"70f8e7b1964892a24e67\"}[chunkId] + \".js\";\n \t\t\thead.appendChild(script);\n \t\t}\n \t};\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"/static/\";\n\n\n\n/** WEBPACK FOOTER **\n ** webpack/bootstrap e7dc5561085d000a9a79\n **/"],"sourceRoot":""}
|
udata/storage/s3.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import Any
|
|
1
|
+
from typing import Any
|
|
2
2
|
import boto3
|
|
3
3
|
from flask import current_app
|
|
4
4
|
import json
|
|
@@ -33,14 +33,14 @@ def store_bytes(bucket: str, filename: str, bytes: bytes):
|
|
|
33
33
|
def store_as_json(bucket: str, filename: str, value):
|
|
34
34
|
return store_bytes(bucket, filename, bytes(json.dumps(value).encode('UTF-8')))
|
|
35
35
|
|
|
36
|
-
def get_bytes(bucket: str, filename: str) ->
|
|
36
|
+
def get_bytes(bucket: str, filename: str) -> bytes | None:
|
|
37
37
|
client = get_client()
|
|
38
38
|
try:
|
|
39
39
|
return client.get_object(Bucket=bucket, Key=filename)['Body'].read()
|
|
40
40
|
except client.exceptions.NoSuchKey:
|
|
41
41
|
return None
|
|
42
42
|
|
|
43
|
-
def get_from_json(bucket: str, filename: str) ->
|
|
43
|
+
def get_from_json(bucket: str, filename: str) -> Any | None:
|
|
44
44
|
bytes = get_bytes(bucket, filename)
|
|
45
45
|
if bytes is None:
|
|
46
46
|
return None
|
udata/tasks.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
from pprint import pprint
|
|
2
1
|
from flask import url_for
|
|
3
2
|
|
|
4
3
|
from udata.core.dataservices.models import Dataservice
|
|
@@ -85,23 +84,30 @@ class DataserviceAPITest(APITestCase):
|
|
|
85
84
|
|
|
86
85
|
|
|
87
86
|
def test_dataservice_api_index(self):
|
|
87
|
+
dataset_a = DatasetFactory()
|
|
88
|
+
dataset_b = DatasetFactory()
|
|
89
|
+
|
|
88
90
|
self.login()
|
|
89
91
|
self.post(url_for('api.dataservices'), {
|
|
90
92
|
'title': 'B',
|
|
91
93
|
'base_api_url': 'https://example.org/B',
|
|
94
|
+
'datasets': [dataset_b.id],
|
|
92
95
|
})
|
|
93
96
|
self.post(url_for('api.dataservices'), {
|
|
94
97
|
'title': 'C',
|
|
95
98
|
'base_api_url': 'https://example.org/C',
|
|
99
|
+
'datasets': [dataset_a.id, dataset_b.id],
|
|
96
100
|
})
|
|
97
101
|
self.post(url_for('api.dataservices'), {
|
|
98
102
|
'title': 'A',
|
|
99
103
|
'base_api_url': 'https://example.org/A',
|
|
104
|
+
'datasets': [dataset_a.id],
|
|
100
105
|
})
|
|
101
|
-
|
|
106
|
+
self.post(url_for('api.dataservices'), {
|
|
102
107
|
'title': 'X',
|
|
103
108
|
'base_api_url': 'https://example.org/X',
|
|
104
109
|
'private': True,
|
|
110
|
+
'datasets': [dataset_a.id],
|
|
105
111
|
})
|
|
106
112
|
|
|
107
113
|
self.assertEqual(Dataservice.objects.count(), 4)
|
|
@@ -115,8 +121,12 @@ class DataserviceAPITest(APITestCase):
|
|
|
115
121
|
self.assertEqual(response.json['total'], 3)
|
|
116
122
|
self.assertEqual(len(response.json['data']), 3)
|
|
117
123
|
self.assertEqual(response.json['data'][0]['title'], 'B')
|
|
124
|
+
self.assertEqual(response.json['data'][0]['datasets'][0]['id'], str(dataset_b.id))
|
|
118
125
|
self.assertEqual(response.json['data'][1]['title'], 'C')
|
|
126
|
+
self.assertEqual(response.json['data'][1]['datasets'][0]['id'], str(dataset_a.id))
|
|
127
|
+
self.assertEqual(response.json['data'][1]['datasets'][1]['id'], str(dataset_b.id))
|
|
119
128
|
self.assertEqual(response.json['data'][2]['title'], 'A')
|
|
129
|
+
self.assertEqual(response.json['data'][2]['datasets'][0]['id'], str(dataset_a.id))
|
|
120
130
|
|
|
121
131
|
response = self.get(url_for('api.dataservices', sort='title'))
|
|
122
132
|
self.assert200(response)
|
|
@@ -153,6 +163,20 @@ class DataserviceAPITest(APITestCase):
|
|
|
153
163
|
self.assertEqual(len(response.json['data']), 1)
|
|
154
164
|
self.assertEqual(response.json['data'][0]['title'], 'B')
|
|
155
165
|
|
|
166
|
+
response = self.get(url_for('api.dataservices', sort='title', dataset=str(dataset_a.id)))
|
|
167
|
+
self.assert200(response)
|
|
168
|
+
|
|
169
|
+
self.assertEqual(response.json['total'], 2)
|
|
170
|
+
self.assertEqual(response.json['data'][0]['title'], 'A')
|
|
171
|
+
self.assertEqual(response.json['data'][0]['datasets'][0]['id'], str(dataset_a.id))
|
|
172
|
+
self.assertEqual(response.json['data'][1]['title'], 'C')
|
|
173
|
+
self.assertEqual(response.json['data'][1]['datasets'][0]['id'], str(dataset_a.id))
|
|
174
|
+
self.assertEqual(response.json['data'][1]['datasets'][1]['id'], str(dataset_b.id))
|
|
175
|
+
|
|
176
|
+
def test_dataservice_api_index_with_wrong_dataset_id(self):
|
|
177
|
+
response = self.get(url_for('api.dataservices', sort='title', dataset=str("xxx")))
|
|
178
|
+
self.assert400(response)
|
|
179
|
+
|
|
156
180
|
def test_dataservice_api_create_with_validation_error(self):
|
|
157
181
|
self.login()
|
|
158
182
|
response = self.post(url_for('api.dataservices'), {
|
|
@@ -761,7 +761,7 @@ class DatasetAPITest(APITestCase):
|
|
|
761
761
|
data['resources'].append(resource_data)
|
|
762
762
|
response = self.put(url_for('api.dataset', dataset=dataset), data)
|
|
763
763
|
self.assert400(response)
|
|
764
|
-
assert response.json['errors']['resources'][0]['schema']['url'] == [_('Invalid URL')]
|
|
764
|
+
assert response.json['errors']['resources'][0]['schema']['url'] == [_('Invalid URL "{url}"').format(url="test")]
|
|
765
765
|
|
|
766
766
|
resource_data['schema'] = {'name': 'unknown-schema'}
|
|
767
767
|
data['resources'].append(resource_data)
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
from flask import url_for
|
|
2
|
+
|
|
3
|
+
from udata.core.dataset.factories import (DatasetFactory)
|
|
4
|
+
from udata.core.dataset.models import Dataset
|
|
5
|
+
from udata.core.reports.models import Report
|
|
6
|
+
from udata.core.reports.constants import REASON_ILLEGAL_CONTENT, REASON_SPAM, reports_reasons_translations
|
|
7
|
+
from udata.i18n import gettext as _
|
|
8
|
+
|
|
9
|
+
from . import APITestCase
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class ReportsReasonsAPITest(APITestCase):
|
|
13
|
+
modules = []
|
|
14
|
+
|
|
15
|
+
def test_reports_reasons_api(self):
|
|
16
|
+
response = self.get(url_for('api.reports_reasons'))
|
|
17
|
+
self.assert200(response)
|
|
18
|
+
self.assertEqual(response.json, reports_reasons_translations())
|
|
19
|
+
|
|
20
|
+
class ReportsAPITest(APITestCase):
|
|
21
|
+
modules = []
|
|
22
|
+
|
|
23
|
+
def test_reports_api_create(self):
|
|
24
|
+
user = self.login()
|
|
25
|
+
illegal_dataset = DatasetFactory.create(owner=user)
|
|
26
|
+
spam_dataset = DatasetFactory.create(owner=user)
|
|
27
|
+
|
|
28
|
+
response = self.post(url_for('api.reports'), {
|
|
29
|
+
'object_type': 'Dataset',
|
|
30
|
+
'object_id': illegal_dataset.id,
|
|
31
|
+
'message': 'This is not appropriate',
|
|
32
|
+
'reason': REASON_ILLEGAL_CONTENT,
|
|
33
|
+
})
|
|
34
|
+
self.assert201(response)
|
|
35
|
+
self.assertEqual(Report.objects.count(), 1)
|
|
36
|
+
|
|
37
|
+
response = self.post(url_for('api.reports'), {
|
|
38
|
+
'object_type': 'Dataset',
|
|
39
|
+
'object_id': spam_dataset.id,
|
|
40
|
+
'message': 'This is spammy',
|
|
41
|
+
'reason': REASON_SPAM,
|
|
42
|
+
})
|
|
43
|
+
self.assert201(response)
|
|
44
|
+
self.assertEqual(Report.objects.count(), 2)
|
|
45
|
+
|
|
46
|
+
reports: list[Report] = list(Report.objects())
|
|
47
|
+
self.assertEqual(Dataset.__name__, reports[0].object_type)
|
|
48
|
+
self.assertEqual(illegal_dataset.id, reports[0].object_id)
|
|
49
|
+
self.assertEqual('This is not appropriate', reports[0].message)
|
|
50
|
+
self.assertEqual(REASON_ILLEGAL_CONTENT, reports[0].reason)
|
|
51
|
+
self.assertEqual(user.id, reports[0].by.id)
|
|
52
|
+
|
|
53
|
+
self.assertEqual(Dataset.__name__, reports[1].object_type)
|
|
54
|
+
self.assertEqual(spam_dataset.id, reports[1].object_id)
|
|
55
|
+
self.assertEqual('This is spammy', reports[1].message)
|
|
56
|
+
self.assertEqual(REASON_SPAM, reports[1].reason)
|
|
57
|
+
self.assertEqual(user.id, reports[1].by.id)
|
|
58
|
+
|
|
59
|
+
response = self.delete(url_for('api.dataset', dataset=illegal_dataset))
|
|
60
|
+
self.assert204(response)
|
|
61
|
+
|
|
62
|
+
reports[0].reload()
|
|
63
|
+
self.assertEqual(Dataset.__name__, reports[0].object_type)
|
|
64
|
+
self.assertEqual(illegal_dataset.id, reports[0].object_id)
|
|
65
|
+
self.assertEqual('This is not appropriate', reports[0].message)
|
|
66
|
+
self.assertEqual(REASON_ILLEGAL_CONTENT, reports[0].reason)
|
|
67
|
+
self.assertEqual(user.id, reports[0].by.id)
|
|
68
|
+
self.assertIsNotNone(reports[0].object_deleted_at)
|
|
69
|
+
|
|
70
|
+
reports[1].reload()
|
|
71
|
+
self.assertEqual(Dataset.__name__, reports[1].object_type)
|
|
72
|
+
self.assertEqual(spam_dataset.id, reports[1].object_id)
|
|
73
|
+
self.assertEqual('This is spammy', reports[1].message)
|
|
74
|
+
self.assertEqual(REASON_SPAM, reports[1].reason)
|
|
75
|
+
self.assertEqual(user.id, reports[1].by.id)
|
|
76
|
+
self.assertIsNone(reports[1].object_deleted_at)
|
|
77
|
+
|
|
78
|
+
# We should take action on manual delete in the database too
|
|
79
|
+
spam_dataset.delete()
|
|
80
|
+
|
|
81
|
+
reports[1].reload()
|
|
82
|
+
self.assertIsNotNone(reports[1].object_deleted_at)
|
|
83
|
+
|
|
84
|
+
response = self.get(url_for('api.reports'))
|
|
85
|
+
self.assert200(response)
|
|
86
|
+
self.assertEqual(len(response.json['data']), 2)
|
|
87
|
+
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
from flask import url_for
|
|
2
|
+
|
|
3
|
+
from udata.models import Member
|
|
4
|
+
from udata.core.organization.factories import OrganizationFactory
|
|
5
|
+
from udata.core.topic.factories import TopicFactory
|
|
6
|
+
from udata.tests.api import APITestCase
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class MeAPIv2Test(APITestCase):
|
|
10
|
+
modules = []
|
|
11
|
+
|
|
12
|
+
def test_my_org_topics(self):
|
|
13
|
+
user = self.login()
|
|
14
|
+
member = Member(user=user, role='editor')
|
|
15
|
+
organization = OrganizationFactory(members=[member])
|
|
16
|
+
topics = [
|
|
17
|
+
TopicFactory(organization=organization, private=False, tags=['energy']),
|
|
18
|
+
TopicFactory(organization=organization, private=True),
|
|
19
|
+
TopicFactory(owner=user),
|
|
20
|
+
]
|
|
21
|
+
# another topic that shouldn't pop up
|
|
22
|
+
TopicFactory()
|
|
23
|
+
|
|
24
|
+
response = self.get(url_for('apiv2.my_org_topics'))
|
|
25
|
+
assert response.status_code == 200
|
|
26
|
+
data = response.json['data']
|
|
27
|
+
assert len(data) == 3
|
|
28
|
+
assert all(
|
|
29
|
+
str(topic.id) in [remote_topic["id"] for remote_topic in data]
|
|
30
|
+
for topic in topics
|
|
31
|
+
)
|
|
32
|
+
assert 'rel' in data[0]['datasets']
|
|
33
|
+
|
|
34
|
+
# topic parser is already tested in topics test
|
|
35
|
+
# we're just making sure one of theme is working
|
|
36
|
+
response = self.get(url_for('apiv2.my_org_topics', tag='energy'))
|
|
37
|
+
assert response.status_code == 200
|
|
38
|
+
data = response.json['data']
|
|
39
|
+
assert len(data) == 1
|
|
40
|
+
assert data[0]['id'] == str(topics[0].id)
|
|
@@ -20,9 +20,12 @@ from udata.core.dataset.rdf import (
|
|
|
20
20
|
temporal_from_rdf, frequency_to_rdf, frequency_from_rdf,
|
|
21
21
|
EU_RDF_REQUENCIES
|
|
22
22
|
)
|
|
23
|
+
from udata.rdf import (
|
|
24
|
+
TAG_TO_EU_HVD_CATEGORIES
|
|
25
|
+
)
|
|
23
26
|
from udata.core.organization.factories import OrganizationFactory
|
|
24
27
|
from udata.i18n import gettext as _
|
|
25
|
-
from udata.rdf import DCAT, DCT, FREQ, SPDX, SCHEMA, SKOS
|
|
28
|
+
from udata.rdf import DCAT, DCATAP, DCT, FREQ, SPDX, SCHEMA, SKOS, HVD_LEGISLATION
|
|
26
29
|
from udata.utils import faker
|
|
27
30
|
from udata.tests.helpers import assert200, assert_redirects
|
|
28
31
|
|
|
@@ -181,6 +184,21 @@ class DatasetToRdfTest:
|
|
|
181
184
|
assert str(d.identifier) == 'https://somewhere.org/dataset'
|
|
182
185
|
assert d.value(DCT.identifier) == Literal('an-identifier')
|
|
183
186
|
|
|
187
|
+
def test_hvd_dataset(self):
|
|
188
|
+
'''Test that a dataset tagged hvd has appropriate DCAT-AP HVD properties'''
|
|
189
|
+
dataset = DatasetFactory(
|
|
190
|
+
resources=ResourceFactory.build_batch(3),
|
|
191
|
+
tags=['hvd', 'mobilite', 'test']
|
|
192
|
+
)
|
|
193
|
+
d = dataset_to_rdf(dataset)
|
|
194
|
+
|
|
195
|
+
assert d.value(DCATAP.applicableLegislation).identifier == URIRef(HVD_LEGISLATION)
|
|
196
|
+
assert d.value(DCATAP.hvdCategory).identifier == URIRef(
|
|
197
|
+
TAG_TO_EU_HVD_CATEGORIES['mobilite']
|
|
198
|
+
)
|
|
199
|
+
for distrib in d.objects(DCAT.distribution):
|
|
200
|
+
assert distrib.value(DCATAP.applicableLegislation).identifier == URIRef(HVD_LEGISLATION)
|
|
201
|
+
|
|
184
202
|
|
|
185
203
|
@pytest.mark.usefixtures('clean_db')
|
|
186
204
|
class RdfToDatasetTest:
|
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
from
|
|
2
|
-
from flask import url_for, current_app, get_flashed_messages
|
|
3
|
-
from flask_login import current_user
|
|
1
|
+
from flask import url_for, current_app
|
|
4
2
|
from flask_security.utils import hash_data
|
|
5
|
-
from udata.auth.views import send_change_email_confirmation_instructions
|
|
6
3
|
from udata.core.user.factories import AdminFactory
|
|
7
4
|
|
|
8
5
|
from . import FrontTestCase
|
udata/tests/plugin.py
CHANGED
|
@@ -8,6 +8,7 @@ from flask import json, template_rendered, url_for, current_app
|
|
|
8
8
|
from flask.testing import FlaskClient
|
|
9
9
|
from lxml import etree
|
|
10
10
|
from werkzeug.urls import url_encode
|
|
11
|
+
from flask_principal import Identity, identity_changed
|
|
11
12
|
|
|
12
13
|
from udata import settings
|
|
13
14
|
from udata.app import create_app
|
|
@@ -49,6 +50,7 @@ class TestClient(FlaskClient):
|
|
|
49
50
|
session['_fresh'] = True
|
|
50
51
|
session['_id'] = current_app.login_manager._session_identifier_generator()
|
|
51
52
|
current_app.login_manager._update_request_context_with_user(user)
|
|
53
|
+
identity_changed.send(current_app._get_current_object(), identity=Identity(user.id))
|
|
52
54
|
return user
|
|
53
55
|
|
|
54
56
|
def logout(self):
|
|
@@ -6,6 +6,7 @@ from rdflib import URIRef, Literal, Graph
|
|
|
6
6
|
from rdflib.namespace import RDF, FOAF
|
|
7
7
|
from rdflib.resource import Resource
|
|
8
8
|
|
|
9
|
+
from udata.core.dataservices.factories import DataserviceFactory, HarvestMetadataFactory
|
|
9
10
|
from udata.core.dataset.factories import DatasetFactory
|
|
10
11
|
from udata.core.dataset.models import Dataset
|
|
11
12
|
from udata.core.organization.factories import OrganizationFactory
|
|
@@ -228,3 +229,68 @@ class SiteRdfViewsTest:
|
|
|
228
229
|
url = url_for('api.site_rdf_catalog_format', format='unknown')
|
|
229
230
|
response = client.get(url)
|
|
230
231
|
assert404(response)
|
|
232
|
+
|
|
233
|
+
def test_catalog_rdf_filter_tag(self, client):
|
|
234
|
+
DatasetFactory.create_batch(4, tags=['my-tag'])
|
|
235
|
+
DatasetFactory.create_batch(3)
|
|
236
|
+
url = url_for('api.site_rdf_catalog_format', format='xml', tag='my-tag')
|
|
237
|
+
|
|
238
|
+
response = client.get(url, headers={'Accept': 'application/xml'})
|
|
239
|
+
assert200(response)
|
|
240
|
+
|
|
241
|
+
graph = Graph().parse(data=response.data, format='xml')
|
|
242
|
+
|
|
243
|
+
datasets = list(graph.subjects(RDF.type, DCAT.Dataset))
|
|
244
|
+
assert len(datasets) == 4
|
|
245
|
+
|
|
246
|
+
for dat in datasets:
|
|
247
|
+
assert graph.value(dat, DCAT.keyword) == Literal('my-tag')
|
|
248
|
+
|
|
249
|
+
def test_catalog_rdf_dataservices(self, client):
|
|
250
|
+
dataset_a = DatasetFactory.create()
|
|
251
|
+
dataset_b = DatasetFactory.create()
|
|
252
|
+
dataset_c = DatasetFactory.create()
|
|
253
|
+
|
|
254
|
+
dataservice_a = DataserviceFactory.create(datasets=[dataset_a.id], harvest=HarvestMetadataFactory())
|
|
255
|
+
dataservice_b = DataserviceFactory.create(datasets=[dataset_b.id])
|
|
256
|
+
dataservice_x = DataserviceFactory.create(datasets=[dataset_a.id, dataset_c.id])
|
|
257
|
+
dataservice_y = DataserviceFactory.create(datasets=[])
|
|
258
|
+
|
|
259
|
+
response = client.get(url_for('api.site_rdf_catalog_format', format='xml'), headers={'Accept': 'application/xml'})
|
|
260
|
+
assert200(response)
|
|
261
|
+
|
|
262
|
+
graph = Graph().parse(data=response.data, format='xml')
|
|
263
|
+
|
|
264
|
+
datasets = list(graph.subjects(RDF.type, DCAT.Dataset))
|
|
265
|
+
assert len(datasets) == 3
|
|
266
|
+
|
|
267
|
+
dataservices = list(graph.subjects(RDF.type, DCAT.DataService))
|
|
268
|
+
assert len(dataservices) == 4
|
|
269
|
+
|
|
270
|
+
# Test first page contains the dataservice without dataset
|
|
271
|
+
response = client.get(url_for('api.site_rdf_catalog_format', format='xml', page_size=1), headers={'Accept': 'application/xml'})
|
|
272
|
+
assert200(response)
|
|
273
|
+
|
|
274
|
+
graph = Graph().parse(data=response.data, format='xml')
|
|
275
|
+
|
|
276
|
+
datasets = list(graph.subjects(RDF.type, DCAT.Dataset))
|
|
277
|
+
assert len(datasets) == 1
|
|
278
|
+
assert str(graph.value(datasets[0], DCT.identifier)) == str(dataset_c.id)
|
|
279
|
+
|
|
280
|
+
dataservices = list(graph.subjects(RDF.type, DCAT.DataService))
|
|
281
|
+
assert len(dataservices) == 2
|
|
282
|
+
assert sorted([str(d.id) for d in [dataservice_x, dataservice_y]]) == sorted([str(graph.value(d, DCT.identifier)) for d in dataservices])
|
|
283
|
+
|
|
284
|
+
# Test second page doesn't contains the dataservice without dataset
|
|
285
|
+
response = client.get(url_for('api.site_rdf_catalog_format', format='xml', page_size=1, page=2), headers={'Accept': 'application/xml'})
|
|
286
|
+
assert200(response)
|
|
287
|
+
|
|
288
|
+
graph = Graph().parse(data=response.data, format='xml')
|
|
289
|
+
|
|
290
|
+
datasets = list(graph.subjects(RDF.type, DCAT.Dataset))
|
|
291
|
+
assert len(datasets) == 1
|
|
292
|
+
assert str(graph.value(datasets[0], DCT.identifier)) == str(dataset_b.id)
|
|
293
|
+
|
|
294
|
+
dataservices = list(graph.subjects(RDF.type, DCAT.DataService))
|
|
295
|
+
assert len(dataservices) == 1
|
|
296
|
+
assert str(graph.value(dataservices[0], DCT.identifier)) == str(dataservice_b.id)
|
udata/tests/test_discussions.py
CHANGED
|
@@ -76,7 +76,7 @@ class DiscussionsTest(APITestCase):
|
|
|
76
76
|
discussion_id = None
|
|
77
77
|
def check_signal(args):
|
|
78
78
|
self.assertIsNotNone(discussion_id)
|
|
79
|
-
self.assertIn(f'http://local.test/api/1/datasets/{dataset.
|
|
79
|
+
self.assertIn(f'http://local.test/api/1/datasets/{dataset.slug}/#discussion-{discussion_id}', args[1]['message'])
|
|
80
80
|
|
|
81
81
|
with assert_emit(on_new_potential_spam, assertions_callback=check_signal):
|
|
82
82
|
response = self.post(url_for('api.discussions'), {
|
|
@@ -122,6 +122,29 @@ class DiscussionsTest(APITestCase):
|
|
|
122
122
|
self.assertStatus(response, 200)
|
|
123
123
|
self.assertFalse(discussion.reload().is_spam())
|
|
124
124
|
|
|
125
|
+
|
|
126
|
+
@pytest.mark.options(SPAM_WORDS=['spam'])
|
|
127
|
+
def test_spam_by_owner(self):
|
|
128
|
+
user = self.login()
|
|
129
|
+
dataset = Dataset.objects.create(title='Test dataset', owner=user)
|
|
130
|
+
|
|
131
|
+
with assert_not_emit(on_new_potential_spam):
|
|
132
|
+
response = self.post(url_for('api.discussions'), {
|
|
133
|
+
'title': 'spam and blah',
|
|
134
|
+
'comment': 'bla bla',
|
|
135
|
+
'subject': {
|
|
136
|
+
'class': 'Dataset',
|
|
137
|
+
'id': dataset.id,
|
|
138
|
+
}
|
|
139
|
+
})
|
|
140
|
+
self.assertStatus(response, 201)
|
|
141
|
+
|
|
142
|
+
with assert_not_emit(on_new_potential_spam):
|
|
143
|
+
response = self.post(url_for('api.discussion', id=response.json['id']), {
|
|
144
|
+
'comment': 'A comment with spam by owner'
|
|
145
|
+
})
|
|
146
|
+
self.assertStatus(response, 200)
|
|
147
|
+
|
|
125
148
|
@pytest.mark.options(SPAM_WORDS=['spam'])
|
|
126
149
|
def test_spam_in_new_discussion_comment(self):
|
|
127
150
|
self.login()
|
|
@@ -495,39 +518,6 @@ class DiscussionsTest(APITestCase):
|
|
|
495
518
|
{'comment': "can't comment"})
|
|
496
519
|
self.assert403(response)
|
|
497
520
|
|
|
498
|
-
@pytest.mark.options(SPAM_WORDS=['spam'], SPAM_ALLOWED_LANGS=['fr'])
|
|
499
|
-
def test_close_discussion_with_spam(self):
|
|
500
|
-
owner = self.login()
|
|
501
|
-
dataset = Dataset.objects.create(title='Test dataset', owner=owner)
|
|
502
|
-
user = UserFactory()
|
|
503
|
-
message = Message(content='Premier message', posted_by=user)
|
|
504
|
-
discussion = Discussion.objects.create(
|
|
505
|
-
subject=dataset,
|
|
506
|
-
user=user,
|
|
507
|
-
title='test discussion',
|
|
508
|
-
discussion=[message]
|
|
509
|
-
)
|
|
510
|
-
on_new_discussion.send(discussion) # Updating metrics.
|
|
511
|
-
|
|
512
|
-
with assert_not_emit(on_discussion_closed):
|
|
513
|
-
with assert_emit(on_new_potential_spam):
|
|
514
|
-
response = self.post(url_for('api.discussion', id=discussion.id), {
|
|
515
|
-
'comment': 'This is a suspicious, real suspicious message in english.',
|
|
516
|
-
'close': True,
|
|
517
|
-
})
|
|
518
|
-
self.assert200(response)
|
|
519
|
-
|
|
520
|
-
discussion.reload()
|
|
521
|
-
self.assertFalse(discussion.is_spam())
|
|
522
|
-
self.assertTrue(discussion.discussion[1].is_spam())
|
|
523
|
-
self.assertTrue('signal_close' in discussion.discussion[1].spam.callbacks)
|
|
524
|
-
|
|
525
|
-
with assert_emit(on_discussion_closed):
|
|
526
|
-
admin = self.login(AdminFactory())
|
|
527
|
-
response = self.delete(url_for('api.discussion_comment_spam', id=discussion.id, cidx=1))
|
|
528
|
-
self.assertStatus(response, 200)
|
|
529
|
-
self.assertFalse(discussion.reload().discussion[1].is_spam())
|
|
530
|
-
|
|
531
521
|
def test_close_discussion_permissions(self):
|
|
532
522
|
dataset = Dataset.objects.create(title='Test dataset')
|
|
533
523
|
user = UserFactory()
|
udata/tests/test_model.py
CHANGED
|
@@ -6,6 +6,7 @@ from datetime import date, datetime, timedelta
|
|
|
6
6
|
from mongoengine.errors import ValidationError
|
|
7
7
|
from mongoengine.fields import BaseField
|
|
8
8
|
|
|
9
|
+
from udata.i18n import _
|
|
9
10
|
from udata.settings import Defaults
|
|
10
11
|
from udata.models import Dataset
|
|
11
12
|
from udata.mongo import db, validate_config, build_test_config
|
|
@@ -366,7 +367,7 @@ class URLFieldTest:
|
|
|
366
367
|
|
|
367
368
|
def test_not_valid(self):
|
|
368
369
|
obj = URLTester(url='invalid')
|
|
369
|
-
with pytest.raises(ValidationError, match='Invalid URL'):
|
|
370
|
+
with pytest.raises(ValidationError, match=_('Invalid URL "{url}"').format(url="invalid")):
|
|
370
371
|
obj.save()
|
|
371
372
|
|
|
372
373
|
def test_strip_spaces(self):
|
|
@@ -384,7 +385,7 @@ class URLFieldTest:
|
|
|
384
385
|
def test_public_private(self):
|
|
385
386
|
url = 'http://10.10.0.2/path/'
|
|
386
387
|
PrivateURLTester(url=url).save()
|
|
387
|
-
with pytest.raises(ValidationError, match='private URL'):
|
|
388
|
+
with pytest.raises(ValidationError, match=_('is a private URL')):
|
|
388
389
|
URLTester(url=url).save()
|
|
389
390
|
|
|
390
391
|
|
udata/tests/test_utils.py
CHANGED
|
Binary file
|