From b64d9e4402b722a4f640062e97d69f4d004dd21b Mon Sep 17 00:00:00 2001 From: anonymous <anonymous> Date: Tue, 25 Jun 2019 10:03:15 +0200 Subject: [PATCH] ODPSH-31: update layout --- .../odsh/i18n/de/LC_MESSAGES/ckanext-odsh.mo | Bin 8305 -> 8386 bytes .../odsh/i18n/de/LC_MESSAGES/ckanext-odsh.po | 11 +- ckanext/odsh/plugin.py | 142 ++++++++++-------- ckanext/odsh/public/odsh.css | 51 +++++++ ckanext/odsh/templates/datarequests/base.html | 55 +++++++ .../odsh/templates/datarequests/comment.html | 41 +++++ ckanext/odsh/templates/datarequests/show.html | 101 +++++++++++++ .../datarequests/snippets/comment_form.html | 29 ++++ .../datarequests/snippets/comment_item.html | 47 ++++++ .../datarequests/snippets/comments.html | 19 +++ ckanext/odsh/tests/test_datarequest.py | 71 +++++++++ 11 files changed, 505 insertions(+), 62 deletions(-) create mode 100644 ckanext/odsh/templates/datarequests/base.html create mode 100644 ckanext/odsh/templates/datarequests/comment.html create mode 100644 ckanext/odsh/templates/datarequests/show.html create mode 100644 ckanext/odsh/templates/datarequests/snippets/comment_form.html create mode 100644 ckanext/odsh/templates/datarequests/snippets/comment_item.html create mode 100644 ckanext/odsh/templates/datarequests/snippets/comments.html create mode 100644 ckanext/odsh/tests/test_datarequest.py diff --git a/ckanext/odsh/i18n/de/LC_MESSAGES/ckanext-odsh.mo b/ckanext/odsh/i18n/de/LC_MESSAGES/ckanext-odsh.mo index ab0a6177c3cc3782e3ad5f9f36bd1a9e3e1f5af1..98510aaaa8b8077e816b5e300aabaeb12c971117 100644 GIT binary patch delta 2293 zcmez9aLBR#o)F7a1_lO(4h9AW83qQ17#0u@f#+~AFfcPPFwBM03!(H<4h9C0(v?vD zIt~T~AqED9O&kmi{0s~XM>!Z6xEUB2u0rXD91!#0axgHkGB7Z3aWXKlGceRM2yikm zh%+!SNN_?l7(i(oPKZGsoD2+H3=9kroD2+t3=9m(oD2*K3=9mVoD2+-3=9m@pyC^# z>JCBmpXG#DbdwX}u=|`03~USx44*g|7&sXi7=CgxFi0@eGcYi7K_q0j7#IW?7#Nhf zAQqW$F))ZRFfh1rfnCZF%LQ>rDi_4y0;s++E(QiZ1_p*&E(Qis1_p*6E(Qiw1_p*j zTnr4n3=9k>xEL5z7#J9?aWOE6FfcIu=3-!wWnf?s;AUXpt!H3h(Bp>q#D<%JfrEj8 zA&eVhU_3X(qC6<Sgd1W&GdIKsGobV$Zb-<j;f93R4sMXo7#L1K<sWi0FjzA%Fudkw zV31;9U{L3QM4b~414BIz0|SFQ55&R{9tH+oP!RJ#d@_*-;(+Bm5QnYhfrQjHsQSH7 z@iRP-D7*?a_$?2_A)lapCSHj7?7R?hF<yuV)OZ={!9F(Ng}BHPO4~tcXI@B<dq52c zhKeUa>2xTa!^^;+$iTo*2<1=ag+$p5UWmgNK<SlG@l8;5yFlR&N)-EfA#rt#7ZP+= zpbFmdLW1@aF9U-%0|Uc9UPw@C@j-G$8XqLBWbr{Ps^Nopq?M0>L70Jop^Fa^lJoc= zA+&`Ll6cSXLDI<EdOijQO$G)AVSb2!Ek8s-GCu=@90LPG3zWZ@AChQ}@I%tdBYp-3 zc?JfCKTy7m0K{T50Z3}MhVuOcAm#)MKs;6imG6ei*UuAxxO6d8;dTLti?0bl9P&m0 z5?8!}3=B*R3=HCe5R0S)Ar6rjWMGhHU|_HmWMI%^U|<LpWMJ?DIb4u|!GeK-;k+ON z!vsbK1`Z)e2+tITq=Dta;51RsupPo+I3^4U>Z`&Kg%5=p7(j{hy)eW<e}o}E5E6le zl(q;&U7!d=UAzdyAvsWfhX~jLhN&VD{Yyk3*?AX~e^G>iK@F7upNl|(l1~(3pq?m1 zgN-P}fFMywVoDT+ln<GrkX%qD3Q3%eqL3i(f%4~zGB7AJFfgnVWnfTZU|={W3W<V` zP<;Yo5dGp}3=FKG{4WO;P!WUVZ*4J%PaMP`i7rMA;*bt8h(XiEAVujmF^I!2i$Ox} zvlt|e{1<}+v8*^Gaq5ag5}&;|#AD%5ey%tJLp`X(YZZt1e402Uu9t{I;&vTW!wIPT zJ#hwx5C#T@H{y^)>nH)ymn{KFLzNN`3wk9O7>pPg7#2%F9C%FvQjUC+fSCVB0ulmj zk_`3WvY1yAlBmQbL2<&sAS21ZV9UV3;4BFVkw!^K6ikzZ_-LLaBq}yYLJT|zrB6#j ze0o(9;(@nNee6;Yhw@87^vg;?9H1`+D*qW67|f&~ab+dNz@Wpxzz{11iQ6tINWPvb z1+i!zlwJX)H%UQ!yhjQW<d>u%CFmn51_pCb886MiV8Fn@;2{lhaHTXP3cI8sxn*U& zG$d$lNJCt9Pa2Y#K1f4c$SecV$R)$TpuxbvAT0y2z(odPL6Ho^z*RC315e68a>oxD zNLrASg+zsoEF@&}Wg+^f$wJar{SjFP215o0h7Yn3pD4*eg4{w5VzI9r#Gp7i1_mt# z28J3rNKw074&u<0a*)J$M-F1}PdSLg)a4=O#>+!W%!%@lkUT37DLJpngQHZ7;g&q4 zR(d24G3c*61A`?41A~+T1A{XI14D=cB(crdT*<MYi7h8Ju{bqlvMF~nXK-nHdTMb= zYSHHH+{WDeVW~xjx22_}=9T1RCTEmPekrzzH!Q!XI5{IHF+DXeC3W*G@#`D_YQEnr delta 2214 zcmX@)_|c*Mo)F7a1_lO(HU<U;83qOh9~KY~fonJz7?>Ft7;2$(Bb09CU|;|#?S%6C zI2ag&7#J8PaWF9OGcYhL<zQgoW?*303Z)NnK+HeO!N9=Ez`*c|gMopafuWw^0|x_x zI0FO252!)`PKZVsPKZGooD2+H3=9kwoD2+t3=9m;oD2*K3=9mRoD2+-3=9lqQ1J;+ zb&H_-*K$HE+Q|uV*nUn11~vu;hD)3b44e!M3^zF$7$g|#85kZzCH`<SFbFU(FfemL zEE3^jU=U+qU{K=%yOhC}3*r!0E{MSaTo41pxEL7t7#J90xfmEk85kIHxEL5z85kIv zxEL6C85kH=a4|5bFfcG|<6>YCVPIgm&BeeV%fP_!0VH3~z`(%A4e^N#H^d+_Ziof0 zP`)=eL}L^;#O3)=x{@0bQqA0ukm~0K`G|pGJ~sn{H3I{~4sHepDFz0HFWiu*;^$#t z;9+235aEH?qsYU+P_N6tz+k`wad{jM#NrYj1_llW28Jpgh!2~g8oHq3GkG9UwulE} z@Gc&R1NKAt=b`GaK*b;PKpg%Vs{b!k9UCu0Jvb3@^Fj;~;DrRSC@;i?3Q%!<C~X3z zEqNIj6d4#8?4bMvUPu(B@<JS*3#H4T;`LB<?Ys~V_3%QXW-@O*B*+#*73|`L1nGWW z1_o^g28PqTkf8j|3&{n>e2}zZ&Ihr`lMmwXAU*~LVFm_<a6U*#X7fQpsF4qnSZDG< z(!?%41_n(A28IVvK36?IM1cW61A`m`14AH`U%(GZBop}|X=6P<1A{yR1H(xu|0O@f zVrBtI>gEuD@TCPH<|qh2JZ2A-kATW&3qTxN099AtA^>smVgZOlb_zh^>XrZl0}}%S z!xN~+=K>Iiyb)kvkY-?DU=w6u&|_d=P!eQd@B%qpkb%L1fq`L;AOph$Mh1qff{-9i z6NaRX5@AS`wm|90!r+juXILZ*QMgVRk~;SYLmYHc7~+Hb!jPc*0aYg_0#T<U0&$2X zlpiVru^>qVqQ6iCl6~8u{COe_3~CGv3|mAXA$eN_WN$qK!*8epPEm*f@}iK$q$dg~ z56na%iN;+Nk~sZDAweDq<>!bpFeo!HFqDfjFeouFFw7Q(M8Q6&zPnKRi6|s@y@v8X ziZU>Wfb#zjQHW1?#UP1JQw-veP%(%>DPoYKvsnz{@&#hxpkp{721z4l#2|_Cl^7(^ z{SkwNfQUGRuO$xgh?6+T#|#X?;*cm#6lY+l2Nj{&;t&n3;tUKSARmZBQt1b%1}O<h zqS26msI!q^U@&4}U<i_cIH*+u;<Kd^5QA4sKtgOQl)py;k~oh^K%(HZ1OtOD0|Ub+ zQ27fg5)C9FLGCIE@rkb_#KrNF5CaRKbd@B;M=g?f14Z<{2<XZxV~&qzWXa8DAF zZJ$a)qUNO}1A`6&0|So~Bq}YX>LK~qMG9h(FO&|4(uq<KA7@KJQgNdc0|ThUoG8V> zV9vn6uwROS!GM8*;ky*X!5Y$#D6^D?<c<hwNXWEHLp;_i4M{umr6CU7R4)zDxKo;e zL4$#T;gmGQg3r<r3lwD_21d$246KlW<c8%kkhni91Br^)GLWE^lZEJam4&3GVp#?T zLk0$h`LYm?T$F{>CC_Cc_SXNAg&4#u$H1V)z`&p_2Ps;^<RC7skb@+?ZaIj-E94*! zyCw%Qm`@&3LORGpLb66466CG&kSOhxhg3on<ss&*k!N7A1QlfR3=GboSYTFwBsTZW cGdcD%O-|%)*!-H?h<mcG_{Pm|#IJDx0JYu5S^xk5 diff --git a/ckanext/odsh/i18n/de/LC_MESSAGES/ckanext-odsh.po b/ckanext/odsh/i18n/de/LC_MESSAGES/ckanext-odsh.po index b09176f7..4a07dff1 100644 --- a/ckanext/odsh/i18n/de/LC_MESSAGES/ckanext-odsh.po +++ b/ckanext/odsh/i18n/de/LC_MESSAGES/ckanext-odsh.po @@ -419,4 +419,13 @@ msgid "Create New Data Request" msgstr "Neuen Datensatz vorschlagen" msgid "Suggest New Data Request" -msgstr "Datensatz vorschlagen" \ No newline at end of file +msgstr "Datensatz vorschlagen" + +msgid "Add New Comment" +msgstr "Kommentieren" + +msgid "Released" +msgstr "Veröffentlicht" + +msgid "Suggester" +msgstr "Vorschlagende" \ No newline at end of file diff --git a/ckanext/odsh/plugin.py b/ckanext/odsh/plugin.py index b8f211af..182ab96d 100644 --- a/ckanext/odsh/plugin.py +++ b/ckanext/odsh/plugin.py @@ -1,3 +1,4 @@ +from multiline_formatter.formatter import MultilineMessagesFormatter import datetime import json import ckan.plugins as plugins @@ -24,7 +25,7 @@ import ckan.plugins as p import logging import validation import precondition - + import sys log = logging.getLogger(__name__) @@ -39,7 +40,7 @@ log = logging.getLogger(__name__) # @wraps(handle_http_exception) # def ret_val(exception): # print("HEHREHR") -# exc = handle_http_exception(exception) +# exc = handle_http_exception(exception) # return jsonify({'code':exc.code, 'message':exc.description}), exc.code # return ret_val @@ -56,7 +57,7 @@ log = logging.getLogger(__name__) _ = toolkit._ -from multiline_formatter.formatter import MultilineMessagesFormatter + class OdshLogger(MultilineMessagesFormatter): multiline_marker = '...' multiline_fmt = multiline_marker + ' : %(message)s' @@ -79,7 +80,7 @@ class OdshLogger(MultilineMessagesFormatter): self.multiline_fmt % dict(record.__dict__, message=line) for line in splitted ) - output = output.replace('"','\\"') + output = output.replace('"', '\\"') output += endl_marker else: output = self._fmt % record.__dict__ @@ -96,7 +97,7 @@ class OdshLogger(MultilineMessagesFormatter): self.multiline_fmt % dict(record.__dict__, message=line) for index, line in enumerate(record.exc_text.splitlines()) ) - output = output.replace('"','\\"') + output = output.replace('"', '\\"') output += endl_marker except UnicodeError: output += '\n'.join( @@ -141,9 +142,10 @@ def odsh_group_id_selected(selected, group_id): return False -def remove_route(map,routename): + +def remove_route(map, routename): route = None - for i,r in enumerate(map.matchlist): + for i, r in enumerate(map.matchlist): if r.name == routename: route = r @@ -178,27 +180,39 @@ class OdshHarvestPlugin(plugins.SingletonPlugin): def update_config(self, config_): toolkit.add_template_directory(config_, 'harvest_templates') plugins.implements(plugins.IRoutes, inherit=True) + def before_map(self, map): - DATASET_TYPE_NAME='harvest' + DATASET_TYPE_NAME = 'harvest' controller = 'ckanext.odsh.controller:OdshHarvestController' - map.connect('{0}_delete'.format(DATASET_TYPE_NAME), '/' + DATASET_TYPE_NAME + '/delete/:id',controller=controller, action='delete') - map.connect('{0}_refresh'.format(DATASET_TYPE_NAME), '/' + DATASET_TYPE_NAME + '/refresh/:id',controller=controller, - action='refresh') - map.connect('{0}_admin'.format(DATASET_TYPE_NAME), '/' + DATASET_TYPE_NAME + '/admin/:id', controller=controller, action='admin') - map.connect('{0}_about'.format(DATASET_TYPE_NAME), '/' + DATASET_TYPE_NAME + '/about/:id', controller=controller, action='about') - map.connect('{0}_clear'.format(DATASET_TYPE_NAME), '/' + DATASET_TYPE_NAME + '/clear/:id', controller=controller, action='clear') - - map.connect('harvest_job_list', '/' + DATASET_TYPE_NAME + '/{source}/job', controller=controller, action='list_jobs') - map.connect('harvest_job_show_last', '/' + DATASET_TYPE_NAME + '/{source}/job/last', controller=controller, action='show_last_job') - map.connect('harvest_job_show', '/' + DATASET_TYPE_NAME + '/{source}/job/{id}', controller=controller, action='show_job') - map.connect('harvest_job_abort', '/' + DATASET_TYPE_NAME + '/{source}/job/{id}/abort', controller=controller, action='abort_job') - - map.connect('harvest_object_show', '/' + DATASET_TYPE_NAME + '/object/:id', controller=controller, action='show_object') - map.connect('harvest_object_for_dataset_show', '/dataset/harvest_object/:id', controller=controller, action='show_object', ref_type='dataset') + map.connect('{0}_delete'.format(DATASET_TYPE_NAME), '/' + + DATASET_TYPE_NAME + '/delete/:id', controller=controller, action='delete') + map.connect('{0}_refresh'.format(DATASET_TYPE_NAME), '/' + DATASET_TYPE_NAME + '/refresh/:id', controller=controller, + action='refresh') + map.connect('{0}_admin'.format(DATASET_TYPE_NAME), '/' + + DATASET_TYPE_NAME + '/admin/:id', controller=controller, action='admin') + map.connect('{0}_about'.format(DATASET_TYPE_NAME), '/' + + DATASET_TYPE_NAME + '/about/:id', controller=controller, action='about') + map.connect('{0}_clear'.format(DATASET_TYPE_NAME), '/' + + DATASET_TYPE_NAME + '/clear/:id', controller=controller, action='clear') + + map.connect('harvest_job_list', '/' + DATASET_TYPE_NAME + + '/{source}/job', controller=controller, action='list_jobs') + map.connect('harvest_job_show_last', '/' + DATASET_TYPE_NAME + + '/{source}/job/last', controller=controller, action='show_last_job') + map.connect('harvest_job_show', '/' + DATASET_TYPE_NAME + + '/{source}/job/{id}', controller=controller, action='show_job') + map.connect('harvest_job_abort', '/' + DATASET_TYPE_NAME + + '/{source}/job/{id}/abort', controller=controller, action='abort_job') + + map.connect('harvest_object_show', '/' + DATASET_TYPE_NAME + + '/object/:id', controller=controller, action='show_object') + map.connect('harvest_object_for_dataset_show', '/dataset/harvest_object/:id', + controller=controller, action='show_object', ref_type='dataset') org_controller = 'ckanext.harvest.controllers.organization:OrganizationController' - map.connect('{0}_org_list'.format(DATASET_TYPE_NAME), '/organization/' + DATASET_TYPE_NAME + '/' + '{id}', controller=org_controller, action='source_list') + map.connect('{0}_org_list'.format(DATASET_TYPE_NAME), '/organization/' + + DATASET_TYPE_NAME + '/' + '{id}', controller=org_controller, action='source_list') return map def after_map(self, map): @@ -209,13 +223,13 @@ class OdshDCATHarvestPlugin(plugins.SingletonPlugin): plugins.implements(IDCATRDFHarvester, inherit=True) def before_update(self, harvest_object, dataset_dict, temp_dict): - + existing_package_dict = self._get_existing_dataset(harvest_object.guid) new_dataset_extras = Extras(dataset_dict['extras']) if new_dataset_extras.key('modified') and \ - new_dataset_extras.value('modified') < existing_package_dict.get('metadata_modified'): + new_dataset_extras.value('modified') < existing_package_dict.get('metadata_modified'): log.info("Modified date of new dataset is not newer than " - + "the already exisiting dataset, ignoring new one.") + + "the already exisiting dataset, ignoring new one.") dataset_dict.clear() def _get_existing_dataset(self, guid): @@ -311,25 +325,26 @@ class OdshPlugin(plugins.SingletonPlugin, DefaultTranslation, DefaultDatasetForm if p.toolkit.asbool(config.get('ckanext.dcat.enable_rdf_endpoints', True)): remove_route(map, 'dcat_catalog') map.connect('dcat_catalog', - config.get('ckanext.dcat.catalog_endpoint', '/catalog.{_format}'), - controller='ckanext.odsh.controller:OdshDCATController', action='read_catalog', - requirements={'_format': 'xml|rdf|n3|ttl|jsonld'}) + config.get('ckanext.dcat.catalog_endpoint', + '/catalog.{_format}'), + controller='ckanext.odsh.controller:OdshDCATController', action='read_catalog', + requirements={'_format': 'xml|rdf|n3|ttl|jsonld'}) # with SubMapper(map, controller='ckanext.odsh.controller:OdshApiController') as m: # m.connect('/catalog2', action='read_catalog') - - # /api ver 3 or none with matomo GET_POST = dict(method=['GET', 'POST']) with SubMapper(map, controller='ckanext.odsh.controller:OdshApiController', path_prefix='/api{ver:/3|}', ver='/3') as m: - m.connect('/action/{logic_function}', action='action', conditions=GET_POST) + m.connect('/action/{logic_function}', + action='action', conditions=GET_POST) with SubMapper(map, controller='ckanext.odsh.controller:OdshFeedController') as m: m.connect('/feeds/custom.atom', action='custom') with SubMapper(map, controller='ckanext.odsh.controller:OdshPackageController') as m: - m.connect('new_view', '/dataset/{id}/resource/{resource_id}/new_view', action='edit_view', ckan_icon='pencil-square-o') + m.connect('new_view', '/dataset/{id}/resource/{resource_id}/new_view', + action='edit_view', ckan_icon='pencil-square-o') with SubMapper(map, controller='ckanext.odsh.controller:OdshGroupController') as m: m.connect('organizations_index', '/organization', action='index') @@ -338,7 +353,8 @@ class OdshPlugin(plugins.SingletonPlugin, DefaultTranslation, DefaultDatasetForm with SubMapper(map, controller='ckanext.odsh.controller:OdshUserController') as m: m.connect('user_index', '/user', action='index') m.connect('/user/edit', action='edit') - m.connect('user_edit', '/user/edit/{id:.*}', action='edit', ckan_icon='cog') + m.connect( + 'user_edit', '/user/edit/{id:.*}', action='edit', ckan_icon='cog') m.connect('user_delete', '/user/delete/{id}', action='delete') m.connect('/user/reset/{id:.*}', action='perform_reset') m.connect('/user/reset', action='request_reset') @@ -350,6 +366,10 @@ class OdshPlugin(plugins.SingletonPlugin, DefaultTranslation, DefaultDatasetForm m.connect('/user/logged_out_redirect', action='logged_out_page') m.connect('user_datasets', '/user/{id:.*}', action='read', ckan_icon='sitemap') + + map.connect('comment_datarequest', '/datarequest/{id}', + controller='ckanext.datarequests.controllers.ui_controller:DataRequestsUI', + action='comment', conditions=dict(method=['GET', 'POST']), ckan_icon='comment') return map def dataset_facets(self, facets_dict, package_type): @@ -372,7 +392,7 @@ class OdshPlugin(plugins.SingletonPlugin, DefaultTranslation, DefaultDatasetForm 'groups': _('Kategorie')}) def _update_schema(self, schema): - for field in ['title', 'notes','license_id']: + for field in ['title', 'notes', 'license_id']: schema.update({field: [toolkit.get_converter('not_empty')]}) for i, item in enumerate(schema['tags']['name']): @@ -394,10 +414,11 @@ class OdshPlugin(plugins.SingletonPlugin, DefaultTranslation, DefaultDatasetForm toolkit.get_converter('validate_licenseAttributionByText'), ] }) - schema.update({'__extras': [toolkit.get_converter('odsh_validate_extras')] }) + schema.update( + {'__extras': [toolkit.get_converter('odsh_validate_extras')]}) - ## only to make sure the spatial field is there for validation - # schema.update({'spatial': [toolkit.get_converter('convert_from_extras')]}) + # only to make sure the spatial field is there for validation + # schema.update({'spatial': [toolkit.get_converter('convert_from_extras')]}) def create_package_schema(self): schema = super(OdshPlugin, self).create_package_schema() @@ -430,7 +451,7 @@ class OdshPlugin(plugins.SingletonPlugin, DefaultTranslation, DefaultDatasetForm # use several daterange queries agains temporal_start and temporal_end field # TODO: use field of type date_range in solr index instead def before_search(self, search_params): - search_params['facet.mincount']=0 + search_params['facet.mincount'] = 0 extras = search_params.get('extras') print(search_params) if not extras: @@ -439,8 +460,8 @@ class OdshPlugin(plugins.SingletonPlugin, DefaultTranslation, DefaultDatasetForm fq = search_params['fq'] - start_date=None - end_date=None + start_date = None + end_date = None try: start_date = odsh_helpers.extend_search_convert_local_to_utc_timestamp( extras.get('ext_startdate')) @@ -462,7 +483,6 @@ class OdshPlugin(plugins.SingletonPlugin, DefaultTranslation, DefaultDatasetForm do_enclosing_query = False end_date = '*' - start_query = '+extras_temporal_start:[{start_date} TO {end_date}]'.format( start_date=start_date, end_date=end_date) @@ -480,37 +500,37 @@ class OdshPlugin(plugins.SingletonPlugin, DefaultTranslation, DefaultDatasetForm enclosing_query = ' OR ({enclosing_query_start} AND {enclosing_query_end})'.format( enclosing_query_start=enclosing_query_start, enclosing_query_end=enclosing_query_end) - if end_date is '*': open_end_query = '(*:* NOT extras_temporal_end:[* TO *])' else: open_end_query = '((*:* NOT extras_temporal_end:[* TO *]) AND extras_temporal_start:[* TO {end_date}])'.format( - end_date=end_date) + end_date=end_date) fq = u'{fq} ({start_query} OR {end_query} {enclosing_query} OR {open_end_query})'.format( fq=fq, start_query=start_query, end_query=end_query, enclosing_query=enclosing_query, open_end_query=open_end_query) - search_params['fq'] = fq return search_params - scores = [ ['0OL'], ['0OL','1RE'], ['0OL','1RE','2OF'], ['0OL','1RE','2OF','3URI'], ['0OL','1RE','2OF','3URI','4LD']] + scores = [['0OL'], ['0OL', '1RE'], ['0OL', '1RE', '2OF'], [ + '0OL', '1RE', '2OF', '3URI'], ['0OL', '1RE', '2OF', '3URI', '4LD']] + def map_qa_score(self, dict_pkg): if 'validated_data_dict' in dict_pkg and 'openness_score' in dict_pkg['validated_data_dict']: - d = json.loads(dict_pkg['validated_data_dict']) - score = -1 - for r in d['resources']: - if 'qa' in r: - i = r['qa'].find('openness_score') - s = int(r['qa'][i+17]) - if s > score: - score=s - if score > 0: - dict_pkg['openness']=OdshPlugin.scores[score-1] - - - #@precondition.not_on_slave + d = json.loads(dict_pkg['validated_data_dict']) + score = -1 + for r in d['resources']: + if 'qa' in r: + i = r['qa'].find('openness_score') + s = int(r['qa'][i+17]) + if s > score: + score = s + if score > 0: + dict_pkg['openness'] = OdshPlugin.scores[score-1] + + # @precondition.not_on_slave + def before_index(self, dict_pkg): # make special date fields solr conform fields = ["issued", "temporal_start", "temporal_end"] @@ -518,11 +538,11 @@ class OdshPlugin(plugins.SingletonPlugin, DefaultTranslation, DefaultDatasetForm field = 'extras_' + field if field in dict_pkg and dict_pkg[field]: d = parse(dict_pkg[field]) - dict_pkg[field] = '{0.year:04d}-{0.month:02d}-{0.day:02d}T00:00:00Z'.format(d) + dict_pkg[field] = '{0.year:04d}-{0.month:02d}-{0.day:02d}T00:00:00Z'.format( + d) # if 'res_format' in dict_pkg: # dict_pkg['res_format']=[e.lower() for e in dict_pkg['res_format']] self.map_qa_score(dict_pkg) return dict_pkg - diff --git a/ckanext/odsh/public/odsh.css b/ckanext/odsh/public/odsh.css index 893d2a64..9b33a5d5 100644 --- a/ckanext/odsh/public/odsh.css +++ b/ckanext/odsh/public/odsh.css @@ -1979,4 +1979,55 @@ p.package-info-categorie .datarequest-item-autor-name { padding-left: 4px; +} + +.comments-heading{ + color: black; + font-weight: normal; + border-top: 2px solid #DBDBDB; + padding-top:10px; +} + +.odsh-comment-wrapper{ + padding-left: 0px; + max-width: 400px; +} + +.odsh-comment-wrapper .controls{ + margin-left: 0px; +} + +.comment-author +{ + font-size:13px; + color: black; + text-decoration: underline; + padding-right: 4px; + border-right: 1px solid; +} + +.comment-header-text .icon-comment{ + font-size:13px; +} + +.comment-date{ + font-size:13px; + color: black; +} + +.odsh-comment-content +{ + font-size:13px; +} + +.datarequest-info.table, +.datarequest-info.table th, +.datarequest-info.table td +{ + border:none; +} + +.datarequest .additional-info{ + font-weight: normal; + font-size: 13px; } \ No newline at end of file diff --git a/ckanext/odsh/templates/datarequests/base.html b/ckanext/odsh/templates/datarequests/base.html new file mode 100644 index 00000000..3bcc18e5 --- /dev/null +++ b/ckanext/odsh/templates/datarequests/base.html @@ -0,0 +1,55 @@ +{% extends "page.html" %} + +{% block styles %} + {{ super() }} + <link rel="stylesheet" href="/datarequests.css" /> +{% endblock %} + +{% block subtitle %} +{% endblock %} + +{% block breadcrumb_content %} + <li class="active">{% link_for _('Data Requests'), controller='ckanext.datarequests.controllers.ui_controller:DataRequestsUI', action='index' %}</li> +{% endblock %} + + {% block main_content %} + + {% block flash %} + {{ super() }} + {% endblock %} + + {% block toolbar %} + {{ super() }} + {% endblock %} + + <div class="datarequest row wrapper{% block wrapper_class %}{% endblock %}{% if self.secondary()|trim == '' %} no-nav{% endif %} is-table-row"> + {# + The pre_primary block can be used to add content to before the + rendering of the main content columns of the page. + #} + {% block pre_primary %} + {% endblock %} + + + {% block primary %} + <div class="primary span9"> + {% block primary_content %} + {{ super() }} + {% endblock %} + </div> + {% endblock %} + + {% block secondary %} + <aside class="secondary span3"> + {% block secondary_content %} + {{ super() }} + {% endblock %} + </aside> + {% endblock %} + + </div> + {% block pre_wrap %} + {% endblock %} + {% endblock %} + </div> +</div> diff --git a/ckanext/odsh/templates/datarequests/comment.html b/ckanext/odsh/templates/datarequests/comment.html new file mode 100644 index 00000000..d778bf81 --- /dev/null +++ b/ckanext/odsh/templates/datarequests/comment.html @@ -0,0 +1,41 @@ +{% extends "datarequests/show.html" %} + +{% block breadcrumb_content %} + {{ super() }} +{% endblock %} + +{% block content_action %} +{% endblock %} + +{% block content_primary_nav %} +{% endblock %} + +{% block subtitle %} +{% endblock %} + +{% block primary_content_inner %} + {% if h.check_access('update_datarequest', {'id':datarequest_id }) %} + {% link_for _('Manage'), controller='ckanext.datarequests.controllers.ui_controller:DataRequestsUI', action='update', id=datarequest_id, class_='btn btn-default', icon='wrench' %} + {% endif %} + + {% if h.check_access('close_datarequest', {'id':datarequest_id }) and not c.datarequest.closed %} + {% link_for _('Close'), controller='ckanext.datarequests.controllers.ui_controller:DataRequestsUI', action='close', id=datarequest_id, class_='btn btn-danger', icon='lock' %} + {% endif %} + + {% snippet "datarequests/snippets/comments.html", comments=c.comments, datarequest=c.datarequest, errors=c.errors, errors_summary=c.errors_summary, updated_comment=c.updated_comment %} + + {% if h.check_access('comment_datarequest', {'id':c.datarequest.id }) %} + <h2 class='comments-heading'>{{_('Add New Comment')}}:</h2> + <div > + + {% set create_comment_error = c.updated_comment is defined and c.updated_comment.id == '' %} + + {% if create_comment_error %} + <a name="comment_focus"></a> + {% endif %} + + {% snippet "datarequests/snippets/comment_form.html", datarequest=c.datarequest, errors=c.errors, errors_summary=c.errors_summary, offering=c.offering, initial_text=c.updated_comment.comment if create_comment_error, focus=create_comment_error, current_user=c.userobj %} + </div> + {% endif %} + +{% endblock %} \ No newline at end of file diff --git a/ckanext/odsh/templates/datarequests/show.html b/ckanext/odsh/templates/datarequests/show.html new file mode 100644 index 00000000..8f6ed711 --- /dev/null +++ b/ckanext/odsh/templates/datarequests/show.html @@ -0,0 +1,101 @@ +{% extends "datarequests/base.html" %} + +{% block title %}{{_('Data Request')}} {{c.datarequest.get('title', '')}}{% endblock %} + +{% set datarequest_id = c.datarequest.get('id') %} + +{% block breadcrumb_content %} + <li>{% link_for _('Data Requests'), controller='ckanext.datarequests.controllers.ui_controller:DataRequestsUI', action='index' %}</li> + <li>{% link_for c.datarequest.get('title'), controller='ckanext.datarequests.controllers.ui_controller:DataRequestsUI', action='show', id=datarequest_id %}</li> +{% endblock %} + +{% block content_action %} + + {% if h.check_access('update_datarequest', {'id':datarequest_id }) %} + {% link_for _('Manage'), controller='ckanext.datarequests.controllers.ui_controller:DataRequestsUI', action='update', id=datarequest_id, class_='btn btn-default', icon='wrench' %} + {% endif %} + + {% if h.check_access('close_datarequest', {'id':datarequest_id }) and not c.datarequest.closed %} + {% link_for _('Close'), controller='ckanext.datarequests.controllers.ui_controller:DataRequestsUI', action='close', id=datarequest_id, class_='btn btn-danger', icon='lock' %} + {% endif %} + +{% endblock %} + +{% block content_primary_nav %} + {{ h.build_nav_icon('show_datarequest', _('Data Request'), id=datarequest_id) }} +{% endblock %} + +{% block secondary_content %} +<section class="additional-info"> + {% block package_additional_info %} + <div>{{ _('Released') }}: {{ h.odsh_render_datetime(c.datarequest.open_time) }}</div> + <div>{{ _('Suggester') }}: {{ c.datarequest.user['display_name'] if c.datarequest.user else _('None') }}</div> + {#<td class="dataset-details" title="{{ c.datarequest.close_time }}">{{ h.time_ago_from_timestamp(c.datarequest.close_time) if c.datarequest.close_time else _('Not closed yet') }}</td>#} + <div >{{ _('Status') }}: + <div class="dataset-details"> + {% if c.datarequest.get('closed', False) %} + <div class="datarequest-label label-closed"> + {% trans %}Closed{% endtrans %} + </div> + {% else %} + <div class="label label-open"> + {% trans %}Open{% endtrans %} + </div> + {% endif %} + </div> + {#{% if c.datarequest.closed %} + <tr> + <th scope="row" class="dataset-label">{{ _('Accepted Dataset') }}</th> + <td class="dataset-details"> + {% if c.datarequest.accepted_dataset %} + {% link_for c.datarequest.accepted_dataset['title'], controller='package', action='read', id=c.datarequest.accepted_dataset.get('id') %} + {% else %} + {{ _('None') }} + {% endif %} + </td> + </tr> + {% endif %} + #} + <div class='comment-count-wrapper'><i class="icon-comment fa fa-comment"></i> {{ h.get_comments_number(c.datarequest.get('id', '')) }}</span> </div> + {% endblock %} +</section> +{% endblock %} + +{% block primary_content_inner %} + {% if c.datarequest.closed %} + <span class="uppercase label label-closed pull-right"> + <i class="icon-lock fa fa-lock"></i> + {{ _('Closed') }} + </span> + {% else %} + <span class="uppercase label label-open pull-right"> + <i class="icon-unlock fa fa-unlock"></i> + {{ _('Open') }} + </span> + {% endif %} + + <h1 class="{% block page_heading_class %}page-heading{% endblock %}">{% block page_heading %}{{ c.datarequest.get('title') }}{% endblock %}</h1> + + {% block datarequest_description %} + {% if c.datarequest.get('description') %} + <div class="notes embedded-content"> + {{ h.render_markdown(c.datarequest.get('description')) }} + </div> + {% endif %} + {% endblock %} + + {% block datarequest_additional_info %} + {% snippet "datarequests/snippets/additional_info.html", datarequest=c.datarequest %} + {% endblock %} + +{% if c.comments %} +{% for comment in c.comments %} +{% snippet "datarequests/snippets/comment_item.html", comment=c.comment, datarequest=c.datarequest, errors=c.errors, errors_summary=c.errors_summary, updated_comment=c.updated_comment %} +{% endfor %} +{% else %} +<p class="empty"> +{{ _('This data request has not been commented yet') }} +</p> +{% endif %} + +{% endblock %} \ No newline at end of file diff --git a/ckanext/odsh/templates/datarequests/snippets/comment_form.html b/ckanext/odsh/templates/datarequests/snippets/comment_form.html new file mode 100644 index 00000000..cbbea780 --- /dev/null +++ b/ckanext/odsh/templates/datarequests/snippets/comment_form.html @@ -0,0 +1,29 @@ +{% import 'macros/form.html' as form %} +{% resource "datarequest/edit_comment.js" %} + +<form class="dataset-form {{ 'comment-edit-form' if comment_id else 'odsh-comment-wrapper' }} {{ 'hide' if comment_id and not (focus and errors) }} form-horizontal" id="comment-form{{ '-' + comment_id if comment_id }}" method="post" data-module="basic-form" action enctype="multipart/form-data"> + + + {% if focus %} + {% block errors %}{{ form.errors(errors_summary) }}{% endblock %} + {% endif %} + + + <input type="hidden" name="datarequest-id" value="{{ datarequest.get('id', '') }}" /> + <input type="hidden" name="comment-id" value="{{ comment_id if comment_id }}" /> + + <div class="controls control-full control-large control-group {{ 'error' if errors and errors.get('Comment') and focus }} editor"> + {% set markdown_tooltip = "<pre><p>__Bold text__ or _italic text_</p><p># title<br>## secondary title<br>### etc</p><p>* list<br>* of<br>* items</p><p>http://auto.link.ed/</p></pre><p><b><a href='http://daringfireball.net/projects/markdown/syntax' target='_blank'>Full markdown syntax</a></b></p><p class='muted'><b>Please note:</b> HTML tags are stripped out for security reasons</p>" %} + <textarea name="comment" cols="20" rows="6" placeholder="{{ _('Add a new Comment') if not comment_id }}">{{ initial_text }}</textarea> + </div> + + <div class="comment-form-actions"> + {% if comment_id %} + <button id="comment-discard-{{ comment_id }}" class="btn btn-danger" name="discard">{{ _('Cancel') }}</button> + <button class="btn btn-primary" type="submit" name="update">{{ _('Update Comment') }}</button> + {% else %} + <button class="btn btn-primary btn-arrow-right" type="submit" name="add">{{ _('Add New Comment') }}</button> + {% endif %} + </div> + +</form> \ No newline at end of file diff --git a/ckanext/odsh/templates/datarequests/snippets/comment_item.html b/ckanext/odsh/templates/datarequests/snippets/comment_item.html new file mode 100644 index 00000000..155e6d1d --- /dev/null +++ b/ckanext/odsh/templates/datarequests/snippets/comment_item.html @@ -0,0 +1,47 @@ +{% set focus = updated_comment is not none and updated_comment.id == comment.id %} +{% set can_update = h.check_access('update_datarequest_comment', {'id':comment.id }) %} + +{% if focus %} + <a name="comment_focus"></a> +{% endif %} + +<div class="odsh-comment-wrapper"> + {# <a href="{{ h.url_for(controller='user', action='read', id=comment.user.get('name')) }}" + class="comment-avatar"> + {{ h.gravatar(comment.user.get('email_hash'), 48) }} + </a> + #} + <div class=""> + <div class="odsh-comment-header"> + <div class="comment-actions"> + {# + {% if h.check_access('delete_datarequest_comment', {'id':comment.id }) %} + <div class="comment-action"> + {% set locale = h.dump_json({'content': _('Are you sure you want to delete this comment?')}) %} + <a class="subtle-btn" id="delete-comment-{{ comment.id }}" href="{% url_for controller='ckanext.datarequests.controllers.ui_controller:DataRequestsUI', action='delete_comment', datarequest_id=datarequest.id, comment_id=comment.id %}" data-module="confirm-action" data-module-i18n="{{ locale }}"><i class="icon-remove fa fa-times"></i></a> + </div> + {% endif %} + {% if can_update %} + <div class="comment-action" id="edit-button"> + <button class="subtle-btn" id="update-comment-{{ comment.id }}" href=""><i class="icon-pencil fa fa-pencil"></i></button> + </div> + {% endif %} + #} + <div class="comment-header-text"> + <i class="icon-comment fa fa-comment"></i> + <a href="{{ h.url_for(controller='user', action='read', id=comment.user.get('name')) }}" class="comment-author">{{ comment.user.get('display_name') }}</a> + <span class='comment-date' title="{{comment.time}}">{{ h.odsh_render_datetime(comment.time).lower() }}</span> + </div> + </div> + </div> + + <div class="odsh-comment-content {{ 'hide' if focus and errors }}" id="comment-{{ comment.id }}"> + {{ h.render_markdown(comment.comment|safe) }} + </div> + + {% if can_update %} + {% snippet "datarequests/snippets/comment_form.html", comment_id=comment.id, datarequest=datarequest, errors=errors, errors_summary=errors_summary, initial_text=updated_comment.comment if focus else comment.comment, focus=focus %} + {% endif %} + + </div> +</div> \ No newline at end of file diff --git a/ckanext/odsh/templates/datarequests/snippets/comments.html b/ckanext/odsh/templates/datarequests/snippets/comments.html new file mode 100644 index 00000000..8ac76155 --- /dev/null +++ b/ckanext/odsh/templates/datarequests/snippets/comments.html @@ -0,0 +1,19 @@ +<h2 class="page-heading"> + {% block page_heading %} + {{datarequest.title}} + {% endblock %} +</h2> + +{{ h.render_markdown(h.get_translated(datarequest, 'description')) }} + +<h2 class='comments-heading'>{{_('Comments')}}:</h2> + +{% if comments %} + {% for comment in comments %} + {% snippet "datarequests/snippets/comment_item.html", comment=comment, datarequest=datarequest, errors=errors, errors_summary=errors_summary, updated_comment=updated_comment %} + {% endfor %} +{% else %} + <p class="empty"> + {{ _('This data request has not been commented yet') }} + </p> +{% endif %} \ No newline at end of file diff --git a/ckanext/odsh/tests/test_datarequest.py b/ckanext/odsh/tests/test_datarequest.py new file mode 100644 index 00000000..d94695c3 --- /dev/null +++ b/ckanext/odsh/tests/test_datarequest.py @@ -0,0 +1,71 @@ + +from ckanext.odsh.tests.test_helpers import AppProxy +import ckanext.odsh.tests.test_helpers as testhelpers +import ckan.tests.factories as factories +import uuid +import pdb +from ckanext.odsh.tests.harvest_sever_mock import HarvestServerMock +import ckanext.odsh.tests.harvest_sever_mock as harvest_sever_mock +import subprocess +import re + +markdown = \ + """ +Lorem markdownum supplex iniquis, nec nostram nam conde tympana, deae Mutinae +regna sepulcro; morae arces quae, pia? Rates Circe, quandoquidem Ausoniae, me, +cacumine apta, saevus abductas navigiis. Sacri ostendit *ad anas* amores nostras +[currebam celeres], milia gaudet eripitur superest circumque auras, [nec]. Si +haurit geminis agendum profana lacertis infamis? + +> Dedit potuit perenni nesciet flumine. Et sui **ibis** mihi supponat, flamina +> mihi rogos, deus manum ora tenebras. Acta nec dominus aenum, haud de ripa +> instabilemque amnis erat nam Patraeque parabat quod membra quamquam. +""" + + +class TestDatarequest: + + def test_nologin_cannot_create_request(self): + pass + + def _create_request(self): + guid = str(uuid.uuid4()) + self._get_app().login() + response = self.app.get('/datarequest/new') + form = response.forms[0] + title = 'datarequest_' + guid + form['title'] = title + form['description'] = markdown + final_response = self.app.submit_form(form) + + id = re.search( + '/datarequest/comment/([a-zA-Z0-9\-]*)">', final_response.body).group(1) + return id + + def test_create_datarequest(self): + # Act + id = self._create_request() + + # Assert + response = self.app.get('/datarequest') + assert id in response + + def test_comment_datarequest(self): + # Arrange + id = self._create_request() + guid = str(uuid.uuid4()) + + # Act + response = self.app.get('/datarequest/comment/'+id) + form = response.forms[0] + form['comment'] = markdown + guid + final_response = self.app.submit_form(form) + + # Assert + assert guid in final_response + + def _get_app(self): + if not hasattr(self, 'app'): + app = AppProxy() + self.app = app + return self.app -- GitLab