def remove_pipe(self, id, pipeline_id): assert id assert pipeline_id try: data_dict = {'id': id} context = {'model': model, 'session': model.Session, 'user': c.user or c.author, 'auth_user_obj': c.userobj} check_access('package_update', context, data_dict) package = get_action('package_show')(context, data_dict) # id is most probably is package.name so we have to get actual id pipe = Pipelines(package['id'], pipeline_id).get() if not pipe: h.flash_error(_(u"Couldn't remove pipeline, because there is no such pipeline assigned to this dataset.")) base.redirect(h.url_for('pipe_assign', id=id)) else: pipe_id = pipe.pipeline_id pipe.delete() pipe.commit() h.flash_success(_(u'Pipeline removed from dataset successfully')) disable_schedules_for_pipe(pipe_id) except NotFound: abort(404, _(u'Dataset not found')) except NotAuthorized: abort(401, _(u'User {user} not authorized to edit {id}').format(user=c.user, id=id)) base.redirect(h.url_for('pipe_assign', id=id))
def test_map_pylons_to_flask_route(self): app = self._get_test_app() response = app.get(url_for('my_home_route')) assert 'Welcome to CKAN' in response.body response = app.get(url_for('home')) assert 'Welcome to CKAN' in response.body
def _set_other_links(self, suffix='', other_params_dict=None): named_route = self._get_named_route() params = {k: v for k, v in request.params.items() if k in ['sort', 'q', 'organization', 'tags', 'vocab_Topics', 'license_id', 'groups', 'res_format', '_show_filters']} if other_params_dict: params.update(other_params_dict) c.other_links = {} c.other_links['all'] = h.url_for(named_route, **params) + suffix params_copy = params.copy() params_copy['ext_indicator'] = 1 c.other_links['indicators'] = h.url_for(named_route, **params_copy) + suffix params_copy['ext_indicator'] = 0 c.other_links['datasets'] = h.url_for(named_route, **params_copy) + suffix params_copy = params.copy() params_copy['ext_feature'] = 1 c.other_links['features'] = h.url_for(named_route, **params_copy) + suffix # c.other_links['params'] = params c.other_links['params_noq'] = {k: v for k, v in params.items() if k not in ['q', '_show_filters', 'id']} c.other_links['params_nosort_noq'] = {k: v for k, v in params.items() if k not in ['sort', 'q', 'id']}
def test_already_requested_doi(self): model.repo.rebuild_db() dataset = factories.Dataset(author='test author') user = factories.Sysadmin() env = {'REMOTE_USER': user['name'].encode('ascii')} # Should redirect back to dataset page response = self.app.get(url_for( controller='ckanext.ands.controller:DatasetDoiController', action='dataset_doi', id=dataset['name']), extra_environ=env) for field in doi_request_fields: response.mustcontain(field) form = response.forms['dataset-doi'] for field in form.fields: if field != 'save': form.set(field, 'test') with patch.object(ckanext.ands.controller, 'mail_recipient') as mock_mail: response = form.submit('submit', extra_environ=env) response = self.app.get(url_for( controller='ckanext.ands.controller:DatasetDoiController', action='dataset_doi', id=dataset['name']), extra_environ=env) response = response.follow(extra_environ=env) response.mustcontain( "You've already requested a DOI for this dataset. You'll be emailed if it is approved.")
def test_catalog_pagination(self): for i in xrange(12): factories.Dataset() app = self._get_test_app() url = url_for('dcat_catalog', _format='rdf') response = app.get(url) content = response.body g = Graph() g.parse(data=content, format='xml') eq_(len([d for d in g.subjects(RDF.type, DCAT.Dataset)]), 10) pagination = [o for o in g.subjects(RDF.type, HYDRA.PagedCollection)][0] eq_(self._object_value(g, pagination, HYDRA.totalItems), '12') eq_(self._object_value(g, pagination, HYDRA.itemsPerPage), '10') eq_(self._object_value(g, pagination, HYDRA.firstPage), url_for('dcat_catalog', _format='rdf', page=1, host='localhost')) eq_(self._object_value(g, pagination, HYDRA.nextPage), url_for('dcat_catalog', _format='rdf', page=2, host='localhost')) eq_(self._object_value(g, pagination, HYDRA.lastPage), url_for('dcat_catalog', _format='rdf', page=2, host='localhost'))
def _filter_resource_tags(package): """ Returns resource links for a package such that any resource with a unique format returns a link to the resource, and any link with a duplicate format returns a link to the package page. """ res_list = [] all_res = h.dict_list_reduce(package['resources'], 'format', unique=False) uniques = [x for x in all_res if all_res.count(x) == 1] non_uniques = set(all_res) - set(uniques) for resource in package['resources']: if resource['format'] in uniques: res_list.append({ 'format': resource['format'], 'url': h.url_for(controller='package', action='resource_read', id=package['name'], resource_id=resource['id']) }) elif resource['format'] in non_uniques: res_list.append({ 'format': resource['format'], 'url': h.url_for(controller='package', action='read', id=package['name']) }) non_uniques.remove(resource['format']) return res_list
def login(self, error=None): # Do any plugin login stuff for item in p.PluginImplementations(p.IAuthenticator): item.login() if 'error' in request.params: h.flash_error(request.params['error']) if request.environ['SCRIPT_NAME'] and g.openid_enabled: # #1662 restriction log.warn('Cannot mount CKAN at a URL and login with OpenID.') g.openid_enabled = False if not c.user: came_from = request.params.get('came_from') if not came_from: came_from = h.url_for( controller='user', action='logged_in', __ckan_no_root=True) c.login_handler = h.url_for( self._get_repoze_handler('login_handler_path'), came_from=came_from) if error: vars = {'error_summary': {'': error}} else: vars = {} return render('user/login.html', extra_vars=vars) else: return render('user/logout_first.html')
def pager_url(q=None, page=None): if sort_option: url = h.url_for( action_alias, page=page, sort=sort_option) + '#datasets-section' else: url = h.url_for(action_alias, page=page) + '#datasets-section' return url
def test_group_index(self): app = self._get_test_app() for i in xrange(1, 26): _i = '0' + str(i) if i < 10 else i factories.Group( name='test-group-{0}'.format(_i), title='Test Group {0}'.format(_i)) url = url_for('group.index') response = app.get(url) for i in xrange(1, 21): _i = '0' + str(i) if i < 10 else i assert_in('Test Group {0}'.format(_i), response) assert 'Test Group 21' not in response url = url_for('group.index', page=1) response = app.get(url) for i in xrange(1, 21): _i = '0' + str(i) if i < 10 else i assert_in('Test Group {0}'.format(_i), response) assert 'Test Group 21' not in response url = url_for('group.index', page=2) response = app.get(url) for i in xrange(21, 26): assert_in('Test Group {0}'.format(i), response) assert 'Test Group 20' not in response
def uebpackage_build_main_navigation(*args): output = h.build_nav_main(*args) # show ciwater related menu options only if the user is loggedin if c.user: link_pkg = h.url_for(controller='ckanext.uebpackage.controllers.packagecreate:PackagecreateController', action='packagecreateform') link_run = h.url_for(controller='ckanext.uebpackage.controllers.uebexecute:UEBexecuteController', action='select_model_package') if p.toolkit.c.action == 'packagecreateform' or p.toolkit.c.action == 'select_model_package': menu = h.literal('<li class="dropdown">') else: menu = h.literal('<li class="dropdown">') menu += h.literal('<a id="drop1" role="button" data-toggle="dropdown" class="dropdown-toggle" href="#">') menu += 'UEB' + h.literal('<b><span class="caret"></span></b>') menu += h.literal('</a>') menu += h.literal('<ul class="dropdown-menu" role="menu" area-labelledby="drop1">') li = h.literal('<li role="presentation"><a role="menuitem" tabindex="-1" href=') + link_pkg + h.literal('>UEB Model Package</a>') + h.literal('</li>') menu += li li = h.literal('<li role="presentation"><a role="menuitem" tabindex="-1" href=') + link_run + h.literal('>Run UEB</a>') + h.literal('</li>') menu += li menu += h.literal('</ul>') menu += h.literal('</li>') output = menu + output return output
def test_atom_feed_page_not_int_gives_error(self): group = factories.Group() offset = url_for(u'feeds.group', id=group['name']) + '?page=abc' app = self._get_test_app() offset = url_for(u'feeds.group', id=group['name']) + '?page=abc' res = app.get(offset, status=400) assert '"page" parameter must be a positive integer' in res, res
def test_email_access_by_page(self): admin = model.User.by_name('testsysadmin') url = h.url_for(controller='user', action='index') profile_url = h.url_for(controller='user', action='read', id='johnfoo') result = self.app.get(url, headers={'Authorization': unicodedata.normalize( 'NFKD', admin.apikey).encode('ascii', 'ignore')}) profile_result = self.app.get(url, headers={'Authorization': unicodedata.normalize( 'NFKD', admin.apikey).encode('ascii', 'ignore')}) assert '*****@*****.**' in str(result.response) assert '*****@*****.**' in str(profile_result.response) user = model.User.by_name('tester') result = self.app.get(url, headers={'Authorization': unicodedata.normalize( 'NFKD', user.apikey).encode('ascii', 'ignore')}) profile_result = self.app.get(url, headers={'Authorization': unicodedata.normalize( 'NFKD', user.apikey).encode('ascii', 'ignore')}) assert '*****@*****.**' not in str( result.response), 'emails should not be visible for normal users' assert '*****@*****.**' not in str( profile_result.response), 'emails should not be visible for normal users' result = self.app.get(url) profile_result = self.app.get(profile_url) assert '*****@*****.**' not in str( result.response), 'emails should not be visible for guests' assert '*****@*****.**' not in str( profile_result.response), 'emails should not be visible for guests'
def __init__(self, session, eppn, mail, fullname, **kwargs): ''' Parameters here contain just names of the environment attributes defined in who.ini, not their values: @param session: 'Shib-Session-ID' @param eppn: 'eppn' @param organization: 'schacHomeOrganization' etc. ''' log.info("Initting ShibbolethIdentifierPlugin...") self.session = session self.eppn = eppn self.mail = mail self.fullname = fullname self.extra_keys = {} self.check_auth_key = kwargs['check_auth_key'] self.check_auth_value = kwargs['check_auth_value'] if(self.check_auth_key is None or self.check_auth_value is None): log.warning('Check auth values not set in who.ini. Shibboleth auth will not work.') else: log.info('Shibboleth auth will be identified by %s = %s', self.check_auth_key, self.check_auth_value) controller = 'ckanext.shibboleth.controller:ShibbolethController' self.login_url = url_for(controller=controller, action='shiblogin') self.login_form_url = url_for(controller='user', action='login') self.logout_url = url_for(controller='user', action='logout')
def pager_url(q=None, page=None): if sort_by: url = h.url_for( 'organizations_index', page=page, sort=sort_by) else: url = h.url_for('organizations_index', page=page) return url
def test_member_users_cannot_add_members(self): user = factories.User() group = factories.Group( users=[{'name': user['name'], 'capacity': 'member'}] ) app = helpers._get_test_app() env = {'REMOTE_USER': user['name'].encode('ascii')} with app.flask_app.test_request_context(): app.get( url_for( controller='group', action='member_new', id=group['id'], ), extra_environ=env, status=403, ) app.post( url_for( controller='group', action='member_new', id=group['id'], ), {'id': 'test', 'username': '******', 'save': 'save', 'role': 'test'}, extra_environ=env, status=403, )
def test_editor_users_cannot_add_members(self): user = factories.User() organization = factories.Organization(users=[{ 'name': user['name'], 'capacity': 'editor' }]) app = helpers._get_test_app() env = {'REMOTE_USER': user['name'].encode('ascii')} with app.flask_app.test_request_context(): app.get( url_for( 'organization.member_new', id=organization['id'], ), extra_environ=env, status=403, ) app.post( url_for( 'organization.member_new', id=organization['id'], ), { 'id': 'test', 'username': '******', 'save': 'save', 'role': 'test' }, extra_environ=env, status=403, )
def test_redirect_when_given_id(self): group = factories.Group() app = helpers._get_test_app() response = app.get(url_for('group.read', id=group['id']), status=302) # redirect replaces the ID with the name in the URL redirected_response = response.follow() expected_url = url_for('group.read', id=group['name']) assert_equal(redirected_response.request.path, expected_url)
def search_url(params): if action == 'read': url = h.url_for(controller='user', action=action, id=id) else: url = h.url_for(controller='user', action=action) params = [(k, v.encode('utf-8') if isinstance(v, basestring) else str(v)) for k, v in params] return url + u'?' + urlencode(params)
def object_uri(uuid, version=None): """ Returns an URI for an object """ if version is None: return url_for(u'object_view', action=u'view', uuid=uuid, qualified=True) else: return url_for(u'object_view_versioned', action=u'view', uuid=uuid, version=version, qualified=True)
def test_general_atom_feed_works(self): dataset = factories.Dataset() offset = url_for(u'feeds.general') app = self._get_test_app() offset = url_for(u'feeds.general') res = app.get(offset) assert u'<title>{0}</title>'.format( dataset['title']) in res.body
def pager_url(q=None, page=None): if sort_option: url = h.url_for( 'browse_list', page=page, sort=sort_option) + \ '#organizationsSection' else: url = h.url_for('browse_list', page=page) + \ '#organizationsSection' return url
def _save_new(self, context, package_type=None): # The staged add dataset used the new functionality when the dataset is # partially created so we need to know if we actually are updating or # this is a real new. is_an_update = False ckan_phase = request.params.get('_ckan_phase') from ckan.lib.search import SearchIndexError try: data_dict = clean_dict(dict_fns.unflatten( tuplize_dict(parse_params(request.POST)))) if ckan_phase: # prevent clearing of groups etc context['allow_partial_update'] = True # sort the tags if 'tag_string' in data_dict: data_dict['tags'] = self._tag_string_to_list(data_dict['tag_string']) if data_dict.get('pkg_name'): is_an_update = True # This is actually an update not a save data_dict['id'] = data_dict['pkg_name'] del data_dict['pkg_name'] # don't change the dataset state data_dict['state'] = 'draft' # this is actually an edit not a save pkg_dict = get_action('package_update')(context, data_dict) if request.params['save'] == 'go-metadata': # redirect to add metadata url = h.url_for(controller='package', action='new_metadata', id=pkg_dict['name']) elif request.params['save'] == 'save-draft': url = h.url_for(controller='package', action='read', id=pkg_dict['name']) else: # redirect to add dataset resources url = h.url_for(controller='package', action='new_resource', id=pkg_dict['name']) redirect(url) # Make sure we don't index this dataset if request.params['save'] not in ['go-resource', 'go-metadata']: data_dict['state'] = 'draft' # allow the state to be changed context['allow_state_change'] = True data_dict['type'] = package_type context['message'] = data_dict.get('log_message', '') pkg_dict = get_action('package_create')(context, data_dict) if ckan_phase and request.params['save'] != 'save-draft': url = h.url_for(controller='package', action='new_resource', id=pkg_dict['name']) redirect(url) elif request.params['save'] == 'save-draft': url = h.url_for(controller='package', action='read', id=pkg_dict['name']) redirect(url) self._form_save_redirect(pkg_dict['name'], 'new', package_type=package_type) except NotAuthorized: abort(401, _('Unauthorized to read package %s') % '') except NotFound, e: abort(404, _('Dataset not found'))
def test_organization_atom_feed_works(self): group = factories.Organization() dataset = factories.Dataset(owner_org=group['id']) offset = url_for(u'feeds.organization', id=group['name']) app = self._get_test_app() offset = url_for(u'feeds.organization', id=group['name']) res = app.get(offset) assert u'<title>{0}</title>'.format( dataset['title']) in res.body
def test_group_atom_feed_works(self): group = factories.Group() dataset = factories.Dataset(groups=[{'id': group['id']}]) offset = url_for(u'feeds.group', id=group['name']) app = self._get_test_app() offset = url_for(u'feeds.group', id=group['name']) res = app.get(offset) assert u'<title>{0}</title>'.format( dataset['title']) in res.body
def test_user_delete_redirects_to_user_index(self): user = CreateTestData.create_user('a_user') url = url_for(controller='user', action='delete', id=user.id) extra_environ = {'REMOTE_USER': '******'} redirect_url = url_for(controller='user', action='index', qualified=True) res = self.app.get(url, status=302, extra_environ=extra_environ) assert user.is_deleted(), user assert res.header('Location').startswith(redirect_url), res.header('Location')
def _getSearchPage(self, query, ext_indicator=None, apikey=None): page = None if ext_indicator != None: url = h.url_for('search', ext_indicator=ext_indicator) else: url = h.url_for('search') if apikey: page = self.app.get(url, headers={'Authorization': unicodedata.normalize('NFKD', apikey).encode('ascii','ignore')}) else: page = self.app.get(url) return page
def test_invalid_sort_param_does_not_crash(self): app = self._get_test_app() with app.flask_app.test_request_context(): group_url = url_for('group.index', sort='title desc nope') app.get(url=group_url) group_url = url_for('group.index', sort='title nope desc nope') app.get(url=group_url)
def test_datasets(self): user = model.User.by_name('tester') offset = h.url_for( controller='ckanext.hdx_search.controllers.search_controller:HDXSearchController', action='search') response = self.app.get(offset, params={'q': 'health', 'ext_indicator':0}) assert '200' in response.status def test_features(self): user = model.User.by_name('tester') offset = h.url_for( controller='ckanext.hdx_search.controllers.search_controller:HDXSearchController', action='search') response = self.app.get(offset, params={'q': 'health', 'ext_feature':1}) assert '200' in response.status
def setup_class(cls): plugins.load('test_resource_preview', 'test_json_resource_preview') cls.plugin = plugins.get_plugin('test_resource_preview') create_test_data.CreateTestData.create() cls.package = model.Package.get('annakarenina') cls.resource = cls.package.resources[0] cls.url = h.url_for('resource.read', id=cls.package.name, resource_id=cls.resource.id) cls.preview_url = h.url_for('resource.datapreview', id=cls.package.id, resource_id=cls.resource.id)
def test_packages(self): tree = etree.parse(self.content_file) self.assert_("annakarenina" in self.cont.body) log.debug(self.cont.body) pkg = Session.query(Package).all()[0] urli = config.get("ckan.site_url") + url_for(controller="package", action="read", id=pkg.name) self.assert_(tree.getroot()[0][0].text == urli) # Needs to be created today as test data is too pkgdate = pkg.latest_related_revision.timestamp.strftime("%Y-%m-%d") self.assert_(tree.getroot()[0][1].text == pkgdate) resurl = config.get("ckan.site_url") + url_for( controller="package", action="resource_read", id=pkg.name, resource_id=pkg.resources[0].id ) self.assert_(tree.getroot()[1][0].text == resurl)
def pager_url(q=None, page=None): params = params_nopage params['page'] = page return h.url_for('organization_read', id=org_code, **params) + suffix
def list(self): format = request.params.get('format', '') if format == 'atom': # Generate and return Atom 1.0 document. from webhelpers.feedgenerator import Atom1Feed feed = Atom1Feed( title=_(u'CKAN Repository Revision History'), link=h.url_for(controller='revision', action='list', id=''), description=_(u'Recent changes to the CKAN repository.'), language=text_type(get_lang()), ) # TODO: make this configurable? # we do not want the system to fall over! maxresults = 200 try: dayHorizon = int(request.params.get('days', 5)) except: dayHorizon = 5 ourtimedelta = timedelta(days=-dayHorizon) since_when = datetime.now() + ourtimedelta revision_query = model.repo.history() revision_query = revision_query.filter( model.Revision.timestamp >= since_when).filter( model.Revision.id != None) revision_query = revision_query.limit(maxresults) for revision in revision_query: package_indications = [] revision_changes = model.repo.list_changes(revision) resource_revisions = revision_changes[model.Resource] package_extra_revisions = revision_changes[model.PackageExtra] for package in revision.packages: if not package: # package is None sometimes - I don't know why, # but in the meantime while that is fixed, # avoid an exception here continue if package.private: continue number = len(package.all_revisions) package_revision = None count = 0 for pr in package.all_revisions: count += 1 if pr.revision.id == revision.id: package_revision = pr break if package_revision and package_revision.state == \ model.State.DELETED: transition = 'deleted' elif package_revision and count == number: transition = 'created' else: transition = 'updated' for resource_revision in resource_revisions: if resource_revision.package_id == package.id: transition += ':resources' break for package_extra_revision in package_extra_revisions: if package_extra_revision.package_id == \ package.id: if package_extra_revision.key == \ 'date_updated': transition += ':date_updated' break indication = "%s:%s" % (package.name, transition) package_indications.append(indication) pkgs = u'[%s]' % ' '.join(package_indications) item_title = u'r%s ' % (revision.id) item_title += pkgs if revision.message: item_title += ': %s' % (revision.message or '') item_link = h.url_for(controller='revision', action='read', id=revision.id) item_description = _('Datasets affected: %s.\n') % pkgs item_description += '%s' % (revision.message or '') item_author_name = revision.author item_pubdate = revision.timestamp feed.add_item( title=item_title, link=item_link, description=item_description, author_name=item_author_name, pubdate=item_pubdate, ) feed.content_type = 'application/atom+xml' return feed.writeString('utf-8') else: query = model.Session.query(model.Revision) revs = query.limit(20).all() filtered_revs = [] for rev in list(revs): private_rev = False for pkg in rev.packages: if pkg.private: private_rev = True break if not private_rev: filtered_revs.append(rev) c.page = h.Page(collection=filtered_revs, page=h.get_page_number(request.params), url=h.pager_url, items_per_page=20) return base.render('revision/list.html')
def _url_for(self, *args, **kw): ''' wrapper to ensue the correct controller is used ''' if self.group_type == 'organization' and 'controller' in kw: kw['controller'] = 'organization' return h.url_for(*args, **kw)
def _save_new(self, context, package_type=None): # The staged add dataset used the new functionality when the dataset is # partially created so we need to know if we actually are updating or # this is a real new. is_an_update = False ckan_phase = request.params.get('_ckan_phase') from ckan.lib.search import SearchIndexError try: data_dict = clean_dict( dict_fns.unflatten(tuplize_dict(parse_params(request.POST)))) if ckan_phase: # prevent clearing of groups etc context['allow_partial_update'] = True # sort the tags if 'tag_string' in data_dict: data_dict['tags'] = self._tag_string_to_list( data_dict['tag_string']) if data_dict.get('pkg_name'): is_an_update = True # This is actually an update not a save data_dict['id'] = data_dict['pkg_name'] del data_dict['pkg_name'] if request.params['save'] == 'finish': data_dict['state'] = 'active' # this is actually an edit not a save pkg_dict = get_action('package_update')(context, data_dict) # redirect to view self._form_save_redirect(pkg_dict['name'], 'new', package_type=package_type) # don't change the dataset state data_dict['state'] = 'draft' # this is actually an edit not a save pkg_dict = get_action('package_update')(context, data_dict) if request.params['save'] == 'go-metadata': # redirect to add metadata url = h.url_for(controller='package', action='new_metadata', id=pkg_dict['name']) else: # redirect to add dataset resources url = h.url_for(controller='package', action='new_resource', id=pkg_dict['name']) redirect(url) # Make sure we don't index this dataset if request.params['save'] not in [ 'go-resource', 'go-metadata', 'finish' ]: data_dict['state'] = 'draft' # allow the state to be changed context['allow_state_change'] = True data_dict['type'] = package_type context['message'] = data_dict.get('log_message', '') try: if (package_type == 'application') and data_dict['from_users']: context['ignore_auth'] = True data_dict['name'] = 'from_users_' + ''.join( random.SystemRandom().choice(string.ascii_lowercase + string.digits) for _ in range(16)) data_dict['status'] = 'unverified' data_dict['private'] = 'False' except: pass pkg_dict = get_action('package_create')(context, data_dict) if ckan_phase and not request.params['save'] == 'finish': # redirect to add dataset resources url = h.url_for(controller='package', action='new_resource', id=pkg_dict['name']) redirect(url) if (package_type == 'application') and data_dict['from_users']: h.flash_notice(_('Application has been submitted')) redirect('/application') self._form_save_redirect(pkg_dict['name'], 'new', package_type=package_type) except NotAuthorized: abort(401, _('Unauthorized to read package %s') % '') except NotFound, e: abort(404, _('Dataset not found'))
def news_delete(self, id): _get_action('news_delete', {'id': id}) h.flash_success(_('News was removed successfully.')) redirect(h.url_for('news_index'))
def test_user_edit_unknown_user(self, app): """Attempt to read edit user for an unknown user redirects to login page.""" response = app.get(url_for("user.edit", id="unknown_person"), status=403)
def test_user_page_anon_access(self, app): """Anon users can access the user list page""" user_url = url_for("user.index") user_response = app.get(user_url, status=200) assert "<title>All Users - CKAN</title>" in user_response
def test_request_reset_without_param(self, app): offset = url_for("user.request_reset") response = app.post(offset).follow() assert "Email is required" in response
def setup(self): super(TestOrganizationList, self).setup() self.app = helpers._get_test_app() self.user = factories.User() self.user_env = {'REMOTE_USER': self.user['name'].encode('ascii')} self.organization_list_url = url_for('organization.index')
def test_user_activity(self): """Test user activity streams HTML rendering.""" # Register a new user. user_dict = { 'name': 'billybeane', 'fullname': 'Billy Beane', 'about': 'General Manager, Oakland Athletics', 'email': '*****@*****.**', 'password': '******' } context = { 'model': ckan.model, 'session': ckan.model.Session, 'user': self.sysadmin_user.name, 'allow_partial_update': True, } user = user_create(context, user_dict) offset = url_for('user.activity', id=user['id']) result = self.app.get(offset, status=200) stripped = self.strip_tags(result) assert '%s signed up' % user['fullname'] in stripped, stripped # Create a new package. package = { 'name': 'baseball_stats', 'title': "Billy's Stats about Baseball Players", } context['user'] = user['name'] # FIXME This test use an old way to get at the schema to # recreate this we need to pretend to be using the api. We # should not be calling package_create like this we should be # going via the api or package controllers context['api_version'] = 3 context['ignore_auth'] = True package = package_create(context, package) result = self.app.get(offset, status=200) stripped = self.strip_tags(result) assert '%s created the dataset %s ' % ( user['fullname'], package['title']) in stripped, stripped # Add a resource to the package. resource = { 'url': 'http://www.example.com', 'description': "Chad Bradford's OBP Stats`", 'format': 'cvs', 'name': 'Chad Bradford Stats', } package['resources'].append(resource) request_data = { 'id': package['id'], 'resources': package['resources'], } package = package_update(context, request_data) result = self.app.get(offset, status=200) stripped = self.strip_tags(result) assert '%s added the resource %s to the dataset %s' % \ (user['fullname'], resource['name'], package['title']) \ in stripped, stripped # Update the package. package['title'] = "Billy's Updated Stats about Baseball Players" package = package_update(context, package) result = self.app.get(offset, status=200) stripped = self.strip_tags(result) assert '%s updated the dataset %s' \ % (user['fullname'], package['title']) \ in stripped, stripped # Update the resource. resource = package['resources'][0] resource['name'] = 'Chad Bradford Updated Stats' resource = resource_update(context, resource) result = self.app.get(offset, status=200) stripped = self.strip_tags(result) assert '%s updated the resource %s in the dataset %s' \ % (user['fullname'], resource['name'], package['title']) \ in stripped, stripped # Delete the resource. context['allow_partial_update'] = False package['resources'] = [] package_update(context, package) result = self.app.get(offset, status=200) stripped = self.strip_tags(result) assert '%s deleted the resource %s from the dataset %s' % \ (user['fullname'], resource['name'], package['title']) \ in stripped, stripped # Follow the package. follow_dataset(context, {'id': package['id']}) result = self.app.get(offset, status=200) stripped = self.strip_tags(result) assert '%s started following %s' % ( user['fullname'], package['title']) not in stripped, stripped # Follow another user. follow_user(context, {'id': 'joeadmin'}) result = self.app.get(offset, status=200) stripped = self.strip_tags(result) assert '%s started following %s' % ( user['fullname'], 'joeadmin') not in stripped, stripped # Create a new group. group = { 'name': 'baseball-stats-group', 'title': 'A Group for Datasets about Baseball' } context['allow_partial_update'] = True group = group_create(context, group) result = self.app.get(offset, status=200) stripped = self.strip_tags(result) assert '%s created the group %s' % (user['fullname'], group['title']) \ in stripped, stripped # Update the group. group['title'] = 'updated' group = group_update(context, group) result = self.app.get(offset, status=200) stripped = self.strip_tags(result) assert '%s updated the group %s' % (user['fullname'], group['title']) \ in stripped, stripped # Delete the group. group['state'] = 'deleted' group_update(context, group) result = self.app.get(offset, status=200) stripped = self.strip_tags(result) assert '%s deleted the group %s' % (user['fullname'], group['title']) \ in stripped, stripped # Add a new tag to the package. tag = {'name': 'baseball'} package['tags'].append(tag) package = package_update(context, package) result = self.app.get(offset, status=200) stripped = self.strip_tags(result) assert '%s added the tag %s to the dataset %s' % \ (user['fullname'], tag['name'], package['title']) \ in stripped, stripped # Remove the tag from the package. package['tags'] = [] context['allow_partial_update'] = False package_update(context, package) result = self.app.get(offset, status=200) stripped = self.strip_tags(result) assert '%s removed the tag %s from the dataset %s' % \ (user['fullname'], tag['name'], package['title']) \ in stripped, stripped # Add an extra to the package. package['extras'].append({'key': 'quality', 'value': '10000'}) package = package_update(context, package) result = self.app.get(offset, status=200) stripped = self.strip_tags(result) assert '%s added the extra "%s" to the dataset %s' % \ (user['fullname'], 'quality', package['title']) \ in stripped, stripped # Update the extra. package['extras'][0]['value'] = 'updated' package = package_update(context, package) result = self.app.get(offset, status=200) stripped = self.strip_tags(result) assert '%s changed the extra "%s" of the dataset %s' % \ (user['fullname'], 'quality', package['title']) \ in stripped, stripped # Delete the extra. del package['extras'][0] package = package_update(context, package) result = self.app.get(offset, status=200) stripped = self.strip_tags(result) assert '%s deleted the extra "%s" from the dataset %s' % \ (user['fullname'], 'quality', package['title']) \ in stripped, stripped # Delete the package. # we need to get round the delete permission context['ignore_auth'] = True package_delete(context, package) del context['ignore_auth'] result = self.app.get(offset, status=200) stripped = self.strip_tags(result) assert '%s deleted the dataset %s' % \ (user['fullname'], package['title']) \ in stripped, stripped # Update the user's profile. user['about'] = '' user_update(context, user) result = self.app.get(offset, status=200) stripped = self.strip_tags(result) assert '%s updated their profile' % user['fullname'] \ in stripped, stripped # By now we've created >15 activities, but only the latest 15 should # appear on the page. result = self.app.get(offset, status=200) assert result.body.count('<span class="actor">') \ == 15, result.body.count('<span class="actor">') # The user's dashboard page should load successfully and have the # latest 15 activities on it. offset = url_for('dashboard.index') extra_environ = { 'Authorization': str(ckan.model.User.get('billybeane').apikey) } result = self.app.get(offset, extra_environ=extra_environ, status=200) assert result.body.count('<span class="actor">') == 15, \ result.body.count('<span class="actor">')
def test_group_doesnt_exist(self): url = url_for('organization.edit', id='doesnt_exist') self.app.get(url=url, extra_environ=self.user_env, status=404)
def test_no_redirect_loop_when_name_is_the_same_as_the_id(self): org = factories.Organization(id='abc', name='abc') app = helpers._get_test_app() app.get(url_for('organization.read', id=org['id']), status=200) # ie no redirect
def manage_datasets(self, id): ''' List datasets associated with the given experience id. ''' context = {'model': model, 'session': model.Session, 'user': c.user or c.author} data_dict = {'id': id} try: check_access('ckanext_experience_update', context) except NotAuthorized: abort(401, _('User not authorized to edit {experience_id}').format( experience_id=id)) # check if experience exists try: c.pkg_dict = get_action('package_show')(context, data_dict) except NotFound: abort(404, _('Experience not found')) except NotAuthorized: abort(401, _('Unauthorized to read experience')) # Are we removing a experience/dataset association? if (request.method == 'POST' and 'bulk_action.experience_remove' in request.params): # Find the datasets to perform the action on, they are prefixed by # dataset_ in the form data dataset_ids = [] for param in request.params: if param.startswith('dataset_'): dataset_ids.append(param[8:]) if dataset_ids: for dataset_id in dataset_ids: get_action('ckanext_experience_package_association_delete')( context, {'experience_id': c.pkg_dict['id'], 'package_id': dataset_id}) h.flash_success( ungettext( "The dataset has been removed from the experience.", "The datasets have been removed from the experience.", len(dataset_ids))) url = h.url_for( controller='ckanext.experience.controller:ExperienceController', action='manage_datasets', id=id) redirect(url) # Are we creating a experience/dataset association? elif (request.method == 'POST' and 'bulk_action.experience_add' in request.params): # Find the datasets to perform the action on, they are prefixed by # dataset_ in the form data dataset_ids = [] for param in request.params: if param.startswith('dataset_'): dataset_ids.append(param[8:]) if dataset_ids: successful_adds = [] for dataset_id in dataset_ids: try: get_action( 'ckanext_experience_package_association_create')( context, {'experience_id': c.pkg_dict['id'], 'package_id': dataset_id}) except ValidationError as e: h.flash_notice(e.error_summary) else: successful_adds.append(dataset_id) if successful_adds: h.flash_success( ungettext( "The dataset has been added to the experience.", "The datasets have been added to the experience.", len(successful_adds))) url = h.url_for( controller='ckanext.experience.controller:ExperienceController', action='manage_datasets', id=id) redirect(url) self._add_dataset_search(c.pkg_dict['id'], c.pkg_dict['name']) # get experience packages c.experience_pkgs = get_action('ckanext_experience_package_list')( context, {'experience_id': c.pkg_dict['id']}) return render('experience/manage_datasets.html')
def test_user_edit_no_user(self, app): response = app.get(url_for("user.edit", id=None), status=400) assert "No user specified" in response
def dataset_experience_list(self, id): ''' Display a list of experiences a dataset is associated with, with an option to add to experience from a list. ''' context = {'model': model, 'session': model.Session, 'user': c.user or c.author, 'for_view': True, 'auth_user_obj': c.userobj} data_dict = {'id': id} try: check_access('package_show', context, data_dict) except NotFound: abort(404, _('Dataset not found')) except NotAuthorized: abort(401, _('Not authorized to see this page')) try: c.pkg_dict = get_action('package_show')(context, data_dict) c.experience_list = get_action('ckanext_package_experience_list')( context, {'package_id': c.pkg_dict['id']}) except NotFound: abort(404, _('Dataset not found')) except logic.NotAuthorized: abort(401, _('Unauthorized to read package')) if request.method == 'POST': # Are we adding the dataset to a experience? new_experience = request.POST.get('experience_added') if new_experience: data_dict = {"experience_id": new_experience, "package_id": c.pkg_dict['id']} try: get_action('ckanext_experience_package_association_create')( context, data_dict) except NotFound: abort(404, _('Experience not found')) else: h.flash_success( _("The dataset has been added to the experience.")) # Are we removing a dataset from a experience? experience_to_remove = request.POST.get('remove_experience_id') if experience_to_remove: data_dict = {"experience_id": experience_to_remove, "package_id": c.pkg_dict['id']} try: get_action('ckanext_experience_package_association_delete')( context, data_dict) except NotFound: abort(404, _('Experience not found')) else: h.flash_success( _("The dataset has been removed from the experience.")) redirect(h.url_for( controller='ckanext.experience.controller:ExperienceController', action='dataset_experience_list', id=c.pkg_dict['name'])) pkg_experience_ids = [experience['id'] for experience in c.experience_list] site_experiences = get_action('ckanext_experience_list')(context, {}) c.experience_dropdown = [[experience['id'], experience['title']] for experience in site_experiences if experience['id'] not in pkg_experience_ids] return render("package/dataset_experience_list.html")
def _get_user_edit_page(app): user = factories.User() env = {"REMOTE_USER": user["name"].encode("ascii")} response = app.get(url=url_for("user.edit"), extra_environ=env) return env, response, user
def test_get_api_version(ver, expected, status, app): resp = app.get(url_for("api.get_api", ver=str(ver)), status=status) if status == 200: assert resp.json["version"] == expected
def test_not_logged_in_dashboard(self, app): for route in ["index", "organizations", "datasets", "groups"]: app.get(url=url_for(u"dashboard.{}".format(route)), status=403)
def search_url(params, package_type=None): if not package_type or package_type == 'dataset': url = h.url_for(controller='package', action='search') else: url = h.url_for('{0}_search'.format(package_type)) return url_with_params(url, params)
def dataset_showcase_list(id): context = { 'model': model, 'session': model.Session, 'user': c.user or c.author, 'for_view': True, 'auth_user_obj': c.userobj } data_dict = {'id': id} try: tk.check_access('package_show', context, data_dict) except tk.ObjectNotFound: return tk.abort(404, _('Dataset not found')) except tk.NotAuthorized: return tk.abort(401, _('Not authorized to see this page')) try: c.pkg_dict = tk.get_action('package_show')(context, data_dict) c.showcase_list = tk.get_action('ckanext_package_showcase_list')( context, { 'package_id': c.pkg_dict['id'] }) except tk.ObjectNotFound: return tk.abort(404, _('Dataset not found')) except tk.NotAuthorized: return tk.abort(401, _('Unauthorized to read package')) if tk.check_ckan_version(min_version='2.9.0'): list_route = 'showcase_blueprint.dataset_showcase_list' else: list_route = 'showcase_dataset_showcase_list' if tk.request.method == 'POST': # Are we adding the dataset to a showcase? form_data = tk.request.form if tk.check_ckan_version( '2.9') else tk.request.params new_showcase = form_data.get('showcase_added') if new_showcase: data_dict = { "showcase_id": new_showcase, "package_id": c.pkg_dict['id'] } try: tk.get_action('ckanext_showcase_package_association_create')( context, data_dict) except tk.ObjectNotFound: return tk.abort(404, _('Showcase not found')) else: h.flash_success( _("The dataset has been added to the showcase.")) # Are we removing a dataset from a showcase? showcase_to_remove = form_data.get('remove_showcase_id') if showcase_to_remove: data_dict = { "showcase_id": showcase_to_remove, "package_id": c.pkg_dict['id'] } try: tk.get_action('ckanext_showcase_package_association_delete')( context, data_dict) except tk.ObjectNotFound: return tk.abort(404, _('Showcase not found')) else: h.flash_success( _("The dataset has been removed from the showcase.")) return h.redirect_to( h.url_for(list_route, id=c.pkg_dict['name'])) pkg_showcase_ids = [showcase['id'] for showcase in c.showcase_list] site_showcases = tk.get_action('ckanext_showcase_list')(context, {}) c.showcase_dropdown = [[showcase['id'], showcase['title']] for showcase in site_showcases if showcase['id'] not in pkg_showcase_ids] return tk.render("package/dataset_showcase_list.html", extra_vars={'pkg_dict': c.pkg_dict})
def bulk_process(self, id): ''' Allow bulk processing of datasets for an organization. Make private/public or delete. For organization admins.''' group_type = self._get_group_type(id.split('@')[0]) if group_type != 'organization': # FIXME: better error raise Exception('Must be an organization') # check we are org admin context = { 'model': model, 'session': model.Session, 'user': c.user or c.author, 'schema': self._db_to_form_schema(group_type=group_type), 'for_view': True, 'extras_as_string': True } data_dict = {'id': id} try: # Do not query for the group datasets when dictizing, as they will # be ignored and get requested on the controller anyway context['include_datasets'] = False c.group_dict = self._action('group_show')(context, data_dict) c.group = context['group'] except NotFound: abort(404, _('Group not found')) except NotAuthorized: abort(401, _('Unauthorized to read group %s') % id) # Search within group action = request.params.get('bulk_action') # If no action then just show the datasets if not action: # unicode format (decoded from utf8) limit = 500 self._read(id, limit) c.packages = c.page.items return render(self._bulk_process_template(group_type)) # process the action first find the datasets to perform the action on. # they are prefixed by dataset_ in the form data datasets = [] for param in request.params: if param.startswith('dataset_'): datasets.append(param[8:]) action_functions = { 'private': 'bulk_update_private', 'public': 'bulk_update_public', 'delete': 'bulk_update_delete', } data_dict = {'datasets': datasets, 'org_id': c.group_dict['id']} try: get_action(action_functions[action])(context, data_dict) except NotAuthorized: abort(401, _('Not authorized to perform bulk update')) base.redirect( h.url_for(controller='organization', action='bulk_process', id=id))
def search_url(params, package_type=None): if not package_type: package_type = u'dataset' url = h.url_for(u'{0}.search'.format(package_type)) return url_with_params(url, params)
revision_date = h.date_str_to_datetime( revision_dict['timestamp']) try: dayHorizon = int(request.params.get('days')) except: dayHorizon = 30 dayAge = (datetime.datetime.now() - revision_date).days if dayAge >= dayHorizon: break if revision_dict['message']: item_title = u'%s' % revision_dict['message'].\ split('\n')[0] else: item_title = u'%s' % revision_dict['id'] item_link = h.url_for(controller='revision', action='read', id=revision_dict['id']) item_description = _('Log message: ') item_description += '%s' % (revision_dict['message'] or '') item_author_name = revision_dict['author'] item_pubdate = revision_date feed.add_item( title=item_title, link=item_link, description=item_description, author_name=item_author_name, pubdate=item_pubdate, ) feed.content_type = 'application/atom+xml' return feed.writeString('utf-8') return render(self._history_template(c.group_dict['type']))
def post(self, package_type): # The staged add dataset used the new functionality when the dataset is # partially created so we need to know if we actually are updating or # this is a real new. context = self._prepare() is_an_update = False ckan_phase = request.form.get(u'_ckan_phase') try: data_dict = clean_dict( dict_fns.unflatten(tuplize_dict(parse_params(request.form))) ) except dict_fns.DataError: return base.abort(400, _(u'Integrity Error')) try: if ckan_phase: # prevent clearing of groups etc context[u'allow_partial_update'] = True # sort the tags if u'tag_string' in data_dict: data_dict[u'tags'] = _tag_string_to_list( data_dict[u'tag_string'] ) if data_dict.get(u'pkg_name'): is_an_update = True # This is actually an update not a save data_dict[u'id'] = data_dict[u'pkg_name'] del data_dict[u'pkg_name'] # don't change the dataset state data_dict[u'state'] = u'draft' # this is actually an edit not a save pkg_dict = get_action(u'package_update')( context, data_dict ) # redirect to add dataset resources url = h.url_for( u'{}_resource.new'.format(package_type), id=pkg_dict[u'name'] ) return h.redirect_to(url) # Make sure we don't index this dataset if request.form[u'save'] not in [ u'go-resource', u'go-metadata' ]: data_dict[u'state'] = u'draft' # allow the state to be changed context[u'allow_state_change'] = True data_dict[u'type'] = package_type context[u'message'] = data_dict.get(u'log_message', u'') pkg_dict = get_action(u'package_create')(context, data_dict) if ckan_phase: # redirect to add dataset resources url = h.url_for( u'{}_resource.new'.format(package_type), id=pkg_dict[u'name'] ) return h.redirect_to(url) return _form_save_redirect( pkg_dict[u'name'], u'new', package_type=package_type ) except NotAuthorized: return base.abort(403, _(u'Unauthorized to read package')) except NotFound as e: return base.abort(404, _(u'Dataset not found')) except SearchIndexError as e: try: exc_str = str(repr(e.args)) except Exception: # We don't like bare excepts exc_str = str(str(e)) return base.abort( 500, _(u'Unable to add package to search index.') + exc_str ) except ValidationError as e: errors = e.error_dict error_summary = e.error_summary if is_an_update: # we need to get the state of the dataset to show the stage we # are on. pkg_dict = get_action(u'package_show')(context, data_dict) data_dict[u'state'] = pkg_dict[u'state'] return EditView().get( package_type, data_dict[u'id'], data_dict, errors, error_summary ) data_dict[u'state'] = u'none' return self.get(package_type, data_dict, errors, error_summary)
def manage_datasets_view(id): context = { 'model': model, 'session': model.Session, 'user': tk.c.user or tk.c.author } data_dict = {'id': id} try: tk.check_access('ckanext_showcase_update', context, data_dict) except tk.NotAuthorized: return tk.abort( 401, _('User not authorized to edit {showcase_id}').format( showcase_id=id)) # check if showcase exists try: tk.c.pkg_dict = tk.get_action('package_show')(context, data_dict) except tk.ObjectNotFound: return tk.abort(404, _('Showcase not found')) except tk.NotAuthorized: return tk.abort(401, _('Unauthorized to read showcase')) # Are we removing a showcase/dataset association? form_data = tk.request.form if tk.check_ckan_version( '2.9') else tk.request.params if tk.check_ckan_version(min_version='2.9.0'): manage_route = 'showcase_blueprint.manage_datasets' else: manage_route = 'showcase_manage_datasets' if (tk.request.method == 'POST' and 'bulk_action.showcase_remove' in form_data): # Find the datasets to perform the action on, they are prefixed by # dataset_ in the form data dataset_ids = [] for param in form_data: if param.startswith('dataset_'): dataset_ids.append(param[8:]) if dataset_ids: for dataset_id in dataset_ids: tk.get_action('ckanext_showcase_package_association_delete')( context, { 'showcase_id': tk.c.pkg_dict['id'], 'package_id': dataset_id }) h.flash_success( tk.ungettext( "The dataset has been removed from the showcase.", "The datasets have been removed from the showcase.", len(dataset_ids))) url = h.url_for(manage_route, id=id) return h.redirect_to(url) # Are we creating a showcase/dataset association? elif (tk.request.method == 'POST' and 'bulk_action.showcase_add' in form_data): # Find the datasets to perform the action on, they are prefixed by # dataset_ in the form data dataset_ids = [] for param in form_data: if param.startswith('dataset_'): dataset_ids.append(param[8:]) if dataset_ids: successful_adds = [] for dataset_id in dataset_ids: try: tk.get_action( 'ckanext_showcase_package_association_create')( context, { 'showcase_id': tk.c.pkg_dict['id'], 'package_id': dataset_id }) except tk.ValidationError as e: h.flash_notice(e.error_summary) else: successful_adds.append(dataset_id) if successful_adds: h.flash_success( tk.ungettext( "The dataset has been added to the showcase.", "The datasets have been added to the showcase.", len(successful_adds))) url = h.url_for(manage_route, id=id) return h.redirect_to(url) _add_dataset_search(tk.c.pkg_dict['id'], tk.c.pkg_dict['name']) # get showcase packages tk.c.showcase_pkgs = tk.get_action('ckanext_showcase_package_list')( context, { 'showcase_id': tk.c.pkg_dict['id'] }) return tk.render('showcase/manage_datasets.html')
def get( self, package_type, id, data=None, errors=None, error_summary=None ): context = self._prepare(id, data) package_type = _get_package_type(id) or package_type try: pkg_dict = get_action(u'package_show')( dict(context, for_view=True), { u'id': id } ) context[u'for_edit'] = True old_data = get_action(u'package_show')(context, {u'id': id}) # old data is from the database and data is passed from the # user if there is a validation error. Use users data if there. if data: old_data.update(data) data = old_data except (NotFound, NotAuthorized): return base.abort(404, _(u'Dataset not found')) # are we doing a multiphase add? if data.get(u'state', u'').startswith(u'draft'): g.form_action = h.url_for(u'{}.new'.format(package_type)) g.form_style = u'new' return CreateView().get( package_type, data=data, errors=errors, error_summary=error_summary ) pkg = context.get(u"package") resources_json = h.json.dumps(data.get(u'resources', [])) try: check_access(u'package_update', context) except NotAuthorized: return base.abort( 403, _(u'User %r not authorized to edit %s') % (g.user, id) ) # convert tags if not supplied in data if data and not data.get(u'tag_string'): data[u'tag_string'] = u', '.join( h.dict_list_reduce(pkg_dict.get(u'tags', {}), u'name') ) errors = errors or {} form_snippet = _get_pkg_template( u'package_form', package_type=package_type ) form_vars = { u'data': data, u'errors': errors, u'error_summary': error_summary, u'action': u'edit', u'dataset_type': package_type, u'form_style': u'edit' } errors_json = h.json.dumps(errors) # TODO: remove g.pkg = pkg g.resources_json = resources_json g.errors_json = errors_json _setup_template_variables( context, {u'id': id}, package_type=package_type ) # we have already completed stage 1 form_vars[u'stage'] = [u'active'] if data.get(u'state', u'').startswith(u'draft'): form_vars[u'stage'] = [u'active', u'complete'] edit_template = _get_pkg_template(u'edit_template', package_type) return base.render( edit_template, extra_vars={ u'form_vars': form_vars, u'form_snippet': form_snippet, u'dataset_type': package_type, u'pkg_dict': pkg_dict, u'pkg': pkg, u'resources_json': resources_json, u'form_snippet': form_snippet, u'errors_json': errors_json } )
def _search_url(params, name): url = h.url_for('showcase_blueprint.manage_datasets', id=name) return url_with_params(url, params)
def _search_url(self, params, name): url = h.url_for( controller='ckanext.experience.controller:ExperienceController', action='manage_datasets', id=name) return url_with_params(url, params)
def test_not_logged_in(self): self.app.get(url=url_for('group.new'), status=403)
def test_custom_package_type_urls(self): nt.eq_(url_for('fancy_type.search'), '/fancy_type/') nt.eq_(url_for('fancy_type.new'), '/fancy_type/new') nt.eq_(url_for('fancy_type.read', id='check'), '/fancy_type/check') nt.eq_(url_for('fancy_type.edit', id='check'), '/fancy_type/edit/check')