-
Notifications
You must be signed in to change notification settings - Fork 3.9k
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
refactor: remove ContentObjectTag model and related functions #34146
refactor: remove ContentObjectTag model and related functions #34146
Conversation
Thanks for the pull request, @rpenido! Please note that it may take us up to several weeks or months to complete a review and merge your PR. Feel free to add as much of the following information to the ticket as you can:
All technical communication about the code itself will be done via the GitHub pull request interface. As a reminder, our process documentation is here. Please let us know once your PR is ready for our review and all tests are green. |
17db766
to
944a650
Compare
944a650
to
d72ae83
Compare
Hi, @pomegranited! I removed a lot of code. Let me know what you think. Also, we will need to override the view here to use this new Implementing this using the rule override would be easier, but I think it's not the best approach: it is more a business rule than a permission one (and also, superusers skip permission checks). |
Rather than overriding the view, we can change the rules to ensure that this gets checked.
We can override that rule here to run the base |
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.
@rpenido Yep, this is looking great. :) I've left a couple inline comments, but haven't done a full review yet, so let me know when it's ready?
object_key = UsageKey.from_string(object_id) | ||
except InvalidKeyError: | ||
try: | ||
object_key = CourseKey.from_string(object_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.
Should use LearningContextKey
(not CourseKey
) and UsageKey
like the previous code -- this supports content library keys too.
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.
The LearningContextKey
doesn't have the org
property. It is defined in the CourseKey
class:
https://github.com/openedx/opaque-keys/blob/dd532d862a51457a8f0c0f5c936fd57ee4d39fbc/opaque_keys/edx/keys.py#L43-L49
Also, the LibraryLocator
inherits from CourseKey
:
https://github.com/openedx/opaque-keys/blob/dd532d862a51457a8f0c0f5c936fd57ee4d39fbc/opaque_keys/edx/locator.py#L412
We are using LearningContextKey
in many places, but I think we should only use CourseKey | UsageKey
(because we rely on the org
info to tag content). Do you think this makes sense?
PS: I didn't change it outside of the functions of this refactor.
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 we should only use CourseKey | UsageKey (because we rely on the org info to tag content)
Ah ok, agreed. I didn't realise LibraryLocator inherited from CourseKey, that's cool.
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.
Do you think we should create a task to fix this through the code?
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.
@rpenido I think this is too minor to warrant a task.. but if you're working on affected code, feel free to change it as you go, and cite this discussion.
455105d
to
252d402
Compare
252d402
to
739fdb5
Compare
I chose that route. The only issue is that the superuser will skip that rule, but besides that, the code is much cleaner. We were not checking this before, so the query count for tagging count went up a bit. We check TaxonomyOrgs one more time and I think we didn't have a select_related when we get a Taxonomy model. Let me know what you think @pomegranited! |
|
||
def test_cannot_tag_across_orgs(self): | ||
""" | ||
Ensure that I cannot apply tags from a taxonomy that's linked to another | ||
org. | ||
""" | ||
# This taxonomy is only linked to the "OpenedX org", so it can't be used for "Axim" content. | ||
taxonomy = self.taxonomy_one_org | ||
tags = [self.tag_one_org.value] | ||
with self.assertRaises(ValueError) as exc: | ||
api.tag_content_object( | ||
object_key=CourseKey.from_string("course-v1:Ax+DemoX+Demo_Course"), | ||
taxonomy=taxonomy, | ||
tags=tags, | ||
) | ||
assert "The specified Taxonomy is not enabled for the content object's org (Ax)" in str(exc.exception) | ||
# But this will work fine: | ||
api.tag_content_object( | ||
object_key=CourseKey.from_string("course-v1:OeX+DemoX+Demo_Course"), | ||
taxonomy=taxonomy, | ||
tags=tags, | ||
) | ||
# As will this: | ||
api.tag_content_object( | ||
object_key=CourseKey.from_string("course-v1:Ax+DemoX+Demo_Course"), | ||
taxonomy=self.taxonomy_both_orgs, | ||
tags=[self.tag_both_orgs.value], | ||
) |
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 test went to the view. We don't check cross-tagging at the API level.
object_tag = getattr(self, tag_attr) | ||
assert self.superuser.has_perm(perm, object_tag) | ||
assert self.staff.has_perm(perm, object_tag) | ||
assert not self.staff.has_perm(perm, object_tag) |
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 a side effect of the change. When we didn't check cross-tagging, a staff user could change objecttags from taxonomies without orgs.
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 don't understand why this test changed?
Staff users are "Taxonomy Administrators", just like superusers are, so they should be able to tag objects using no-org taxonomies too.
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.
The issue is that it is not trivial to differentiate a no-org taxonomy and a taxonomy from another org.
I fixed here: 1a4c858
But now taxonomy admins can also use a Taxonomy from orgA to tag an object from orgB (like superuser).
This is ready for a final review @pomegranited! |
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've requested a small change, and I have concerns about the "staff user" permissions change noted in the tests.
But other than that, this is working beautifully, so we're close! I tested this in my devstack, and was able to:
- View/add/remove object tags on units (using fix: fixed typo in updateContentTaxonomyTags URL [FC-0036] frontend-app-authoring#815)
- View/add/remove object tags on library blocks (using feat: View/Edit tags for Library Components openedx-unsupported/frontend-app-library-authoring#400)
object_tag = getattr(self, tag_attr) | ||
assert self.superuser.has_perm(perm, object_tag) | ||
assert self.staff.has_perm(perm, object_tag) | ||
assert not self.staff.has_perm(perm, object_tag) |
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 don't understand why this test changed?
Staff users are "Taxonomy Administrators", just like superusers are, so they should be able to tag objects using no-org taxonomies too.
2c7e806
to
2c6986e
Compare
2c6986e
to
1a4c858
Compare
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.
One nit, and a comment about the permissions change, but this looks good to merge once the nit is addressed 👍
- I tested this on my devstack:
- Installed this branch on lms/cms and ran migrations
- Set up sample data using https://github.com/open-craft/taxonomy-sample-data/
- Ran fix: fixed typo in updateContentTaxonomyTags URL [FC-0036] frontend-app-authoring#815 to test tagging units: view, add, remove tags
- Ran feat: View/Edit tags for Library Components openedx-unsupported/frontend-app-library-authoring#400 to test tagging libraries: view, add, remove tags
- I read through the code
-
I checked for accessibility issuesN/A -
Includes documentationN/A -
User-facing strings are extracted for translationN/A
# Taxonomy admins can tag any object using any taxonomy | ||
if oel_tagging.is_taxonomy_admin(user): | ||
return 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.
We can avoid the "Taxonomy admins can tag any object using any taxonomy" issue like this, however: this change bumps the query count for updating object tags up from 7 to 13!
# Taxonomy admins can tag any object using any taxonomy | |
if oel_tagging.is_taxonomy_admin(user): | |
return True | |
# Only Taxonomy admins can tag objects using a no-org taxonomy | |
if not perm_obj.taxonomy.taxonomyorg_set.exists(): | |
return oel_tagging.is_taxonomy_admin(user) |
So I can't actually recommend this change. But, I have a task next sprint to fix these query counts, so I'll handle making this change if needed.
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.
Besides the query count, I wonder if it is worth making this differentiation: if adminA adds this taxonomy to an org, does this change the permission from adminB?
I'm uncomfortable with this, but I think treating no-org and cross-org the same way (allowing or blocking) would be the best path here.
I commented on the issue you created about the query count.
The staff account is probably the best-case scenario. But I'm sure that you will find what we got wrong.
Hi @bradenmacdonald! Could you do a CC review here? |
62acf86
to
dfb908e
Compare
e2439ac
to
cc6e2fd
Compare
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.
Do we have tests that you can't tag things that aren't xblocks/courses/libraries?
If so, I think I'm good with this change. Though I did like the API where you could pass UsageKeys directly instead of having to convert them to strings all the time.
|
||
operations = [ | ||
migrations.DeleteModel( | ||
name='ContentObjectTag', |
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 is no data stored with this model, right? This won't delete any actual database rows?
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.
Right. Also, we weren't using it outside auto-tagging: our rest API uses the ObjectTag model (this is the main issue that motivated this PR)
@@ -1534,6 +1541,129 @@ def test_tag_xblock_invalid(self, user_attr, taxonomy_attr): | |||
response = self.client.put(url, {"tags": ["invalid"]}, format="json") | |||
assert response.status_code == status.HTTP_400_BAD_REQUEST | |||
|
|||
@ddt.data( | |||
# userA and userS are staff in libraryA and can tag using enabled taxonomies |
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.
Who are userA
and userS
? I see them mentioned a few times in this file, but I think those are typos or from an older version. Here I only see user
, staff
, and staffA
.
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.
Done: 78b3d53
openedx/core/djangoapps/content_tagging/rest_api/v1/tests/test_views.py
Outdated
Show resolved
Hide resolved
|
||
ContentKey = Union[LearningContextKey, UsageKey] | ||
ContentKey = Union[LibraryLocatorV2, CourseKey, UsageKey] |
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's wrong with leaving [LearningContextKey, UsageKey]
? Less specific?
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 need an Org to validate the permissions.
The org property is defined in the CourseKey
and the LibraryLocatorV2
for our cases. For the UsageKey
, we get the org from the context_key
(and we also check if the contet_key
is a CourseKey
or LibraryLocatorV2
).
We could use LearningContext
and duck typing to check if we have the org field (directly in the key or in its contex_key).
I personally prefer strict typing to make sure the use conforms with what we are implementing and testing here.
I added a generic test here: 2791963 Are there some specific string keys that we can also test? |
Co-authored-by: Braden MacDonald <[email protected]>
@rpenido 🎉 Your pull request was merged! Please take a moment to answer a two question survey so we can improve your experience in the future. |
2U Release Notice: This PR has been deployed to the edX staging environment in preparation for a release to production. |
2U Release Notice: This PR has been deployed to the edX production environment. |
1 similar comment
2U Release Notice: This PR has been deployed to the edX production environment. |
Description
This PR removes the ContentObjectTag model and some overridden tagging functions from
oel_tagging.
Testing instruction
Please ensure that the tests cover the expected behavior of the refactor.
Private-ref: FAL-3610