-
Notifications
You must be signed in to change notification settings - Fork 8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
adding the notes table and versioning #171
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking good so far! There are a few minor comments, but overall it's looking pretty solid, and the refactored code is much easier to read. I know I started this review before your latest commits, so you might have addressed some of this already - if so, disregard the comments that don't apply.
biblib/models.py
Outdated
__versioned__ = {} | ||
id = Column(Integer, primary_key=True) | ||
content = Column(UnicodeText) | ||
bibcode = Column(String(50), nullable=False) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd make this length 19, instead of 50
biblib/models.py
Outdated
|
||
note = Notes(content=content, bibcode=bibcode, library_id=library.id) | ||
session.add(note) | ||
session.commit() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generally we leave the session handling (session.add()
and session.commit()
) for the calling function. It can be done here, as you have it, but for consistency, let's move these to the calling function. To see what I mean, check how add_bibcodes
on the Library class is being used.
""" | ||
if not n_revisions: n_revisions = current_app.config.get('NUMBER_REVISIONS', 7) | ||
if not n_revisions: | ||
n_revisions = current_app.config.get('NUMBER_REVISIONS', 7) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Totally fine to treat notes the same as libraries for removing revisions, as you have here, for consistency and to keep the revisions tables from getting out of control. However, it's worth keeping an eye on the notes versions table and seeing how frequently notes are being changed and whether storing 7 revisions is enough - my intuition is that notes may have more frequent changes than libraries, and thus a user might need access to earlier versions. No need to change this now, but just something to keep in mind, and keep an eye on.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay. I'll keep that in mind.
biblib/views/library_view.py
Outdated
return library_error | ||
|
||
# If set to True, return notes in library | ||
notes = request.args.get('notes', type=bool, default=True) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I realized we never added the allowed params to the docstring when we first added support for pagination (e.g. start
, rows
, etc. - the things returned via your self.load_parameters
call. Those, plus this new notes
param should be added to the docstring here. Eventually, you'll also need to update the API docs (https://ui.adsabs.harvard.edu/help/api/api-docs.html) to add this param, but we can talk about that later.
biblib/views/library_view.py
Outdated
|
||
def process_solr(self, library, start, rows, sort, fl): | ||
""" | ||
Processes the request for raw library |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like a copy/paste error - just update the text
biblib/views/library_view.py
Outdated
) | ||
# Extract the canonical bibcodes and create a hashmap | ||
# in which the alternate bibcode is the key and the canonical bibcode is the value | ||
alternate_bibcodes = cls.get_alternate_bibcodes(solr_docs) | ||
|
||
with current_app.session_scope() as session: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a session getting passed around in one of the calling functions - you should be able to reuse it here.
biblib/views/library_view.py
Outdated
|
||
def is_library_public_or_has_special_token(self, library, request): | ||
""" | ||
HTTP GET request that returns all the documents inside a given |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copy/paste error - update text
biblib/views/library_view.py
Outdated
) | ||
return err(NO_PERMISSION_ERROR) | ||
|
||
current_app.logger.warning('Library: {0} is private'.format(library_id)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know this is pre-existing code, but it's weird that it's generating a warning-level log for this - can you downgrade it to info-level?
from biblib.tests.base import TestCaseDatabase | ||
from sqlalchemy import exc | ||
import pytest |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this leftover from testing? I don't see it in here
@@ -1,16 +1,16 @@ | |||
""" | |||
Tests Views of the application | |||
""" | |||
|
|||
import json |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Leftover from testing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the merge with timestamp_sort
looks good. Just had a couple of minor comments.
biblib/views/library_view.py
Outdated
sort = request.args.get('sort', 'date desc') | ||
#timestamp sorting is handled in biblib so we need to change the sort to something SOLR understands. | ||
if sort in ['time asc', 'time desc']: | ||
current_app.logger.debug("sort order is set to{}".format(sort)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd add a space in the log statement, but This all looks reasonable.
op.create_index(op.f('ix_notes_version_end_transaction_id'), 'notes_version', ['end_transaction_id'], unique=False) | ||
op.create_index(op.f('ix_notes_version_operation_type'), 'notes_version', ['operation_type'], unique=False) | ||
op.create_index(op.f('ix_notes_version_transaction_id'), 'notes_version', ['transaction_id'], unique=False) | ||
op.create_table('notes', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is just a readability thing, but I would put a space between the last create_index
and the create_table
to differentiate between calls for notes_version
vs. notes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry this took me so long! I have some high level questions and suggestions, along with a couple more detailed comments. Let's chat about this during our next meeting - a synchronous review will go faster on my part.
biblib/models.py
Outdated
session.add(note) | ||
session.commit() | ||
return note | ||
try: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is this try/except handling? Looks like you've got pretty good exception handling in this method already.
biblib/views/library_view.py
Outdated
@@ -508,132 +397,92 @@ def process_library_request(self, data): | |||
library_notes: <dict> Dictionary of library notes, including orphan | |||
notes (those not associated with a bibcode in the library) | |||
""" | |||
with current_app.session_scope() as session: | |||
try: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In general, it's better to have as little code as possible inside a try
- if something fails and there's a ton of code in there, it can be really hard to debug. Try to rewrite this to include only the bare minimum of what might fail
biblib/views/notes_view.py
Outdated
- read | ||
""" | ||
|
||
try: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment about the try
here - I like how you're handling the separate types of exceptions separately, but better to wrap each line in the try/except separately
biblib/views/notes_view.py
Outdated
|
||
current_app.logger.info('Getting note for document {0} in library {1}.'.format(document_id, library_id)) | ||
|
||
return response, 200 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you stick a line break between this line and the next? Just for readability - took me a sec to find this return statement
The following type of user can update the content: | ||
|
||
- owner | ||
- admin |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
write
type permissions should also be able to edit
biblib/views/notes_view.py
Outdated
service_uid = self.helper_absolute_uid_to_service_uid(absolute_uid=user) | ||
|
||
# Check the user's permissions | ||
if not self.update_access(service_uid=service_uid, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
update to write_access
Permissions: | ||
----------- | ||
The following type of user can delete the note: | ||
- owner |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's let the admin
and write
permission types also delete the notes - both of these are able to delete records from a library, so it's more consistent that we also allow them to delete notes
biblib/views/notes_view.py
Outdated
'requesting to delete note for document {1} and library {2}.' | ||
.format(service_uid, document_id, library)) | ||
|
||
if not self.delete_access(service_uid=service_uid, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
update to write_access
if shared_with_me: | ||
response['shared_with_me'] = shared_with_me | ||
|
||
return response |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We'll have to be careful with the deployment, when we're ready to do it - changing the keys in the response (libraries
-> my_libraries
/shared_with_me
) will make this not backwards compatible, so both UIs will need to be updated. Alternatively, we could figure out a way to make this backwards compatible. Let's talk more about this.
biblib/views/user_view.py
Outdated
output_libraries.append(payload) | ||
|
||
return output_libraries | ||
if (permissions and main_permission in ['owner']) or not permissions: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where is permissions
set? I see permission.permissions
but not just permissions
, but maybe I'm missing it. Either way, I have some concerns about the or not permissions
part being lumped in with the 'owner'
permission. Depending on how permissions
is assigned, either stick the or not permissions
in the elif
, or an else
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Approved after fixing the extra log message, per our discussion
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me. Excited to see it in action.
I would really like your input this. I wrote the model but I'm not sure if it's the best approach. Please, let me know your thoughts.
I also made some changes to manage.py but I haven't fully reviewed those yet, but feel free to give me some pointers.