udata 7.0.8.dev28841__py2.py3-none-any.whl → 8.0.1__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 +6 -4
- udata/api/oauth2.py +2 -1
- udata/api_fields.py +254 -0
- udata/core/badges/models.py +2 -1
- udata/core/dataservices/__init__.py +0 -0
- udata/core/dataservices/api.py +84 -0
- udata/core/dataservices/models.py +130 -0
- udata/core/dataset/apiv2.py +2 -0
- udata/core/dataset/models.py +1 -0
- udata/core/dataset/rdf.py +21 -1
- udata/core/metrics/commands.py +18 -3
- udata/core/metrics/models.py +2 -3
- udata/core/organization/api_fields.py +28 -3
- udata/core/organization/models.py +3 -1
- udata/core/owned.py +39 -2
- udata/core/spatial/api.py +5 -10
- udata/core/spatial/models.py +7 -2
- udata/core/spatial/tasks.py +7 -0
- udata/core/spatial/tests/test_api.py +26 -0
- udata/core/user/api.py +11 -7
- udata/core/user/models.py +13 -2
- udata/harvest/backends/dcat.py +14 -8
- udata/harvest/tests/dcat/catalog.xml +1 -0
- udata/harvest/tests/test_dcat_backend.py +3 -0
- udata/routing.py +6 -0
- udata/settings.py +4 -1
- udata/static/admin.css +2 -2
- udata/static/admin.css.map +1 -1
- udata/static/chunks/{0.6f1698738c9b0618b673.js → 0.93c3ae13b5b94753ee80.js} +3 -3
- udata/static/chunks/0.93c3ae13b5b94753ee80.js.map +1 -0
- udata/static/chunks/{14.f4037a917d5364cb564b.js → 14.e64890872b31c55fcdf7.js} +2 -2
- udata/static/chunks/14.e64890872b31c55fcdf7.js.map +1 -0
- udata/static/chunks/{2.7c89fae92899be371ed3.js → 2.614b3e73b072982fd9b1.js} +2 -2
- udata/static/chunks/2.614b3e73b072982fd9b1.js.map +1 -0
- udata/static/chunks/{5.3dc97ea195d251881552.js → 5.48417db6b33328fa9d6a.js} +2 -2
- udata/static/chunks/5.48417db6b33328fa9d6a.js.map +1 -0
- udata/static/common.js +1 -1
- udata/static/common.js.map +1 -1
- udata/tasks.py +1 -0
- udata/tests/api/__init__.py +3 -0
- udata/tests/api/test_dataservices_api.py +236 -0
- udata/tests/api/test_organizations_api.py +78 -5
- udata/tests/api/test_user_api.py +47 -13
- udata/tests/plugin.py +5 -0
- {udata-7.0.8.dev28841.dist-info → udata-8.0.1.dist-info}/METADATA +17 -3
- {udata-7.0.8.dev28841.dist-info → udata-8.0.1.dist-info}/RECORD +51 -46
- udata/core/metrics/api.py +0 -10
- udata/static/chunks/0.6f1698738c9b0618b673.js.map +0 -1
- udata/static/chunks/14.f4037a917d5364cb564b.js.map +0 -1
- udata/static/chunks/2.7c89fae92899be371ed3.js.map +0 -1
- udata/static/chunks/5.3dc97ea195d251881552.js.map +0 -1
- {udata-7.0.8.dev28841.dist-info → udata-8.0.1.dist-info}/LICENSE +0 -0
- {udata-7.0.8.dev28841.dist-info → udata-8.0.1.dist-info}/WHEEL +0 -0
- {udata-7.0.8.dev28841.dist-info → udata-8.0.1.dist-info}/entry_points.txt +0 -0
- {udata-7.0.8.dev28841.dist-info → udata-8.0.1.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,d,_=0,n=[];_<b.length;_++)d=b[_],f[d]&&n.push.apply(n,f[d]),f[d]=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);n.length;)n.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:"
|
|
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,d,_=0,n=[];_<b.length;_++)d=b[_],f[d]&&n.push.apply(n,f[d]),f[d]=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);n.length;)n.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:"48417db6b33328fa9d6a",6:"f84539bd4c419b36cc19",7:"11ac4de064ae59691d49",8:"17d1afb591ad1495bd03",9:"07503e7f7ec02919f696",10:"e97ea231893dc435d6b5",11:"7266fef2dddc1db403d9",12:"59f035a9438e2baf5126",13:"91b177d7d531fd55cf5d",14:"e64890872b31c55fcdf7",15:"92b2cef3032ea35da04a",16:"e866757bab9f6b0a3f1b",17:"15ecbcf8f0b2968689e8",18:"ad41fb75ac4226e1f3ce",19:"619b83ac597516dcd03e",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"}[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 ee03f1fa39a515ac0121"],"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\":\"6f1698738c9b0618b673\",\"1\":\"ff8196d42cab0f031d3f\",\"2\":\"7c89fae92899be371ed3\",\"3\":\"1ca609753b5a02de0ca3\",\"4\":\"95e6a070a0eb2ed08fdd\",\"5\":\"3dc97ea195d251881552\",\"6\":\"f84539bd4c419b36cc19\",\"7\":\"11ac4de064ae59691d49\",\"8\":\"17d1afb591ad1495bd03\",\"9\":\"07503e7f7ec02919f696\",\"10\":\"e97ea231893dc435d6b5\",\"11\":\"7266fef2dddc1db403d9\",\"12\":\"59f035a9438e2baf5126\",\"13\":\"91b177d7d531fd55cf5d\",\"14\":\"f4037a917d5364cb564b\",\"15\":\"92b2cef3032ea35da04a\",\"16\":\"e866757bab9f6b0a3f1b\",\"17\":\"15ecbcf8f0b2968689e8\",\"18\":\"ad41fb75ac4226e1f3ce\",\"19\":\"619b83ac597516dcd03e\",\"20\":\"14a92e5c503f74ff40df\",\"21\":\"ccbfce6680a2b11a5284\",\"22\":\"bc79367e5f4c8ad00038\",\"23\":\"5486b3fc83b194d55191\",\"24\":\"e905e3f6ba089a34b07c\",\"25\":\"e20b4daac9fb2bdceee6\",\"26\":\"c8f33e73b9117b70aef8\",\"27\":\"6779f92692327013b446\",\"28\":\"280c392f19bc9e908abf\",\"29\":\"daadfa33135efe4e5534\",\"30\":\"b2464d08ccbeb40ec74e\",\"32\":\"3251a701a677ab35e980\",\"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\":\"6f1698738c9b0618b673\",\"1\":\"ff8196d42cab0f031d3f\",\"2\":\"7c89fae92899be371ed3\",\"3\":\"1ca609753b5a02de0ca3\",\"4\":\"95e6a070a0eb2ed08fdd\",\"5\":\"3dc97ea195d251881552\",\"6\":\"f84539bd4c419b36cc19\",\"7\":\"11ac4de064ae59691d49\",\"8\":\"17d1afb591ad1495bd03\",\"9\":\"07503e7f7ec02919f696\",\"10\":\"e97ea231893dc435d6b5\",\"11\":\"7266fef2dddc1db403d9\",\"12\":\"59f035a9438e2baf5126\",\"13\":\"91b177d7d531fd55cf5d\",\"14\":\"f4037a917d5364cb564b\",\"15\":\"92b2cef3032ea35da04a\",\"16\":\"e866757bab9f6b0a3f1b\",\"17\":\"15ecbcf8f0b2968689e8\",\"18\":\"ad41fb75ac4226e1f3ce\",\"19\":\"619b83ac597516dcd03e\",\"20\":\"14a92e5c503f74ff40df\",\"21\":\"ccbfce6680a2b11a5284\",\"22\":\"bc79367e5f4c8ad00038\",\"23\":\"5486b3fc83b194d55191\",\"24\":\"e905e3f6ba089a34b07c\",\"25\":\"e20b4daac9fb2bdceee6\",\"26\":\"c8f33e73b9117b70aef8\",\"27\":\"6779f92692327013b446\",\"28\":\"280c392f19bc9e908abf\",\"29\":\"daadfa33135efe4e5534\",\"30\":\"b2464d08ccbeb40ec74e\",\"32\":\"3251a701a677ab35e980\",\"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 ee03f1fa39a515ac0121\n **/"],"sourceRoot":""}
|
|
1
|
+
{"version":3,"sources":["webpack:///common.js","webpack:///webpack/bootstrap ede79b8cd6024fb06864"],"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\":\"48417db6b33328fa9d6a\",\"6\":\"f84539bd4c419b36cc19\",\"7\":\"11ac4de064ae59691d49\",\"8\":\"17d1afb591ad1495bd03\",\"9\":\"07503e7f7ec02919f696\",\"10\":\"e97ea231893dc435d6b5\",\"11\":\"7266fef2dddc1db403d9\",\"12\":\"59f035a9438e2baf5126\",\"13\":\"91b177d7d531fd55cf5d\",\"14\":\"e64890872b31c55fcdf7\",\"15\":\"92b2cef3032ea35da04a\",\"16\":\"e866757bab9f6b0a3f1b\",\"17\":\"15ecbcf8f0b2968689e8\",\"18\":\"ad41fb75ac4226e1f3ce\",\"19\":\"619b83ac597516dcd03e\",\"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\":\"48417db6b33328fa9d6a\",\"6\":\"f84539bd4c419b36cc19\",\"7\":\"11ac4de064ae59691d49\",\"8\":\"17d1afb591ad1495bd03\",\"9\":\"07503e7f7ec02919f696\",\"10\":\"e97ea231893dc435d6b5\",\"11\":\"7266fef2dddc1db403d9\",\"12\":\"59f035a9438e2baf5126\",\"13\":\"91b177d7d531fd55cf5d\",\"14\":\"e64890872b31c55fcdf7\",\"15\":\"92b2cef3032ea35da04a\",\"16\":\"e866757bab9f6b0a3f1b\",\"17\":\"15ecbcf8f0b2968689e8\",\"18\":\"ad41fb75ac4226e1f3ce\",\"19\":\"619b83ac597516dcd03e\",\"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 ede79b8cd6024fb06864\n **/"],"sourceRoot":""}
|
udata/tasks.py
CHANGED
|
@@ -162,6 +162,7 @@ def init_app(app):
|
|
|
162
162
|
import udata.core.tags.tasks # noqa
|
|
163
163
|
import udata.core.activity.tasks # noqa
|
|
164
164
|
import udata.core.dataset.tasks # noqa
|
|
165
|
+
import udata.core.spatial.tasks # noqa
|
|
165
166
|
import udata.core.reuse.tasks # noqa
|
|
166
167
|
import udata.core.user.tasks # noqa
|
|
167
168
|
import udata.core.organization.tasks # noqa
|
udata/tests/api/__init__.py
CHANGED
|
@@ -29,5 +29,8 @@ class APITestCase(FrontTestCase):
|
|
|
29
29
|
def put(self, url, data=None, json=True, *args, **kwargs):
|
|
30
30
|
return self.api.put(url, data=data, json=json, *args, **kwargs)
|
|
31
31
|
|
|
32
|
+
def patch(self, url, data=None, json=True, *args, **kwargs):
|
|
33
|
+
return self.api.patch(url, data=data, json=json, *args, **kwargs)
|
|
34
|
+
|
|
32
35
|
def delete(self, url, data=None, *args, **kwargs):
|
|
33
36
|
return self.api.delete(url, data=data, *args, **kwargs)
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
from pprint import pprint
|
|
2
|
+
from flask import url_for
|
|
3
|
+
|
|
4
|
+
from udata.core.dataservices.models import Dataservice
|
|
5
|
+
from udata.core.dataset.factories import (DatasetFactory, LicenseFactory)
|
|
6
|
+
from udata.i18n import gettext as _
|
|
7
|
+
from udata.core.user.factories import UserFactory
|
|
8
|
+
from udata.core.organization.factories import OrganizationFactory
|
|
9
|
+
from udata.core.organization.models import Member
|
|
10
|
+
|
|
11
|
+
from . import APITestCase
|
|
12
|
+
|
|
13
|
+
class DataserviceAPITest(APITestCase):
|
|
14
|
+
modules = []
|
|
15
|
+
|
|
16
|
+
def test_dataservice_api_create(self):
|
|
17
|
+
user = self.login()
|
|
18
|
+
datasets = DatasetFactory.create_batch(3)
|
|
19
|
+
license = LicenseFactory.create()
|
|
20
|
+
|
|
21
|
+
response = self.post(url_for('api.dataservices'), {
|
|
22
|
+
'title': 'My API',
|
|
23
|
+
'base_api_url': 'https://example.org',
|
|
24
|
+
})
|
|
25
|
+
self.assert201(response)
|
|
26
|
+
self.assertEqual(Dataservice.objects.count(), 1)
|
|
27
|
+
|
|
28
|
+
dataservice = Dataservice.objects.first()
|
|
29
|
+
|
|
30
|
+
response = self.get(url_for('api.dataservice', dataservice=dataservice))
|
|
31
|
+
self.assert200(response)
|
|
32
|
+
|
|
33
|
+
self.assertEqual(response.json['title'], 'My API')
|
|
34
|
+
self.assertEqual(response.json['base_api_url'], 'https://example.org')
|
|
35
|
+
self.assertEqual(response.json['owner']['id'], str(user.id))
|
|
36
|
+
|
|
37
|
+
response = self.patch(url_for('api.dataservice', dataservice=dataservice), {
|
|
38
|
+
'title': 'Updated title',
|
|
39
|
+
'tags': ['hello', 'world'],
|
|
40
|
+
'private': True,
|
|
41
|
+
'datasets': [datasets[0].id, datasets[2].id],
|
|
42
|
+
'license': license.id,
|
|
43
|
+
'extras': {
|
|
44
|
+
'foo': 'bar',
|
|
45
|
+
},
|
|
46
|
+
})
|
|
47
|
+
self.assert200(response)
|
|
48
|
+
|
|
49
|
+
self.assertEqual(response.json['title'], 'Updated title')
|
|
50
|
+
self.assertEqual(response.json['base_api_url'], 'https://example.org')
|
|
51
|
+
self.assertEqual(response.json['tags'], ['hello', 'world'])
|
|
52
|
+
self.assertEqual(response.json['private'], True)
|
|
53
|
+
self.assertEqual(response.json['datasets'][0]['title'], datasets[0].title)
|
|
54
|
+
self.assertEqual(response.json['datasets'][1]['title'], datasets[2].title)
|
|
55
|
+
self.assertEqual(response.json['extras'], {
|
|
56
|
+
'foo': 'bar',
|
|
57
|
+
})
|
|
58
|
+
self.assertEqual(response.json['license'], license.title)
|
|
59
|
+
self.assertEqual(response.json['self_api_url'], 'http://local.test/api/1/dataservices/updated-title/')
|
|
60
|
+
dataservice.reload()
|
|
61
|
+
self.assertEqual(dataservice.title, 'Updated title')
|
|
62
|
+
self.assertEqual(dataservice.base_api_url, 'https://example.org')
|
|
63
|
+
self.assertEqual(dataservice.tags, ['hello', 'world'])
|
|
64
|
+
self.assertEqual(dataservice.private, True)
|
|
65
|
+
self.assertEqual(dataservice.datasets[0].title, datasets[0].title)
|
|
66
|
+
self.assertEqual(dataservice.datasets[1].title, datasets[2].title)
|
|
67
|
+
self.assertEqual(dataservice.extras, {
|
|
68
|
+
'foo': 'bar',
|
|
69
|
+
})
|
|
70
|
+
self.assertEqual(dataservice.license.title, license.title)
|
|
71
|
+
self.assertEqual(dataservice.self_api_url(), 'http://local.test/api/1/dataservices/updated-title/')
|
|
72
|
+
|
|
73
|
+
response = self.delete(url_for('api.dataservice', dataservice=dataservice))
|
|
74
|
+
self.assert204(response)
|
|
75
|
+
|
|
76
|
+
self.assertEqual(Dataservice.objects.count(), 1)
|
|
77
|
+
|
|
78
|
+
dataservice.reload()
|
|
79
|
+
self.assertEqual(dataservice.title, 'Updated title')
|
|
80
|
+
self.assertEqual(dataservice.base_api_url, 'https://example.org')
|
|
81
|
+
self.assertIsNotNone(dataservice.deleted_at)
|
|
82
|
+
|
|
83
|
+
# response = self.get(url_for('api.dataservice', dataservice=dataservice))
|
|
84
|
+
# self.assert410(response)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def test_dataservice_api_index(self):
|
|
88
|
+
self.login()
|
|
89
|
+
self.post(url_for('api.dataservices'), {
|
|
90
|
+
'title': 'B',
|
|
91
|
+
'base_api_url': 'https://example.org/B',
|
|
92
|
+
})
|
|
93
|
+
self.post(url_for('api.dataservices'), {
|
|
94
|
+
'title': 'C',
|
|
95
|
+
'base_api_url': 'https://example.org/C',
|
|
96
|
+
})
|
|
97
|
+
self.post(url_for('api.dataservices'), {
|
|
98
|
+
'title': 'A',
|
|
99
|
+
'base_api_url': 'https://example.org/A',
|
|
100
|
+
})
|
|
101
|
+
response = self.post(url_for('api.dataservices'), {
|
|
102
|
+
'title': 'X',
|
|
103
|
+
'base_api_url': 'https://example.org/X',
|
|
104
|
+
'private': True,
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
self.assertEqual(Dataservice.objects.count(), 4)
|
|
108
|
+
|
|
109
|
+
response = self.get(url_for('api.dataservices'))
|
|
110
|
+
self.assert200(response)
|
|
111
|
+
|
|
112
|
+
self.assertEqual(response.json['previous_page'], None)
|
|
113
|
+
self.assertEqual(response.json['next_page'], None)
|
|
114
|
+
self.assertEqual(response.json['page'], 1)
|
|
115
|
+
self.assertEqual(response.json['total'], 3)
|
|
116
|
+
self.assertEqual(len(response.json['data']), 3)
|
|
117
|
+
self.assertEqual(response.json['data'][0]['title'], 'B')
|
|
118
|
+
self.assertEqual(response.json['data'][1]['title'], 'C')
|
|
119
|
+
self.assertEqual(response.json['data'][2]['title'], 'A')
|
|
120
|
+
|
|
121
|
+
response = self.get(url_for('api.dataservices', sort='title'))
|
|
122
|
+
self.assert200(response)
|
|
123
|
+
|
|
124
|
+
self.assertEqual(response.json['previous_page'], None)
|
|
125
|
+
self.assertEqual(response.json['next_page'], None)
|
|
126
|
+
self.assertEqual(response.json['page'], 1)
|
|
127
|
+
self.assertEqual(response.json['total'], 3)
|
|
128
|
+
self.assertEqual(len(response.json['data']), 3)
|
|
129
|
+
self.assertEqual(response.json['data'][0]['title'], 'A')
|
|
130
|
+
self.assertEqual(response.json['data'][1]['title'], 'B')
|
|
131
|
+
self.assertEqual(response.json['data'][2]['title'], 'C')
|
|
132
|
+
|
|
133
|
+
response = self.get(url_for('api.dataservices', sort='-title'))
|
|
134
|
+
self.assert200(response)
|
|
135
|
+
|
|
136
|
+
self.assertEqual(response.json['previous_page'], None)
|
|
137
|
+
self.assertEqual(response.json['next_page'], None)
|
|
138
|
+
self.assertEqual(response.json['page'], 1)
|
|
139
|
+
self.assertEqual(response.json['total'], 3)
|
|
140
|
+
self.assertEqual(len(response.json['data']), 3)
|
|
141
|
+
self.assertEqual(response.json['data'][0]['title'], 'C')
|
|
142
|
+
self.assertEqual(response.json['data'][1]['title'], 'B')
|
|
143
|
+
self.assertEqual(response.json['data'][2]['title'], 'A')
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
response = self.get(url_for('api.dataservices', page_size=1))
|
|
147
|
+
self.assert200(response)
|
|
148
|
+
|
|
149
|
+
self.assertEqual(response.json['previous_page'], None)
|
|
150
|
+
assert response.json['next_page'].endswith(url_for('api.dataservices', page_size=1, page=2))
|
|
151
|
+
self.assertEqual(response.json['page'], 1)
|
|
152
|
+
self.assertEqual(response.json['total'], 3)
|
|
153
|
+
self.assertEqual(len(response.json['data']), 1)
|
|
154
|
+
self.assertEqual(response.json['data'][0]['title'], 'B')
|
|
155
|
+
|
|
156
|
+
def test_dataservice_api_create_with_validation_error(self):
|
|
157
|
+
self.login()
|
|
158
|
+
response = self.post(url_for('api.dataservices'), {
|
|
159
|
+
'base_api_url': 'https://example.org',
|
|
160
|
+
})
|
|
161
|
+
self.assert400(response)
|
|
162
|
+
self.assertEqual(Dataservice.objects.count(), 0)
|
|
163
|
+
|
|
164
|
+
def test_dataservice_api_create_with_unkwown_license(self):
|
|
165
|
+
self.login()
|
|
166
|
+
response = self.post(url_for('api.dataservices'), {
|
|
167
|
+
'title': 'My title',
|
|
168
|
+
'base_api_url': 'https://example.org',
|
|
169
|
+
'license': 'unwkown-license',
|
|
170
|
+
})
|
|
171
|
+
self.assert400(response)
|
|
172
|
+
self.assertEqual(response.json['errors']['license'], ["Unknown reference 'unwkown-license'"])
|
|
173
|
+
self.assertEqual(Dataservice.objects.count(), 0)
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def test_dataservice_api_create_with_unkwown_contact_point(self):
|
|
177
|
+
self.login()
|
|
178
|
+
|
|
179
|
+
response = self.post(url_for('api.dataservices'), {
|
|
180
|
+
'title': 'My title',
|
|
181
|
+
'base_api_url': 'https://example.org',
|
|
182
|
+
'contact_point': '66212433e42ab56639ad516e',
|
|
183
|
+
})
|
|
184
|
+
self.assert400(response)
|
|
185
|
+
self.assertEqual(response.json['errors']['contact_point'], ["Unknown reference '66212433e42ab56639ad516e'"])
|
|
186
|
+
self.assertEqual(Dataservice.objects.count(), 0)
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def test_dataservice_api_create_with_custom_user_or_org(self):
|
|
190
|
+
other = UserFactory()
|
|
191
|
+
other_member = Member(user=other, role='editor')
|
|
192
|
+
other_org = OrganizationFactory(members=[other_member])
|
|
193
|
+
|
|
194
|
+
me = self.login()
|
|
195
|
+
me_member = Member(user=me, role='editor')
|
|
196
|
+
me_org = OrganizationFactory(members=[me_member])
|
|
197
|
+
|
|
198
|
+
response = self.post(url_for('api.dataservices'), {
|
|
199
|
+
'title': 'My title',
|
|
200
|
+
'base_api_url': 'https://example.org',
|
|
201
|
+
'owner': other.id,
|
|
202
|
+
})
|
|
203
|
+
self.assert400(response)
|
|
204
|
+
self.assertEqual(response.json['errors']['owner'], [_("You can only set yourself as owner")])
|
|
205
|
+
self.assertEqual(Dataservice.objects.count(), 0)
|
|
206
|
+
|
|
207
|
+
response = self.post(url_for('api.dataservices'), {
|
|
208
|
+
'title': 'My title',
|
|
209
|
+
'base_api_url': 'https://example.org',
|
|
210
|
+
'organization': other_org.id,
|
|
211
|
+
})
|
|
212
|
+
self.assert400(response)
|
|
213
|
+
self.assertEqual(response.json['errors']['organization'], [_("Permission denied for this organization")])
|
|
214
|
+
self.assertEqual(Dataservice.objects.count(), 0)
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
response = self.post(url_for('api.dataservices'), {
|
|
218
|
+
'title': 'My title',
|
|
219
|
+
'base_api_url': 'https://example.org',
|
|
220
|
+
'owner': me.id,
|
|
221
|
+
})
|
|
222
|
+
self.assert201(response)
|
|
223
|
+
dataservice = Dataservice.objects(id=response.json['id']).first()
|
|
224
|
+
self.assertEqual(dataservice.owner.id, me.id)
|
|
225
|
+
self.assertEqual(dataservice.organization, None)
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
response = self.post(url_for('api.dataservices'), {
|
|
229
|
+
'title': 'My title',
|
|
230
|
+
'base_api_url': 'https://example.org',
|
|
231
|
+
'organization': me_org.id,
|
|
232
|
+
})
|
|
233
|
+
self.assert201(response)
|
|
234
|
+
dataservice = Dataservice.objects(id=response.json['id']).first()
|
|
235
|
+
self.assertEqual(dataservice.owner, None)
|
|
236
|
+
self.assertEqual(dataservice.organization.id, me_org.id)
|
|
@@ -191,8 +191,7 @@ class MembershipAPITest:
|
|
|
191
191
|
user = api.login()
|
|
192
192
|
data = {'comment': 'a comment'}
|
|
193
193
|
|
|
194
|
-
|
|
195
|
-
response = api.post(api_url, data)
|
|
194
|
+
response = api.post(url_for('api.request_membership', org=organization), data)
|
|
196
195
|
assert201(response)
|
|
197
196
|
|
|
198
197
|
organization.reload()
|
|
@@ -209,14 +208,13 @@ class MembershipAPITest:
|
|
|
209
208
|
assert request.handled_by is None
|
|
210
209
|
assert request.refusal_comment is None
|
|
211
210
|
|
|
212
|
-
def
|
|
211
|
+
def test_request_existing_pending_membership_do_not_duplicate_it(self, api):
|
|
213
212
|
user = api.login()
|
|
214
213
|
previous_request = MembershipRequest(user=user, comment='previous')
|
|
215
214
|
organization = OrganizationFactory(requests=[previous_request])
|
|
216
215
|
data = {'comment': 'a comment'}
|
|
217
216
|
|
|
218
|
-
|
|
219
|
-
response = api.post(api_url, data)
|
|
217
|
+
response = api.post(url_for('api.request_membership', org=organization), data)
|
|
220
218
|
assert200(response)
|
|
221
219
|
|
|
222
220
|
organization.reload()
|
|
@@ -233,6 +231,81 @@ class MembershipAPITest:
|
|
|
233
231
|
assert request.handled_by is None
|
|
234
232
|
assert request.refusal_comment is None
|
|
235
233
|
|
|
234
|
+
def test_get_membership_requests(self, api):
|
|
235
|
+
user = api.login()
|
|
236
|
+
applicant = UserFactory(email="thibaud@example.org")
|
|
237
|
+
membership_request = MembershipRequest(user=applicant, comment='test')
|
|
238
|
+
member = Member(user=user, role='admin')
|
|
239
|
+
organization = OrganizationFactory(
|
|
240
|
+
members=[member], requests=[membership_request])
|
|
241
|
+
|
|
242
|
+
response = api.get(url_for('api.request_membership', org=organization))
|
|
243
|
+
assert200(response)
|
|
244
|
+
|
|
245
|
+
assert len(response.json) == 1
|
|
246
|
+
assert response.json[0]['comment'] == 'test'
|
|
247
|
+
assert response.json[0]['user']['email'] == 'thibaud@example.org' # Can see email of applicant
|
|
248
|
+
|
|
249
|
+
def test_only_org_member_can_get_membership_requests(self, api):
|
|
250
|
+
api.login()
|
|
251
|
+
applicant = UserFactory(email="thibaud@example.org")
|
|
252
|
+
membership_request = MembershipRequest(user=applicant, comment='test')
|
|
253
|
+
organization = OrganizationFactory(
|
|
254
|
+
members=[], requests=[membership_request])
|
|
255
|
+
|
|
256
|
+
response = api.get(url_for('api.request_membership', org=organization))
|
|
257
|
+
assert403(response)
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
def test_get_members_with_or_without_email(self, api):
|
|
261
|
+
admin = Member(user=UserFactory(email="admin@example.org"), role='admin', since="2024-04-14")
|
|
262
|
+
editor = Member(user=UserFactory(email="editor@example.org"), role='editor')
|
|
263
|
+
other = UserFactory(email="other@example.org")
|
|
264
|
+
|
|
265
|
+
organization = OrganizationFactory(members=[admin, editor])
|
|
266
|
+
|
|
267
|
+
# Admin can see emails
|
|
268
|
+
api.login(admin.user)
|
|
269
|
+
response = api.get(url_for('api.organization', org=organization))
|
|
270
|
+
assert200(response)
|
|
271
|
+
|
|
272
|
+
members = response.json['members']
|
|
273
|
+
assert len(members) == 2
|
|
274
|
+
assert members[0]['role'] == 'admin'
|
|
275
|
+
assert members[0]['since'] == '2024-04-14T00:00:00+00:00'
|
|
276
|
+
assert members[0]['user']['email'] == 'admin@example.org'
|
|
277
|
+
|
|
278
|
+
assert members[1]['role'] == 'editor'
|
|
279
|
+
assert members[1]['user']['email'] == 'editor@example.org'
|
|
280
|
+
|
|
281
|
+
# Editor can see emails
|
|
282
|
+
api.login(editor.user)
|
|
283
|
+
response = api.get(url_for('api.organization', org=organization))
|
|
284
|
+
assert200(response)
|
|
285
|
+
|
|
286
|
+
members = response.json['members']
|
|
287
|
+
assert len(members) == 2
|
|
288
|
+
assert members[0]['role'] == 'admin'
|
|
289
|
+
assert members[0]['since'] == '2024-04-14T00:00:00+00:00'
|
|
290
|
+
assert members[0]['user']['email'] == 'admin@example.org'
|
|
291
|
+
|
|
292
|
+
assert members[1]['role'] == 'editor'
|
|
293
|
+
assert members[1]['user']['email'] == 'editor@example.org'
|
|
294
|
+
|
|
295
|
+
# Others cannot see emails
|
|
296
|
+
api.login(other)
|
|
297
|
+
response = api.get(url_for('api.organization', org=organization))
|
|
298
|
+
assert200(response)
|
|
299
|
+
|
|
300
|
+
members = response.json['members']
|
|
301
|
+
assert len(members) == 2
|
|
302
|
+
assert members[0]['role'] == 'admin'
|
|
303
|
+
assert members[0]['since'] == '2024-04-14T00:00:00+00:00'
|
|
304
|
+
assert members[0]['user']['email'] is None
|
|
305
|
+
|
|
306
|
+
assert members[1]['role'] == 'editor'
|
|
307
|
+
assert members[1]['user']['email'] is None
|
|
308
|
+
|
|
236
309
|
def test_accept_membership(self, api):
|
|
237
310
|
user = api.login()
|
|
238
311
|
applicant = UserFactory()
|
udata/tests/api/test_user_api.py
CHANGED
|
@@ -4,7 +4,7 @@ from udata.core import storages
|
|
|
4
4
|
from udata.core.user.factories import AdminFactory, UserFactory
|
|
5
5
|
from udata.models import Follow
|
|
6
6
|
from udata.utils import faker
|
|
7
|
-
from udata.tests.helpers import create_test_image
|
|
7
|
+
from udata.tests.helpers import capture_mails, create_test_image
|
|
8
8
|
|
|
9
9
|
from . import APITestCase
|
|
10
10
|
|
|
@@ -153,6 +153,8 @@ class UserAPITest(APITestCase):
|
|
|
153
153
|
|
|
154
154
|
def test_user_api_full_text_search_first_name(self):
|
|
155
155
|
'''It should find users based on first name'''
|
|
156
|
+
self.login(AdminFactory())
|
|
157
|
+
|
|
156
158
|
for i in range(4):
|
|
157
159
|
UserFactory(
|
|
158
160
|
first_name='test-{0}'.format(i) if i % 2 else faker.word())
|
|
@@ -164,6 +166,8 @@ class UserAPITest(APITestCase):
|
|
|
164
166
|
|
|
165
167
|
def test_user_api_full_text_search_last_name(self):
|
|
166
168
|
'''It should find users based on last name'''
|
|
169
|
+
self.login(AdminFactory())
|
|
170
|
+
|
|
167
171
|
for i in range(4):
|
|
168
172
|
UserFactory(
|
|
169
173
|
last_name='test-{0}'.format(i) if i % 2 else faker.word())
|
|
@@ -175,6 +179,8 @@ class UserAPITest(APITestCase):
|
|
|
175
179
|
|
|
176
180
|
def test_user_api_full_text_search_unicode(self):
|
|
177
181
|
'''It should find user with special characters'''
|
|
182
|
+
self.login(AdminFactory())
|
|
183
|
+
|
|
178
184
|
for i in range(4):
|
|
179
185
|
UserFactory(
|
|
180
186
|
first_name='test-{0}'.format(i) if i % 2 else faker.word())
|
|
@@ -189,14 +195,17 @@ class UserAPITest(APITestCase):
|
|
|
189
195
|
|
|
190
196
|
def test_find_users_api_no_match(self):
|
|
191
197
|
'''It should not find user if no match'''
|
|
198
|
+
self.login(AdminFactory())
|
|
192
199
|
UserFactory.create_batch(3)
|
|
193
200
|
|
|
194
201
|
response = self.get(url_for('api.users', q='xxxxxx'))
|
|
195
202
|
self.assert200(response)
|
|
196
203
|
self.assertEqual(len(response.json['data']), 0)
|
|
197
204
|
|
|
198
|
-
def
|
|
205
|
+
def test_users_as_admin(self):
|
|
199
206
|
'''It should provide a list of users'''
|
|
207
|
+
self.login(AdminFactory(email="thibaud@example.org"))
|
|
208
|
+
|
|
200
209
|
user = UserFactory(
|
|
201
210
|
about=faker.paragraph(),
|
|
202
211
|
website=faker.url(),
|
|
@@ -204,14 +213,25 @@ class UserAPITest(APITestCase):
|
|
|
204
213
|
metrics={'datasets': 10, 'followers': 1, 'following': 0, 'reuses': 2})
|
|
205
214
|
response = self.get(url_for('api.users'))
|
|
206
215
|
self.assert200(response)
|
|
207
|
-
|
|
208
|
-
self.assertEqual(
|
|
209
|
-
self.assertEqual(
|
|
210
|
-
self.assertEqual(
|
|
211
|
-
self.assertEqual(
|
|
212
|
-
self.assertEqual(
|
|
213
|
-
self.assertEqual(
|
|
214
|
-
self.assertEqual(
|
|
216
|
+
users = response.json['data']
|
|
217
|
+
self.assertEqual(users[1]['email'], "thibaud@example.org") # Admin user created for login
|
|
218
|
+
self.assertEqual(users[0]['id'], str(user.id))
|
|
219
|
+
self.assertEqual(users[0]['slug'], user.slug)
|
|
220
|
+
self.assertEqual(users[0]['first_name'], user.first_name)
|
|
221
|
+
self.assertEqual(users[0]['last_name'], user.last_name)
|
|
222
|
+
self.assertEqual(users[0]['website'], user.website)
|
|
223
|
+
self.assertEqual(users[0]['about'], user.about)
|
|
224
|
+
self.assertEqual(users[0]['metrics'], user.metrics)
|
|
225
|
+
|
|
226
|
+
def test_users_forbidden(self):
|
|
227
|
+
UserFactory()
|
|
228
|
+
|
|
229
|
+
response = self.get(url_for('api.users'))
|
|
230
|
+
self.assert401(response)
|
|
231
|
+
|
|
232
|
+
self.login()
|
|
233
|
+
response = self.get(url_for('api.users'))
|
|
234
|
+
self.assert403(response)
|
|
215
235
|
|
|
216
236
|
def test_get_user(self):
|
|
217
237
|
'''It should get a user'''
|
|
@@ -335,15 +355,29 @@ class UserAPITest(APITestCase):
|
|
|
335
355
|
{'file': (file, 'test.png')},
|
|
336
356
|
json=False,
|
|
337
357
|
)
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
358
|
+
with capture_mails() as mails:
|
|
359
|
+
response = self.delete(url_for('api.user', user=other_user))
|
|
360
|
+
self.assertEqual(list(storages.avatars.list_files()), [])
|
|
361
|
+
self.assert204(response)
|
|
362
|
+
self.assertEquals(len(mails), 1)
|
|
363
|
+
|
|
341
364
|
other_user.reload()
|
|
342
365
|
response = self.delete(url_for('api.user', user=other_user))
|
|
343
366
|
self.assert410(response)
|
|
344
367
|
response = self.delete(url_for('api.user', user=user))
|
|
345
368
|
self.assert403(response)
|
|
346
369
|
|
|
370
|
+
def test_delete_user_without_notify(self):
|
|
371
|
+
user = AdminFactory()
|
|
372
|
+
self.login(user)
|
|
373
|
+
other_user = UserFactory()
|
|
374
|
+
|
|
375
|
+
with capture_mails() as mails:
|
|
376
|
+
response = self.delete(url_for('api.user', user=other_user, no_mail=True))
|
|
377
|
+
self.assert204(response)
|
|
378
|
+
self.assertEqual(len(mails), 0)
|
|
379
|
+
|
|
380
|
+
|
|
347
381
|
def test_contact_points(self):
|
|
348
382
|
user = AdminFactory()
|
|
349
383
|
self.login(user)
|
udata/tests/plugin.py
CHANGED
|
@@ -192,6 +192,11 @@ class ApiClient(object):
|
|
|
192
192
|
return self.client.put(url, data or {}, *args, **kwargs)
|
|
193
193
|
return self.perform('put', url, data=data or {}, *args, **kwargs)
|
|
194
194
|
|
|
195
|
+
def patch(self, url, data=None, json=True, *args, **kwargs):
|
|
196
|
+
if not json:
|
|
197
|
+
return self.client.patch(url, data or {}, *args, **kwargs)
|
|
198
|
+
return self.perform('patch', url, data=data or {}, *args, **kwargs)
|
|
199
|
+
|
|
195
200
|
def delete(self, url, data=None, *args, **kwargs):
|
|
196
201
|
return self.perform('delete', url, data=data or {}, *args, **kwargs)
|
|
197
202
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: udata
|
|
3
|
-
Version:
|
|
3
|
+
Version: 8.0.1
|
|
4
4
|
Summary: Open data portal
|
|
5
5
|
Home-page: https://github.com/opendatateam/udata
|
|
6
6
|
Author: Opendata Team
|
|
@@ -131,11 +131,25 @@ for publishing udata's roadmap and for building consensus around it.
|
|
|
131
131
|
It is collectively taken care of by members of the
|
|
132
132
|
[OpenDataTeam](https://github.com/opendatateam).
|
|
133
133
|
|
|
134
|
-
[readthedocs-url]: https://udata.readthedocs.io/en/
|
|
134
|
+
[readthedocs-url]: https://udata.readthedocs.io/en/v8.0.1/
|
|
135
135
|
|
|
136
136
|
# Changelog
|
|
137
137
|
|
|
138
|
-
##
|
|
138
|
+
## 8.0.1 (2024-05-28)
|
|
139
|
+
|
|
140
|
+
- Add dataservices in beta [#2986](https://github.com/opendatateam/udata/pull/2986)
|
|
141
|
+
- Remove deprecated `metrics_for` route [#3022](https://github.com/opendatateam/udata/pull/3022)
|
|
142
|
+
- Fix spatial coverage fetching perfs. Need to schedule `compute-geozones-metrics` [#3018](https://github.com/opendatateam/udata/pull/3018)
|
|
143
|
+
- Delete a user without sending mail [#3031](https://github.com/opendatateam/udata/pull/3031)
|
|
144
|
+
- Convert known HVD categories used as theme to keywords [#3014](https://github.com/opendatateam/udata/pull/3014)
|
|
145
|
+
- Allow for series in CSW ISO 19139 DCAT backend [#3028](https://github.com/opendatateam/udata/pull/3028)
|
|
146
|
+
- Add `email` to membership request list API response, add `since` to org members API responses, add `email` to members of org on show org endpoint for org's admins and editors [#3038](https://github.com/opendatateam/udata/pull/3038)
|
|
147
|
+
- Add `resources_downloads` to datasets metrics [#3042](https://github.com/opendatateam/udata/pull/3042)
|
|
148
|
+
- Fix do not override resources extras on admin during update [#3043](https://github.com/opendatateam/udata/pull/3043)
|
|
149
|
+
- Endpoint /users is now protected by admin permissions [#3047](https://github.com/opendatateam/udata/pull/3047)
|
|
150
|
+
- Fix trailing `/` inside `GeoZone` routes not redirecting. Disallow `/` inside `GeoZone` ids [#3045](https://github.com/opendatateam/udata/pull/3045)
|
|
151
|
+
|
|
152
|
+
## 8.0.0 (2024-04-23)
|
|
139
153
|
|
|
140
154
|
- **breaking change** Migrate to Python 3.11 [#2992](https://github.com/opendatateam/udata/pull/2992) [#3021](https://github.com/opendatateam/udata/pull/3021)
|
|
141
155
|
- **breaking change** Fix datetime serialization in extras (return ISO string in JSON). Warning, `ujson` shouldn't be installed anymore on the project to allow `cls` parameter to override the JSONEncoder [#3019](https://github.com/opendatateam/udata/pull/3019)
|