def openspending_report(self): if not dgu_helpers.is_sysadmin(): abort(401, 'User must be a sysadmin to view this page.') self._set_openspending_reports_dir() c.content = open(c.openspending_report_dir + "/index.html").read() return render('data/openspending_report.html')
def linked_data_admin(self): """ """ import git if not dgu_helpers.is_sysadmin() and not c.user in [ 'user_d24373', 'user_d102361' ]: abort(403) prefix = 'dgu.jekyll.ukgovld.' c.repo_url = pylons.config.get(prefix + "repo.url", None) c.repo_branch = pylons.config.get(prefix + "repo.branch", None) source_repo_path = pylons.config.get(prefix + "local.source", None) build_path = pylons.config.get(prefix + "local.build", None) deploy_path = pylons.config.get(prefix + "local.deploy", None) if not all([c.repo_url, c.repo_branch, source_repo_path, build_path, deploy_path]) or \ not os.path.exists(source_repo_path): c.error = "System not configured, please setup ckan.ini" if not os.path.exists(source_repo_path): c.error = "Repo path %s does not exist" % source_repo_path return render('data/ukgovld.html') # Ensure repo exists locally try: repo = git.Repo(source_repo_path) except git.InvalidGitRepositoryError, e: repo = git.Repo.init(source_repo_path) repo.create_remote('origin', c.repo_url)
def report_abuse(self, id): """ When a user reports something as offensive, this action will mark it ready for moderation. If the user reporting is a system administrator it will be marked, but also made invisible so that it no longer shows up """ import ckan.model as model from ckanext.dgu.model.feedback import Feedback fb = Feedback.get(id) if fb: fb.moderated = False fb.moderation_required = True if is_sysadmin(): fb.visible = False flash_notice( "Queued. As you are an administrator, this item has been hidden" ) else: flash_notice( "Thank you for your feedback, the item has been queued for moderation" ) model.Session.add(fb) model.Session.commit() h.redirect_to(request.referer or '/data')
def linked_data_admin(self): """ """ import git if not dgu_helpers.is_sysadmin() and not c.user in ['user_d24373', 'user_d102361']: abort(403) prefix = 'dgu.jekyll.ukgovld.' c.repo_url = pylons.config.get(prefix + "repo.url", None) c.repo_branch = pylons.config.get(prefix + "repo.branch", None) source_repo_path = pylons.config.get(prefix + "local.source", None) build_path = pylons.config.get(prefix + "local.build", None) deploy_path = pylons.config.get(prefix + "local.deploy", None) if not all([c.repo_url, c.repo_branch, source_repo_path, build_path, deploy_path]) or \ not os.path.exists(source_repo_path): c.error = "System not configured, please setup ckan.ini" if not os.path.exists(source_repo_path): c.error = "Repo path %s does not exist" % source_repo_path return render('data/ukgovld.html') # Ensure repo exists locally try: repo = git.Repo(source_repo_path) except git.InvalidGitRepositoryError, e: repo = git.Repo.init(source_repo_path) repo.create_remote('origin', c.repo_url)
def openspending_report(self): if not dgu_helpers.is_sysadmin(): abort(401, 'User must be a sysadmin to view this page.') self._set_openspending_reports_dir() c.content = open (c.openspending_report_dir + "/index.html").read() return render('data/openspending_report.html')
def linked_data_admin(self): """ Instructions for installing Ruby via RVM: \curl -sSL https://get.rvm.io | bash -s stable # Comment out lines in .bashrc and .bash_profile source "$HOME/.rvm/scripts/rvm" rvm autolibs distable rvm install 1.9.3 rvm use 1.9.3 rvm gemset create ukgovld rvm alias create ukgovldwg 1.9.3@ukgovld cd /vagrant/src/ckanext-dgu/ ~/.rvm/wrappers/ukgovldwg/bundle rvm wrapper ukgovldwg jekyll """ import git if not dgu_helpers.is_sysadmin() and not c.user in [ 'user_d24373', 'user_d102361' ]: abort(401) prefix = 'dgu.jekyll.ukgovld.' c.repo_url = pylons.config.get(prefix + "repo.url", None) c.repo_branch = pylons.config.get(prefix + "repo.branch", None) source_repo_path = pylons.config.get(prefix + "local.source", None) build_path = pylons.config.get(prefix + "local.build", None) deploy_path = pylons.config.get(prefix + "local.deploy", None) if source_repo_path and (not os.path.exists(source_repo_path) and source_repo_path.startswith('/tmp/')): # Directories in /tmp won't survive a reboot os.makedirs(source_repo_path) if build_path and (not os.path.exists(build_path) and build_path.startswith('/tmp/')): # Directories in /tmp won't survive a reboot os.makedirs(build_path) if not all([c.repo_url, c.repo_branch, source_repo_path, build_path, deploy_path]) or \ not os.path.exists(source_repo_path): c.error = "System not configured, please setup ckan.ini" if source_repo_path and not os.path.exists(source_repo_path): c.error = "Repo path %s does not exist" % source_repo_path return render('data/ukgovld.html') # Ensure repo exists locally try: repo = git.Repo(source_repo_path) except git.InvalidGitRepositoryError, e: repo = git.Repo.init(source_repo_path) repo.create_remote('origin', c.repo_url)
def linked_data_admin(self): """ Instructions for installing Ruby via RVM: \curl -sSL https://get.rvm.io | bash -s stable # Comment out lines in .bashrc and .bash_profile source "$HOME/.rvm/scripts/rvm" rvm autolibs distable rvm install 1.9.3 rvm use 1.9.3 rvm gemset create ukgovld rvm alias create ukgovldwg 1.9.3@ukgovld cd /vagrant/src/ckanext-dgu/ ~/.rvm/wrappers/ukgovldwg/bundle rvm wrapper ukgovldwg jekyll """ import git if not dgu_helpers.is_sysadmin() and not c.user in ['user_d24373', 'user_d102361']: abort(401) prefix = 'dgu.jekyll.ukgovld.' c.repo_url = pylons.config.get(prefix + "repo.url", None) c.repo_branch = pylons.config.get(prefix + "repo.branch", None) source_repo_path = pylons.config.get(prefix + "local.source", None) build_path = pylons.config.get(prefix + "local.build", None) deploy_path = pylons.config.get(prefix + "local.deploy", None) if source_repo_path and (not os.path.exists(source_repo_path) and source_repo_path.startswith('/tmp/')): # Directories in /tmp won't survive a reboot os.makedirs(source_repo_path) if build_path and (not os.path.exists(build_path) and build_path.startswith('/tmp/')): # Directories in /tmp won't survive a reboot os.makedirs(build_path) if not all([c.repo_url, c.repo_branch, source_repo_path, build_path, deploy_path]) or \ not os.path.exists(source_repo_path): c.error = "System not configured, please setup ckan.ini" if source_repo_path and not os.path.exists(source_repo_path): c.error = "Repo path %s does not exist" % source_repo_path return render('data/ukgovld.html') # Ensure repo exists locally try: repo = git.Repo(source_repo_path) except git.InvalidGitRepositoryError, e: repo = git.Repo.init(source_repo_path) repo.create_remote('origin', c.repo_url)
def edit(self, id): """ Allows editing of commitments for a specific publisher """ from ckanext.dgu.model.commitment import Commitment from ckanext.dgu.lib import helpers as dgu_helpers context = {'model': model, 'session': model.Session, 'user': c.user or c.author, 'extras_as_string': True, 'save': 'save' in request.params} if not dgu_helpers.is_sysadmin(): abort(401, "You are not allowed to edit the commitments for this publisher") try: c.publisher_dict = get_action('organization_show')(context, {'id': id}) except NotAuthorized: abort(401, _('Unauthorized to read commitments')) except ObjectNotFound: abort(404, _('Publisher not found')) c.publisher = context.get('group') c.publishers = model.Session.query(model.Group).filter(model.Group.state=='active')\ .order_by(model.Group.title).all() c.errors = {} if request.method == "POST": # need to flatten the request into some commitments, if there is an ID then # we should update them, if there isn't then add them. # TODO: Work out how to remove them. Perhaps get the current IDs and do a diff # If successful redirect to read() h.redirect_to(h.url_for(controller='ckanext.dgu.controllers.commitment:CommitmentController', action='commitments', id=c.publisher.name)) c.commitments = Commitment.get_for_publisher(c.publisher.name).order_by('commitment.commitment_text') return render('commitment/edit.html')
def openspending_publisher_report(self, id): if not dgu_helpers.is_sysadmin(): abort(401, 'User must be a sysadmin to view this page.') id = id.replace('.html', '') if id.startswith('publisher-'): publisher_name = id.replace('publisher-', '') # Check the publisher actually exists, for security publisher = model.Group.by_name(publisher_name) if publisher: c.report_name = id else: abort(404, 'Publisher not found') self._set_openspending_reports_dir() path = c.openspending_report_dir + "/" + c.report_name + ".html" c.content = open(path).read() # Jinja needs it as unicode c.content = c.content.decode('utf8') return render('data/openspending_publisher_report.html') else: abort(404)
def report_abuse(self, id): """ When a user reports something as offensive, this action will mark it ready for moderation. If the user reporting is a system administrator it will be marked, but also made invisible so that it no longer shows up """ import ckan.model as model from ckanext.dgu.model.feedback import Feedback fb = Feedback.get(id) if fb: fb.moderated = False fb.moderation_required = True if is_sysadmin(): fb.visible = False flash_notice("Queued. As you are an administrator, this item has been hidden") else: flash_notice("Thank you for your feedback, the item has been queued for moderation") model.Session.add(fb) model.Session.commit() h.redirect_to(request.referer or '/data')
def get_publishers(self): from ckan.model.group import Group if dgu_helpers.is_sysadmin(): groups = Group.all(group_type='organization') elif c.userobj: # need to get c.userobj again as it may be detached from the # session since the last time we called get_groups (it caches) c.userobj = model.User.by_name(c.user) # For each group where the user is an admin, we should also include # all of the child publishers. admin_groups = set() for g in c.userobj.get_groups('organization', 'admin'): for pub in publib.go_down_tree(g): admin_groups.add(pub) editor_groups = c.userobj.get_groups('organization', 'editor') groups = list(admin_groups) + editor_groups 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, 'contact-name': g.extras.get('contact-name', ''), 'contact-email': g.extras.get('contact-email', ''), 'contact-phone': g.extras.get('contact-phone', ''), 'foi-name': g.extras.get('foi-name', ''), 'foi-email': g.extras.get('foi-email', ''), 'foi-phone': g.extras.get('foi-phone', ''), 'foi-web': g.extras.get('foi-web', ''), } for g in groups] return dict((g['name'], g) for g in groups)
def nii(self, format=None): import ckan.model as model from ckanext.dgu.lib.reports import nii_report if 'regenerate' in request.GET and dguhelpers.is_sysadmin(): from ckan.lib.helpers import flash_notice from ckanext.dgu.lib.reports import cached_reports cached_reports(['nii_report']) flash_notice("Report regenerated") h.redirect_to('/data/reports/nii') tmpdata = nii_report(use_cache=True) c.data = {} # Get the date time the report was generated, or now if it doesn't # appear in the cache cache_data = model.Session.query(model.DataCache.created)\ .filter(model.DataCache.object_id=='__all__')\ .filter(model.DataCache.key == 'nii-report').first() c.generated_date = cache_data[0] if cache_data else datetime.datetime.now() c.total_broken_packages = 0 c.total_broken_resources = 0 # Convert the lists of IDs into something usable in the template, # this could be faster if we did a bulk-fetch of groupname->obj for # instance. for k,list_of_dicts in tmpdata.iteritems(): g = model.Group.get(k) c.data[g] = [] for dct in list_of_dicts: for pkgname,results in dct.iteritems(): c.total_broken_resources += len(results) if len(results): c.total_broken_packages += 1 c.data[g].append({model.Package.get(pkgname): results}) def _stringify(s, encoding, errors): if s is None: return '' if isinstance(s, unicode): return s.encode(encoding, errors) elif isinstance(s, (int , float)): pass #let csv.QUOTE_NONNUMERIC do its thing. elif not isinstance(s, str): s=str(s) return s if format == 'csv': import csv # Set the content-disposition so that it downloads the file response.headers['Content-Type'] = "text/csv; charset=utf-8" response.headers['Content-Disposition'] = str('attachment; filename=nii-broken-resources.csv') writer = csv.writer(response) writer.writerow(['Publisher', 'Parent publisher', 'Dataset name', 'Resource title', 'Resource link', 'Data link']) for publisher in c.data.keys(): parent_groups = publisher.get_parent_groups(type='organization') parent_publisher = parent_groups[0].title if len(parent_groups) > 0 else '' for items in c.data[publisher]: for dataset, resources in items.iteritems(): if len(resources) == 0: continue for resid,resdesc in resources: resource = model.Resource.get(resid) row = [ publisher.title, parent_publisher, _stringify(dataset.title, 'utf-8', 'ignore'), _stringify(resource.description, 'utf-8', 'ignore') or 'No name', 'http://data.gov.uk/dataset/%s/resource/%s' % (dataset.name,resource.id,), _stringify(resource.url, 'utf-8', 'ignore'), 'Yes' if dataset.extras.get('external_reference','') == 'ONSHUB' else 'No' ] writer.writerow(row) return '' return t.render('reports/nii.html')
def nii(self, format=None): import ckan.model as model from ckanext.dgu.lib.reports import nii_report if 'regenerate' in request.GET and dguhelpers.is_sysadmin(): from ckan.lib.helpers import flash_notice from ckanext.dgu.lib.reports import cached_reports cached_reports(['nii_report']) flash_notice("Report regenerated") h.redirect_to('/data/reports/nii') tmpdata = nii_report(use_cache=True) c.data = {} # Get the date time the report was generated, or now if it doesn't # appear in the cache cache_data = model.Session.query(model.DataCache.created)\ .filter(model.DataCache.object_id=='__all__')\ .filter(model.DataCache.key == 'nii-report').first() c.generated_date = cache_data[ 0] if cache_data else datetime.datetime.now() c.total_broken_packages = 0 c.total_broken_resources = 0 # Convert the lists of IDs into something usable in the template, # this could be faster if we did a bulk-fetch of groupname->obj for # instance. for k, list_of_dicts in tmpdata.iteritems(): g = model.Group.get(k) c.data[g] = [] for dct in list_of_dicts: for pkgname, results in dct.iteritems(): c.total_broken_resources += len(results) if len(results): c.total_broken_packages += 1 c.data[g].append({model.Package.get(pkgname): results}) def _stringify(s, encoding, errors): if s is None: return '' if isinstance(s, unicode): return s.encode(encoding, errors) elif isinstance(s, (int, float)): pass #let csv.QUOTE_NONNUMERIC do its thing. elif not isinstance(s, str): s = str(s) return s if format == 'csv': import csv # Set the content-disposition so that it downloads the file response.headers['Content-Type'] = "text/csv; charset=utf-8" response.headers['Content-Disposition'] = str( 'attachment; filename=nii-broken-resources.csv') writer = csv.writer(response) writer.writerow([ 'Publisher', 'Parent publisher', 'Dataset name', 'Resource title', 'Resource link', 'Data link' ]) for publisher in c.data.keys(): parent_groups = publisher.get_parent_groups( type='organization') parent_publisher = parent_groups[0].title if len( parent_groups) > 0 else '' for items in c.data[publisher]: for dataset, resources in items.iteritems(): if len(resources) == 0: continue for resid, resdesc in resources: resource = model.Resource.get(resid) row = [ publisher.title, parent_publisher, _stringify(dataset.title, 'utf-8', 'ignore'), _stringify(resource.description, 'utf-8', 'ignore') or 'No name', 'http://data.gov.uk/dataset/%s/resource/%s' % ( dataset.name, resource.id, ), _stringify(resource.url, 'utf-8', 'ignore'), 'Yes' if dataset.extras.get( 'external_reference', '') == 'ONSHUB' else 'No' ] writer.writerow(row) return '' return t.render('reports/nii.html')
def viz_upload(self): """ Provides direct upload to DGU for users in specific publishers. This is specifically for the social investment publishers so that they can host their files somewhere. """ import ckan.model as model ALLOWED_PUBLISHERS = set([ 'seedbed' 'health-social-ventures', 'big-issue-cooperate', 'social-incubator-east', 'young-academy', 'dotforge-social-ventures', 'wayra-unltd', 'social-incubator-north', 'bethnal-green-ventures', 'hub-launchpad', 'the-social-investment-business-group', ]) # Check auth .. user must be in one of selected groups. context = {"model": model, "session": model.Session, "user": c.user} if dgu_helpers.is_sysadmin(): user_orgs = ALLOWED_PUBLISHERS else: res = get_action("organization_list_for_user")( context, { "permission": "create_dataset" }) user_orgs = set([o['name'] for o in res]) & ALLOWED_PUBLISHERS if not user_orgs: abort(401) publisher_q = " OR ".join( ["publisher:{}".format(o) for o in user_orgs]) res = get_action("package_search")(context, { "fq": "({})".format(publisher_q), 'rows': 100 }) c.package_names = [( p['name'], u"{} ({})".format(p['title'], p['organization']['title']), ) for p in res['results']] if not c.package_names: flash_error( "There are no datasets available in your organisation. You will be unable to upload." ) return render('viz/upload.html') c.package_names = sorted(c.package_names) if request.method == 'POST': success, errors = self._validate_viz_upload(request.POST) c.title = request.POST.get('title', '') c.format = request.POST.get('format', '') c.dataset = request.POST.get('dataset', '') if not success: error_list = "<li>" + "</li><li>".join(errors) + "</li>" flash_error( 'There was a problem with your submission<br/><ul>{}</ul>'. format(error_list), allow_html=True) return render('viz/upload.html') extension, url = self._store_file(request.POST['upload'], c.dataset) if not c.format: c.format = extension[1:].upper() # Create resource resource = { u'description': c.title, u'url': url, u'format': c.format } # Show and update package pkg = get_action('package_show')(context, {'id': c.dataset}) pkg['resources'].append(resource) res = get_action('package_update')(context, pkg) log.info('Added viz to dataset %s: %s', pkg['name'], resource) flash_success( 'The file has been uploaded and added to the dataset. <a href="/dataset/{}" style="text-decoration:underline;">View dataset</a>' .format(c.dataset), allow_html=True) return redirect('/data/viz/upload') return render('viz/upload.html')
def system_dashboard(self): if not dgu_helpers.is_sysadmin(): abort(401, 'User must be a sysadmin to view this page.') return render('data/system_dashboard.html')
since_timestamp = date_str_to_datetime(since_timestamp) except (ValueError, TypeError), inst: example = now.strftime('%Y-%m-%d%%20%H:%M') # e.g. 2013-11-30%2023:15 abort(400, 'Could not parse timestamp "%s": %s. Must be UTC. Example: since-time=%s' % (since_timestamp, inst, example)) elif in_the_last_x_minutes is not None: try: in_the_last_x_minutes = int(in_the_last_x_minutes) except ValueError, inst: abort(400, 'Could not parse number of minutes "%s"' % in_the_last_x_minutes) since_timestamp = now - \ datetime.timedelta(minutes=in_the_last_x_minutes) else: abort(400, 'Must specify revisions parameter. It must be one from: since-revision-id since-timestamp in-the-last-x-minutes') # limit is higher if sysadmin if is_sysadmin(): max_limit = 1000 else: max_limit = 50 # Get the revisions in the requested time frame revs = model.Session.query(model.Revision) \ .filter(model.Revision.timestamp >= since_timestamp) \ .order_by(model.Revision.timestamp.asc()) \ .limit(max_limit) \ .all() result = OrderedDict(( ('number_of_revisions', len(revs)), ('since_timestamp', since_timestamp.strftime('%Y-%m-%d %H:%M')), ('current_timestamp', now.strftime('%Y-%m-%d %H:%M')), ('since_revision_id', revs[0].id if revs else None),
def viz_upload(self): """ Provides direct upload to DGU for users in specific publishers. This is specifically for the social investment publishers so that they can host their files somewhere. """ import ckan.model as model ALLOWED_PUBLISHERS = set([ 'seedbed' 'health-social-ventures', 'big-issue-cooperate', 'social-incubator-east', 'young-academy', 'dotforge-social-ventures', 'wayra-unltd', 'social-incubator-north', 'bethnal-green-ventures', 'hub-launchpad', 'the-social-investment-business-group', ]) # Check auth .. user must be in one of selected groups. context = {"model": model, "session": model.Session, "user": c.user} if dgu_helpers.is_sysadmin(): user_orgs = ALLOWED_PUBLISHERS else: res = get_action("organization_list_for_user")(context, {"permission": "create_dataset"}) user_orgs = set([o['name'] for o in res]) & ALLOWED_PUBLISHERS if not user_orgs: abort(401) publisher_q = " OR ".join(["publisher:{}".format(o) for o in user_orgs]) res = get_action("package_search")(context, {"fq": "({})".format(publisher_q), 'rows': 100}) c.package_names = [(p['name'],u"{} ({})".format(p['title'], p['organization']['title']),) for p in res['results']] if not c.package_names: flash_error("There are no datasets available in your organisation. You will be unable to upload.") return render('viz/upload.html') c.package_names = sorted(c.package_names) if request.method == 'POST': success, errors = self._validate_viz_upload(request.POST) c.title = request.POST.get('title', '') c.format = request.POST.get('format', '') c.dataset = request.POST.get('dataset', '') if not success: error_list = "<li>" + "</li><li>".join(errors) + "</li>" flash_error('There was a problem with your submission<br/><ul>{}</ul>'.format(error_list), allow_html=True) return render('viz/upload.html') extension, url = self._store_file(request.POST['upload'], c.dataset) if not c.format: c.format = extension[1:].upper() # Create resource resource = { u'description': c.title, u'url': url, u'format': c.format } # Show and update package pkg = get_action('package_show')(context, {'id': c.dataset}) pkg['resources'].append(resource) res = get_action('package_update')(context, pkg) log.info('Added viz to dataset %s: %s', pkg['name'], resource) flash_success('The file has been uploaded and added to the dataset. <a href="/dataset/{}" style="text-decoration:underline;">View dataset</a>'.format(c.dataset), allow_html=True) return redirect('/data/viz/upload') return render('viz/upload.html')