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 Binary files a/ckanext/odsh/i18n/de/LC_MESSAGES/ckanext-odsh.mo and b/ckanext/odsh/i18n/de/LC_MESSAGES/ckanext-odsh.mo differ diff --git a/ckanext/odsh/i18n/de/LC_MESSAGES/ckanext-odsh.po b/ckanext/odsh/i18n/de/LC_MESSAGES/ckanext-odsh.po index b09176f7ebfd5b11c0e4dd8f0f2e3861d4c9a458..4a07dff13b76b13a625f6ead5cad299229b99d1e 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 b8f211afbfa74dfb885195c9d6022e1d6bec1b1c..182ab96d0d48c0ab1780f522d94fbbec47920bc1 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 893d2a6448f901338b316cee8c5b20b39af43432..9b33a5d51641c922e3794c47b4e5e3025296b9c3 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 0000000000000000000000000000000000000000..3bcc18e5deefdf1cbe72134cd1973c1c08152537 --- /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 0000000000000000000000000000000000000000..d778bf814b2e1ca067858547fc7723b44d41af1f --- /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 0000000000000000000000000000000000000000..8f6ed7113289f8c798c22dd1c3335f589991292f --- /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 0000000000000000000000000000000000000000..cbbea780d1fc4db6599dd1a951f5e165d8de99c8 --- /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 0000000000000000000000000000000000000000..155e6d1d624c87095d1b9203ccaf8ce7423a292b --- /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 0000000000000000000000000000000000000000..8ac7615579a61bc7420ad79b54fee408609f15b9 --- /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 0000000000000000000000000000000000000000..d94695c39bbdce33b6d54810375ec8896b95cafc --- /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