Merge branch '13-clean-up-before-2.0' into 2.0-dataset-sources
This commit is contained in:
commit
96e1cec1ac
28
README.rst
28
README.rst
|
@ -94,32 +94,10 @@ The commands should be run with the pyenv activated and refer to your sites conf
|
||||||
|
|
||||||
paster --plugin=ckanext-harvest harvester sources --config=mysite.ini
|
paster --plugin=ckanext-harvest harvester sources --config=mysite.ini
|
||||||
|
|
||||||
Authorization Profiles
|
Authorization
|
||||||
======================
|
=============
|
||||||
|
|
||||||
Starting from CKAN 1.6.1, the harvester extension offers the ability to use
|
TODO
|
||||||
different authorization profiles. These can be defined in your ini file as::
|
|
||||||
|
|
||||||
ckan.harvest.auth.profile = <profile_name>
|
|
||||||
|
|
||||||
The two available profiles right now are:
|
|
||||||
|
|
||||||
* `default`: This is the default profile, the same one that this extension has
|
|
||||||
used historically. Basically, only sysadmins can manage anything related to
|
|
||||||
harvesting, including creating and editing harvest sources or running harvest
|
|
||||||
jobs.
|
|
||||||
|
|
||||||
* `publisher`: When using this profile, sysadmins can still perform any
|
|
||||||
harvesting related action, but in addition, users belonging to a publisher
|
|
||||||
(with role `admin`) can manage and run their own harvest sources and jobs.
|
|
||||||
Note that this requires CKAN core to also use the `publisher` authorization
|
|
||||||
profile, i.e you will also need to add::
|
|
||||||
|
|
||||||
ckan.auth.profile = publisher
|
|
||||||
|
|
||||||
To know more about the CKAN publisher auth profile, visit:
|
|
||||||
|
|
||||||
http://oldwiki.ckan.org/Working_with_the_publisher_auth_profile
|
|
||||||
|
|
||||||
|
|
||||||
The CKAN harvester
|
The CKAN harvester
|
||||||
|
|
|
@ -11,6 +11,9 @@ import ckan.new_authz
|
||||||
|
|
||||||
from ckan.controllers.group import GroupController
|
from ckan.controllers.group import GroupController
|
||||||
|
|
||||||
|
from ckanext.harvest.plugin import DATASET_TYPE_NAME
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from collections import OrderedDict # 2.7
|
from collections import OrderedDict # 2.7
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
@ -39,7 +42,7 @@ class OrganizationController(GroupController):
|
||||||
except p.toolkit.NotAuthorized:
|
except p.toolkit.NotAuthorized:
|
||||||
abort(401, p.toolkit._('Unauthorized to read group %s') % id)
|
abort(401, p.toolkit._('Unauthorized to read group %s') % id)
|
||||||
|
|
||||||
self._read(id, limit, dataset_type='harvest_source')
|
self._read(id, limit, dataset_type=DATASET_TYPE_NAME)
|
||||||
return render('source/org_source_list.html')
|
return render('source/org_source_list.html')
|
||||||
|
|
||||||
def _read(self, id, limit, dataset_type=None):
|
def _read(self, id, limit, dataset_type=None):
|
||||||
|
|
|
@ -4,19 +4,13 @@ from lxml.etree import XMLSyntaxError
|
||||||
from pylons.i18n import _
|
from pylons.i18n import _
|
||||||
|
|
||||||
from ckan import model
|
from ckan import model
|
||||||
from ckan.model.group import Group
|
|
||||||
|
|
||||||
import ckan.lib.helpers as h, json
|
|
||||||
from ckan.lib.base import BaseController, c, g, request, \
|
|
||||||
response, session, render, config, abort, redirect
|
|
||||||
|
|
||||||
from ckan.lib.navl.dictization_functions import DataError
|
|
||||||
from ckan.logic import NotFound, ValidationError, get_action, NotAuthorized
|
|
||||||
from ckanext.harvest.plugin import DATASET_TYPE_NAME
|
|
||||||
from ckanext.harvest.logic.schema import harvest_source_form_to_db_schema
|
|
||||||
|
|
||||||
from ckan.lib.helpers import Page,pager_url
|
|
||||||
import ckan.plugins as p
|
import ckan.plugins as p
|
||||||
|
import ckan.lib.helpers as h, json
|
||||||
|
from ckan.lib.base import BaseController, c, \
|
||||||
|
response, render, abort, redirect
|
||||||
|
|
||||||
|
from ckanext.harvest.plugin import DATASET_TYPE_NAME
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
@ -29,211 +23,29 @@ class ViewController(BaseController):
|
||||||
|
|
||||||
super(ViewController,self).__before__(action, **params)
|
super(ViewController,self).__before__(action, **params)
|
||||||
|
|
||||||
#TODO: remove
|
|
||||||
c.publisher_auth = (config.get('ckan.harvest.auth.profile',None) == 'publisher')
|
|
||||||
|
|
||||||
c.dataset_type = DATASET_TYPE_NAME
|
c.dataset_type = DATASET_TYPE_NAME
|
||||||
|
|
||||||
def _get_publishers(self):
|
|
||||||
groups = None
|
|
||||||
user = model.User.get(c.user)
|
|
||||||
if c.publisher_auth:
|
|
||||||
if user.sysadmin:
|
|
||||||
groups = Group.all(group_type='publisher')
|
|
||||||
elif c.userobj:
|
|
||||||
groups = c.userobj.get_groups('publisher')
|
|
||||||
else: # anonymous user shouldn't have access to this page anyway.
|
|
||||||
groups = []
|
|
||||||
|
|
||||||
# Be explicit about which fields we make available in the template
|
|
||||||
groups = [ {
|
|
||||||
'name': g.name,
|
|
||||||
'id': g.id,
|
|
||||||
'title': g.title,
|
|
||||||
} for g in groups ]
|
|
||||||
|
|
||||||
return groups
|
|
||||||
|
|
||||||
|
|
||||||
def index(self):
|
|
||||||
context = {'model':model, 'user':c.user,'session':model.Session}
|
|
||||||
try:
|
|
||||||
# Request all harvest sources
|
|
||||||
c.sources = get_action('harvest_source_list')(context,{})
|
|
||||||
except NotAuthorized,e:
|
|
||||||
abort(401,self.not_auth_message)
|
|
||||||
|
|
||||||
if c.publisher_auth:
|
|
||||||
c.sources = sorted(c.sources,key=lambda source : source['publisher_title'])
|
|
||||||
|
|
||||||
c.status = config.get('ckan.harvest.status')
|
|
||||||
|
|
||||||
return render('index.html')
|
|
||||||
|
|
||||||
def new(self,data = None,errors = None, error_summary = None):
|
|
||||||
|
|
||||||
if ('save' in request.params) and not data:
|
|
||||||
return self._save_new()
|
|
||||||
|
|
||||||
data = data or {}
|
|
||||||
errors = errors or {}
|
|
||||||
error_summary = error_summary or {}
|
|
||||||
|
|
||||||
try:
|
|
||||||
context = {'model':model, 'user':c.user}
|
|
||||||
harvesters_info = get_action('harvesters_info_show')(context,{})
|
|
||||||
except NotAuthorized,e:
|
|
||||||
abort(401,self.not_auth_message)
|
|
||||||
|
|
||||||
vars = {'data': data, 'errors': errors, 'error_summary': error_summary, 'harvesters': harvesters_info}
|
|
||||||
|
|
||||||
c.groups = self._get_publishers()
|
|
||||||
|
|
||||||
vars['form_items'] = self._make_autoform_items(harvesters_info)
|
|
||||||
|
|
||||||
c.form = render('source/old_new_source_form.html', extra_vars=vars)
|
|
||||||
return render('source/new.html')
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def _save_new(self):
|
|
||||||
try:
|
|
||||||
data_dict = dict(request.params)
|
|
||||||
self._check_data_dict(data_dict)
|
|
||||||
context = {'model':model, 'user':c.user, 'session':model.Session,
|
|
||||||
'schema':harvest_source_form_schema()}
|
|
||||||
|
|
||||||
source = get_action('harvest_source_create')(context,data_dict)
|
|
||||||
|
|
||||||
# Create a harvest job for the new source
|
|
||||||
get_action('harvest_job_create')(context,{'source_id':source['id']})
|
|
||||||
|
|
||||||
h.flash_success(_('New harvest source added successfully.'
|
|
||||||
'A new harvest job for the source has also been created.'))
|
|
||||||
redirect('/harvest/%s' % source['id'])
|
|
||||||
except NotAuthorized,e:
|
|
||||||
abort(401,self.not_auth_message)
|
|
||||||
except DataError,e:
|
|
||||||
abort(400, 'Integrity Error')
|
|
||||||
except ValidationError,e:
|
|
||||||
errors = e.error_dict
|
|
||||||
error_summary = e.error_summary if hasattr(e,'error_summary') else None
|
|
||||||
return self.new(data_dict, errors, error_summary)
|
|
||||||
|
|
||||||
def edit(self, id, data = None,errors = None, error_summary = None):
|
|
||||||
|
|
||||||
if ('save' in request.params) and not data:
|
|
||||||
return self._save_edit(id)
|
|
||||||
|
|
||||||
|
|
||||||
if not data:
|
|
||||||
try:
|
|
||||||
context = {'model':model, 'user':c.user}
|
|
||||||
|
|
||||||
old_data = get_action('harvest_source_show')(context, {'id':id})
|
|
||||||
except NotFound:
|
|
||||||
abort(404, _('Harvest Source not found'))
|
|
||||||
except NotAuthorized,e:
|
|
||||||
abort(401,self.not_auth_message)
|
|
||||||
|
|
||||||
data = data or old_data
|
|
||||||
errors = errors or {}
|
|
||||||
error_summary = error_summary or {}
|
|
||||||
try:
|
|
||||||
context = {'model':model, 'user':c.user}
|
|
||||||
harvesters_info = get_action('harvesters_info_show')(context,{})
|
|
||||||
except NotAuthorized,e:
|
|
||||||
abort(401,self.not_auth_message)
|
|
||||||
|
|
||||||
vars = {'data': data, 'errors': errors, 'error_summary': error_summary, 'harvesters': harvesters_info}
|
|
||||||
|
|
||||||
c.groups = self._get_publishers()
|
|
||||||
|
|
||||||
vars['form_items'] = self._make_autoform_items(harvesters_info)
|
|
||||||
|
|
||||||
c.form = render('source/old_new_source_form.html', extra_vars=vars)
|
|
||||||
|
|
||||||
return render('source/edit.html')
|
|
||||||
|
|
||||||
def _save_edit(self,id):
|
|
||||||
try:
|
|
||||||
data_dict = dict(request.params)
|
|
||||||
data_dict['id'] = id
|
|
||||||
self._check_data_dict(data_dict)
|
|
||||||
context = {'model':model, 'user':c.user, 'session':model.Session,
|
|
||||||
'schema':harvest_source_form_schema()}
|
|
||||||
|
|
||||||
source = get_action('harvest_source_update')(context,data_dict)
|
|
||||||
|
|
||||||
h.flash_success(_('Harvest source edited successfully.'))
|
|
||||||
redirect('/harvest/%s' %id)
|
|
||||||
except NotAuthorized,e:
|
|
||||||
abort(401,self.not_auth_message)
|
|
||||||
except DataError,e:
|
|
||||||
abort(400, _('Integrity Error'))
|
|
||||||
except NotFound, e:
|
|
||||||
abort(404, _('Harvest Source not found'))
|
|
||||||
except ValidationError,e:
|
|
||||||
errors = e.error_dict
|
|
||||||
error_summary = e.error_summary if hasattr(e,'error_summary') else None
|
|
||||||
return self.edit(id,data_dict, errors, error_summary)
|
|
||||||
|
|
||||||
def _check_data_dict(self, data_dict):
|
|
||||||
'''Check if the return data is correct'''
|
|
||||||
|
|
||||||
# TODO: remove frequency once it is added to the frontend!
|
|
||||||
surplus_keys_schema = ['id','publisher_id','user_id','config','save','frequency']
|
|
||||||
schema_keys = harvest_source_form_to_db_schema().keys()
|
|
||||||
keys_in_schema = set(schema_keys) - set(surplus_keys_schema)
|
|
||||||
|
|
||||||
# user_id is not yet used, we'll set the logged user one for the time being
|
|
||||||
if not data_dict.get('user_id',None):
|
|
||||||
if c.userobj:
|
|
||||||
data_dict['user_id'] = c.userobj.id
|
|
||||||
if keys_in_schema - set(data_dict.keys()):
|
|
||||||
log.info(_('Incorrect form fields posted'))
|
|
||||||
raise DataError(data_dict)
|
|
||||||
|
|
||||||
def read(self,id):
|
|
||||||
try:
|
|
||||||
context = {'model':model, 'user':c.user}
|
|
||||||
c.source = get_action('harvest_source_show')(context, {'id':id})
|
|
||||||
c.page = Page(
|
|
||||||
collection=c.source['status']['packages'],
|
|
||||||
page=request.params.get('page', 1),
|
|
||||||
items_per_page=20,
|
|
||||||
url=pager_url
|
|
||||||
)
|
|
||||||
|
|
||||||
return render('source/read.html')
|
|
||||||
except NotFound:
|
|
||||||
abort(404,_('Harvest source not found'))
|
|
||||||
except NotAuthorized,e:
|
|
||||||
abort(401,self.not_auth_message)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def delete(self,id):
|
def delete(self,id):
|
||||||
try:
|
try:
|
||||||
context = {'model':model, 'user':c.user}
|
context = {'model':model, 'user':c.user}
|
||||||
get_action('harvest_source_delete')(context, {'id':id})
|
p.toolkit.get_action('harvest_source_delete')(context, {'id':id})
|
||||||
|
|
||||||
h.flash_success(_('Harvesting source successfully inactivated'))
|
h.flash_success(_('Harvesting source successfully inactivated'))
|
||||||
redirect(h.url_for('harvest'))
|
redirect(h.url_for('harvest'))
|
||||||
except NotFound:
|
except p.toolkit.ObjectNotFound:
|
||||||
abort(404,_('Harvest source not found'))
|
abort(404,_('Harvest source not found'))
|
||||||
except NotAuthorized,e:
|
except p.toolkit.NotAuthorized:
|
||||||
abort(401,self.not_auth_message)
|
abort(401,self.not_auth_message)
|
||||||
|
|
||||||
|
|
||||||
def create_harvesting_job(self,id):
|
def refresh(self, id):
|
||||||
try:
|
try:
|
||||||
context = {'model':model, 'user':c.user, 'session':model.Session}
|
context = {'model':model, 'user':c.user, 'session':model.Session}
|
||||||
get_action('harvest_job_create')(context,{'source_id':id})
|
p.toolkit.get_action('harvest_job_create')(context,{'source_id':id})
|
||||||
h.flash_success(_('Refresh requested, harvesting will take place within 15 minutes.'))
|
h.flash_success(_('Refresh requested, harvesting will take place within 15 minutes.'))
|
||||||
except NotFound:
|
except p.toolkit.ObjectNotFound:
|
||||||
abort(404,_('Harvest source not found'))
|
abort(404,_('Harvest source not found'))
|
||||||
except NotAuthorized,e:
|
except p.toolkit.NotAuthorized:
|
||||||
abort(401,self.not_auth_message)
|
abort(401,self.not_auth_message)
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
if 'Can not create jobs on inactive sources' in str(e):
|
if 'Can not create jobs on inactive sources' in str(e):
|
||||||
|
@ -245,13 +57,13 @@ class ViewController(BaseController):
|
||||||
msg = 'An error occurred: [%s]' % str(e)
|
msg = 'An error occurred: [%s]' % str(e)
|
||||||
h.flash_error(msg)
|
h.flash_error(msg)
|
||||||
|
|
||||||
redirect(h.url_for('harvest'))
|
redirect(h.url_for('{0}_admin'.format(DATASET_TYPE_NAME), id=id))
|
||||||
|
|
||||||
def show_object(self,id):
|
def show_object(self,id):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
context = {'model':model, 'user':c.user}
|
context = {'model':model, 'user':c.user}
|
||||||
obj = get_action('harvest_object_show')(context, {'id':id})
|
obj = p.toolkit.get_action('harvest_object_show')(context, {'id':id})
|
||||||
|
|
||||||
# Check content type. It will probably be either XML or JSON
|
# Check content type. It will probably be either XML or JSON
|
||||||
try:
|
try:
|
||||||
|
@ -278,9 +90,9 @@ class ViewController(BaseController):
|
||||||
|
|
||||||
response.headers['Content-Length'] = len(content)
|
response.headers['Content-Length'] = len(content)
|
||||||
return content.encode('utf-8')
|
return content.encode('utf-8')
|
||||||
except NotFound:
|
except p.toolkit.ObjectNotFound:
|
||||||
abort(404,_('Harvest object not found'))
|
abort(404,_('Harvest object not found'))
|
||||||
except NotAuthorized,e:
|
except p.toolkit.NotAuthorized:
|
||||||
abort(401,self.not_auth_message)
|
abort(401,self.not_auth_message)
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
msg = 'An error occurred: [%s]' % str(e)
|
msg = 'An error occurred: [%s]' % str(e)
|
||||||
|
@ -293,10 +105,9 @@ class ViewController(BaseController):
|
||||||
context = {'model': model, 'user': c.user}
|
context = {'model': model, 'user': c.user}
|
||||||
source_dict = p.toolkit.get_action('harvest_source_show')(context,
|
source_dict = p.toolkit.get_action('harvest_source_show')(context,
|
||||||
{'id': source_id})
|
{'id': source_id})
|
||||||
except NotFound:
|
except p.toolkit.ObjectNotFound:
|
||||||
abort(404, p.toolkit._('Harvest source not found'))
|
abort(404, p.toolkit._('Harvest source not found'))
|
||||||
except NotAuthorized,e:
|
except p.toolkit.NotAuthorized:
|
||||||
|
|
||||||
abort(401,self.not_auth_message)
|
abort(401,self.not_auth_message)
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
msg = 'An error occurred: [%s]' % str(e)
|
msg = 'An error occurred: [%s]' % str(e)
|
||||||
|
@ -308,20 +119,20 @@ class ViewController(BaseController):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
context = {'model':model, 'user':c.user}
|
context = {'model':model, 'user':c.user}
|
||||||
c.job = get_action('harvest_job_show')(context, {'id': id})
|
c.job = p.toolkit.get_action('harvest_job_show')(context, {'id': id})
|
||||||
c.job_report = get_action('harvest_job_report')(context, {'id': id})
|
c.job_report = p.toolkit.get_action('harvest_job_report')(context, {'id': id})
|
||||||
|
|
||||||
if not source_dict:
|
if not source_dict:
|
||||||
source_dict = get_action('harvest_source_show')(context, {'id': c.job['source_id']})
|
source_dict = p.toolkit.get_action('harvest_source_show')(context, {'id': c.job['source_id']})
|
||||||
|
|
||||||
c.harvest_source = source_dict
|
c.harvest_source = source_dict
|
||||||
c.is_last_job = is_last
|
c.is_last_job = is_last
|
||||||
|
|
||||||
return render('source/job/read.html')
|
return render('source/job/read.html')
|
||||||
|
|
||||||
except NotFound:
|
except p.toolkit.ObjectNotFound:
|
||||||
abort(404,_('Harvest job not found'))
|
abort(404,_('Harvest job not found'))
|
||||||
except NotAuthorized,e:
|
except p.toolkit.NotAuthorized:
|
||||||
abort(401,self.not_auth_message)
|
abort(401,self.not_auth_message)
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
msg = 'An error occurred: [%s]' % str(e)
|
msg = 'An error occurred: [%s]' % str(e)
|
||||||
|
@ -330,22 +141,22 @@ class ViewController(BaseController):
|
||||||
def about(self, id):
|
def about(self, id):
|
||||||
try:
|
try:
|
||||||
context = {'model':model, 'user':c.user}
|
context = {'model':model, 'user':c.user}
|
||||||
c.harvest_source = get_action('harvest_source_show')(context, {'id':id})
|
c.harvest_source = p.toolkit.get_action('harvest_source_show')(context, {'id':id})
|
||||||
return render('source/about.html')
|
return render('source/about.html')
|
||||||
except NotFound:
|
except p.toolkit.ObjectNotFound:
|
||||||
abort(404,_('Harvest source not found'))
|
abort(404,_('Harvest source not found'))
|
||||||
except NotAuthorized,e:
|
except p.toolkit.NotAuthorized:
|
||||||
abort(401,self.not_auth_message)
|
abort(401,self.not_auth_message)
|
||||||
|
|
||||||
def admin(self, id):
|
def admin(self, id):
|
||||||
try:
|
try:
|
||||||
context = {'model':model, 'user':c.user}
|
context = {'model':model, 'user':c.user}
|
||||||
p.toolkit.check_access('harvest_source_update', context, {'id': id})
|
p.toolkit.check_access('harvest_source_update', context, {'id': id})
|
||||||
c.harvest_source = get_action('harvest_source_show')(context, {'id':id})
|
c.harvest_source = p.toolkit.get_action('harvest_source_show')(context, {'id':id})
|
||||||
return render('source/admin.html')
|
return render('source/admin.html')
|
||||||
except NotFound:
|
except p.toolkit.ObjectNotFound:
|
||||||
abort(404,_('Harvest source not found'))
|
abort(404,_('Harvest source not found'))
|
||||||
except NotAuthorized,e:
|
except p.toolkit.NotAuthorized:
|
||||||
abort(401,self.not_auth_message)
|
abort(401,self.not_auth_message)
|
||||||
|
|
||||||
def show_last_job(self, source):
|
def show_last_job(self, source):
|
||||||
|
@ -364,51 +175,15 @@ class ViewController(BaseController):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
context = {'model':model, 'user':c.user}
|
context = {'model':model, 'user':c.user}
|
||||||
c.harvest_source = get_action('harvest_source_show')(context, {'id': source})
|
c.harvest_source = p.toolkit.get_action('harvest_source_show')(context, {'id': source})
|
||||||
c.jobs = get_action('harvest_job_list')(context, {'source_id': c.harvest_source['id']})
|
c.jobs = p.toolkit.get_action('harvest_job_list')(context, {'source_id': c.harvest_source['id']})
|
||||||
|
|
||||||
return render('source/job/list.html')
|
return render('source/job/list.html')
|
||||||
|
|
||||||
except NotFound:
|
except p.toolkit.ObjectNotFound:
|
||||||
abort(404,_('Harvest source not found'))
|
abort(404,_('Harvest source not found'))
|
||||||
except NotAuthorized,e:
|
except p.toolkit.NotAuthorized, e:
|
||||||
abort(401,self.not_auth_message)
|
abort(401,self.not_auth_message)
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
msg = 'An error occurred: [%s]' % str(e)
|
msg = 'An error occurred: [%s]' % str(e)
|
||||||
abort(500,msg)
|
abort(500,msg)
|
||||||
|
|
||||||
|
|
||||||
def _make_autoform_items(self, harvesters_info):
|
|
||||||
states = [{'text': 'active', 'value': 'True'},
|
|
||||||
{'text': 'withdrawn', 'value': 'False'},]
|
|
||||||
|
|
||||||
harvest_list = []
|
|
||||||
harvest_descriptions = p.toolkit.literal('<ul>')
|
|
||||||
for harvester in harvesters_info:
|
|
||||||
harvest_list.append({'text':harvester['title'], 'value': harvester['name']})
|
|
||||||
harvest_descriptions += p.toolkit.literal('<li><span class="harvester-title">')
|
|
||||||
harvest_descriptions += harvester['title']
|
|
||||||
harvest_descriptions += p.toolkit.literal('</span>: ')
|
|
||||||
harvest_descriptions += harvester['description']
|
|
||||||
harvest_descriptions += p.toolkit.literal('</li>')
|
|
||||||
harvest_descriptions += p.toolkit.literal('</ul>')
|
|
||||||
|
|
||||||
items = [
|
|
||||||
{'name': 'url', 'control': 'input', 'label': _('URL'), 'placeholder': _(''), 'extra_info': 'This should include the http:// part of the URL'},
|
|
||||||
{'name': 'type', 'control': 'select', 'options': harvest_list, 'label': _('Source type'), 'placeholder': _(''), 'extra_info': 'Which type of source does the URL above represent? '},
|
|
||||||
{'control': 'html', 'html': harvest_descriptions},
|
|
||||||
{'name': 'title', 'control': 'input', 'label': _('Title'), 'placeholder': _(''), 'extra_info': 'This will be shown as the datasets source.'},
|
|
||||||
{'name': 'description', 'control': 'textarea', 'label': _('Description'), 'placeholder': _(''), 'extra_info':'You can add your own notes here about what the URL above represents to remind you later.'},]
|
|
||||||
|
|
||||||
if c.groups:
|
|
||||||
pubs = []
|
|
||||||
for group in c.groups:
|
|
||||||
pubs.append({'text':group['title'], 'value': group['id']})
|
|
||||||
items.append({'name': 'publisher_id', 'control': 'select', 'options': pubs, 'label': _('Publisher'), 'placeholder': _('')})
|
|
||||||
|
|
||||||
items += [
|
|
||||||
{'name': 'config', 'control': 'textarea', 'label': _('Configuration'), 'placeholder': _(''), 'extra_info': ''},
|
|
||||||
{'name': 'active', 'control': 'select', 'options': states, 'label': _('State'), 'placeholder': _(''), 'extra_text': ''},
|
|
||||||
]
|
|
||||||
|
|
||||||
return items
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import re
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from ckan import logic
|
from ckan import logic
|
||||||
|
@ -137,15 +136,3 @@ def _check_for_existing_jobs(context, source_id):
|
||||||
exist = len(exist_new + exist_running) > 0
|
exist = len(exist_new + exist_running) > 0
|
||||||
|
|
||||||
return exist
|
return exist
|
||||||
|
|
||||||
|
|
||||||
def _error_summary(error_dict):
|
|
||||||
error_summary = {}
|
|
||||||
for key, error in error_dict.iteritems():
|
|
||||||
error_summary[_prettify(key)] = error[0]
|
|
||||||
return error_summary
|
|
||||||
|
|
||||||
def _prettify(field_name):
|
|
||||||
field_name = re.sub('(?<!\w)[Uu]rl(?!\w)', 'URL', field_name.replace('_', ' ').capitalize())
|
|
||||||
return field_name.replace('_', ' ')
|
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import logging
|
import logging
|
||||||
from sqlalchemy import or_, func
|
from sqlalchemy import or_
|
||||||
from ckan.model import User
|
from ckan.model import User
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ from ckanext.harvest.model import (HarvestSource, HarvestJob, HarvestObject)
|
||||||
from ckanext.harvest.logic.dictization import (harvest_source_dictize,
|
from ckanext.harvest.logic.dictization import (harvest_source_dictize,
|
||||||
harvest_job_dictize,
|
harvest_job_dictize,
|
||||||
harvest_object_dictize)
|
harvest_object_dictize)
|
||||||
from ckanext.harvest.logic.schema import harvest_source_db_to_form_schema
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
@side_effect_free
|
@side_effect_free
|
||||||
|
@ -99,6 +99,9 @@ def harvest_source_show_status(context, data_dict):
|
||||||
|
|
||||||
@side_effect_free
|
@side_effect_free
|
||||||
def harvest_source_list(context, data_dict):
|
def harvest_source_list(context, data_dict):
|
||||||
|
'''
|
||||||
|
TODO: Use package search
|
||||||
|
'''
|
||||||
|
|
||||||
check_access('harvest_source_list',context,data_dict)
|
check_access('harvest_source_list',context,data_dict)
|
||||||
|
|
||||||
|
@ -113,6 +116,10 @@ def harvest_source_list(context, data_dict):
|
||||||
|
|
||||||
@side_effect_free
|
@side_effect_free
|
||||||
def harvest_source_for_a_dataset(context, data_dict):
|
def harvest_source_for_a_dataset(context, data_dict):
|
||||||
|
'''
|
||||||
|
TODO: Deprecated, harvest source id is added as an extra to each dataset
|
||||||
|
automatically
|
||||||
|
'''
|
||||||
'''For a given dataset, return the harvest source that
|
'''For a given dataset, return the harvest source that
|
||||||
created or last updated it, otherwise NotFound.'''
|
created or last updated it, otherwise NotFound.'''
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,10 @@ from ckanext.harvest.model import HarvestSource, HarvestJob, HarvestObject, \
|
||||||
|
|
||||||
|
|
||||||
def harvest_source_dictize(source, context):
|
def harvest_source_dictize(source, context):
|
||||||
|
'''
|
||||||
|
TODO: Deprecated
|
||||||
|
'''
|
||||||
|
|
||||||
out = source.as_dict()
|
out = source.as_dict()
|
||||||
|
|
||||||
out['publisher_title'] = u''
|
out['publisher_title'] = u''
|
||||||
|
@ -90,6 +94,9 @@ def harvest_object_dictize(obj, context):
|
||||||
return out
|
return out
|
||||||
|
|
||||||
def _get_source_status(source, context):
|
def _get_source_status(source, context):
|
||||||
|
'''
|
||||||
|
TODO: Deprecated, use harvest_source_show_status instead
|
||||||
|
'''
|
||||||
|
|
||||||
model = context.get('model')
|
model = context.get('model')
|
||||||
detailed = context.get('detailed',True)
|
detailed = context.get('detailed',True)
|
||||||
|
|
|
@ -16,7 +16,7 @@ from ckanext.harvest.model import HarvestSource, HarvestJob, HarvestObject
|
||||||
log = getLogger(__name__)
|
log = getLogger(__name__)
|
||||||
assert not log.disabled
|
assert not log.disabled
|
||||||
|
|
||||||
DATASET_TYPE_NAME = 'harvest_source'
|
DATASET_TYPE_NAME = 'harvest'
|
||||||
|
|
||||||
class Harvest(p.SingletonPlugin, DefaultDatasetForm):
|
class Harvest(p.SingletonPlugin, DefaultDatasetForm):
|
||||||
|
|
||||||
|
@ -173,25 +173,6 @@ class Harvest(p.SingletonPlugin, DefaultDatasetForm):
|
||||||
|
|
||||||
self.startup = True
|
self.startup = True
|
||||||
|
|
||||||
auth_profile = config.get('ckan.harvest.auth.profile',None)
|
|
||||||
|
|
||||||
if auth_profile:
|
|
||||||
# Check if auth profile exists
|
|
||||||
module_root = 'ckanext.harvest.logic.auth'
|
|
||||||
module_path = '%s.%s' % (module_root, auth_profile)
|
|
||||||
try:
|
|
||||||
module = __import__(module_path)
|
|
||||||
except ImportError,e:
|
|
||||||
raise ImportError('Unknown auth profile: %s' % auth_profile)
|
|
||||||
|
|
||||||
# If we are using the publisher auth profile, make sure CKAN core
|
|
||||||
# also uses it.
|
|
||||||
if auth_profile == 'publisher' and \
|
|
||||||
not config.get('ckan.auth.profile','') == 'publisher':
|
|
||||||
raise Exception('You must enable the "publisher" auth profile'
|
|
||||||
+' in CKAN in order to use it on the harvest extension'
|
|
||||||
+' (adding "ckan.auth.profile=publisher" to your ini file)')
|
|
||||||
|
|
||||||
# Setup harvest model
|
# Setup harvest model
|
||||||
model_setup()
|
model_setup()
|
||||||
|
|
||||||
|
@ -199,19 +180,13 @@ class Harvest(p.SingletonPlugin, DefaultDatasetForm):
|
||||||
|
|
||||||
def before_map(self, map):
|
def before_map(self, map):
|
||||||
|
|
||||||
|
# Most of the routes are defined via the IDatasetForm interface
|
||||||
|
# (ie they are the ones for a package type)
|
||||||
controller = 'ckanext.harvest.controllers.view:ViewController'
|
controller = 'ckanext.harvest.controllers.view:ViewController'
|
||||||
map.connect('harvest', '/harvest',controller=controller,action='index')
|
|
||||||
|
|
||||||
map.connect('/harvest/new', controller=controller, action='new')
|
|
||||||
map.connect('/harvest/edit/:id', controller=controller, action='edit')
|
|
||||||
map.connect('/harvest/delete/:id',controller=controller, action='delete')
|
|
||||||
map.connect('/harvest/:id', controller=controller, action='read')
|
|
||||||
|
|
||||||
map.connect('harvesting_job_create', '/harvest/refresh/:id',controller=controller,
|
|
||||||
action='create_harvesting_job')
|
|
||||||
|
|
||||||
map.connect('harvest_object_show', '/harvest/object/:id', controller=controller, action='show_object')
|
|
||||||
|
|
||||||
|
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}_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}_about'.format(DATASET_TYPE_NAME), '/' + DATASET_TYPE_NAME + '/about/:id', controller=controller, action='about')
|
||||||
|
|
||||||
|
@ -219,8 +194,10 @@ class Harvest(p.SingletonPlugin, DefaultDatasetForm):
|
||||||
map.connect('harvest_job_show_last', '/' + DATASET_TYPE_NAME + '/{source}/job/last', controller=controller, action='show_last_job')
|
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_show', '/' + DATASET_TYPE_NAME + '/{source}/job/{id}', controller=controller, action='show_job')
|
||||||
|
|
||||||
|
map.connect('harvest_object_show', '/' + DATASET_TYPE_NAME + '/object/:id', controller=controller, action='show_object')
|
||||||
|
|
||||||
org_controller = 'ckanext.harvest.controllers.organization:OrganizationController'
|
org_controller = 'ckanext.harvest.controllers.organization:OrganizationController'
|
||||||
map.connect('harvest_source_org_list', '/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
|
return map
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ Example:
|
||||||
{% set truncate_title = truncate_title or 80 %}
|
{% set truncate_title = truncate_title or 80 %}
|
||||||
{% set title = source.title or source.name %}
|
{% set title = source.title or source.name %}
|
||||||
{% set source_type = h.get_pkg_dict_extra(source, 'source_type') %}
|
{% set source_type = h.get_pkg_dict_extra(source, 'source_type') %}
|
||||||
{% set url = h.url_for('harvest_source_edit', id=source.name) if within_organization else h.url_for('harvest_source_read', id=source.name) %}
|
{% set url = h.url_for('harvest_edit', id=source.name) if within_organization else h.url_for('harvest_read', id=source.name) %}
|
||||||
|
|
||||||
<li class="{{ item_class or "dataset-item" }}">
|
<li class="{{ item_class or "dataset-item" }}">
|
||||||
<div class="dataset-content">
|
<div class="dataset-content">
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
{% if source.status.last_job and (source.status.last_job.status == 'New' or source.status.last_job.status == 'Running') %}
|
{% if source.status.last_job and (source.status.last_job.status == 'New' or source.status.last_job.status == 'Running') %}
|
||||||
<li><a class="btn disabled" rel="tooltip" title="There already is an unrun job for this source"><i class="icon-refresh icon-large"></i> Refresh</a></li>
|
<li><a class="btn disabled" rel="tooltip" title="There already is an unrun job for this source"><i class="icon-refresh icon-large"></i> Refresh</a></li>
|
||||||
{% else %}
|
{% else %}
|
||||||
<li>{{ h.nav_named_link(_('Refresh'), 'harvesting_job_create', id=source.id, class_='btn', icon='refresh')}}</li>
|
<li>{{ h.nav_named_link(_('Refresh'), '{0}_refresh'.format(c.dataset_type), id=source.id, class_='btn', icon='refresh')}}</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<li>{{ h.nav_named_link(_('View harvest source'), '{0}_read'.format(c.dataset_type), id=source.name, class_='btn', icon='eye-open')}}</li>
|
<li>{{ h.nav_named_link(_('View harvest source'), '{0}_read'.format(c.dataset_type), id=source.name, class_='btn', icon='eye-open')}}</li>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -13,10 +13,10 @@
|
||||||
|
|
||||||
{{ form.input('title', id='field-title', label=_('Title'), placeholder=_('eg. A descriptive title'), value=data.title, error=errors.title, classes=['control-full'], attrs={'data-module': 'slug-preview-target'}) }}
|
{{ form.input('title', id='field-title', label=_('Title'), placeholder=_('eg. A descriptive title'), value=data.title, error=errors.title, classes=['control-full'], attrs={'data-module': 'slug-preview-target'}) }}
|
||||||
|
|
||||||
{% set prefix = 'harvest_source' %}
|
{% set prefix = 'harvest' %}
|
||||||
{% set domain = h.url_for(controller='package', action='read', id='', qualified=true) %}
|
{% set domain = h.url_for('{0}_read'.format(c.dataset_type), id='', qualified=true) %}
|
||||||
{% set domain = domain|replace("http://", "")|replace("https://", "") %}
|
{% set domain = domain|replace("http://", "")|replace("https://", "") %}
|
||||||
{% set attrs = {'data-module': 'slug-preview-slug', 'data-module-prefix': domain, 'data-module-placeholder': '<dataset>'} %}
|
{% set attrs = {'data-module': 'slug-preview-slug', 'data-module-prefix': domain, 'data-module-placeholder': '<harvest-source>'} %}
|
||||||
|
|
||||||
{{ form.prepend('name', id='field-name', label=_('Name'), prepend=prefix, placeholder=_('eg. my-dataset'), value=data.name, error=errors.name, attrs=attrs) }}
|
{{ form.prepend('name', id='field-name', label=_('Name'), prepend=prefix, placeholder=_('eg. my-dataset'), value=data.name, error=errors.name, attrs=attrs) }}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue