def _test_get_media(self, klass): attrname = klass.__name__.lower() + 's' event = self.create_event() setattr(event, attrname, [ klass(url=u'http://example.com/abc', license=u'CC By'), klass(url=u'http://example.com/123', license=u'Art Libre'), ]) DBSession.flush() response = self.app.get( '/v1/events/%s' % event.id, headers={'Accept': 'application/vnd.collection+json'}) event_data = response.json['collection']['items'][0]['data'] self.assertIn( {'name': attrname, "value": [ { "url": u"http://example.com/abc", "license": u"CC By" }, { "url": u"http://example.com/123", "license": u"Art Libre" } ]}, event_data)
def get_event(self, **kwargs): event = self.create_event(**kwargs) DBSession.flush() response = self.app.get('/v1/events/%s' % event.id, headers={'Accept': 'text/calendar'}) return event, response
def harvest(): query = DBSession.query(Source) for source in query: error_message = u"Failed to harvest source {id} with URL {url}".format( id=source.id, url=source.url, ) try: response = requests.get(source.url) if response.status_code != 200: continue content = response.text try: json.loads(content) is_json = True except ValueError: is_json = False request = HarvestRequest(content) if is_json: cstruct = json_extractor(request) else: cstruct = icalendar_extractor(request) harvest_cstruct(cstruct, source) if request.errors: log.warning(error_message, exc_info=True) for error in request.errors: log.warning(error['description']) except Exception: log.warning(error_message, exc_info=True) DBSession.flush()
def collection_post(self): """Add a new event""" event_info = json.loads(self.request.body) event = Event(**event_info) DBSession.add(event) DBSession.flush() return {'id': event.id, 'status': 'created'}
def initTestingDB(): engine = create_engine('sqlite://') Base.metadata.create_all(engine) DBSession.configure(bind=engine) #with transaction.manager: # model = Page('FrontPage', 'This is the front page') # DBSession.add(model) return DBSession
def test_all_fields(self): event_id = self.post_event(example_data) DBSession.flush() response = self.app.get( '/v1/events/%s' % event_id, headers={'Accept': 'application/vnd.collection+json'}) event_data = response.json['collection']['items'][0]['data'] self.assertEqualIgnoringId(event_data, example_data)
def test_datetime(self): event = self.create_event() event.start_time = datetime(2014, 1, 25, 16) DBSession.flush() response = self.app.get('/v1/events', headers={'Accept': 'text/csv'}) reader = csv.DictReader(StringIO(csv_text(response.text))) row = next(reader) self.assertEqual(row['start_time'], '2014-01-25T16:00:00')
def test_update_from_uid_with_domain_part(self): self.create_event(title=u'Existing event', id=u'*****@*****.**') DBSession.flush() self.setup_requests_mock(body_text=valid_icalendar) source = self.make_source() harvest() self.mock_requests.get.assert_called_with(source.url) event = DBSession.query(Event).one() self.assertEqual(event.title, u"Capitole du Libre")
def delete(self): """Delete a specific event by id""" id = self.request.matchdict['id'] try: event = DBSession.query(Event).filter_by(id=id).one() except NoResultFound: raise HTTPNotFound() DBSession.delete(event) return {'status': 'deleted'}
def test_get_tags(self): event = self.create_event() event.tags = [Tag(name=u'Music'), Tag(name=u"音楽")] DBSession.flush() response = self.app.get( '/v1/events/%s' % event.id, headers={'Accept': 'application/vnd.collection+json'}) event_data = response.json['collection']['items'][0]['data'] self.assertIn({'name': "tags", 'value': [u'Music', u"音楽"]}, event_data)
def test_tags(self): event = self.create_event() event.tags = [Tag(name=u'Tag1'), Tag(name=u'Tag2')] DBSession.flush() response = self.app.get('/v1/events', headers={'Accept': 'text/csv'}) reader = csv.DictReader(StringIO(response.text)) row = next(reader) self.assertEqual(row['tags'], u'Tag1, Tag2')
def main(argv=sys.argv): if len(argv) < 2: usage(argv) config_uri = argv[1] options = parse_vars(argv[2:]) setup_logging(config_uri) settings = get_appsettings(config_uri, options=options) engine = engine_from_config(settings, 'sqlalchemy.') DBSession.configure(bind=engine) Base.metadata.create_all(engine)
def test_header(self): self.create_event(title=u'Événement 1') self.create_event(title=u'Événement 2') DBSession.flush() response = self.app.get('/v1/events', headers={'Accept': 'text/csv'}) reader = csv.DictReader(StringIO(response.text)) self.assertIn('title', reader.fieldnames)
def test_get_categories(self): event = self.create_event() event.categories = [Tag(name=u'Music'), Tag(name=u"音楽")] DBSession.flush() response = self.app.get( '/v1/events/%s' % event.id, headers={'Accept': 'application/vnd.collection+json'}) event_data = response.json['collection']['items'][0]['data'] self.assertIn({'name': "categories", 'value': [u'Music', u"音楽"]}, event_data)
def test_location(self): self.create_event(title=u'Événement 1', location=Location(name=u'Évian')) DBSession.flush() response = self.app.get('/v1/events', headers={'Accept': 'text/csv'}) reader = csv.DictReader(StringIO(csv_text(response.text))) row = next(reader) self.assertEqual(row['location_name'], 'Évian') self.assertNotIn('location_event_id', row)
def test_title(self): self.create_event(title=u'Événement 1') self.create_event(title=u'Événement 2') DBSession.flush() response = self.app.get('/v1/events', headers={'Accept': 'text/csv'}) reader = csv.DictReader(StringIO(csv_text(response.text))) row = next(reader) self.assertIn('title', row) self.assertEqual(row['title'], 'Événement 1')
def delete(self): """Delete a resource by id""" id = self.request.matchdict['id'] try: event = DBSession.query(self.model).filter_by( id=id, provider_id=self.request.validated['provider_id'], ).one() except NoResultFound: raise HTTPNotFound() DBSession.delete(event)
def test_random_fields(self): self.create_event(title=u'Événement 1', press_contact_name=u'Émile') self.create_event(title=u'Événement 2', description=u'Foo bar') DBSession.flush() response = self.app.get('/v1/events', headers={'Accept': 'text/csv'}) reader = csv.DictReader(StringIO(csv_text(response.text))) row = next(reader) self.assertEqual(row['press_contact_name'], 'Émile') row = next(reader) self.assertEqual(row['description'], u'Foo bar')
def test_tags(self): tags = ['tag1', 'tag2'] event1 = self.create_event(tags=tags) DBSession.flush() self.assertTrue(event1.id.endswith("@example.com")) self.assertEqual(event1.tags[0].name, 'tag1') tag = event1.tags[0] event2 = self.create_event(tags=tags) DBSession.flush() self.assertTrue(event2.id.endswith("@example.com")) self.assertEqual(event2.tags[0].name, 'tag1') self.assertEqual(tag, event2.tags[0])
def test_categories(self): categories = ['category1', 'category2'] event1 = self.create_event(categories=categories) DBSession.flush() self.assertTrue(event1.id.endswith("@example.com")) self.assertEqual(event1.categories[0].name, 'category1') category = event1.categories[0] event2 = self.create_event(categories=categories) DBSession.flush() self.assertTrue(event2.id.endswith("@example.com")) self.assertEqual(event2.categories[0].name, 'category1') self.assertEqual(category, event2.categories[0])
def test_sounds(self): event = self.create_event() event.sounds = [ Sound(url=u'http://example.com/sound1', license='CC BY'), Sound(url=u'http://example.com/sound2', license='Whatever'), ] DBSession.flush() response = self.app.get('/v1/events', headers={'Accept': 'text/csv'}) reader = csv.DictReader(StringIO(csv_text(response.text))) row = next(reader) self.assertEqual( row['sounds'], u'http://example.com/sound1 (CC BY), ' + 'http://example.com/sound2 (Whatever)')
def setUp(self): self.config = testing.setUp() from sqlalchemy import create_engine engine = create_engine('sqlite://') from ode.models import ( Base, MyModel, ) DBSession.configure(bind=engine) Base.metadata.create_all(engine) with transaction.manager: model = MyModel(name='one') DBSession.add(model)
def test_post(self): body_data = """title,description,start_time,end_time Événement,A great event,2014-01-25T15:00,2014-01-25T19:00 Autre Événement,Another great event,2014-01-26T15:00,2014-01-26T19:00 """ self.app.post('/v1/events', body_data, status=201, headers={ 'Content-Type': 'text/csv', 'X-ODE-Provider-Id': '123', }) self.assertEqual(DBSession.query(Event).count(), 2) event = DBSession.query(Event).filter_by(title=u'Événement').one() self.assertEqual(event.description, u'A great event')
def test_bogus_icalendar_data_does_not_crash_harvesting(self): log_mock = self.patch('ode.harvesting.log') source1 = self.make_source(url=u"http://example.com/a", provider_id='123') self.make_source(url=u"http://example.com/b", provider_id='456') self.setup_requests_mock() self.mock_requests.get.side_effect = [ Mock( status_code=200, content_type='text/calendar', text='*** BOGUS DATA ***', ), Mock( status_code=200, content_type='text/calendar', text=valid_icalendar, ), ] harvest() self.assertEqual(DBSession.query(Event).count(), 1) expected_messasge = "Invalid iCalendar request body: " actual_message = log_mock.warning.call_args[0][0] self.assertTrue(actual_message.startswith(expected_messasge)) log_mock.warning.assert_any_call( u"Failed to harvest source {} with URL {}".format( source1.id, source1.url), exc_info=True)
def test_post_single_event(self): calendar = self.make_icalendar(titles=[u'Événement']) response = self.post(calendar) items = response.json['collection']['items'] event = DBSession.query(Event).filter_by(title=u'Événement').one() self.assertEqual(items[0]['href'], 'http://localhost/v1/events/%s' % quote(event.id))
def put(self): """Update existing event by id""" event_id = self.request.matchdict['id'] query = DBSession.query(Event).filter_by(id=event_id) if not query.update(self.request.validated): raise HTTPNotFound() return {'status': 'updated'}
def test_bogus_json_data(self): log_mock = self.patch('ode.harvesting.log') self.make_source(url=u"http://example.com/a", provider_id='123') self.setup_requests_mock(content_type='text/json', body_text=u'{"foo": 42}') harvest() self.assertEqual(DBSession.query(Event).count(), 0) log_mock.warning.assert_any_call(u"Invalid Collection+JSON input")
def test_fetch_json_data_from_source(self): self.setup_requests_mock(content_type='text/json', body_text=valid_json) source = self.make_source() harvest() self.mock_requests.get.assert_called_with(source.url) event = DBSession.query(Event).one() self.assertEqual(event.title, u"Test medias") self.assertEqual(event.description, u"Description")
def get(self): """Get a specific resource by id""" id = self.request.matchdict['id'] try: resource = DBSession.query(self.model).filter_by(id=id).one() except NoResultFound: raise HTTPNotFound() items = [resource.to_item(self.request)] return self.collection_json(items)
def test_fetch_data_from_source(self): self.setup_requests_mock() source = self.make_source() harvest() self.mock_requests.get.assert_called_with(source.url) event = DBSession.query(Event).one() self.assertEqual(event.title, u"Capitole du Libre") self.assertEqual( event.url, u"http://www.agendadulibre.org/showevent.php?id=7064") self.assertEqual(event.description, u"Un évènement de l'Agenda du Libre")
def test_fetch_data_from_source(self): self.setup_requests_mock() source = self.make_source() harvest() self.mock_requests.get.assert_called_with(source.url) event = DBSession.query(Event).one() self.assertEqual(event.title, u"Capitole du Libre") self.assertEqual(event.url, u"http://www.agendadulibre.org/showevent.php?id=7064") self.assertEqual(event.description, u"Un évènement de l'Agenda du Libre")
def main(global_config, **settings): """ This function returns a Pyramid WSGI application. """ engine = engine_from_config(settings, 'sqlalchemy.') DBSession.configure(bind=engine) Base.metadata.bind = engine config = Configurator(settings=settings) config.include('cornice') config.add_static_view('static', 'static', cache_max_age=3600) config.add_route('home', '/') config.add_renderer('json', 'ode.renderers.JsonRenderer') config.add_renderer('csv', 'ode.renderers.CsvRenderer') config.add_renderer('ical', 'ode.renderers.IcalRenderer') config.add_renderer('no_content', 'ode.renderers.NoContentRenderer') config.add_cornice_deserializer('text/calendar', icalendar_extractor) config.add_cornice_deserializer(COLLECTION_JSON_MIMETYPE, json_extractor) config.add_cornice_deserializer('text/csv', csv_extractor) config.add_translation_dirs('colander:locale/', 'ode:locale/') config.scan(ignore='ode.tests') return config.make_wsgi_app()
def get(self): """Get a specific event by id""" id = self.request.matchdict['id'] try: event = DBSession.query(Event).filter_by(id=id).one() except NoResultFound: raise HTTPNotFound() return { 'status': 'success', 'event': event.json_data(), }
def test_post_multiple_events(self): calendar = self.make_icalendar(titles=[u'Événement 1', u'Événement 2']) response = self.post(calendar) items = response.json['collection']['items'] event = DBSession.query(Event).filter_by(title=u'Événement 1').one() for item in items: for name, value in item['data']: if name == u'title' and value == u'Événement 1': expected_url = u'http://localhost/v1/events/%s' % quote( event.id) self.assertEqual(items[0]['href'], expected_url)
def collection_post(self): """Add new resources""" items = self.request.validated['items'] provider_id = self.request.validated['provider_id'] result_items = [] for item in items: item['data']['provider_id'] = provider_id resource = None if 'id' in item['data'].keys(): resource = self.model.get_by_id(item['data']['id']) if resource is not None: if provider_id != resource.provider_id: self.request.response.status_code = 403 return self.collection_json( [resource.to_item(self.request)] ) resource.update_from_appstruct(item['data']) DBSession.merge(resource) if resource is None: resource = self.model(**item['data']) DBSession.add(resource) DBSession.flush() result_items.append(resource.to_item(self.request)) response = self.request.response response.status_code = 201 if len(result_items) == 1: # POSTed a single item, we can send the Location header response.headers['location'] = result_items[0]['href'] return self.collection_json(result_items)
def collection_post(self): """Add new resources""" items = self.request.validated['items'] provider_id = self.request.validated['provider_id'] result_items = [] for item in items: item['data']['provider_id'] = provider_id resource = None if 'id' in item['data'].keys(): resource = self.model.get_by_id(item['data']['id']) if resource is not None: if provider_id != resource.provider_id: self.request.response.status_code = 403 return self.collection_json( [resource.to_item(self.request)]) resource.update_from_appstruct(item['data']) DBSession.merge(resource) if resource is None: resource = self.model(**item['data']) DBSession.add(resource) DBSession.flush() result_items.append(resource.to_item(self.request)) response = self.request.response response.status_code = 201 if len(result_items) == 1: # POSTed a single item, we can send the Location header response.headers['location'] = result_items[0]['href'] return self.collection_json(result_items)
def _test_get_media(self, klass): attrname = klass.__name__.lower() + 's' event = self.create_event() setattr(event, attrname, [ klass(url=u'http://example.com/abc', license=u'CC By'), klass(url=u'http://example.com/123', license=u'Art Libre'), ]) DBSession.flush() response = self.app.get( '/v1/events/%s' % event.id, headers={'Accept': 'application/vnd.collection+json'}) event_data = response.json['collection']['items'][0]['data'] self.assertIn( { 'name': attrname, "value": [{ "url": u"http://example.com/abc", "license": u"CC By" }, { "url": u"http://example.com/123", "license": u"Art Libre" }] }, event_data)
def put(self): """Update an existing resource by id""" resouce_id = self.request.matchdict['id'] query = DBSession.query(self.model).filter_by( id=resouce_id, provider_id=self.request.validated['provider_id'], ) self.request.validated['provider_id'] = { 'value': self.request.validated['provider_id'] } event = query.first() if not event: raise HTTPNotFound() event.update_from_appstruct(self.request.validated['items'][0]['data']) return {'status': 'updated'}
def put(self): """Update an existing resource by id""" resouce_id = self.request.matchdict['id'] query = DBSession.query(self.model).filter_by( id=resouce_id, provider_id=self.request.validated['provider_id'], ) self.request.validated['provider_id'] = { 'value': self.request.validated['provider_id'] } event = query.first() if not event: raise HTTPNotFound() event.update_from_appstruct( self.request.validated['items'][0]['data']) return {'status': 'updated'}
def test_create_source(self): sources_info = { 'template': { 'data': [ {'name': 'url', 'value': u'http://example.com/mysource'}, {'name': 'active', 'value': True}, ] } } response = self.app.post_json('/v1/sources', sources_info, headers=self.WRITE_HEADERS, status=201) source = DBSession.query(Source).one() self.assertEqual(response.headers['location'], 'http://localhost/v1/sources/%s' % source.id) self.assertEqual(source.url, u'http://example.com/mysource') self.assertEqual(source.active, True)
def test_update_source(self): source = self.make_source() response = self.app.put_json('/v1/sources/%s' % source.id, { 'template': { 'data': [{ 'name': 'url', 'value': 'http://example.com/myothersource' }, { 'name': 'active', 'value': False }] } }, headers=self.WRITE_HEADERS) self.assertEqual(response.json['status'], 'updated') source = DBSession.query(Source).one() self.assertEqual(source.url, u'http://example.com/myothersource') self.assertEqual(source.active, False)
def test_update_source(self): source = self.make_source() response = self.app.put_json( '/v1/sources/%s' % source.id, { 'template': { 'data': [ {'name': 'url', 'value': 'http://example.com/myothersource'}, {'name': 'active', 'value': False} ] } }, headers=self.WRITE_HEADERS) self.assertEqual(response.json['status'], 'updated') source = DBSession.query(Source).one() self.assertEqual(source.url, u'http://example.com/myothersource') self.assertEqual(source.active, False)
def collection_get_query(self): query = DBSession.query(self.model) query = self.collection_get_filter_query(query) sort_by = self.request.validated.get('sort_by') if sort_by: order_criterion = getattr(self.model, sort_by, None) if order_criterion: if self.request.validated['sort_direction'] == 'desc': order_criterion = order_criterion.desc() query = query.order_by(order_criterion) else: message = self._( u"${sort_by} is not a valid sorting criterion", mapping={'sort_by': sort_by}) raise HTTPBadRequest(message) total_count = query.count() limit = self.request.validated.get('limit', COLLECTION_MAX_LENGTH) query = query.limit(limit) offset = self.request.validated.get('offset') if offset: query = query.offset(offset) return (query, total_count)
def make_source(self, url=u"http://example.com", provider_id='123'): source = Source(url=url, provider_id=provider_id) DBSession.add(source) DBSession.flush() return source