def update_note(): params = request.form body = params.get('body', None) is_private = to_bool_or_none(params.get('isPrivate', False)) note_id = params.get('id', None) subject = params.get('subject', None) topics = get_note_topics_from_http_post() note = Note.find_by_id(note_id=note_id) if note_id else None if not note: raise ResourceNotFoundError('Note not found') if not subject: raise BadRequestError('Note subject is required') if note.author_uid != current_user.get_uid(): raise ForbiddenRequestError( 'Sorry, you are not the author of this note.') if (is_private is not note.is_private ) and not current_user.can_access_private_notes: raise ForbiddenRequestError( 'Sorry, you are not authorized to manage note privacy') note = Note.update( body=process_input_from_rich_text_editor(body), is_private=is_private, note_id=note_id, subject=subject, topics=topics, ) note_read = NoteRead.find_or_create(current_user.get_id(), note_id) return tolerant_jsonify( _boa_note_to_compatible_json(note=note, note_read=note_read))
def test_unauthorized(self, client, fake_auth, mock_coe_advising_note): """Advisor cannot delete the note of another.""" fake_auth.login('6446') response = client.delete( f'/api/notes/delete/{mock_coe_advising_note.id}') assert response.status_code == 403 assert Note.find_by_id(mock_coe_advising_note.id)
def delete_note(note_id): if not current_user.is_admin: raise ForbiddenRequestError('Sorry, you are not authorized to delete notes.') note = Note.find_by_id(note_id=note_id) if not note: raise ResourceNotFoundError('Note not found') Note.delete(note_id=note_id) return tolerant_jsonify({'message': f'Note {note_id} deleted'}), 200
def get_note(note_id): note = Note.find_by_id(note_id=note_id) if not note: raise ResourceNotFoundError('Note not found') note_read = NoteRead.when_user_read_note(current_user.get_id(), str(note.id)) return tolerant_jsonify( _boa_note_to_compatible_json(note=note, note_read=note_read))
def test_advisor_cannot_delete(self, client, fake_auth, mock_coe_advising_note): """Advisor cannot delete her own note.""" fake_auth.login(mock_coe_advising_note.author_uid) response = client.delete( f'/api/notes/delete/{mock_coe_advising_note.id}') assert response.status_code == 403 assert Note.find_by_id(mock_coe_advising_note.id)
def test_user_without_advising_data_access(self, client, fake_auth, mock_coe_advising_note): """Denies access to a user who cannot access notes and appointments.""" fake_auth.login(coe_advisor_no_advising_data_uid) response = client.delete( f'/api/notes/delete/{mock_coe_advising_note.id}') assert response.status_code == 401 assert Note.find_by_id(mock_coe_advising_note.id)
def test_admin_delete(self, client, fake_auth, mock_coe_advising_note): """Admin can delete another user's note.""" original_count_per_sid = len(Note.get_notes_by_sid(mock_coe_advising_note.sid)) fake_auth.login(admin_uid) note_id = mock_coe_advising_note.id response = client.delete(f'/api/notes/delete/{note_id}') assert response.status_code == 200 assert not Note.find_by_id(note_id) assert 1 == original_count_per_sid - len(Note.get_notes_by_sid(mock_coe_advising_note.sid)) assert not Note.update(note_id=note_id, subject='Deleted note cannot be updated')
def test_unauthorized_update_note(self, app, client, fake_auth, mock_coe_advising_note): """Deny user's attempt to edit someone else's note.""" original_subject = mock_coe_advising_note.subject fake_auth.login(asc_advisor_uid) assert self._api_note_update( app, client, note_id=mock_coe_advising_note.id, subject='Hack someone else\'s subject!', body='Hack someone else\'s body!', expected_status_code=403, ) assert Note.find_by_id(note_id=mock_coe_advising_note.id).subject == original_subject
def remove_attachment(note_id, attachment_id): existing_note = Note.find_by_id(note_id=note_id) if not existing_note: raise BadRequestError('Note id not found.') if existing_note.author_uid != current_user.get_uid() and not current_user.is_admin: raise ForbiddenRequestError('You are not authorized to remove attachments from this note.') note = Note.delete_attachment( note_id=note_id, attachment_id=int(attachment_id), ) return tolerant_jsonify( _boa_note_to_compatible_json( note=note, note_read=NoteRead.find_or_create(current_user.get_id(), note_id), ), )
def test_update_note_with_raw_url_in_body(self, app, client, fake_auth, mock_coe_advising_note): """Updates subject and body of note.""" fake_auth.login(mock_coe_advising_note.author_uid) expected_subject = 'There must have been a plague of them' body = '<p>They were <a href="http://www.guzzle.com">www.guzzle.com</a> at <b>https://marsh.mallows.com</b> and <a href="http://www.foxnews.com">FOX news</a></p>' # noqa: E501 expected_body = '<p>They were <a href="http://www.guzzle.com">www.guzzle.com</a> at <b><a href="https://marsh.mallows.com" target="_blank">https://marsh.mallows.com</a></b> and <a href="http://www.foxnews.com">FOX news</a></p>' # noqa: E501 updated_note_response = self._api_note_update( app, client, note_id=mock_coe_advising_note.id, subject=expected_subject, body=body, ) assert updated_note_response['read'] is True updated_note = Note.find_by_id(note_id=mock_coe_advising_note.id) assert updated_note.subject == expected_subject assert updated_note.body == expected_body
def test_remove_all_topics(self, app, client, fake_auth, new_coe_note, asc_advising_note): """Update a note: delete existing topic, leaving none behind.""" fake_auth.login(asc_advising_note.author_uid) expected_topics = [] updated_note_response = self._api_note_update( app, client, note_id=asc_advising_note.id, subject=asc_advising_note.subject, body=asc_advising_note.body, topics=expected_topics, ) assert updated_note_response['read'] is True assert len(updated_note_response['topics']) == 0 updated_note = Note.find_by_id(note_id=asc_advising_note.id) assert len(updated_note.topics) == 0
def update_note(): params = request.form note_id = params.get('id', None) subject = params.get('subject', None) body = params.get('body', None) topics = get_note_topics_from_http_post() if not note_id or not subject: raise BadRequestError('Note requires \'id\' and \'subject\'') if Note.find_by_id(note_id=note_id).author_uid != current_user.get_uid(): raise ForbiddenRequestError('Sorry, you are not the author of this note.') note = Note.update( note_id=note_id, subject=subject, body=process_input_from_rich_text_editor(body), topics=topics, ) note_read = NoteRead.find_or_create(current_user.get_id(), note_id) return tolerant_jsonify(_boa_note_to_compatible_json(note=note, note_read=note_read))
def test_update_note_with_topics(self, app, client, fake_auth, new_coe_note, asc_advising_note): """Update a note: delete existing topic and add a new one.""" fake_auth.login(asc_advising_note.author_uid) expected_topics = ['no color no contrast', 'joyful mask'] updated_note_response = self._api_note_update( app, client, note_id=asc_advising_note.id, subject=asc_advising_note.subject, body=asc_advising_note.body, topics=expected_topics, ) assert updated_note_response['read'] is True assert len(updated_note_response['topics']) == 2 assert 'Joyful Mask' in updated_note_response['topics'] assert 'No Color No Contrast' in updated_note_response['topics'] updated_note = Note.find_by_id(note_id=asc_advising_note.id) assert len(updated_note.topics) == 2
def add_attachment(note_id): if Note.find_by_id(note_id=note_id).author_uid != current_user.get_uid(): raise ForbiddenRequestError('Sorry, you are not the author of this note.') attachments = _get_attachments(request.files) if len(attachments) != 1: raise BadRequestError('A single attachment file must be supplied.') note = Note.add_attachment( note_id=note_id, attachment=attachments[0], ) note_json = note.to_api_json() return tolerant_jsonify( note_to_compatible_json( note=note_json, note_read=NoteRead.find_or_create(current_user.get_id(), note_id), attachments=note_json.get('attachments'), topics=note_json.get('topics'), ), )
def add_attachments(note_id): note = Note.find_by_id(note_id=note_id) if note.author_uid != current_user.get_uid(): raise ForbiddenRequestError('Sorry, you are not the author of this note.') attachments = get_note_attachments_from_http_post() attachment_limit = app.config['NOTES_ATTACHMENTS_MAX_PER_NOTE'] if len(attachments) + len(note.attachments) > attachment_limit: raise BadRequestError(f'No more than {attachment_limit} attachments may be uploaded at once.') for attachment in attachments: note = Note.add_attachment( note_id=note_id, attachment=attachment, ) return tolerant_jsonify( _boa_note_to_compatible_json( note=note, note_read=NoteRead.find_or_create(current_user.get_id(), note_id), ), )
def update_note(): params = request.form note_id = params.get('id', None) subject = params.get('subject', None) body = params.get('body', None) topics = _get_topics(params) delete_ids_ = params.get('deleteAttachmentIds') or [] delete_ids_ = delete_ids_ if isinstance(delete_ids_, list) else str(delete_ids_).split(',') delete_attachment_ids = [int(id_) for id_ in delete_ids_] if not note_id or not subject: raise BadRequestError('Note requires \'id\' and \'subject\'') if Note.find_by_id(note_id=note_id).author_uid != current_user.get_uid(): raise ForbiddenRequestError('Sorry, you are not the author of this note.') note = Note.update( note_id=note_id, subject=subject, body=process_input_from_rich_text_editor(body), topics=topics, attachments=_get_attachments(request.files, tolerate_none=True), delete_attachment_ids=delete_attachment_ids, ) note_read = NoteRead.find_or_create(current_user.get_id(), note_id) return tolerant_jsonify(_boa_note_to_compatible_json(note=note, note_read=note_read))