def show(self, id): """Return a user's remembered forms. :URL: ``GET /rememberedforms/id`` with optional query string parameters for ordering and pagination. :param str id: the ``id`` value of a user model. :returns: a list form models. .. note:: Any authenticated user is authorized to access this resource. Restricted forms are filtered from the array on a per-user basis. .. note:: See :func:`utils.add_order_by` and :func:`utils.add_pagination` for the query string parameters that effect ordering and pagination. """ user = Session.query(User).get(id) if user: try: query = h.eagerload_form(Session.query(Form))\ .filter(Form.memorizers.contains(user)) query = h.add_order_by(query, dict(request.GET), self.query_builder) query = h.filter_restricted_models('Form', query) return h.add_pagination(query, dict(request.GET)) except Invalid, e: response.status_int = 400 return {'errors': e.unpack_errors()}
def update(self, id): """Update a user and return it. :URL: ``PUT /users/id`` :Request body: JSON object representing the user with updated attribute values. :param str id: the ``id`` value of the user to be updated. :returns: the updated user model. """ user = Session.query(User).get(int(id)) if user: try: schema = UserSchema() values = json.loads(unicode(request.body, request.charset)) state = h.get_state_object(values) state.user_to_update = user.get_full_dict() current_user = Session.query(User).get(session['user'].id) state.user = current_user.get_full_dict() data = schema.to_python(values, state) user = update_user(user, data) # user will be False if there are no changes (cf. update_user). if user: Session.add(user) Session.commit() return user.get_full_dict() else: response.status_int = 400 return {'error': u'The update request failed because the submitted data were not new.'} except h.JSONDecodeError: response.status_int = 400 return h.JSONDecodeErrorResponse except Invalid, e: response.status_int = 400 return {'errors': e.unpack_errors()}
def show(self, id): """Return a user's remembered forms. :URL: ``GET /rememberedforms/id`` with optional query string parameters for ordering and pagination. :param str id: the ``id`` value of a user model. :returns: a list form models. .. note:: Any authenticated user is authorized to access this resource. Restricted forms are filtered from the array on a per-user basis. .. note:: See :func:`utils.add_order_by` and :func:`utils.add_pagination` for the query string parameters that effect ordering and pagination. """ user = Session.query(User).get(id) if user: try: query = h.eagerload_form(Session.query(Form))\ .filter(Form.memorizers.contains(user)) query = h.add_order_by(query, dict(request.GET), self.query_builder) query = h.filter_restricted_models('Form', query) return h.add_pagination(query, dict(request.GET)) except Invalid, e: response.status_int = 400 return {'errors': e.unpack_errors()}
def test_create(self): """Tests that POST /elicitationmethods creates a new elicitation method or returns an appropriate error if the input is invalid. """ original_EM_count = Session.query(ElicitationMethod).count() # Create a valid one params = json.dumps({'name': u'em', 'description': u'Described.'}) response = self.app.post(url('elicitationmethods'), params, self.json_headers, self.extra_environ_admin) resp = json.loads(response.body) new_EM_count = Session.query(ElicitationMethod).count() assert new_EM_count == original_EM_count + 1 assert resp['name'] == u'em' assert resp['description'] == u'Described.' assert response.content_type == 'application/json' # Invalid because name is not unique params = json.dumps({'name': u'em', 'description': u'Described.'}) response = self.app.post(url('elicitationmethods'), params, self.json_headers, self.extra_environ_admin, status=400) resp = json.loads(response.body) assert resp['errors']['name'] == u'The submitted value for ElicitationMethod.name is not unique.' assert response.content_type == 'application/json' # Invalid because name is empty params = json.dumps({'name': u'', 'description': u'Described.'}) response = self.app.post(url('elicitationmethods'), params, self.json_headers, self.extra_environ_admin, status=400) resp = json.loads(response.body) assert resp['errors']['name'] == u'Please enter a value' # Invalid because name is too long params = json.dumps({'name': u'name' * 400, 'description': u'Described.'}) response = self.app.post(url('elicitationmethods'), params, self.json_headers, self.extra_environ_admin, status=400) resp = json.loads(response.body) assert resp['errors']['name'] == u'Enter a value not more than 255 characters long'
def test_update(self): """Tests that PUT /speakers/id updates the speaker with id=id.""" # Create a speaker to update. params = self.speaker_create_params.copy() params.update({ 'first_name': u'first_name', 'last_name': u'last_name', 'page_content': u'page_content', 'dialect': u'dialect' }) params = json.dumps(params) response = self.app.post(url('speakers'), params, self.json_headers, self.extra_environ_admin) resp = json.loads(response.body) speaker_count = Session.query(Speaker).count() speaker_id = resp['id'] original_datetime_modified = resp['datetime_modified'] # Update the speaker sleep( 1 ) # sleep for a second to ensure that MySQL registers a different datetime_modified for the update params = self.speaker_create_params.copy() params.update({ 'first_name': u'first_name', 'last_name': u'last_name', 'page_content': u'page_content', 'dialect': u'updated dialect.' }) params = json.dumps(params) response = self.app.put(url('speaker', id=speaker_id), params, self.json_headers, self.extra_environ_admin) resp = json.loads(response.body) datetime_modified = resp['datetime_modified'] new_speaker_count = Session.query(Speaker).count() assert speaker_count == new_speaker_count assert datetime_modified != original_datetime_modified assert response.content_type == 'application/json' # Attempt an update with no new input and expect to fail sleep( 1 ) # sleep for a second to ensure that MySQL could register a different datetime_modified for the update response = self.app.put(url('speaker', id=speaker_id), params, self.json_headers, self.extra_environ_admin, status=400) resp = json.loads(response.body) speaker_count = new_speaker_count new_speaker_count = Session.query(Speaker).count() our_speaker_datetime_modified = Session.query(Speaker).get( speaker_id).datetime_modified assert our_speaker_datetime_modified.isoformat() == datetime_modified assert speaker_count == new_speaker_count assert resp[ 'error'] == u'The update request failed because the submitted data were not new.' assert response.content_type == 'application/json'
def test_update(self): """Tests that PUT /pages/id updates the page with id=id.""" # Create a page to update. params = self.page_create_params.copy() params.update({ 'name': u'page', 'markup_language': u'Markdown', 'content': self.md_contents }) params = json.dumps(params) response = self.app.post(url('pages'), params, self.json_headers, self.extra_environ_admin) resp = json.loads(response.body) page_count = Session.query(Page).count() page_id = resp['id'] original_datetime_modified = resp['datetime_modified'] # Update the page sleep( 1 ) # sleep for a second to ensure that MySQL registers a different datetime_modified for the update params = self.page_create_params.copy() params.update({ 'name': u'Awesome Page', 'markup_language': u'Markdown', 'content': self.md_contents }) params = json.dumps(params) response = self.app.put(url('page', id=page_id), params, self.json_headers, self.extra_environ_admin) resp = json.loads(response.body) datetime_modified = resp['datetime_modified'] new_page_count = Session.query(Page).count() assert page_count == new_page_count assert datetime_modified != original_datetime_modified assert resp['name'] == u'Awesome Page' assert response.content_type == 'application/json' # Attempt an update with no new input and expect to fail sleep( 1 ) # sleep for a second to ensure that MySQL could register a different datetime_modified for the update response = self.app.put(url('page', id=page_id), params, self.json_headers, self.extra_environ_admin, status=400) resp = json.loads(response.body) page_count = new_page_count new_page_count = Session.query(Page).count() our_page_datetime_modified = Session.query(Page).get( page_id).datetime_modified assert our_page_datetime_modified.isoformat() == datetime_modified assert page_count == new_page_count assert resp[ 'error'] == u'The update request failed because the submitted data were not new.' assert response.content_type == 'application/json'
def test_delete(self): """Tests that DELETE /tags/id deletes the tag with id=id.""" # Create a tag to delete. params = json.dumps({'name': u'name', 'description': u'description'}) response = self.app.post(url('tags'), params, self.json_headers, self.extra_environ_admin) resp = json.loads(response.body) tag_count = Session.query(Tag).count() tag_id = resp['id'] # Now delete the tag response = self.app.delete(url('tag', id=tag_id), headers=self.json_headers, extra_environ=self.extra_environ_admin) resp = json.loads(response.body) new_tag_count = Session.query(Tag).count() assert new_tag_count == tag_count - 1 assert resp['id'] == tag_id assert response.content_type == 'application/json' # Trying to get the deleted tag from the db should return None deleted_tag = Session.query(Tag).get(tag_id) assert deleted_tag == None # Delete with an invalid id id = 9999999999999 response = self.app.delete(url('tag', id=id), headers=self.json_headers, extra_environ=self.extra_environ_admin, status=404) assert u'There is no tag with id %s' % id in json.loads(response.body)['error'] assert response.content_type == 'application/json' # Delete without an id response = self.app.delete(url('tag', id=''), status=404, headers=self.json_headers, extra_environ=self.extra_environ_admin) assert json.loads(response.body)['error'] == 'The resource could not be found.' assert response.content_type == 'application/json' # Create a form, tag it, delete the tag and show that the form no longer # has the tag. tag = model.Tag() tag.name = u'tag' form = model.Form() form.transcription = u'test' form.tags.append(tag) Session.add_all([form, tag]) Session.commit() form_id = form.id tag_id = tag.id response = self.app.delete(url('tag', id=tag_id), headers=self.json_headers, extra_environ=self.extra_environ_admin) deleted_tag = Session.query(Tag).get(tag_id) form = Session.query(model.Form).get(form_id) assert response.content_type == 'application/json' assert deleted_tag == None assert form.tags == []
def test_create(self): """Tests that POST /tags creates a new tag or returns an appropriate error if the input is invalid. """ original_tag_count = Session.query(Tag).count() # Create a valid one params = json.dumps({'name': u'tag', 'description': u'Described.'}) response = self.app.post(url('tags'), params, self.json_headers, self.extra_environ_admin) resp = json.loads(response.body) new_tag_count = Session.query(Tag).count() assert new_tag_count == original_tag_count + 1 assert resp['name'] == u'tag' assert resp['description'] == u'Described.' assert response.content_type == 'application/json' # Invalid because name is not unique params = json.dumps({'name': u'tag', 'description': u'Described.'}) response = self.app.post(url('tags'), params, self.json_headers, self.extra_environ_admin, status=400) resp = json.loads(response.body) assert resp['errors'][ 'name'] == u'The submitted value for Tag.name is not unique.' # Invalid because name is empty params = json.dumps({'name': u'', 'description': u'Described.'}) response = self.app.post(url('tags'), params, self.json_headers, self.extra_environ_admin, status=400) resp = json.loads(response.body) assert resp['errors']['name'] == u'Please enter a value' assert response.content_type == 'application/json' # Invalid because name is too long params = json.dumps({ 'name': u'name' * 400, 'description': u'Described.' }) response = self.app.post(url('tags'), params, self.json_headers, self.extra_environ_admin, status=400) resp = json.loads(response.body) assert resp['errors'][ 'name'] == u'Enter a value not more than 255 characters long' assert response.content_type == 'application/json'
def test_delete(self): """Tests that DELETE /formsearches/id deletes the form search with id=id.""" # Create a form search to delete. query = {'filter': ['Form', 'transcription', 'regex', u'[a-g]{3,}']} params = self.form_search_create_params.copy() params.update({ 'name': u'form search', 'description': u'This one\'s worth saving!', 'search': query }) params = json.dumps(params) response = self.app.post(url('formsearches'), params, self.json_headers, self.extra_environ_admin) resp = json.loads(response.body) form_search_count = Session.query(FormSearch).count() form_search_id = resp['id'] assert resp['name'] == u'form search' assert resp['description'] == u"This one's worth saving!" assert resp['search'] == query # Now delete the form_search response = self.app.delete(url('formsearch', id=form_search_id), headers=self.json_headers, extra_environ=self.extra_environ_admin) resp = json.loads(response.body) new_form_search_count = Session.query(FormSearch).count() assert new_form_search_count == form_search_count - 1 assert resp['id'] == form_search_id assert response.content_type == 'application/json' # Trying to get the deleted form_search from the db should return None deleted_form_search = Session.query(FormSearch).get(form_search_id) assert deleted_form_search == None # Delete with an invalid id id = 9999999999999 response = self.app.delete(url('formsearch', id=id), headers=self.json_headers, extra_environ=self.extra_environ_admin, status=404) assert u'There is no form search with id %s' % id in json.loads( response.body)['error'] assert response.content_type == 'application/json' # Delete without an id response = self.app.delete(url('formsearch', id=''), status=404, headers=self.json_headers, extra_environ=self.extra_environ_admin) assert json.loads( response.body)['error'] == 'The resource could not be found.'
def authenticate(self): """Session-based authentication. :URL: ``POST /login/authenticate`` :request body: A JSON object with ``"username"`` and ``"password"`` string values :returns: ``{"authenticated": True}`` on success, an error dictionary on failure. """ try: schema = LoginSchema() values = json.loads(unicode(request.body, request.charset)) result = schema.to_python(values) username = result['username'] user_from_username = Session.query(User).filter( User.username == username).first() if user_from_username: salt = user_from_username.salt password = unicode( h.encrypt_password(result['password'], str(salt))) user = Session.query(User).filter( User.username == username).filter( User.password == password).first() if user: session['user'] = user session.save() home_page = Session.query(Page).filter( Page.name == u'home').first() return { 'authenticated': True, 'user': user, 'homepage': home_page } else: response.status_int = 401 return { 'error': u'The username and password provided are not valid.' } else: response.status_int = 401 return { 'error': u'The username and password provided are not valid.' } except h.JSONDecodeError: response.status_int = 400 return h.JSONDecodeErrorResponse except Invalid, e: response.status_int = 400 return {'errors': e.unpack_errors()}
def test_delete(self): """Tests that DELETE /speakers/id deletes the speaker with id=id.""" # Create a speaker to delete. params = self.speaker_create_params.copy() params.update({ 'first_name': u'first_name', 'last_name': u'last_name', 'page_content': u'page_content', 'dialect': u'dialect' }) params = json.dumps(params) response = self.app.post(url('speakers'), params, self.json_headers, self.extra_environ_admin) resp = json.loads(response.body) speaker_count = Session.query(Speaker).count() speaker_id = resp['id'] # Now delete the speaker response = self.app.delete(url('speaker', id=speaker_id), headers=self.json_headers, extra_environ=self.extra_environ_admin) resp = json.loads(response.body) new_speaker_count = Session.query(Speaker).count() assert new_speaker_count == speaker_count - 1 assert resp['id'] == speaker_id assert response.content_type == 'application/json' # Trying to get the deleted speaker from the db should return None deleted_speaker = Session.query(Speaker).get(speaker_id) assert deleted_speaker == None assert response.content_type == 'application/json' # Delete with an invalid id id = 9999999999999 response = self.app.delete(url('speaker', id=id), headers=self.json_headers, extra_environ=self.extra_environ_admin, status=404) assert u'There is no speaker with id %s' % id in json.loads( response.body)['error'] assert response.content_type == 'application/json' # Delete without an id response = self.app.delete(url('speaker', id=''), status=404, headers=self.json_headers, extra_environ=self.extra_environ_admin) assert json.loads( response.body)['error'] == 'The resource could not be found.' assert response.content_type == 'application/json'
def test_create(self): """Tests that POST /pages creates a new page or returns an appropriate error if the input is invalid. """ original_page_count = Session.query(Page).count() # Create a valid one params = self.page_create_params.copy() params.update({ 'name': u'page', 'markup_language': u'Markdown', 'content': self.md_contents }) params = json.dumps(params) response = self.app.post(url('pages'), params, self.json_headers, self.extra_environ_admin) resp = json.loads(response.body) new_page_count = Session.query(Page).count() assert new_page_count == original_page_count + 1 assert resp['name'] == u'page' assert resp['content'] == self.md_contents assert resp['html'] == h.get_HTML_from_contents(self.md_contents, 'Markdown') assert response.content_type == 'application/json' # Invalid because name is empty and markup language is invalid params = self.page_create_params.copy() params.update({ 'name': u'', 'markup_language': u'markdownable', 'content': self.md_contents }) params = json.dumps(params) response = self.app.post(url('pages'), params, self.json_headers, self.extra_environ_admin, status=400) resp = json.loads(response.body) assert resp['errors']['name'] == u'Please enter a value' assert resp['errors']['markup_language'] == \ u"Value must be one of: Markdown; reStructuredText (not u'markdownable')" assert response.content_type == 'application/json' # Invalid because name is too long params = self.page_create_params.copy() params.update({ 'name': u'name' * 200, 'markup_language': u'Markdown', 'content': self.md_contents }) params = json.dumps(params) response = self.app.post(url('pages'), params, self.json_headers, self.extra_environ_admin, status=400) resp = json.loads(response.body) assert resp['errors']['name'] == u'Enter a value not more than 255 characters long' assert response.content_type == 'application/json'
def test_update(self): """Tests that PUT /formsearches/id updates the form search with id=id.""" # Create a form search to update. query = {'filter': ['Form', 'transcription', 'regex', u'[a-g]{3,}']} params = self.form_search_create_params.copy() params.update({ 'name': u'form search', 'description': u'This one\'s worth saving!', 'search': query }) params = json.dumps(params) response = self.app.post(url('formsearches'), params, self.json_headers, self.extra_environ_admin) resp = json.loads(response.body) form_search_count = Session.query(FormSearch).count() form_search_id = resp['id'] original_datetime_modified = resp['datetime_modified'] assert resp['name'] == u'form search' assert resp['description'] == u"This one's worth saving!" assert resp['search'] == query # Update the form search sleep(1) # sleep for a second to ensure that MySQL registers a different datetime_modified for the update params = self.form_search_create_params.copy() params.update({ 'name': u'form search for keeping', 'description': u'This one\'s worth saving!', 'search': query }) params = json.dumps(params) response = self.app.put(url('formsearch', id=form_search_id), params, self.json_headers, self.extra_environ_admin) resp = json.loads(response.body) datetime_modified = resp['datetime_modified'] new_form_search_count = Session.query(FormSearch).count() assert form_search_count == new_form_search_count assert datetime_modified != original_datetime_modified assert response.content_type == 'application/json' # Attempt an update with no new input and expect to fail sleep(1) # sleep for a second to ensure that MySQL could register a different datetime_modified for the update response = self.app.put(url('formsearch', id=form_search_id), params, self.json_headers, self.extra_environ_admin, status=400) resp = json.loads(response.body) form_search_count = new_form_search_count new_form_search_count = Session.query(FormSearch).count() our_form_search_datetime_modified = Session.query(FormSearch).get(form_search_id).datetime_modified assert our_form_search_datetime_modified.isoformat() == datetime_modified assert form_search_count == new_form_search_count assert resp['error'] == u'The update request failed because the submitted data were not new.' assert response.content_type == 'application/json'
def test_update(self): """Tests that PUT /elicitationmethods/id updates the elicitationmethod with id=id.""" # Create an elicitation method to update. params = json.dumps({'name': u'name', 'description': u'description'}) response = self.app.post(url('elicitationmethods'), params, self.json_headers, self.extra_environ_admin) resp = json.loads(response.body) elicitation_method_count = Session.query(ElicitationMethod).count() elicitation_method_id = resp['id'] original_datetime_modified = resp['datetime_modified'] # Update the elicitation method sleep( 1 ) # sleep for a second to ensure that MySQL registers a different datetime_modified for the update params = json.dumps({ 'name': u'name', 'description': u'More content-ful description.' }) response = self.app.put( url('elicitationmethod', id=elicitation_method_id), params, self.json_headers, self.extra_environ_admin) resp = json.loads(response.body) datetime_modified = resp['datetime_modified'] new_elicitation_method_count = Session.query(ElicitationMethod).count() assert elicitation_method_count == new_elicitation_method_count assert datetime_modified != original_datetime_modified assert response.content_type == 'application/json' # Attempt an update with no new input and expect to fail sleep( 1 ) # sleep for a second to ensure that MySQL could register a different datetime_modified for the update response = self.app.put(url('elicitationmethod', id=elicitation_method_id), params, self.json_headers, self.extra_environ_admin, status=400) resp = json.loads(response.body) elicitation_method_count = new_elicitation_method_count new_elicitation_method_count = Session.query(ElicitationMethod).count() our_EM_datetime_modified = Session.query(ElicitationMethod).get( elicitation_method_id).datetime_modified assert our_EM_datetime_modified.isoformat() == datetime_modified assert elicitation_method_count == new_elicitation_method_count assert resp[ 'error'] == u'The update request failed because the submitted data were not new.' assert response.content_type == 'application/json'
def test_update(self): """Tests that PUT /speakers/id updates the speaker with id=id.""" # Create a speaker to update. params = self.speaker_create_params.copy() params.update({ 'first_name': u'first_name', 'last_name': u'last_name', 'page_content': u'page_content', 'dialect': u'dialect' }) params = json.dumps(params) response = self.app.post(url('speakers'), params, self.json_headers, self.extra_environ_admin) resp = json.loads(response.body) speaker_count = Session.query(Speaker).count() speaker_id = resp['id'] original_datetime_modified = resp['datetime_modified'] # Update the speaker sleep(1) # sleep for a second to ensure that MySQL registers a different datetime_modified for the update params = self.speaker_create_params.copy() params.update({ 'first_name': u'first_name', 'last_name': u'last_name', 'page_content': u'page_content', 'dialect': u'updated dialect.' }) params = json.dumps(params) response = self.app.put(url('speaker', id=speaker_id), params, self.json_headers, self.extra_environ_admin) resp = json.loads(response.body) datetime_modified = resp['datetime_modified'] new_speaker_count = Session.query(Speaker).count() assert speaker_count == new_speaker_count assert datetime_modified != original_datetime_modified assert response.content_type == 'application/json' # Attempt an update with no new input and expect to fail sleep(1) # sleep for a second to ensure that MySQL could register a different datetime_modified for the update response = self.app.put(url('speaker', id=speaker_id), params, self.json_headers, self.extra_environ_admin, status=400) resp = json.loads(response.body) speaker_count = new_speaker_count new_speaker_count = Session.query(Speaker).count() our_speaker_datetime_modified = Session.query(Speaker).get(speaker_id).datetime_modified assert our_speaker_datetime_modified.isoformat() == datetime_modified assert speaker_count == new_speaker_count assert resp['error'] == u'The update request failed because the submitted data were not new.' assert response.content_type == 'application/json'
def test_delete(self): """Tests that DELETE /pages/id deletes the page with id=id.""" # Create a page to delete. params = self.page_create_params.copy() params.update({ 'name': u'page', 'markup_language': u'Markdown', 'content': self.md_contents }) params = json.dumps(params) response = self.app.post(url('pages'), params, self.json_headers, self.extra_environ_admin) resp = json.loads(response.body) page_count = Session.query(Page).count() page_id = resp['id'] # Now delete the page response = self.app.delete(url('page', id=page_id), headers=self.json_headers, extra_environ=self.extra_environ_admin) resp = json.loads(response.body) new_page_count = Session.query(Page).count() assert new_page_count == page_count - 1 assert resp['id'] == page_id assert response.content_type == 'application/json' # Trying to get the deleted page from the db should return None deleted_page = Session.query(Page).get(page_id) assert deleted_page == None assert response.content_type == 'application/json' # Delete with an invalid id id = 9999999999999 response = self.app.delete(url('page', id=id), headers=self.json_headers, extra_environ=self.extra_environ_admin, status=404) assert u'There is no page with id %s' % id in json.loads( response.body)['error'] assert response.content_type == 'application/json' # Delete without an id response = self.app.delete(url('page', id=''), status=404, headers=self.json_headers, extra_environ=self.extra_environ_admin) assert json.loads( response.body)['error'] == 'The resource could not be found.'
def test_update(self): """Tests that PUT /pages/id updates the page with id=id.""" # Create a page to update. params = self.page_create_params.copy() params.update({ 'name': u'page', 'markup_language': u'Markdown', 'content': self.md_contents }) params = json.dumps(params) response = self.app.post(url('pages'), params, self.json_headers, self.extra_environ_admin) resp = json.loads(response.body) page_count = Session.query(Page).count() page_id = resp['id'] original_datetime_modified = resp['datetime_modified'] # Update the page sleep(1) # sleep for a second to ensure that MySQL registers a different datetime_modified for the update params = self.page_create_params.copy() params.update({ 'name': u'Awesome Page', 'markup_language': u'Markdown', 'content': self.md_contents }) params = json.dumps(params) response = self.app.put(url('page', id=page_id), params, self.json_headers, self.extra_environ_admin) resp = json.loads(response.body) datetime_modified = resp['datetime_modified'] new_page_count = Session.query(Page).count() assert page_count == new_page_count assert datetime_modified != original_datetime_modified assert resp['name'] == u'Awesome Page' assert response.content_type == 'application/json' # Attempt an update with no new input and expect to fail sleep(1) # sleep for a second to ensure that MySQL could register a different datetime_modified for the update response = self.app.put(url('page', id=page_id), params, self.json_headers, self.extra_environ_admin, status=400) resp = json.loads(response.body) page_count = new_page_count new_page_count = Session.query(Page).count() our_page_datetime_modified = Session.query(Page).get(page_id).datetime_modified assert our_page_datetime_modified.isoformat() == datetime_modified assert page_count == new_page_count assert resp['error'] == u'The update request failed because the submitted data were not new.' assert response.content_type == 'application/json'
def index(self): """Get all collection resources. :URL: ``GET /collections`` with optional query string parameters for ordering and pagination. :returns: a list of all collection resources. .. note:: See :func:`utils.add_order_by` and :func:`utils.add_pagination` for the query string parameters that effect ordering and pagination. .. note:: ``GET /collections`` does not return the forms of the collections returned. For that, a second request is required, i.e., to ``GET /collections/id`` with the relevant ``id`` value. """ try: query = h.eagerload_collection(Session.query(Collection)) query = h.add_order_by(query, dict(request.GET), self.query_builder) query = h.filter_restricted_models('Collection', query) return h.add_pagination(query, dict(request.GET)) except Invalid, e: response.status_int = 400 return {'errors': e.unpack_errors()}
def update(self, id): """Update a page and return it. :URL: ``PUT /pages/id`` :Request body: JSON object representing the page with updated attribute values. :param str id: the ``id`` value of the page to be updated. :returns: the updated page model. """ page = Session.query(Page).get(int(id)) if page: try: schema = PageSchema() values = json.loads(unicode(request.body, request.charset)) data = schema.to_python(values) page = update_page(page, data) # page will be False if there are no changes (cf. update_page). if page: Session.add(page) Session.commit() return page else: response.status_int = 400 return {'error': u'The update request failed because the submitted data were not new.'} except h.JSONDecodeError: response.status_int = 400 return h.JSONDecodeErrorResponse except Invalid, e: response.status_int = 400 return {'errors': e.unpack_errors()}
def update(self, id): """Update a morpheme language model and return it. :URL: ``PUT /morphemelanguagemodels/id`` :Request body: JSON object representing the morpheme language model with updated attribute values. :param str id: the ``id`` value of the morpheme language model to be updated. :returns: the updated morpheme language model model. """ morpheme_language_model = h.eagerload_morpheme_language_model(Session.query(MorphemeLanguageModel)).get(int(id)) if morpheme_language_model: try: schema = MorphemeLanguageModelSchema() values = json.loads(unicode(request.body, request.charset)) state = h.get_state_object(values) state.id = id data = schema.to_python(values, state) morpheme_language_model_dict = morpheme_language_model.get_dict() morpheme_language_model = update_morpheme_language_model(morpheme_language_model, data) # morpheme_language_model will be False if there are no changes (cf. update_morpheme_language_model). if morpheme_language_model: backup_morpheme_language_model(morpheme_language_model_dict) Session.add(morpheme_language_model) Session.commit() return morpheme_language_model else: response.status_int = 400 return {'error': u'The update request failed because the submitted data were not new.'} except h.JSONDecodeError: response.status_int = 400 return h.JSONDecodeErrorResponse except Invalid, e: response.status_int = 400 return {'errors': e.unpack_errors()}
def delete(self, id): """Delete an existing collection and return it. :URL: ``DELETE /collections/id`` :param str id: the ``id`` value of the collection to be deleted. :returns: the deleted collection model. .. note:: Only administrators and a collection's enterer can delete it. """ collection = h.eagerload_collection(Session.query(Collection), eagerload_forms=True).get(id) if collection: if session['user'].role == u'administrator' or \ collection.enterer is session['user']: session['user'] = Session.merge(session['user']) collection.modifier = session['user'] collection_dict = collection.get_full_dict() backup_collection(collection_dict) update_collections_that_reference_this_collection(collection, self.query_builder, deleted=True) Session.delete(collection) Session.commit() return collection_dict else: response.status_int = 403 return h.unauthorized_msg else: response.status_int = 404 return {'error': 'There is no collection with id %s' % id}
def edit(self, id): """Return a user resource and the data needed to update it. :URL: ``GET /users/edit`` :param str id: the ``id`` value of the user that will be updated. :returns: a dictionary of the form:: {"user": {...}, "data": {...}} where the value of the ``user`` key is a dictionary representation of the user and the value of the ``user`` key is a dictionary of lists of resources. .. note:: See :func:`get_new_user_data` to understand how the query string parameters can affect the contents of the lists in the returned dictionary. """ user = Session.query(User).get(id) if user: data = get_new_user_data(request.GET) return {'data': data, 'user': user.get_full_dict()} else: response.status_int = 404 return {'error': 'There is no user with id %s' % id}
def edit(self, id): """Return a morphological parser and the data needed to update it. :URL: ``GET /morphologicalparsers/id/edit`` :param str id: the ``id`` value of the morphological parser that will be updated. :returns: a dictionary of the form:: {"morphological_parser": {...}, "data": {...}} where the value of the ``morphological_parser`` key is a dictionary representation of the morphological_parser and the value of the ``data`` key is the data structure returned by the ``new`` action, i.e., a representation of the corpora, phonologies and morphologies in the system. """ morphological_parser = h.eagerload_morphological_parser( Session.query(MorphologicalParser)).get(id) if morphological_parser: return { 'data': get_data_for_new_edit(dict(request.GET)), 'morphological_parser': morphological_parser } else: response.status_int = 404 return { 'error': 'There is no morphological parser with id %s' % id }
def serve_arpa(self, id): """Serve the generated ARPA file of the morpheme language model. :URL: ``PUT /morphemelanguagemodels/serve_arpa/id`` :param str id: the ``id`` value of a morpheme language model. :returns: a stream of bytes -- the ARPA file of the LM. """ lm = Session.query(MorphemeLanguageModel).get(id) if lm: arpa_path = lm.get_file_path('arpa') if os.path.isfile(arpa_path): if authorized_to_access_arpa_file(session['user'], lm): return forward( FileApp(arpa_path, content_type='text/plain')) else: response.status_int = 403 return json.dumps(h.unauthorized_msg) else: response.status_int = 404 return json.dumps({ 'error': 'The ARPA file for morpheme language model %s has not been compiled yet.' % id }) else: response.status_int = 404 return json.dumps({ 'error': 'There is no morpheme language model with id %s' % id })
def parse(self, id): """Parse the input word transcriptions using the morphological parser with id=``id``. :param str id: the ``id`` value of the morphological parser that will be used. :Request body: JSON object of the form ``{'transcriptions': [t1, t2, ...]}``. :returns: if the morphological parser exists and foma is installed, a JSON object of the form ``{t1: p1, t2: p2, ...}`` where ``t1`` and ``t2`` are transcriptions of words from the request body and ``p1`` and ``p2`` are the most probable morphological parsers of t1 and t2. """ parser = Session.query(MorphologicalParser).get(id) if not parser: response.status_int = 404 return {'error': 'There is no morphological parser with id %s' % id} if not h.foma_installed(): response.status_int = 400 return {'error': 'Foma and flookup are not installed.'} try: inputs = json.loads(unicode(request.body, request.charset)) schema = TranscriptionsSchema inputs = schema.to_python(inputs) return parser.parse(inputs['transcriptions']) except h.JSONDecodeError: response.status_int = 400 return h.JSONDecodeErrorResponse except Invalid, e: response.status_int = 400 return {'errors': e.unpack_errors()}
def apply(self, id, direction): """Call foma apply in the direction of ``direction`` on the input in the request body using a morphology. :param str id: the ``id`` value of the morphology that will be used. :param str direction: the direction of foma application. :Request body: JSON object of the form ``{'transcriptions': [t1, t2, ...]}``. :returns: if the morphology exists and foma is installed, a JSON object of the form ``{t1: [p1t1, p2t1, ...], ...}`` where ``t1`` is a transcription from the request body and ``p1t1``, ``p2t1``, etc. are outputs of ``t1`` after apply up/down. """ morphology = Session.query(Morphology).get(id) if morphology: if h.foma_installed(): morphology_binary_path = morphology.get_file_path('binary') if os.path.isfile(morphology_binary_path): try: inputs = json.loads(unicode(request.body, request.charset)) inputs = MorphemeSequencesSchema.to_python(inputs) inputs = [h.normalize(i) for i in inputs['morpheme_sequences']] return morphology.apply(direction, inputs) except h.JSONDecodeError: response.status_int = 400 return h.JSONDecodeErrorResponse except Invalid, e: response.status_int = 400 return {'errors': e.unpack_errors()} else: response.status_int = 400 return {'error': 'Morphology %d has not been compiled yet.' % morphology.id} else: response.status_int = 400 return {'error': 'Foma and flookup are not installed.'}
def export(self): """Update the local store with the persistence layer and return the store. """ persisted = dict((p.transcription, p.parse) for p in Session.query(Parse).filter(Parse.parser_id==self.parser.id).all()) self._store.update(persisted) return self._store
def show(self, id): """Return a morphology. :URL: ``GET /morphologies/id`` :param str id: the ``id`` value of the morphology to be returned. :GET param str script: if set to '1', the script will be returned with the morphology :GET param str lexicon: if set to '1', the lexicon (dict) will be returned with the morphology :returns: a morphology model object. """ morphology = h.eagerload_morphology(Session.query(Morphology)).get(id) if morphology: morphology_dict = morphology.get_dict() if request.GET.get('script') == u'1': morphology_script_path = morphology.get_file_path('script') if os.path.isfile(morphology_script_path): morphology_dict['script'] = codecs.open(morphology_script_path, mode='r', encoding='utf8').read() else: morphology_dict['script'] = u'' if request.GET.get('lexicon') == u'1': morphology_lexicon_path = morphology.get_file_path('lexicon') if os.path.isfile(morphology_lexicon_path): morphology_dict['lexicon'] = cPickle.load(open(morphology_lexicon_path, 'rb')) else: morphology_dict['lexicon'] = {} return morphology_dict else: response.status_int = 404 return {'error': 'There is no morphology with id %s' % id}
def servefile(self, id, file_id): """Return the corpus as a file in the format specified in the URL query string. :URL: ``PUT /corpora/id/servefile/file_id``. :param str id: the ``id`` value of the corpus. :param str file_id: the ``id`` value of the corpus file. :returns: the file data """ corpus = Session.query(Corpus).get(id) if corpus: try: corpus_file = filter(lambda cf: cf.id == int(file_id), corpus.files)[0] corpus_file_path = os.path.join(get_corpus_dir_path(corpus), '%s.gz' % corpus_file.filename) if authorized_to_access_corpus_file(session['user'], corpus_file): return forward( FileApp(corpus_file_path, content_type='application/x-gzip')) else: response.status_int = 403 return json.dumps(h.unauthorized_msg) except Exception: response.status_int = 400 return json.dumps({ 'error': 'Unable to serve corpus file %d of corpus %d' % (file_id, id) }) else: response.status_int = 404 return json.dumps({'error': 'There is no corpus with id %s' % id})
def servecompiled(self, id): """Serve the compiled foma script of the morphophonology FST of the morphological parser. :URL: ``PUT /morphologicalparsers/servecompiled/id`` :param str id: the ``id`` value of a morphological parser. :returns: a stream of bytes -- the compiled morphological parser script. """ parser = Session.query(MorphologicalParser).get(id) if parser: if h.foma_installed(): binary_path = parser.get_file_path('binary') if os.path.isfile(binary_path): return forward(FileApp(binary_path)) else: response.status_int = 400 return json.dumps({ 'error': 'The morphophonology foma script of ' 'MorphologicalParser %d has not been compiled yet.' % parser.id }) else: response.status_int = 400 return json.dumps( {'error': 'Foma and flookup are not installed.'}) else: response.status_int = 404 return json.dumps( {'error': 'There is no morphological parser with id %s' % id})
def edit(self, id): """Return a user resource and the data needed to update it. :URL: ``GET /users/edit`` :param str id: the ``id`` value of the user that will be updated. :returns: a dictionary of the form:: {"user": {...}, "data": {...}} where the value of the ``user`` key is a dictionary representation of the user and the value of the ``user`` key is a dictionary of lists of resources. .. note:: See :func:`get_new_user_data` to understand how the query string parameters can affect the contents of the lists in the returned dictionary. """ user = Session.query(User).get(id) if user: data = get_new_user_data(request.GET) return {'data': data, 'user': user.get_full_dict()} else: response.status_int = 404 return {'error': 'There is no user with id %s' % id}
def get_probabilities(self, id): """Return the probability of each sequence of morphemes passed in the JSON PUT params. :param list morpheme_sequences: space-delimited morphemes in form|gloss|category format wherer "|" is actually ``h.rare_delimiter``. :returns: a dictionary with morpheme sequences as keys and log probabilities as values. """ lm = Session.query(MorphemeLanguageModel).get(id) if lm: try: schema = MorphemeSequencesSchema() values = json.loads(unicode(request.body, request.charset)) data = schema.to_python(values) morpheme_sequences = [ h.normalize(ms) for ms in data['morpheme_sequences'] ] return lm.get_probabilities(morpheme_sequences) except h.JSONDecodeError: response.status_int = 400 return h.JSONDecodeErrorResponse except Invalid, e: response.status_int = 400 return {'errors': e.unpack_errors()} except Exception: response.status_int = 400 return { 'error': 'An error occurred while trying to generate probabilities.' }
def update(self, id): """Update a syntactic category and return it. :URL: ``PUT /syntacticcategorys/id`` :Request body: JSON object representing the syntactic category with updated attribute values. :param str id: the ``id`` value of the syntactic category to be updated. :returns: the updated syntactic category model. """ syntactic_category = Session.query(SyntacticCategory).get(int(id)) if syntactic_category: try: old_name = syntactic_category.name schema = SyntacticCategorySchema() values = json.loads(unicode(request.body, request.charset)) state = h.get_state_object(values) state.id = id data = schema.to_python(values, state) syntactic_category = update_syntactic_category(syntactic_category, data) # syntactic_category will be False if there are no changes (cf. update_syntactic_category). if syntactic_category: Session.add(syntactic_category) Session.commit() if syntactic_category.name != old_name: update_forms_referencing_this_category(syntactic_category) return syntactic_category else: response.status_int = 400 return {"error": u"The update request failed because the submitted data were not new."} except h.JSONDecodeError: response.status_int = 400 return h.JSONDecodeErrorResponse except Invalid, e: response.status_int = 400 return {"errors": e.unpack_errors()}
def edit(self, id): """Return a morpheme language model and the data needed to update it. :URL: ``GET /morphemelanguagemodels/id/edit`` :param str id: the ``id`` value of the morpheme language model that will be updated. :returns: a dictionary of the form:: {"morpheme_language_model": {...}, "data": {...}} where the value of the ``morpheme_language_model`` key is a dictionary representation of the morpheme_language_model and the value of the ``data`` key is the data structure returned by the ``new`` action. """ lm = h.eagerload_morpheme_language_model( Session.query(MorphemeLanguageModel)).get(id) if lm: return { 'data': get_data_for_new_edit(dict(request.GET)), 'morpheme_language_model': lm } else: response.status_int = 404 return { 'error': 'There is no morpheme language model with id %s' % id }
def serve_file(id, reduced=False): """Serve the content (binary data) of a file. :param str id: the ``id`` value of the file whose file data will be served. :param bool reduced: toggles serving of file data or reduced-size file data. """ file = Session.query(File).options(subqueryload(File.parent_file)).get(id) if getattr(file, 'parent_file', None): file = file.parent_file elif getattr(file, 'url', None): response.status_int = 400 return json.dumps({'error': u'The content of file %s is stored elsewhere at %s' % (id, file.url)}) if file: files_dir = h.get_OLD_directory_path('files', config=config) if reduced: filename = getattr(file, 'lossy_filename', None) if not filename: response.status_int = 404 return json.dumps({'error': u'There is no size-reduced copy of file %s' % id}) file_path = os.path.join(files_dir, 'reduced_files', filename) else: file_path = os.path.join(files_dir, file.filename) unrestricted_users = h.get_unrestricted_users() if h.user_is_authorized_to_access_model(session['user'], file, unrestricted_users): return forward(FileApp(file_path)) else: response.status_int = 403 return json.dumps(h.unauthorized_msg) else: response.status_int = 404 return json.dumps({'error': 'There is no file with id %s' % id})
def applydown(self, id): """Apply-down (i.e., phonologize) the input in the request body using a phonology. :URL: ``PUT /phonologies/applydown/id`` (or ``PUT /phonologies/phonologize/id``) :param str id: the ``id`` value of the phonology that will be used. :Request body: JSON object of the form ``{'transcriptions': [t1, t2, ...]}``. :returns: if the phonology exists and foma is installed, a JSON object of the form ``{t1: [p1t1, p2t1, ...], ...}`` where ``t1`` is a transcription from the request body and ``p1t1``, ``p2t1``, etc. are phonologized outputs of ``t1``. """ phonology = Session.query(Phonology).get(id) if phonology: if h.foma_installed(): binary_path = phonology.get_file_path('binary') if os.path.isfile(binary_path): try: inputs = json.loads(unicode(request.body, request.charset)) inputs = MorphophonemicTranscriptionsSchema.to_python(inputs) inputs = [h.normalize(i) for i in inputs['transcriptions']] return phonology.applydown(inputs) except h.JSONDecodeError: response.status_int = 400 return h.JSONDecodeErrorResponse except Invalid, e: response.status_int = 400 return {'errors': e.unpack_errors()} else: response.status_int = 400 return {'error': 'Phonology %d has not been compiled yet.' % phonology.id} else: response.status_int = 400 return {'error': 'Foma and flookup are not installed.'}
def search(self, id): """Return the remembered forms of a user that match the input JSON query. :URL: ``SEARCH /rememberedforms/id`` (or ``POST /rememberedforms/id/search``). :param str id: the ``id`` value of the user whose remembered forms are searched. :request body: A JSON object of the form:: {"query": {"filter": [ ... ], "order_by": [ ... ]}, "paginator": { ... }} where the ``order_by`` and ``paginator`` attributes are optional. """ user = Session.query(User).get(id) if user: try: json_search_params = unicode(request.body, request.charset) python_search_params = json.loads(json_search_params) query = h.eagerload_form( self.query_builder.get_SQLA_query( python_search_params.get('query'))) query = query.filter(Form.memorizers.contains(user)) query = h.filter_restricted_models('Form', query) return h.add_pagination(query, python_search_params.get('paginator')) except h.JSONDecodeError: response.status_int = 400 return h.JSONDecodeErrorResponse except (OLDSearchParseError, Invalid), e: response.status_int = 400 return {'errors': e.unpack_errors()} except:
def show(self, id): """Return a morphological parser. :URL: ``GET /morphologicalparsers/id`` :param str id: the ``id`` value of the morphological parser to be returned. :GET param str script: if set to '1', the script will be returned with the morphological parser :returns: a morphological parser model object. """ morphological_parser = h.eagerload_morphological_parser( Session.query(MorphologicalParser)).get(id) if morphological_parser: morphological_parser_dict = morphological_parser.get_dict() if request.GET.get('script') == u'1': morphological_parser_dir_path = h.get_model_directory_path( morphological_parser, config) morphological_parser_script_path = h.get_model_file_path( morphological_parser, morphological_parser_dir_path, file_type='script') if os.path.isfile(morphological_parser_script_path): morphological_parser_dict['script'] = codecs.open( morphological_parser_script_path, mode='r', encoding='utf8').read() else: morphological_parser_dict['script'] = u'' return morphological_parser_dict else: response.status_int = 404 return { 'error': 'There is no morphological parser with id %s' % id }
def compile(self, id): """Compile the script of a phonology as a foma FST. :URL: ``PUT /phonologies/compile/id`` :param str id: the ``id`` value of the phonology whose script will be compiled. :returns: if the phonology exists and foma is installed, the phonology model is returned; ``GET /phonologies/id`` must be polled to determine when and how the compilation task has terminated. .. note:: The script is compiled asynchronously in a worker thread. See :mod:`onlinelinguisticdatabase.lib.foma_worker`. """ phonology = Session.query(Phonology).get(id) if phonology: if h.foma_installed(): foma_worker_q.put({ 'id': h.generate_salt(), 'func': 'compile_phonology', 'args': { 'phonology_id': phonology.id, 'user_id': session['user'].id, 'timeout': h.phonology_compile_timeout } }) return phonology else: response.status_int = 400 return {'error': 'Foma and flookup are not installed.'} else: response.status_int = 404 return {'error': 'There is no phonology with id %s' % id}
def generate(self, id): """Generate the files that constitute the morpheme language model, crucially the file that holds the pickled LM trie. :URL: ``PUT /morpheme_language_model/id/generate`` :param str id: the ``id`` value of the morpheme language model whose files will be generated. :returns: the morpheme language model is returned; ``GET /morpheme_language_model/id`` must be polled to determine when the generation task has terminated. """ lm = Session.query(MorphemeLanguageModel).get(id) if not lm: response.status_int = 404 return { 'error': 'There is no morpheme language model with id %s' % id } args = { 'morpheme_language_model_id': lm.id, 'user_id': session['user'].id, 'timeout': h.morpheme_language_model_generate_timeout } foma_worker_q.put({ 'id': h.generate_salt(), 'func': 'generate_language_model', 'args': args }) return lm
def get_probabilities(self, id): """Return the probability of each sequence of morphemes passed in the JSON PUT params. :param list morpheme_sequences: space-delimited morphemes in form|gloss|category format wherer "|" is actually ``h.rare_delimiter``. :returns: a dictionary with morpheme sequences as keys and log probabilities as values. """ lm = Session.query(MorphemeLanguageModel).get(id) if lm: try: schema = MorphemeSequencesSchema() values = json.loads(unicode(request.body, request.charset)) data = schema.to_python(values) morpheme_sequences = [h.normalize(ms) for ms in data['morpheme_sequences']] return lm.get_probabilities(morpheme_sequences) except h.JSONDecodeError: response.status_int = 400 return h.JSONDecodeErrorResponse except Invalid, e: response.status_int = 400 return {'errors': e.unpack_errors()} except Exception: response.status_int = 400 return {'error': 'An error occurred while trying to generate probabilities.'}
def delete(self, id): """Delete an existing orthography and return it. :URL: ``DELETE /orthographies/id`` :param str id: the ``id`` value of the orthography to be deleted. :returns: the deleted orthography model. .. note:: Contributors can only delete orthographies that are not used in the active application settings. """ orthography = Session.query(Orthography).get(id) if orthography: app_set = h.get_application_settings() if session['user'].role == u'administrator' or orthography not in ( app_set.storage_orthography, app_set.input_orthography, app_set.output_orthography): Session.delete(orthography) Session.commit() return orthography else: response.status = 403 return { 'error': u'Only administrators are permitted to delete orthographies that are used in the active application settings.' } else: response.status_int = 404 return {'error': 'There is no orthography with id %s' % id}
def index(self): """Get all collection resources. :URL: ``GET /collections`` with optional query string parameters for ordering and pagination. :returns: a list of all collection resources. .. note:: See :func:`utils.add_order_by` and :func:`utils.add_pagination` for the query string parameters that effect ordering and pagination. .. note:: ``GET /collections`` does not return the forms of the collections returned. For that, a second request is required, i.e., to ``GET /collections/id`` with the relevant ``id`` value. """ try: query = h.eagerload_collection(Session.query(Collection)) query = h.add_order_by(query, dict(request.GET), self.query_builder) query = h.filter_restricted_models('Collection', query) return h.add_pagination(query, dict(request.GET)) except Invalid, e: response.status_int = 400 return {'errors': e.unpack_errors()}
def edit(self, id): """Return an application settings and the data needed to update it. :URL: ``GET /applicationsettings/edit`` with optional query string parameters :param str id: the ``id`` value of the application settings that will be updated. :returns: a dictionary of the form:: {"application_settings": {...}, "data": {...}} where the value of the ``application_settings`` key is a dictionary representation of the application settings and the value of the ``data`` key is a dictionary containing the objects necessary to update an application settings, viz. the return value of :func:`ApplicationsettingsController.new`. .. note:: This action can be thought of as a combination of :func:`ApplicationsettingsController.show` and :func:`ApplicationsettingsController.new`. See :func:`get_new_application_settings_data` to understand how the query string parameters can affect the contents of the lists in the ``data`` dictionary. """ application_settings = h.eagerload_application_settings( Session.query(ApplicationSettings)).get(id) if application_settings: return {'data': get_new_application_settings_data(request.GET), 'application_settings': application_settings} else: response.status_int = 404 return {'error': 'There is no application settings with id %s' % id}
def show(self, id): """Return a collection. :URL: ``GET /collections/id`` :param str id: the ``id`` value of the collection to be returned. :returns: a collection model object. .. note:: Returns all of the forms of the collection, unlike the other collections actions. """ collection = h.eagerload_collection(Session.query(Collection), eagerload_forms=True).get(id) if collection: unrestricted_users = h.get_unrestricted_users() user = session['user'] if h.user_is_authorized_to_access_model(user, collection, unrestricted_users): return collection.get_full_dict() else: response.status_int = 403 return h.unauthorized_msg else: response.status_int = 404 return {'error': 'There is no collection with id %s' % id}
def servefile(self, id, file_id): """Return the corpus as a file in the format specified in the URL query string. :URL: ``PUT /corpora/id/servefile/file_id``. :param str id: the ``id`` value of the corpus. :param str file_id: the ``id`` value of the corpus file. :returns: the file data """ corpus = Session.query(Corpus).get(id) if corpus: try: corpus_file = filter(lambda cf: cf.id == int(file_id), corpus.files)[0] corpus_file_path = os.path.join(get_corpus_dir_path(corpus), '%s.gz' % corpus_file.filename) if authorized_to_access_corpus_file(session['user'], corpus_file): return forward(FileApp(corpus_file_path, content_type='application/x-gzip')) else: response.status_int = 403 return json.dumps(h.unauthorized_msg) except Exception: response.status_int = 400 return json.dumps({'error': 'Unable to serve corpus file %d of corpus %d' % ( file_id, id)}) else: response.status_int = 404 return json.dumps({'error': 'There is no corpus with id %s' % id})
def delete(self, id): """Delete an existing collection and return it. :URL: ``DELETE /collections/id`` :param str id: the ``id`` value of the collection to be deleted. :returns: the deleted collection model. .. note:: Only administrators and a collection's enterer can delete it. """ collection = h.eagerload_collection(Session.query(Collection), eagerload_forms=True).get(id) if collection: if session['user'].role == u'administrator' or \ collection.enterer is session['user']: session['user'] = Session.merge(session['user']) collection.modifier = session['user'] collection_dict = collection.get_full_dict() backup_collection(collection_dict) update_collections_that_reference_this_collection( collection, self.query_builder, deleted=True) Session.delete(collection) Session.commit() return collection_dict else: response.status_int = 403 return h.unauthorized_msg else: response.status_int = 404 return {'error': 'There is no collection with id %s' % id}
def parse(self, id): """Parse the input word transcriptions using the morphological parser with id=``id``. :param str id: the ``id`` value of the morphological parser that will be used. :Request body: JSON object of the form ``{'transcriptions': [t1, t2, ...]}``. :returns: if the morphological parser exists and foma is installed, a JSON object of the form ``{t1: p1, t2: p2, ...}`` where ``t1`` and ``t2`` are transcriptions of words from the request body and ``p1`` and ``p2`` are the most probable morphological parsers of t1 and t2. """ parser = Session.query(MorphologicalParser).get(id) if not parser: response.status_int = 404 return {'error': 'There is no morphological parser with id %s' % id} if not h.foma_installed(): response.status_int = 400 return {'error': 'Foma and flookup are not installed.'} try: inputs = json.loads(unicode(request.body, request.charset)) schema = TranscriptionsSchema inputs = schema.to_python(inputs) inputs = [h.normalize(w) for w in inputs['transcriptions']] parses = parser.parse(inputs) # TODO: allow for a param which causes the candidates to be # returned as well as/instead of only the most probable parse # candidate. return dict((transcription, parse) for transcription, (parse, candidates) in parses.iteritems()) except h.JSONDecodeError: response.status_int = 400 return h.JSONDecodeErrorResponse except Invalid, e: response.status_int = 400 return {'errors': e.unpack_errors()}
def edit(self, id): """GET /formsearches/id/edit: Return the data necessary to update an existing OLD form search. """ """Return a form search and the data needed to update it. :URL: ``GET /formsearches/edit`` with optional query string parameters :param str id: the ``id`` value of the form search that will be updated. :returns: a dictionary of the form:: {"form_search": {...}, "data": {...}} where the value of the ``form_search`` key is a dictionary representation of the form search and the value of the ``data`` key is a dictionary containing the data necessary to update a form search. """ form_search = h.eagerload_form_search( Session.query(FormSearch)).get(id) if form_search: data = { 'search_parameters': h.get_search_parameters(self.query_builder) } return {'data': data, 'form_search': form_search} else: response.status_int = 404 return {'error': 'There is no form search with id %s' % id}
def export_deprecated(self, id): """Export the parser as a self-contained archive including a Python interface and all required files. """ try: parser = Session.query(MorphologicalParser).get(id) directory = parser.directory archive_dir = os.path.join(directory, 'archive') if os.path.exists(archive_dir): rmtree(archive_dir) os.mkdir(archive_dir) parser.copy_files(archive_dir) parser.phonology.copy_files(archive_dir) parser.morphology.copy_files(archive_dir) parser.language_model.copy_files(archive_dir) lib_path = os.path.join(config['here'], 'onlinelinguisticdatabase', 'lib') simplelm_path = os.path.join(lib_path, 'simplelm') parser_path = os.path.join(lib_path, 'parser.py') parse_path = os.path.join(lib_path, 'parse.py') new_parse_path = os.path.join(archive_dir, 'parse.py') copytree(simplelm_path, os.path.join(archive_dir, 'simplelm')) copyfile(parser_path, os.path.join(archive_dir, 'parser.py')) copyfile(parse_path, new_parse_path) os.chmod(new_parse_path, 0744) data = parser.export() data_path = os.path.join(archive_dir, 'data.pickle') cPickle.dump(data, open(data_path, 'wb')) zip_path = h.zipdir(archive_dir) return forward(FileApp(zip_path)) except Exception, e: log.warn(e) response.status_int = 400 return json.dumps({'error': 'An error occured while attempting to export ' 'morphological parser %s' % id})
def edit(self, id): """Return a page and the data needed to update it. :URL: ``GET /pages/edit`` :param str id: the ``id`` value of the page that will be updated. :returns: a dictionary of the form:: {"page": {...}, "data": {...}} where the value of the ``page`` key is a dictionary representation of the page and the value of the ``data`` key is the list of valid markup language names. """ page = Session.query(Page).get(id) if page: return { 'data': { 'markup_languages': h.markup_languages }, 'page': page } else: response.status_int = 404 return {'error': 'There is no page with id %s' % id}
def update(self, id): """Update a source and return it. :URL: ``PUT /sources/id`` :Request body: JSON object representing the source with updated attribute values. :param str id: the ``id`` value of the source to be updated. :returns: the updated source model. """ source = Session.query(Source).get(int(id)) if source: try: schema = SourceSchema() values = json.loads(unicode(request.body, request.charset)) state = h.get_state_object(values) state.id = id data = schema.to_python(values, state) source = update_source(source, data) # source will be False if there are no changes (cf. update_source). if source: Session.add(source) Session.commit() return source else: response.status_int = 400 return {'error': u'The update request failed because the submitted data were not new.'} except h.JSONDecodeError: response.status_int = 400 return h.JSONDecodeErrorResponse except Invalid, e: response.status_int = 400 return {'errors': e.unpack_errors()}
def search(self, id): """Return the remembered forms of a user that match the input JSON query. :URL: ``SEARCH /rememberedforms/id`` (or ``POST /rememberedforms/id/search``). :param str id: the ``id`` value of the user whose remembered forms are searched. :request body: A JSON object of the form:: {"query": {"filter": [ ... ], "order_by": [ ... ]}, "paginator": { ... }} where the ``order_by`` and ``paginator`` attributes are optional. """ user = Session.query(User).get(id) if user: try: json_search_params = unicode(request.body, request.charset) python_search_params = json.loads(json_search_params) query = h.eagerload_form( self.query_builder.get_SQLA_query(python_search_params.get('query'))) query = query.filter(Form.memorizers.contains(user)) query = h.filter_restricted_models('Form', query) return h.add_pagination(query, python_search_params.get('paginator')) except h.JSONDecodeError: response.status_int = 400 return h.JSONDecodeErrorResponse except (OLDSearchParseError, Invalid), e: response.status_int = 400 return {'errors': e.unpack_errors()} except:
def edit(self, id): """Return a file and the data needed to update it. :URL: ``GET /files/edit`` with optional query string parameters :param str id: the ``id`` value of the file that will be updated. :returns: a dictionary of the form:: {"file": {...}, "data": {...}} where the value of the ``file`` key is a dictionary representation of the file and the value of the ``data`` key is a dictionary containing the objects necessary to update a file, viz. the return value of :func:`FilesController.new` .. note:: This action can be thought of as a combination of :func:`FilesController.show` and :func:`FilesController.new`. See :func:`get_new_edit_file_data` to understand how the query string parameters can affect the contents of the lists in the ``data`` dictionary. """ response.content_type = 'application/json' file = h.eagerload_file(Session.query(File)).get(id) if file: unrestricted_users = h.get_unrestricted_users() if h.user_is_authorized_to_access_model(session['user'], file, unrestricted_users): return {'data': get_new_edit_file_data(request.GET), 'file': file} else: response.status_int = 403 return h.unauthorized_msg else: response.status_int = 404 return {'error': 'There is no file with id %s' % id}
def update(self, id): """Update an application settings and return it. :URL: ``PUT /applicationsettings/id`` :Request body: JSON object representing the application settings with updated attribute values. :param str id: the ``id`` value of the application settings to be updated. :returns: the updated application settings model. """ application_settings = h.eagerload_application_settings( Session.query(ApplicationSettings)).get(int(id)) if application_settings: try: schema = ApplicationSettingsSchema() values = json.loads(unicode(request.body, request.charset)) data = schema.to_python(values) # Try to create an updated ApplicationSetting object. application_settings = update_application_settings(application_settings, data) # application_settings will be False if there are no changes if application_settings: Session.add(application_settings) Session.commit() app_globals.application_settings = h.ApplicationSettings() return application_settings else: response.status_int = 400 return {'error': 'The update request failed because the submitted data were not new.'} except h.JSONDecodeError: response.status_int = 400 return h.JSONDecodeErrorResponse except Invalid, e: response.status_int = 400 return {'errors': e.unpack_errors()}
def edit(self, id): """Return a speaker resource and the data needed to update it. :URL: ``GET /speakers/edit`` :param str id: the ``id`` value of the speaker that will be updated. :returns: a dictionary of the form:: {"speaker": {...}, "data": {...}} where the value of the ``speaker`` key is a dictionary representation of the speaker and the value of the ``data`` key is an empty dictionary. TODO: implement a `get_new_speaker_data` function here, similar to that defined in controllers/user.py so that GET params can effect what data are returned. """ speaker = Session.query(Speaker).get(id) if speaker: return { 'data': {'markup_languages': h.markup_languages}, 'speaker': speaker } else: response.status_int = 404 return {'error': 'There is no speaker with id %s' % id}