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