Example #1
0
    def login(self):

    	params = toolkit.request.params

	if 'id_token' in params:
		try:
			mail_verified = self.verify_email(params['id_token'])
		except GoogleAuthException, e:
			toolkit.abort(500)

		user_account = email_to_ckan_user(mail_verified)

		user_ckan = self.get_ckanuser(user_account)

		if not user_ckan:
			user_ckan = toolkit.get_action('user_create')(
                    				context={'ignore_auth': True},
                    				data_dict={'email': mail_verified,
                               			'name': user_account,
                               			'password': self.get_ckanpasswd()})

		pylons.session['ckanext-google-user'] = user_ckan['name']
        	pylons.session['ckanext-google-email'] = mail_verified

		#to revoke the Google token uncomment the code below
		#pylons.session['ckanext-google-accesstoken'] = params['token']
            	pylons.session.save()
	def new(self, data=None, errors=None, error_summary=None):
		context = self._get_context()

		try:
			tk.check_access('oauth2provider_client_create', context)
		except tk.NotAuthorized:
			tk.abort(401, _('Unauthorized to create an oauth2 client'))

		if tk.request.method == 'POST':
			data = dict(tk.request.params)
			try:
				data['user_id'] = model.User.by_name(data['username']).id
			except AttributeError:
				data['user_id'] = None
			client = tk.get_action('oauth2provider_client_create')(context, data)
			return tk.redirect_to('oauth2provider_client_list')

		data = data or {}
		errors = errors or {}
		error_summary = error_summary or {}
		vars = {'data': data, 'errors': errors,
				'error_summary': error_summary, 'action': 'new'}

		return tk.render('ckanext/oauth2provider/client/new.html',
			extra_vars=vars)
    def edit(self, organization_name, inventory_entry_id, data=None,
             errors=None, error_summary=None):
        context = {'model': model,
                   'session': model.Session,
                   'user': c.user or c.author,
                   'organization_name': c.organization_name,
                   'save': 'save' in request.params,
                   'schema': default_inventory_entry_schema_create()}

        if context['save'] and not data:
            return self._save_edit(inventory_entry_id, context)

        try:
            old_data = get_action('inventory_entry_show')(
                context, {'id': inventory_entry_id})
            data = data or old_data
        except NotFound:
            abort(404, _('Inventory Entry not found'))
        except NotAuthorized:
            abort(401, _('Unauthorized to read inventory entry'))

        data = data or {}
        errors = errors or {}
        error_summary = error_summary or {}
        vars = {'data': data, 'errors': errors, 'error_summary': error_summary,
                'action': 'edit'}

        c.form = render('inventory/entry/inventory_entry_form.html', extra_vars=vars)

        return render('inventory/entry/edit.html')
Example #4
0
    def index(self):
        try:
            reports = t.get_action('report_list')({}, {})
        except t.NotAuthorized:
            t.abort(401)

        return t.render('report/index.html', extra_vars={'reports': reports})
 def __before__(self, action, **params):
     super(InventoryManageController, self).__before__(action, **params)
     context = {'user': c.user, 'auth_user_obj': c.userobj}
     try:
         check_access('user_show', context, {})
     except NotAuthorized:
         abort(401, 'You need to have an account.')
Example #6
0
 def report_comment(self, dataset_id, issue_number, comment_id):
     dataset = self._before_dataset(dataset_id)
     if request.method == 'POST':
         if not c.user:
             msg = _('You must be logged in to report comments')
             toolkit.abort(401, msg)
         try:
             toolkit.get_action('issue_comment_report')(
                 data_dict={
                     'comment_id': comment_id,
                     'issue_number': issue_number,
                     'dataset_id': dataset_id
                 }
             )
             h.flash_success(
                 _('Comment has been reported to an administrator')
             )
             h.redirect_to('issues_show',
                           dataset_id=dataset_id,
                           issue_number=issue_number)
         except toolkit.ValidationError:
             toolkit.abort(404)
         except ReportAlreadyExists, e:
             h.flash_error(e.message)
         h.redirect_to('issues_show', dataset_id=dataset_id,
                       issue_number=issue_number)
    def delete(self, dataset_id, issue_number):
        dataset = self._before_dataset(dataset_id)
        if 'cancel' in request.params:
            h.redirect_to('issues_show',
                          dataset_id=dataset_id,
                          issue_number=issue_number)

        if request.method == 'POST':
            try:
                toolkit.get_action('issue_delete')(
                    data_dict={'issue_number': issue_number,
                               'dataset_id': dataset_id}
                )
            except toolkit.NotAuthorized:
                msg = _('Unauthorized to delete issue {0}'.format(
                    issue_number))
                toolkit.abort(401, msg)

            h.flash_notice(
                _('Issue {0} has been deleted.'.format(issue_number))
            )
            h.redirect_to('issues_dataset', dataset_id=dataset_id)
        else:
            return render('issues/confirm_delete.html',
                          extra_vars={
                              'issue_number': issue_number,
                              'pkg': dataset,
                          })
Example #8
0
    def new(self, data=None, errors=None, error_summary=None):
        '''This is a modified version of the core user controller

        We have removed the lines redirecting the user the logout page
        if they are already logged in, this allows sysadmins to create
        users as we have disabled user registration unless they are
        sys admins'''
        context = {'model': model, 'session': model.Session,
                   'user': toolkit.c.user or toolkit.c.author,
                   'auth_user_obj': toolkit.c.userobj,
                   'schema': self._new_form_to_db_schema(),
                   'save': 'save' in toolkit.request.params}

        try:
            toolkit.check_access('user_create', context)
        except toolkit.NotAuthorized:
            toolkit.abort(401, toolkit._('Unauthorized to create a user'))

        if context['save'] and not data:
            return self._save_new(context)

        data = data or {}
        errors = errors or {}
        error_summary = error_summary or {}
        vars = {'data': data, 'errors': errors, 'error_summary': error_summary}

        toolkit.c.is_sysadmin = new_authz.is_sysadmin(toolkit.c.user)
        toolkit.c.form = toolkit.render(self.new_user_form, extra_vars=vars)
        return toolkit.render('user/new.html')
Example #9
0
    def read_catalog(self, _format=None):

        if not _format:
            _format = check_access_header()

        if not _format:
            return index_endpoint()

        _profiles = toolkit.request.params.get('profiles')
        if _profiles:
            _profiles = _profiles.split(',')

        data_dict = {
            'page': toolkit.request.params.get('page'),
            'modified_since': toolkit.request.params.get('modified_since'),
            'q': toolkit.request.params.get('q'),
            'fq': toolkit.request.params.get('fq'),
            'format': _format,
            'profiles': _profiles,
        }

        toolkit.response.headers.update(
            {'Content-type': CONTENT_TYPES[_format]})
        try:
            return toolkit.get_action('dcat_catalog_show')({}, data_dict)
        except (toolkit.ValidationError, RDFProfileException) as e:
            toolkit.abort(409, str(e))
 def report_view(self, id):
     """
     """    
     page = int(tk.request.params.get('page', 0))
     perpage = int(tk.request.params.get('perpage', 10))
         
     report, results, total, show_org = self._report_view(id, page, perpage)
     
     tk.c.sub_title = _(report['name'])
     
     tk.c.total = total
     tk.c.page = page
     tk.c.perpage = perpage
     tk.c.start_record = (page * perpage) + 1
     tk.c.end_record = min((page * perpage) + perpage, total)
     tk.c.lastpage = int(math.ceil(total / perpage))
     tk.c.report = report
         
     if report['report_on'] == "activities":          
         tk.c.activities = results
     elif report['report_on'] == "details":
         tk.c.users = results
         tk.c.show_org = show_org
     else:
         tk.abort(404, tk._('Report not found'))
         
     return render('vdojstats-report-view.html')
Example #11
0
    def dump(self, resource_id):
        data, errors = dict_fns.validate(dict(request.GET), dump_schema())
        if errors:
            abort(400, u'\n'.join(
                u'{0}: {1}'.format(k, ' '.join(e)) for k, e in errors.items()))

        try:
            dump_to(
                resource_id,
                response,
                fmt=data['format'],
                offset=data['offset'],
                limit=data.get('limit'),
                options={u'bom': data['bom']},
                sort=data['sort'],
                search_params={
                    k: v for k, v in data.items() if k in [
                        'filters',
                        'q',
                        'distinct',
                        'plain',
                        'language',
                        'fields']},
                )
        except ObjectNotFound:
            abort(404, _('DataStore resource not found'))
Example #12
0
    def export(self):

        context = {'model': model, 'user': toolkit.c.user,
                   'auth_user_obj': toolkit.c.userobj}
        try:
            toolkit.check_access('export_csv', context, {})
        except toolkit.NotAuthorized:
            toolkit.abort(401, toolkit._(
                'Need to be organization administrator to export as CSV')
            )
        columns = os.path.join(this_directory(), "columns.json")

        csv_table = export(columns)

        # export() returns user IDs not user names in the "Uploaded By" column
        # because that's all the dataset dicts that package_search() returns
        # contain. Convert these IDs to user names ourselves.
        convert_user_ids_to_user_names(csv_table)

        csv_string = convert_csv_table_to_csv_string(csv_table)

        toolkit.response.headers["Content-type"] = "text/csv"
        toolkit.response.headers["Content-disposition"] = (
            "attachment; filename=export.csv")
        return csv_string
Example #13
0
    def review(self, id):
        """
        sends review notification to all journal admins
        """

        context = self._context()

        try:
            tk.check_access('package_update', context, {'id': id})
        except tk.NotAuthorized:
            tk.abort(403, 'Unauthorized')

        c.pkg_dict = tk.get_action('package_show')(context, {'id': id})

        # avoid multiple notifications (eg. when someone calls review directly)
        if c.pkg_dict.get('dara_edawax_review', 'false') == 'true':
            h.flash_error("Package has already been sent to review")
            redirect(id)

        user_name = tk.c.userobj.fullname or tk.c.userobj.email
        admins = get_group_or_org_admin_ids(c.pkg_dict['owner_org'])
        addresses = map(lambda admin_id: model.User.get(admin_id).email, admins)
        note = n.review(addresses, user_name, id)

        if note:
            c.pkg_dict['dara_edawax_review'] = 'true'
            tk.get_action('package_update')(context, c.pkg_dict)
            h.flash_success('Notification to Editors sent.')
        else:
            h.flash_error('ERROR: Mail could not be sent. Please try again later or contact the site admin.')

        redirect(id)
Example #14
0
 def check(*args, **kwargs):
     id = kwargs['id']
     controller = args[0]
     pkg = tk.get_action('package_show')(None, {'id': id})
     if not check_journal_role(pkg, 'admin') and not h.check_access('sysadmin'):
         tk.abort(403, 'Unauthorized')
     return func(controller, id)
Example #15
0
    def read_dataset(self, _id, _format=None):

        if not _format:
            _format = check_access_header()

        if not _format:
            if toolkit.check_ckan_version(max_version='2.8.99'):
                return read_endpoint(_id)
            else:
                return read_endpoint(_get_package_type(_id), _id)

        _profiles = toolkit.request.params.get('profiles')
        if _profiles:
            _profiles = _profiles.split(',')

        toolkit.response.headers.update(
            {'Content-type': CONTENT_TYPES[_format]})

        try:
            result = toolkit.get_action('dcat_dataset_show')({}, {'id': _id,
                'format': _format, 'profiles': _profiles})
        except toolkit.ObjectNotFound:
            toolkit.abort(404)
        except (toolkit.ValidationError, RDFProfileException) as e:
            toolkit.abort(409, str(e))

        return result
Example #16
0
    def login(self):
        '''Handle an attempt to login using Persona.

        '''
        # Get the params that were posted to /user/login.
        params = toolkit.request.params

        if 'assertion' in params:
            # We've found an assetion from Persona, try to verify it.
            try:
                email = verify_login(params['assertion'])
            except PersonaVerificationError, e:
                toolkit.abort(500)

            user = get_user(email)
            if not user:
                # A user with this email address doesn't yet exist in CKAN,
                # so create one.
                user = toolkit.get_action('user_create')(
                    context={'ignore_auth': True},
                    data_dict={'email': email,
                               'name': generate_user_name(email),
                               'password': generate_password()})

            # Store the name of the verified logged-in user in the Beaker
            # sesssion store.
            pylons.session['ckanext-persona-user'] = user['name']
            pylons.session['ckanext-persona-email'] = email
            pylons.session.save()
Example #17
0
    def request_reset(self):
        context = {"model": model, "session": model.Session, "user": toolkit.c.user, "auth_user_obj": toolkit.c.userobj}
        data_dict = {"id": toolkit.request.params.get("user")}
        try:
            toolkit.check_access("request_reset", context)
        except toolkit.NotAuthorized:
            toolkit.abort(401, toolkit._("Unauthorized to request reset password."))

        if toolkit.request.method == "POST":
            id = toolkit.request.params.get("user")

            context = {"model": model, "user": toolkit.c.user}

            data_dict = {"id": id}
            user_obj = None
            try:
                toolkit.get_action("user_show")(context, data_dict)
                user_obj = context["user_obj"]
            except toolkit.ObjectNotFound:
                h.flash_error(toolkit._("No such user: %s") % id)

            if user_obj:
                try:
                    mailer.send_reset_link(user_obj)
                    h.flash_success(toolkit._("Please check your inbox for " "a reset code."))
                    h.redirect_to("/")
                except mailer.MailerException, e:
                    h.flash_error(toolkit._("Could not send reset link: %s") % unicode(e))
 def save_content(self, context=None):
     context = {'model': model, 'session': model.Session,
                'auth_user_obj': c.userobj,
                'for_view': True}
     try:
         _check_access('is_data_curator', context)
     except toolkit.NotAuthorized, e:
         toolkit.abort(401, e.extra_msg)
Example #19
0
 def my_privates(self, username):
     if not toolkit.c.userobj or toolkit.c.user != username or not toolkit.c.userobj.sysadmin:
         return toolkit.abort(403, )
     user = model.User.get(username)
     if not user:
         return toolkit.abort(404, 'User {0} not found'.format(username))
     queryset = self._my_datasets_query(user, True).limit(20)
     return self.json_response(self._build_datasets(queryset))
 def __before__(self, action, **params):
     super(InventoryAdminController, self).__before__(action, **params)
     context = {'user': c.user, 'auth_user_obj': c.userobj}
     try:
         check_access('sysadmin', context, {})
     except NotAuthorized:
         # TODO @palcu: you should only be in a special group, not be sysadmin
         abort(401, 'Need to be system administrator to check inventory')
Example #21
0
    def organization_dcat_validation(self, _id):
        try:
            dcat_validation_dict = \
                toolkit.get_action('dcat_validation')({}, {'id': _id})
        except toolkit.ObjectNotFound:
            toolkit.abort(404, toolkit._('Organization not found'))

        toolkit.response.headers.update({'Content-type': 'application/json'})

        return json.dumps(dcat_validation_dict)
Example #22
0
 def result_page(offset, limit):
     try:
         return get_action('datastore_search')(None, {
             'resource_id': resource_id,
             'limit':
                 PAGINATE_BY if limit is None
                 else min(PAGINATE_BY, limit),
             'offset': offset,
             })
     except ObjectNotFound:
         abort(404, _('DataStore resource not found'))
Example #23
0
 def start_writer(fields):
     if fmt == 'csv':
         return csv_writer(response, fields, resource_id, bom)
     if fmt == 'tsv':
         return tsv_writer(response, fields, resource_id, bom)
     if fmt == 'json':
         return json_writer(response, fields, resource_id, bom)
     if fmt == 'xml':
         return xml_writer(response, fields, resource_id, bom)
     abort(400, _(
         u'format: must be one of %s') % u', '.join(DUMP_FORMATS))
Example #24
0
    def dump(self, resource_id):
        try:
            offset = int_validator(request.GET.get('offset', 0), {})
        except Invalid as e:
            abort(400, u'offset: ' + e.error)
        try:
            limit = int_validator(request.GET.get('limit'), {})
        except Invalid as e:
            abort(400, u'limit: ' + e.error)
        bom = boolean_validator(request.GET.get('bom'), {})
        fmt = request.GET.get('format', 'csv')

        def start_writer(fields):
            if fmt == 'csv':
                return csv_writer(response, fields, resource_id, bom)
            if fmt == 'tsv':
                return tsv_writer(response, fields, resource_id, bom)
            if fmt == 'json':
                return json_writer(response, fields, resource_id, bom)
            if fmt == 'xml':
                return xml_writer(response, fields, resource_id, bom)
            abort(400, _(
                u'format: must be one of %s') % u', '.join(DUMP_FORMATS))

        def result_page(offset, limit):
            try:
                return get_action('datastore_search')(None, {
                    'resource_id': resource_id,
                    'limit':
                        PAGINATE_BY if limit is None
                        else min(PAGINATE_BY, limit),
                    'offset': offset,
                    })
            except ObjectNotFound:
                abort(404, _('DataStore resource not found'))

        result = result_page(offset, limit)
        columns = [x['id'] for x in result['fields']]

        with start_writer(result['fields']) as wr:
            while True:
                if limit is not None and limit <= 0:
                    break

                for record in result['records']:
                    wr.writerow([record[column] for column in columns])

                if len(result['records']) < PAGINATE_BY:
                    break
                offset += PAGINATE_BY
                if limit is not None:
                    limit -= PAGINATE_BY

                result = result_page(offset, limit)
Example #25
0
    def broken_links_by_email(self):

        try:
            report = toolkit.get_action(
                "ckanext_deadoralive_broken_links_by_email")(data_dict={})
        except toolkit.NotAuthorized:
            toolkit.abort(401)
        extra_vars = {"report": report}

        return toolkit.render("broken_links_by_email.html",
                              extra_vars=extra_vars)
Example #26
0
    def dcat_json(self):

        data_dict = {
            'page': toolkit.request.params.get('page'),
            'modified_since': toolkit.request.params.get('modified_since'),
        }

        try:
            datasets = toolkit.get_action('dcat_datasets_list')({},
                                                                data_dict)
        except toolkit.ValidationError, e:
            toolkit.abort(409, str(e))
Example #27
0
 def all_reported_issues(self, organization_id):
     '''show all issues over max_strikes and are not moderated'''
     try:
         issues, organization = all_reported_issues(organization_id)
         extra_vars = {
             'issues': issues.get('results', []),
             'organization': organization,
         }
         return toolkit.render("issues/moderation.html",
                               extra_vars=extra_vars)
     except toolkit.ObjectNotFound:
         toolkit.abort(404, toolkit._('Organization not found'))
 def get_status(self, request_id):
     context = {
         'model': model,
         'session': model.Session,
     }
     try:
         request_status = toolkit.get_action('get_change_request')(context,
             {'id': request_id})
         if not request_status:
             toolkit.abort(404, toolkit._(
                 'Request {0} not found'.format(request_id)))
     except toolkit.ValidationError, e:
         helpers.flash_error('{0}'.format(e.error_dict['message']))
Example #29
0
 def _call_action(self, action, data_dict=None, key=None):
     context = dict(user=toolkit.c.user)
     if data_dict is None:
         data_dict = dict(toolkit.request.params)
     action_function = toolkit.get_action(action)
     try:
         result = action_function(context, data_dict)
     except toolkit.NotAuthorized:
         toolkit.abort(403)
     toolkit.response.headers['Content-Type'] = 'application/json'
     if key:
         result = result[key]
     return json.dumps(result)
Example #30
0
    def config(self):

        #在「/ckan-admin/dsp-integrate」頁面render之前,先確認使用者是否為sysadmin。

        context = {'model': c.model,
                   'user': c.user, 'auth_user_obj': c.userobj}
        try:
            toolkit.check_access('sysadmin', context, {})
        except toolkit.NotAuthorized:
            toolkit.abort(401, _('Need to be system administrator to administer') )
        c.revision_change_state_allowed = True

        return toolkit.render('admin/sync.html')
Example #31
0
def proxy_resource(context: Context, data_dict: DataDict):
    u'''Chunked proxy for resources. To make sure that the file is not too
    large, first, we try to get the content length from the headers.
    If the headers to not contain a content length (if it is a chinked
    response), we only transfer as long as the transferred data is
    less than the maximum file size.

    '''
    resource_id = data_dict[u'resource_id']
    log.info(u'Proxify resource {id}'.format(id=resource_id))
    try:
        resource = get_action(u'resource_show')(context, {u'id': resource_id})
    except logic.NotFound:
        return abort(404, _(u'Resource not found'))
    url = resource[u'url']

    parts = urlsplit(url)
    if not parts.scheme or not parts.netloc:
        return abort(409, _(u'Invalid URL.'))

    max_file_size = config.get_value(u'ckan.resource_proxy.max_file_size')
    response = make_response()
    try:
        # first we try a HEAD request which may not be supported
        did_get = False
        r = requests.head(url, timeout=TIMEOUT)
        # Servers can refuse HEAD requests. 405 is the appropriate
        # response, but 400 with the invalid method mentioned in the
        # text, or a 403 (forbidden) status is also possible (#2412,
        # #2530)
        if r.status_code in (400, 403, 405):
            r = requests.get(url, timeout=TIMEOUT, stream=True)
            did_get = True
        r.raise_for_status()

        cl = r.headers.get(u'content-length')

        if cl and int(cl) > max_file_size:
            return abort(
                409,
                (u'Content is too large to be proxied. Allowed'
                 u'file size: {allowed}, Content-Length: {actual}.').format(
                     allowed=max_file_size, actual=cl))

        if not did_get:
            r = requests.get(url, timeout=TIMEOUT, stream=True)

        response.headers[u'content-type'] = r.headers[u'content-type']
        response.charset = r.encoding

        length = 0
        chunk_size = config.get_value(u'ckan.resource_proxy.chunk_size')

        for chunk in r.iter_content(chunk_size=chunk_size):
            response.stream.write(chunk)
            length += len(chunk)

            if length >= max_file_size:
                return abort(409,
                             headers={u'content-encoding': u''},
                             detail=u'Content is too large to be proxied.')

    except requests.exceptions.HTTPError as error:
        details = u'Could not proxy resource. Server responded with %s %s' % (
            error.response.status_code, error.response.reason)
        return abort(409, detail=details)
    except requests.exceptions.ConnectionError as error:
        details = u'''Could not proxy resource because a
                            connection error occurred. %s''' % error
        return abort(502, detail=details)
    except requests.exceptions.Timeout:
        details = u'Could not proxy resource because the connection timed out.'
        return abort(504, detail=details)
    return response
            tk.abort(400, tk._(u'Integrity Error'))
        except tk.ValidationError, e:
            errors = e.error_dict
            error_summary = e.error_summary
            return self.new(data_dict, errors, error_summary)

    def _save_edit(self, id, context):
        try:
            data_dict = clean_dict(
                dict_fns.unflatten(
                    tuplize_dict(parse_params(tk.request.params))))
            data_dict['id'] = id
            context['message'] = data_dict.get('log_message', '')
            context['allow_partial_update'] = True
            metadata_schema = tk.get_action('metadata_schema_update')(
                context, data_dict)
            tk.h.redirect_to(
                'metadata_schema_read',
                id=metadata_schema['name'],
                metadata_standard_id=tk.c.metadata_standard['name'])
        except tk.ObjectNotFound:
            tk.abort(404, tk._('Metadata schema not found'))
        except tk.NotAuthorized, e:
            tk.abort(403, e.message)
        except dict_fns.DataError:
            tk.abort(400, tk._(u'Integrity Error'))
        except tk.ValidationError, e:
            errors = e.error_dict
            error_summary = e.error_summary
            return self.edit(id, data_dict, errors, error_summary)
class MetadataSchemaController(tk.BaseController):
    def _set_metadata_standard_context(self, metadata_standard_id):
        if metadata_standard_id and not tk.c.metadata_standard:
            context = {
                'model': model,
                'session': model.Session,
                'user': tk.c.user
            }
            data_dict = {'id': metadata_standard_id}
            try:
                tk.c.metadata_standard = tk.get_action(
                    'metadata_standard_show')(context, data_dict)
            except tk.ObjectNotFound:
                tk.abort(404, tk._('Metadata standard not found'))
            except tk.NotAuthorized:
                tk.abort(403, tk._('Not authorized to see this page'))

    def index(self, metadata_standard_id=None):
        self._set_metadata_standard_context(metadata_standard_id)

        page = tk.h.get_page_number(tk.request.params) or 1
        items_per_page = 21

        context = {
            'model': model,
            'session': model.Session,
            'user': tk.c.user,
            'for_view': True
        }

        q = tk.c.q = tk.request.params.get('q', '')
        sort_by = tk.c.sort_by_selected = tk.request.params.get('sort')
        try:
            tk.check_access('site_read', context)
            tk.check_access('metadata_schema_list', context)
        except tk.NotAuthorized:
            tk.abort(403, tk._('Not authorized to see this page'))

        if tk.c.userobj:
            context['user_id'] = tk.c.userobj.id
            context['user_is_admin'] = tk.c.userobj.sysadmin

        try:
            data_dict_global_results = {
                'metadata_standard_id': metadata_standard_id,
                'all_fields': False,
                'q': q,
                'sort': sort_by,
                'type': 'metadata_schema',
            }
            global_results = tk.get_action('metadata_schema_list')(
                context, data_dict_global_results)
        except tk.ValidationError as e:
            if e.error_dict and e.error_dict.get('message'):
                msg = e.error_dict['message']
            else:
                msg = str(e)
            tk.h.flash_error(msg)
            tk.c.page = helpers.Page([], 0)
            return tk.render('metadata_schema/index.html')

        data_dict_page_results = {
            'metadata_standard_id': metadata_standard_id,
            'all_fields': True,
            'q': q,
            'sort': sort_by,
            'limit': items_per_page,
            'offset': items_per_page * (page - 1),
        }
        page_results = tk.get_action('metadata_schema_list')(
            context, data_dict_page_results)

        tk.c.page = helpers.Page(
            collection=global_results,
            page=page,
            url=tk.h.pager_url,
            items_per_page=items_per_page,
        )

        tk.c.page.items = page_results
        return tk.render('metadata_schema/index.html')

    def new(self,
            data=None,
            errors=None,
            error_summary=None,
            metadata_standard_id=None):
        self._set_metadata_standard_context(metadata_standard_id)

        context = {
            'model': model,
            'session': model.Session,
            'user': tk.c.user,
            'save': 'save' in tk.request.params
        }
        try:
            tk.check_access('metadata_schema_create', context)
        except tk.NotAuthorized:
            tk.abort(403, tk._('Unauthorized to create a metadata schema'))

        if context['save'] and not data and tk.request.method == 'POST':
            return self._save_new(context)

        data = data or {}
        errors = errors or {}
        error_summary = error_summary or {}
        vars = {
            'data': data,
            'errors': errors,
            'error_summary': error_summary,
            'action': 'new',
            'organization_lookup_list': self._organization_lookup_list(),
            'infrastructure_lookup_list': self._infrastructure_lookup_list()
        }

        tk.c.is_sysadmin = authz.is_sysadmin(tk.c.user)
        tk.c.form = tk.render('metadata_schema/edit_form.html',
                              extra_vars=vars)
        return tk.render('metadata_schema/new.html')

    def edit(self,
             id,
             data=None,
             errors=None,
             error_summary=None,
             metadata_standard_id=None):
        self._set_metadata_standard_context(metadata_standard_id)

        context = {
            'model': model,
            'session': model.Session,
            'user': tk.c.user,
            'save': 'save' in tk.request.params,
            'for_edit': True
        }
        data_dict = {'id': id}

        if context['save'] and not data and tk.request.method == 'POST':
            return self._save_edit(id, context)

        try:
            old_data = tk.get_action('metadata_schema_show')(context,
                                                             data_dict)
            data = data or old_data
        except (tk.ObjectNotFound, tk.NotAuthorized):
            tk.abort(404, tk._('Metadata schema not found'))

        tk.c.metadata_schema = old_data
        try:
            tk.check_access('metadata_schema_update', context)
        except tk.NotAuthorized:
            tk.abort(
                403,
                tk._('User %r not authorized to edit %s') % (tk.c.user, id))

        errors = errors or {}
        vars = {
            'data': data,
            'errors': errors,
            'error_summary': error_summary,
            'action': 'edit',
            'organization_lookup_list': self._organization_lookup_list(),
            'infrastructure_lookup_list': self._infrastructure_lookup_list()
        }

        tk.c.form = tk.render('metadata_schema/edit_form.html',
                              extra_vars=vars)
        return tk.render('metadata_schema/edit.html')

    def delete(self, id, metadata_standard_id=None):
        if 'cancel' in tk.request.params:
            tk.h.redirect_to('metadata_schema_edit',
                             id=id,
                             metadata_standard_id=metadata_standard_id)

        context = {'model': model, 'session': model.Session, 'user': tk.c.user}
        try:
            tk.check_access('metadata_schema_delete', context, {'id': id})
        except tk.NotAuthorized:
            tk.abort(403, tk._('Unauthorized to delete metadata schema'))

        try:
            if tk.request.method == 'POST':
                tk.get_action('metadata_schema_delete')(context, {'id': id})
                tk.h.flash_notice(tk._('Metadata Schema has been deleted.'))
                tk.h.redirect_to('metadata_schema_index',
                                 metadata_standard_id=metadata_standard_id)
            tk.c.metadata_schema = tk.get_action('metadata_schema_show')(
                context, {
                    'id': id
                })
        except tk.NotAuthorized:
            tk.abort(403, tk._('Unauthorized to delete metadata schema'))
        except tk.ObjectNotFound:
            tk.abort(404, tk._('Metadata_schema not found'))
        return tk.render('metadata_schema/confirm_delete.html')

    def read(self, id, metadata_standard_id=None):
        self._set_metadata_standard_context(metadata_standard_id)
        context = {
            'model': model,
            'session': model.Session,
            'user': tk.c.user,
            'for_view': True
        }
        tk.c.metadata_schema = tk.get_action('metadata_schema_show')(context, {
            'id': id
        })
        return tk.render('metadata_schema/read.html')

    def about(self, id, metadata_standard_id=None):
        self._set_metadata_standard_context(metadata_standard_id)
        context = {
            'model': model,
            'session': model.Session,
            'user': tk.c.user,
            'for_view': True
        }
        tk.c.metadata_schema = tk.get_action('metadata_schema_show')(context, {
            'id': id
        })
        return tk.render('metadata_schema/about.html')

    def activity(self, id, metadata_standard_id=None):
        self._set_metadata_standard_context(metadata_standard_id)
        context = {
            'model': model,
            'session': model.Session,
            'user': tk.c.user,
            'for_view': True
        }
        tk.c.metadata_schema = tk.get_action('metadata_schema_show')(context, {
            'id': id
        })
        return tk.render('metadata_schema/activity_stream.html')

    @staticmethod
    def _organization_lookup_list():
        """
        Return a list of {'value': name, 'text': display_name} dicts for populating the
        organization select control.
        """
        context = {'model': model, 'session': model.Session, 'user': tk.c.user}
        organizations = tk.get_action('organization_list')(context, {
            'all_fields': True
        })
        return [{'value': '', 'text': tk._('(All)')}] + \
               [{'value': organization['name'], 'text': organization['display_name']}
                for organization in organizations]

    @staticmethod
    def _infrastructure_lookup_list():
        """
        Return a list of {'value': name, 'text': display_name} dicts for populating the
        infrastructure select control.
        """
        context = {'model': model, 'session': model.Session, 'user': tk.c.user}
        infrastructures = tk.get_action('infrastructure_list')(
            context, {
                'all_fields': True
            })
        return [{'value': '', 'text': tk._('(All)')}] + \
               [{'value': infrastructure['name'], 'text': infrastructure['display_name']}
                for infrastructure in infrastructures]

    def _save_new(self, context):
        try:
            data_dict = clean_dict(
                dict_fns.unflatten(
                    tuplize_dict(parse_params(tk.request.params))))
            context['message'] = data_dict.get('log_message', '')
            metadata_schema = tk.get_action('metadata_schema_create')(
                context, data_dict)
            tk.h.redirect_to(
                'metadata_schema_read',
                id=metadata_schema['name'],
                metadata_standard_id=tk.c.metadata_standard['name'])
        except tk.ObjectNotFound:
            tk.abort(404, tk._('Metadata schema not found'))
        except tk.NotAuthorized, e:
            tk.abort(403, e.message)
        except dict_fns.DataError:
            tk.abort(400, tk._(u'Integrity Error'))
    def index(self, metadata_standard_id=None):
        self._set_metadata_standard_context(metadata_standard_id)

        page = tk.h.get_page_number(tk.request.params) or 1
        items_per_page = 21

        context = {
            'model': model,
            'session': model.Session,
            'user': tk.c.user,
            'for_view': True
        }

        q = tk.c.q = tk.request.params.get('q', '')
        sort_by = tk.c.sort_by_selected = tk.request.params.get('sort')
        try:
            tk.check_access('site_read', context)
            tk.check_access('metadata_schema_list', context)
        except tk.NotAuthorized:
            tk.abort(403, tk._('Not authorized to see this page'))

        if tk.c.userobj:
            context['user_id'] = tk.c.userobj.id
            context['user_is_admin'] = tk.c.userobj.sysadmin

        try:
            data_dict_global_results = {
                'metadata_standard_id': metadata_standard_id,
                'all_fields': False,
                'q': q,
                'sort': sort_by,
                'type': 'metadata_schema',
            }
            global_results = tk.get_action('metadata_schema_list')(
                context, data_dict_global_results)
        except tk.ValidationError as e:
            if e.error_dict and e.error_dict.get('message'):
                msg = e.error_dict['message']
            else:
                msg = str(e)
            tk.h.flash_error(msg)
            tk.c.page = helpers.Page([], 0)
            return tk.render('metadata_schema/index.html')

        data_dict_page_results = {
            'metadata_standard_id': metadata_standard_id,
            'all_fields': True,
            'q': q,
            'sort': sort_by,
            'limit': items_per_page,
            'offset': items_per_page * (page - 1),
        }
        page_results = tk.get_action('metadata_schema_list')(
            context, data_dict_page_results)

        tk.c.page = helpers.Page(
            collection=global_results,
            page=page,
            url=tk.h.pager_url,
            items_per_page=items_per_page,
        )

        tk.c.page.items = page_results
        return tk.render('metadata_schema/index.html')
Example #35
0
    def submit_feedback(self):
        """ Retrieves the necessary data and sends a feedback email
        to the appropriate recipient.
        """
        context = {
            'model': model,
            'session': model.Session,
            'user': g.user,
            'for_view': True,
            'auth_user_obj': g.userobj
        }
        protocol, host = h.get_site_protocol_and_host()
        full_current_url = h.full_current_url()

        if protocol is not None and host is not None and host in full_current_url:
            package = get_action('package_show')(context, {
                'id': request.GET['id']
            })
            if 'error' not in package:
                data_dict = {}
                not_provided = 'Not provided'
                if 'name' not in request.GET:
                    data_dict['name'] = not_provided
                else:
                    data_dict['name'] = request.GET['name'].encode('utf8')
                if 'email' not in request.GET:
                    data_dict['email'] = not_provided
                else:
                    data_dict['email'] = request.GET['email'].encode('utf8')
                if 'comments' not in request.GET:
                    data_dict['comments'] = not_provided
                else:
                    data_dict['comments'] = request.GET['comments'].encode(
                        'utf8')

                data_dict['resource_id'] = request.GET.get('resource_id', '')
                data_dict['captcha'] = request.GET.get('captcha', '')

                if (data_dict.get('captcha', '') or request.GET.get(
                        'captchaCatch', 'none') not in ['dev', 'prod']):
                    # Do not indicate failure or success since captcha was filled likely bot;
                    # 7 is the expected arguments in the query string;
                    # captchaCatch is serverside generated value hence can either be 'dev' or 'prod'
                    redirect_to('/')
                    return package

                # If there is value for either maintenance_email or author_email, use that.
                # If both of them null then send the email to [email protected]
                # Logic written to maintain legacy data
                # Once all the records in database have 'maintainer_email',
                # remove this and feedback_email = package.get('maintainer_email', '')
                feedback_email = package.get('maintainer_email', '')
                if not feedback_email:
                    feedback_email = package.get('author_email', '')
                if not feedback_email:
                    feedback_email = '*****@*****.**'

                if 'organization' in package and package['organization']:
                    feedback_organisation = _strip_non_ascii(
                        package['organization'].get('title', ''))
                else:
                    feedback_organisation = 'None'
                feedback_resource_name = ''
                feedback_dataset = _strip_non_ascii(package.get('title', ''))

                package_name = _strip_non_ascii(package.get('name', ''))
                feedback_origins = "{0}/dataset/{1}".format(host, package_name)

                if data_dict['resource_id'] != '':
                    feedback_origins = "{0}/resource/{1}".format(
                        feedback_origins, data_dict['resource_id'])
                    package_resources = package.get('resources', [])
                    for resource in package_resources:
                        if data_dict['resource_id'] == resource.get('id'):
                            feedback_resource_name = _strip_non_ascii(
                                resource.get('name', ''))

                email_subject = '{0} Feedback {1} {2}'.format(
                    host, feedback_dataset, feedback_resource_name)
                email_recipient_name = 'All'

                email_to = (config.get('feedback_form_recipients',
                                       '')).split(',')
                if feedback_email != '' and feedback_email:
                    email_to.append(feedback_email)
                else:
                    feedback_email = ''

                email_to = [e for e in email_to if e is not None]

                email_to = [i.strip() for i in email_to if i.strip() != '']
                if email_to:
                    email_body = "Name: {0} \r\nEmail: {1} \r\nComments: {2} \r\nFeedback Organisation: {3} \r\n" \
                        "Feedback Email: {4} \r\nFeedback Dataset: {5} \r\nFeedback Resource: {6} \r\n" \
                        "Feedback URL: {7}://{8}".format(
                            cgi.escape(_strip_non_ascii(data_dict['name'])),
                            cgi.escape(_strip_non_ascii(data_dict['email'])),
                            cgi.escape(_strip_non_ascii(data_dict['comments'])),
                            cgi.escape(feedback_organisation),
                            cgi.escape(_strip_non_ascii(feedback_email)),
                            cgi.escape(feedback_dataset),
                            cgi.escape(feedback_resource_name),
                            cgi.escape(protocol),
                            cgi.escape(feedback_origins)
                        )
                    try:
                        _feedback_mail_recipient(email_recipient_name,
                                                 email_to, g.site_title,
                                                 g.site_url, email_subject,
                                                 email_body)
                    except Exception:
                        return abort(
                            404,
                            'This form submission is invalid or CKAN mail is not configured.'
                        )

                    # Redirect to home page if no thanks page is found
                    success_redirect = config.get('feedback_redirection', '/')
                    req = requests.get(protocol + '://' + host +
                                       success_redirect,
                                       verify=False)
                    if req.status_code == requests.codes.ok:
                        redirect_to(success_redirect)
                    else:
                        redirect_to('/')
                else:
                    abort(404, 'Form submission is invalid no recipients.')

            return package
        else:
            abort(404, 'Invalid request source')
Example #36
0
def package_history(id: str, activity_id: str) -> Union[Response, str]:
    context = cast(
        Context,
        {
            "model": model,
            "session": model.Session,
            "user": tk.g.user,
            "for_view": True,
            "auth_user_obj": tk.g.userobj,
        },
    )
    data_dict = {"id": id, "include_tracking": True}

    # check if package exists
    try:
        pkg_dict = tk.get_action("package_show")(context, data_dict)
        pkg = context["package"]
    except (tk.ObjectNotFound, tk.NotAuthorized):
        return tk.abort(404, tk._("Dataset not found"))

    # if the user specified a package id, redirect to the package name
    if (
        data_dict["id"] == pkg_dict["id"]
        and data_dict["id"] != pkg_dict["name"]
    ):
        return tk.h.redirect_to(
            "activity.package_history",
            id=pkg_dict["name"],
            activity_id=activity_id,
        )

    tk.g.pkg_dict = pkg_dict
    tk.g.pkg = pkg
    # NB templates should not use g.pkg, because it takes no account of
    # activity_id

    # view an 'old' version of the package, as recorded in the
    # activity stream
    try:
        activity = tk.get_action("activity_show")(
            context, {"id": activity_id, "include_data": True}
        )
    except tk.ObjectNotFound:
        tk.abort(404, tk._("Activity not found"))
    except tk.NotAuthorized:
        tk.abort(403, tk._("Unauthorized to view activity data"))
    current_pkg = pkg_dict
    try:
        pkg_dict = activity["data"]["package"]
    except KeyError:
        tk.abort(404, tk._("Dataset not found"))
    if "id" not in pkg_dict or "resources" not in pkg_dict:
        log.info(
            "Attempt to view unmigrated or badly migrated dataset "
            "{} {}".format(id, activity_id)
        )
        tk.abort(
            404, tk._("The detail of this dataset activity is not available")
        )
    if pkg_dict["id"] != current_pkg["id"]:
        log.info(
            "Mismatch between pkg id in activity and URL {} {}".format(
                pkg_dict["id"], current_pkg["id"]
            )
        )
        # the activity is not for the package in the URL - don't allow
        # misleading URLs as could be malicious
        tk.abort(404, tk._("Activity not found"))
    # The name is used lots in the template for links, so fix it to be
    # the current one. It's not displayed to the user anyway.
    pkg_dict["name"] = current_pkg["name"]

    # Earlier versions of CKAN only stored the package table in the
    # activity, so add a placeholder for resources, or the template
    # will crash.
    pkg_dict.setdefault("resources", [])

    # can the resources be previewed?
    for resource in pkg_dict["resources"]:
        resource_views = tk.get_action("resource_view_list")(
            context, {"id": resource["id"]}
        )
        resource["has_views"] = len(resource_views) > 0

    package_type = pkg_dict["type"] or "dataset"
    _setup_template_variables(context, {"id": id}, package_type=package_type)

    return tk.render(
        "package/history.html",
        {
            "dataset_type": package_type,
            "pkg_dict": pkg_dict,
            "pkg": pkg,
        },
    )
Example #37
0
def package_activity(id: str) -> Union[Response, str]:  # noqa
    """Render this package's public activity stream page."""
    after = tk.h.get_request_param("after")
    before = tk.h.get_request_param("before")
    activity_type = tk.h.get_request_param("activity_type")

    context = cast(
        Context,
        {
            "model": model,
            "session": model.Session,
            "user": tk.g.user,
            "for_view": True,
            "auth_user_obj": tk.g.userobj,
        },
    )

    data_dict = {"id": id}
    base_limit = tk.config.get_value("ckan.activity_list_limit")
    max_limit = tk.config.get_value("ckan.activity_list_limit_max")
    limit = min(base_limit, max_limit)
    activity_types = [activity_type] if activity_type else None
    is_first_page = after is None and before is None

    try:
        pkg_dict = tk.get_action("package_show")(context, data_dict)
        activity_dict = {
            "id": pkg_dict["id"],
            "after": after,
            "before": before,
            # ask for one more just to know if this query has more results
            "limit": limit + 1,
            "activity_types": activity_types,
        }
        pkg = context["package"]
        package_activity_stream = tk.get_action("package_activity_list")(
            context, activity_dict
        )
        dataset_type = pkg_dict["type"] or "dataset"
    except tk.ObjectNotFound:
        return tk.abort(404, tk._("Dataset not found"))
    except tk.NotAuthorized:
        return tk.abort(403, tk._("Unauthorized to read dataset %s") % id)
    except tk.ValidationError:
        return tk.abort(400, tk._("Invalid parameters"))

    prev_page = None
    next_page = None

    has_more = len(package_activity_stream) > limit
    # remove the extra item if exists
    if has_more:
        if after:
            # drop the first element
            package_activity_stream.pop(0)
        else:
            # drop the last element
            package_activity_stream.pop()

    # if "after", we came from the next page. So it exists
    # if "before" (or is_first_page), we only show next page if we know
    # we have more rows
    if after or (has_more and (before or is_first_page)):
        before_time = datetime.fromisoformat(
            package_activity_stream[-1]["timestamp"]
        )
        next_page = tk.h.url_for(
            "dataset.activity",
            id=id,
            activity_type=activity_type,
            before=before_time.timestamp(),
        )

    # if "before", we came from the previous page. So it exists
    # if "after", we only show previous page if we know
    # we have more rows
    if before or (has_more and after):
        after_time = datetime.fromisoformat(
            package_activity_stream[0]["timestamp"]
        )
        prev_page = tk.h.url_for(
            "dataset.activity",
            id=id,
            activity_type=activity_type,
            after=after_time.timestamp(),
        )

    return tk.render(
        "package/activity.html",
        {
            "dataset_type": dataset_type,
            "pkg_dict": pkg_dict,
            "pkg": pkg,
            "activity_stream": package_activity_stream,
            "id": id,  # i.e. package's current name
            "limit": limit,
            "has_more": has_more,
            "activity_type": activity_type,
            "activity_types": VALIDATORS_PACKAGE_ACTIVITY_TYPES.keys(),
            "prev_page": prev_page,
            "next_page": next_page,
        },
    )
Example #38
0
def resource_history(id: str, resource_id: str, activity_id: str) -> str:
    context = cast(
        Context,
        {
            "model": model,
            "session": model.Session,
            "user": tk.g.user,
            "auth_user_obj": tk.g.userobj,
            "for_view": True,
        },
    )

    try:
        package = tk.get_action("package_show")(context, {"id": id})
    except (tk.ObjectNotFound, tk.NotAuthorized):
        return tk.abort(404, tk._("Dataset not found"))

    # view an 'old' version of the package, as recorded in the
    # activity stream
    current_pkg = package
    try:
        activity = context["session"].query(Activity).get(activity_id)
        assert activity
        package = activity.data["package"]
    except AttributeError:
        tk.abort(404, tk._("Dataset not found"))

    if package["id"] != current_pkg["id"]:
        log.info(
            "Mismatch between pkg id in activity and URL {} {}".format(
                package["id"], current_pkg["id"]
            )
        )
        # the activity is not for the package in the URL - don't allow
        # misleading URLs as could be malicious
        tk.abort(404, tk._("Activity not found"))
    # The name is used lots in the template for links, so fix it to be
    # the current one. It's not displayed to the user anyway.
    package["name"] = current_pkg["name"]

    # Don't crash on old (unmigrated) activity records, which do not
    # include resources or extras.
    package.setdefault("resources", [])

    resource = None
    for res in package.get("resources", []):
        if res["id"] == resource_id:
            resource = res
            break
    if not resource:
        return tk.abort(404, tk._("Resource not found"))

    # get package license info
    license_id = package.get("license_id")
    try:
        package["isopen"] = model.Package.get_license_register()[
            license_id
        ].isopen()
    except KeyError:
        package["isopen"] = False

    resource_views = tk.get_action("resource_view_list")(
        context, {"id": resource_id}
    )
    resource["has_views"] = len(resource_views) > 0

    current_resource_view = None
    view_id = tk.request.args.get("view_id")
    if resource["has_views"]:
        if view_id:
            current_resource_view = [
                rv for rv in resource_views if rv["id"] == view_id
            ]
            if len(current_resource_view) == 1:
                current_resource_view = current_resource_view[0]
            else:
                return tk.abort(404, tk._("Resource view not found"))
        else:
            current_resource_view = resource_views[0]

    # required for nav menu
    pkg = context["package"]
    dataset_type = pkg.type

    # TODO: remove
    tk.g.package = package
    tk.g.resource = resource
    tk.g.pkg = pkg
    tk.g.pkg_dict = package

    extra_vars: dict[str, Any] = {
        "resource_views": resource_views,
        "current_resource_view": current_resource_view,
        "dataset_type": dataset_type,
        "pkg_dict": package,
        "package": package,
        "resource": resource,
        "pkg": pkg,  # NB it is the current version of the dataset, so ignores
        # activity_id. Still used though in resource views for
        # backward compatibility
    }

    return tk.render("package/resource_history.html", extra_vars)
Example #39
0
def group_changes_multiple(is_organization: bool, group_type: str) -> str:
    """
    Called when a user specifies a range of versions they want to look at
    changes between. Verifies that the range is valid and finds the set of
    activity diffs for the changes in the given version range, then
    re-renders changes.html with the list.
    """
    set_org(is_organization)
    extra_vars = {}
    new_id = tk.h.get_request_param("new_id")
    old_id = tk.h.get_request_param("old_id")

    context = cast(
        Context,
        {
            "model": model,
            "session": model.Session,
            "user": tk.g.user,
            "auth_user_obj": tk.g.userobj,
        },
    )

    # check to ensure that the old activity is actually older than
    # the new activity
    old_activity = tk.get_action("activity_show")(
        context, {"id": old_id, "include_data": False}
    )
    new_activity = tk.get_action("activity_show")(
        context, {"id": new_id, "include_data": False}
    )

    old_timestamp = old_activity["timestamp"]
    new_timestamp = new_activity["timestamp"]

    t1 = datetime.strptime(old_timestamp, "%Y-%m-%dT%H:%M:%S.%f")
    t2 = datetime.strptime(new_timestamp, "%Y-%m-%dT%H:%M:%S.%f")

    time_diff = t2 - t1
    # if the time difference is negative, just return the change that put us
    # at the more recent ID we were just looking at
    # TODO: do something better here - go back to the previous page,
    # display a warning that the user can't look at a sequence where
    # the newest item is older than the oldest one, etc
    if time_diff.total_seconds() < 0:
        return group_changes(
            tk.h.get_request_param("current_new_id"),
            group_type,
            is_organization,
        )

    done = False
    current_id = new_id
    diff_list = []

    while not done:
        try:
            activity_diff = tk.get_action("activity_diff")(
                context,
                {
                    "id": current_id,
                    "object_type": "group",
                    "diff_type": "html",
                },
            )
        except tk.ObjectNotFound as e:
            log.info("Activity not found: {} - {}".format(str(e), current_id))
            return tk.abort(404, tk._("Activity not found"))
        except tk.NotAuthorized:
            return tk.abort(403, tk._("Unauthorized to view activity data"))

        diff_list.append(activity_diff)

        if activity_diff["activities"][0]["id"] == old_id:
            done = True
        else:
            current_id = activity_diff["activities"][0]["id"]

    group_id: str = diff_list[0]["activities"][1]["data"]["group"]["id"]
    current_group_dict = tk.get_action(group_type + "_show")(
        context, {"id": group_id}
    )
    group_activity_list = tk.get_action(group_type + "_activity_list")(
        context, {"id": group_id, "limit": 100}
    )

    extra_vars: dict[str, Any] = {
        "activity_diffs": diff_list,
        "group_dict": current_group_dict,
        "group_activity_list": group_activity_list,
        "group_type": current_group_dict["type"],
    }

    return tk.render(_replace_group_org("group/changes.html"), extra_vars)
Example #40
0
def _get_dashboard_context(
    filter_type: Optional[str] = None,
    filter_id: Optional[str] = None,
    q: Optional[str] = None,
) -> dict[str, Any]:
    """Return a dict needed by the dashboard view to determine context."""

    def display_name(followee: dict[str, Any]) -> Optional[str]:
        """Return a display name for a user, group or dataset dict."""
        display_name = followee.get("display_name")
        fullname = followee.get("fullname")
        title = followee.get("title")
        name = followee.get("name")
        return display_name or fullname or title or name

    if filter_type and filter_id:
        context = cast(
            Context,
            {
                "model": model,
                "session": model.Session,
                "user": tk.g.user,
                "auth_user_obj": tk.g.userobj,
                "for_view": True,
            },
        )
        data_dict: dict[str, Any] = {
            "id": filter_id,
            "include_num_followers": True,
        }
        followee = None

        action_functions = {
            "dataset": "package_show",
            "user": "******",
            "group": "group_show",
            "organization": "organization_show",
        }
        action_name = action_functions.get(filter_type)
        if action_name is None:
            tk.abort(404, tk._("Follow item not found"))

        action_function = tk.get_action(action_name)
        try:
            followee = action_function(context, data_dict)
        except (tk.ObjectNotFound, tk.NotAuthorized):
            tk.abort(404, tk._("{0} not found").format(filter_type))

        if followee is not None:
            return {
                "filter_type": filter_type,
                "q": q,
                "context": display_name(followee),
                "selected_id": followee.get("id"),
                "dict": followee,
            }

    return {
        "filter_type": filter_type,
        "q": q,
        "context": tk._("Everything"),
        "selected_id": False,
        "dict": None,
    }
Example #41
0
    def restricted_request_access_form(self,
                                       package_id,
                                       resource_id,
                                       data=None,
                                       errors=None,
                                       error_summary=None):
        '''Redirects to form
        '''
        user_id = toolkit.c.user

        if not user_id:
            toolkit.abort(
                401,
                _('Access request form is available to logged in users only.'))

        context = {
            'model': model,
            'session': model.Session,
            'user': user_id,
            'save': 'save' in request.params
        }

        data = data or {}
        errors = errors or {}
        error_summary = error_summary or {}

        if (context['save']) and not data and not errors:
            return self._send_request(context)

        if not data:
            data['package_id'] = package_id
            data['resource_id'] = resource_id

            try:
                user = toolkit.get_action('user_show')(context, {
                    'id': user_id
                })
                data['user_id'] = user_id
                data['user_name'] = user.get('display_name', user_id)
                data['user_email'] = user.get('email', '')

                resource_name = ""

                pkg = toolkit.get_action('package_show')(context, {
                    'id': package_id
                })
                data['package_name'] = pkg.get('name')
                resources = pkg.get('resources', [])
                for resource in resources:
                    if resource['id'] == resource_id:
                        resource_name = resource['name']
                        break
                else:
                    toolkit.abort(404, 'Dataset resource not found')
                # get mail
                contact_details = self._get_contact_details(pkg)
            except toolkit.ObjectNotFound:
                toolkit.abort(404, _('Dataset not found'))
            except Exception as e:
                log.warn('Exception Request Form: ' + repr(e))
                toolkit.abort(
                    404,
                    _('Exception retrieving dataset for the form (' + str(e) +
                      ')'))
            except:
                toolkit.abort(
                    404,
                    _('Unknown exception retrieving dataset for the form'))

            data['resource_name'] = resource_name
            data['maintainer_email'] = contact_details.get('contact_email', '')
            data['maintainer_name'] = contact_details.get('contact_name', '')
        else:
            pkg = data.get('pkg_dict', {})

        extra_vars = {
            'pkg_dict': pkg,
            'data': data,
            'errors': errors,
            'error_summary': error_summary
        }
        return render('restricted/restricted_request_access_form.html',
                      extra_vars=extra_vars)
Example #42
0
    def format_mapping(self):
        try:
            tk.check_access('sysadmin', {'user': g.user, model: model})
        except tk.NotAuthorized:
            return tk.abort(403)
        if request.method == 'POST':
            old = request.POST.get('from')
            new = request.POST.get('to')
            if old and new:
                ids = set()
                res_query = model.Session.query(model.Resource).filter_by(
                    format=old, state='active'
                )
                for res in res_query:
                    ids.add(res.package_id)

                res_query.update({'format': new})
                model.Session.commit()
                for id in ids:
                    clear(id)
                    rebuild(id, defer_commit=True)
                commit()
                tk.h.flash_success(
                    'Updated. Records changed: {}'.format(len(ids))
                )
            return tk.redirect_to('format_mapping')

        defined = set(
            map(lambda (_1, fmt, _3): fmt,
                h.resource_formats().values())
        )
        db_formats = model.Session.query(
            model.Resource.format, func.count(model.Resource.id),
            func.count(model.PackageExtra.value)
        ).outerjoin(
            model.PackageExtra,
            (model.Resource.package_id == model.PackageExtra.package_id)
            & ((model.PackageExtra.key == 'harvest_portal')
               | (model.PackageExtra.key.is_(None)))
        ).group_by(model.Resource.format).filter(
            model.Resource.format != '', model.Resource.state == 'active'
        )
        db_formats = db_formats.all()

        format_types = {
            f: {
                True: 'Partially external',
                e == 0: 'Local',
                t - e == 0: 'External'
            }[True]
            for (f, t, e) in db_formats
        }
        used = set(format_types)
        undefined = used - defined

        extra_vars = {
            'undefined': undefined,
            'defined': defined,
            'format_types': format_types
        }
        return tk.render('admin/format_mapping.html', extra_vars)
def before_request():
    try:
        context = dict(model=model, user=g.user, auth_user_obj=g.userobj)
        logic.check_access(u'sysadmin', context)
    except NotAuthorized:
        abort(403, _(u'Need to be system administrator to administer'))
def _add_or_reply(comment_type, content_item_id, content_type, parent_id=None):
    """
    Allows the user to add a comment to an existing dataset or datarequest
    :param comment_type: Either 'new' or 'reply'
    :param content_item_id:
    :param content_type: string 'dataset' or 'datarequest'
    :return:
    """
    content_type = 'dataset' if 'content_type' not in vars() else content_type

    context = {'model': model, 'user': c.user}

    data_dict = {'id': content_item_id}

    # Auth check to make sure the user can see this content item
    helpers.check_content_access(content_type, context, data_dict)

    try:
        # Load the content item
        helpers.get_content_item(content_type, context, data_dict)
    except:
        abort(403)

    if request.method == 'POST':
        data_dict = clean_dict(
            unflatten(
                tuplize_dict(
                    parse_params(
                        request_helpers.RequestHelper(
                            request).get_post_params()))))
        data_dict['parent_id'] = c.parent.id if 'parent' in dir(c) else None

        data_dict['url'] = '/%s/%s' % (content_type,
                                       content_item_id if content_type
                                       == 'datarequest' else c.pkg.name)

        success = False
        try:
            res = get_action('comment_create')(context, data_dict)
            success = True
        except ValidationError as ve:
            log.debug(ve)
            if ve.error_dict and ve.error_dict.get('message'):
                msg = ve.error_dict['message']
            else:
                msg = str(ve)
            h.flash_error(msg)
        except Exception as e:
            log.debug(e)
            abort(403)

        if success:
            email_notifications.notify_admins_and_comment_notification_recipients(
                helpers.get_org_id(content_type),
                toolkit.c.userobj,
                'notification-new-comment',
                content_type,
                helpers.get_content_item_id(content_type),
                res['thread_id'],
                res['parent_id'] if comment_type == 'reply' else None,
                res['id'],
                c.pkg_dict['title']
                if content_type == 'dataset' else c.datarequest['title'],
                res['content']  # content is the comment that has been cleaned up in the action comment_create
            )

            if notification_helpers.comment_notification_recipients_enabled():
                if comment_type == 'reply':
                    # Add the user who submitted the reply to comment notifications for this thread
                    notification_helpers.add_commenter_to_comment_notifications(
                        toolkit.c.userobj.id, res['thread_id'],
                        res['parent_id'])
                else:
                    # Add the user who submitted the comment notifications for this new thread
                    notification_helpers.add_commenter_to_comment_notifications(
                        toolkit.c.userobj.id, res['thread_id'], res['id'])

        return h.redirect_to(
            helpers.get_redirect_url(
                content_type, content_item_id if content_type == 'datarequest'
                else c.pkg.name, 'comment_' + str(res['id']) if success else
                ('comment_form' if comment_type == 'new' else 'reply_' +
                 str(parent_id))))

    return helpers.render_content_template(content_type)
Example #45
0
    def view(self, report_name, organization=None, refresh=False):
        try:
            report = t.get_action('report_show')({}, {'id': report_name})
        except t.NotAuthorized:
            t.abort(401)
        except t.ObjectNotFound:
            t.abort(404)

        # ensure correct url is being used
        if 'organization' in t.request.environ['pylons.routes_dict'] and \
                'organization' not in report['option_defaults']:
            t.redirect_to(helpers.relative_url_for(organization=None))
        elif 'organization' not in t.request.environ['pylons.routes_dict'] and \
                'organization' in report['option_defaults'] and \
                report['option_defaults']['organization']:
            org = report['option_defaults']['organization']
            t.redirect_to(helpers.relative_url_for(organization=org))
        if 'organization' in t.request.params:
            # organization should only be in the url - let the param overwrite
            # the url.
            t.redirect_to(helpers.relative_url_for())

        # options
        options = Report.add_defaults_to_options(t.request.params,
                                                 report['option_defaults'])
        option_display_params = {}
        if 'format' in options:
            format = options.pop('format')
        else:
            format = None
        if 'organization' in report['option_defaults']:
            options['organization'] = organization
        options_html = {}
        c.options = options  # for legacy genshi snippets
        for option in options:
            if option not in report['option_defaults']:
                # e.g. 'refresh' param
                log.warn(
                    'Not displaying report option HTML for param %s as option not recognized'
                )
                continue
            option_display_params = {
                'value': options[option],
                'default': report['option_defaults'][option]
            }
            try:
                options_html[option] = \
                    t.render_snippet('report/option_%s.html' % option,
                                     data=option_display_params)
            except TemplateNotFound:
                log.warn(
                    'Not displaying report option HTML for param %s as no template found'
                )
                continue

        # Alternative way to refresh the cache - not in the UI, but is
        # handy for testing
        try:
            refresh = t.asbool(t.request.params.get('refresh'))
            if 'refresh' in options:
                options.pop('refresh')
        except ValueError:
            refresh = False

        # Refresh the cache if requested
        if t.request.method == 'POST' and not format:
            refresh = True

        if refresh:
            try:
                t.get_action('report_refresh')({}, {
                    'id': report_name,
                    'options': options
                })
            except t.NotAuthorized:
                t.abort(401)
            # Don't want the refresh=1 in the url once it is done
            t.redirect_to(helpers.relative_url_for(refresh=None))

        # Check for any options not allowed by the report
        for key in options:
            if key not in report['option_defaults']:
                t.abort(400, 'Option not allowed by report: %s' % key)

        try:
            data, report_date = t.get_action('report_data_get')(
                {}, {
                    'id': report_name,
                    'options': options
                })
        except t.ObjectNotFound:
            t.abort(404)
        except t.NotAuthorized:
            t.abort(401)

        if format and format != 'html':
            ensure_data_is_dicts(data)
            anonymise_user_names(data,
                                 organization=options.get('organization'))
            if format == 'csv':
                try:
                    key = t.get_action('report_key_get')({}, {
                        'id': report_name,
                        'options': options
                    })
                except t.NotAuthorized:
                    t.abort(401)
                filename = 'report_%s.csv' % key
                t.response.headers['Content-Type'] = 'application/csv'
                t.response.headers['Content-Disposition'] = str(
                    'attachment; filename=%s' % (filename))
                return make_csv_from_dicts(data['table'])
            elif format == 'json':
                t.response.headers['Content-Type'] = 'application/json'
                data['generated_at'] = report_date
                return json.dumps(data)
            else:
                t.abort(400, 'Format not known - try html, json or csv')

        are_some_results = bool(data['table'] if 'table' in data else data)
        # A couple of context variables for legacy genshi reports
        c.data = data
        c.options = options
        return t.render('report/view.html',
                        extra_vars={
                            'report': report,
                            'report_name': report_name,
                            'data': data,
                            'report_date': report_date,
                            'options': options,
                            'options_html': options_html,
                            'report_template': report['template'],
                            'are_some_results': are_some_results
                        })