Skip to content
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

Merged
merged 26 commits into from
Dec 14, 2023
Merged

adding the notes table and versioning #171

merged 26 commits into from
Dec 14, 2023

Conversation

femalves
Copy link
Contributor

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.

@femalves femalves marked this pull request as ready for review October 11, 2023 21:04
Copy link
Member

@kelockhart kelockhart left a 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)
Copy link
Member

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()
Copy link
Member

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)
Copy link
Member

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.

Copy link
Contributor Author

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.

return library_error

# If set to True, return notes in library
notes = request.args.get('notes', type=bool, default=True)
Copy link
Member

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.


def process_solr(self, library, start, rows, sort, fl):
"""
Processes the request for raw library
Copy link
Member

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

)
# 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:
Copy link
Member

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.


def is_library_public_or_has_special_token(self, library, request):
"""
HTTP GET request that returns all the documents inside a given
Copy link
Member

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

)
return err(NO_PERMISSION_ERROR)

current_app.logger.warning('Library: {0} is private'.format(library_id))
Copy link
Member

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
Copy link
Member

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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leftover from testing?

Copy link
Contributor

@tjacovich tjacovich left a 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.

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))
Copy link
Contributor

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',
Copy link
Contributor

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

Copy link
Member

@kelockhart kelockhart left a 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:
Copy link
Member

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.

@@ -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:
Copy link
Member

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

- read
"""

try:
Copy link
Member

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


current_app.logger.info('Getting note for document {0} in library {1}.'.format(document_id, library_id))

return response, 200
Copy link
Member

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
Copy link
Member

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

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,
Copy link
Member

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
Copy link
Member

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

'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,
Copy link
Member

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
Copy link
Member

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.

output_libraries.append(payload)

return output_libraries
if (permissions and main_permission in ['owner']) or not permissions:
Copy link
Member

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

Copy link
Member

@kelockhart kelockhart left a 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

Copy link
Contributor

@tjacovich tjacovich left a 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.

@femalves femalves merged commit f584fb5 into master Dec 14, 2023
1 check passed
@femalves femalves deleted the adding_notes branch December 14, 2023 21:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants