-
Notifications
You must be signed in to change notification settings - Fork 11
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
feat: Copy object tags [FC-0062] #236
Changes from 8 commits
d653a8e
3e985d6
fcd8437
6b73ec4
3dc5b0d
2bb68ee
744a539
adbf967
4f8c0d3
6395019
7289b22
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
""" | ||
Open edX Learning ("Learning Core"). | ||
""" | ||
__version__ = "0.14.0" | ||
__version__ = "0.16.0" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
# Generated by Django 4.2.16 on 2024-10-04 19:21 | ||
|
||
from django.db import migrations, models | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
dependencies = [ | ||
('oel_tagging', '0017_alter_tagimporttask_status'), | ||
] | ||
|
||
operations = [ | ||
migrations.AddField( | ||
model_name='objecttag', | ||
name='is_copied', | ||
field=models.BooleanField(default=False, help_text="True if this object tag has been copied from one object to another using 'copy_tags' api function"), | ||
), | ||
] |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -795,6 +795,13 @@ class ObjectTag(models.Model): | |||||
"Tag associated with this object tag. Provides the tag's 'value' if set." | ||||||
), | ||||||
) | ||||||
is_copied = models.BooleanField( | ||||||
default=False, | ||||||
help_text=_( | ||||||
"True if this object tag has been copied from one object to another" | ||||||
" using 'copy_tags' api function" | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this should not be here. If the tagging app is reused in another project other than edx-platform, a copied tag does not necessarily mean it is read-only in the UI. |
||||||
), | ||||||
) | ||||||
_export_id = case_insensitive_char_field( | ||||||
max_length=255, | ||||||
help_text=_( | ||||||
|
@@ -981,6 +988,7 @@ def copy(self, object_tag: ObjectTag) -> Self: | |||||
self.tag = object_tag.tag | ||||||
self.taxonomy = object_tag.taxonomy | ||||||
self.object_id = object_tag.object_id | ||||||
self.is_copied = object_tag.is_copied | ||||||
self._value = object_tag._value # pylint: disable=protected-access | ||||||
self._export_id = object_tag._export_id # pylint: disable=protected-access | ||||||
return self |
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -913,3 +913,136 @@ def test_get_object_tag_counts_deleted_disabled(self) -> None: | |||
assert tagging_api.get_object_tag_counts("object_*") == {obj1: 1, obj2: 2} | ||||
tagging_api.add_tag_to_taxonomy(self.taxonomy, "DPANN", parent_tag_value="Archaea") | ||||
assert tagging_api.get_object_tag_counts("object_*") == {obj1: 2, obj2: 2} | ||||
|
||||
def test_copy_tags(self) -> None: | ||||
obj1 = "object_id1" | ||||
obj2 = "object_id2" | ||||
|
||||
tags_list = [ | ||||
{ | ||||
"value": "English", | ||||
"taxonomy": self.language_taxonomy, | ||||
}, | ||||
{ | ||||
"value": "DPANN", | ||||
"taxonomy": self.taxonomy, | ||||
}, | ||||
] | ||||
|
||||
for tag_object in tags_list: | ||||
tagging_api.tag_object(object_id=obj1, taxonomy=tag_object["taxonomy"], tags=[tag_object["value"]]) | ||||
|
||||
tagging_api.copy_tags(obj1, obj2) | ||||
|
||||
object_tags = tagging_api.get_object_tags(obj2) | ||||
|
||||
assert len(object_tags) == 2 | ||||
for index, object_tag in enumerate(object_tags): | ||||
object_tag.full_clean() | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||||
assert object_tag.value == tags_list[index]["value"] | ||||
assert not object_tag.is_deleted | ||||
assert object_tag.taxonomy == tags_list[index]["taxonomy"] | ||||
assert object_tag.object_id == obj2 | ||||
assert object_tag.is_copied is True | ||||
|
||||
def test_copy_tags_with_non_copied(self) -> None: | ||||
obj1 = "object_id1" | ||||
obj2 = "object_id2" | ||||
|
||||
tagging_api.tag_object(object_id=obj1, taxonomy=self.language_taxonomy, tags=["English"]) | ||||
|
||||
tagging_api.tag_object(object_id=obj2, taxonomy=self.taxonomy, tags=["Chordata"]) | ||||
tagging_api.tag_object(object_id=obj2, taxonomy=self.free_text_taxonomy, tags=["has a notochord"]) | ||||
|
||||
tagging_api.copy_tags(obj1, obj2) | ||||
object_tags = tagging_api.get_object_tags(obj2) | ||||
|
||||
# Tags must be the non-copied and the copied tag. | ||||
expected_tags = [ | ||||
{ | ||||
"value": "has a notochord", | ||||
"taxonomy": self.free_text_taxonomy, | ||||
"copied": False, | ||||
}, | ||||
{ | ||||
"value": "English", | ||||
"taxonomy": self.language_taxonomy, | ||||
"copied": True, | ||||
}, | ||||
{ | ||||
"value": "Chordata", | ||||
"taxonomy": self.taxonomy, | ||||
"copied": False, | ||||
}, | ||||
] | ||||
assert len(object_tags) == 3 | ||||
for index, object_tag in enumerate(object_tags): | ||||
assert object_tag.value == expected_tags[index]["value"] | ||||
assert not object_tag.is_deleted | ||||
assert object_tag.taxonomy == expected_tags[index]["taxonomy"] | ||||
assert object_tag.object_id == obj2 | ||||
assert object_tag.is_copied == expected_tags[index]["copied"] | ||||
|
||||
# Delete tags of 'obj1' and add other | ||||
tagging_api.delete_object_tags(obj1) | ||||
tagging_api.tag_object(object_id=obj1, taxonomy=self.taxonomy, tags=["DPANN"]) | ||||
tagging_api.copy_tags(obj1, obj2) | ||||
object_tags = tagging_api.get_object_tags(obj2) | ||||
|
||||
# Tags must be the non-copied and the new copied tag. | ||||
# The previous copied tags must be deleted. | ||||
expected_tags = [ | ||||
{ | ||||
"value": "has a notochord", | ||||
"taxonomy": self.free_text_taxonomy, | ||||
"copied": False, | ||||
}, | ||||
{ | ||||
"value": "DPANN", | ||||
"taxonomy": self.taxonomy, | ||||
"copied": True, | ||||
}, | ||||
{ | ||||
"value": "Chordata", | ||||
"taxonomy": self.taxonomy, | ||||
"copied": False, | ||||
}, | ||||
] | ||||
assert len(object_tags) == 3 | ||||
for index, object_tag in enumerate(object_tags): | ||||
assert object_tag.value == expected_tags[index]["value"] | ||||
assert not object_tag.is_deleted | ||||
assert object_tag.taxonomy == expected_tags[index]["taxonomy"] | ||||
assert object_tag.object_id == obj2 | ||||
assert object_tag.is_copied == expected_tags[index]["copied"] | ||||
|
||||
# Add a tag used by 'obj2' | ||||
tagging_api.tag_object(object_id=obj1, taxonomy=self.free_text_taxonomy, tags=["has a notochord"]) | ||||
tagging_api.copy_tags(obj1, obj2) | ||||
object_tags = tagging_api.get_object_tags(obj2) | ||||
|
||||
# The non-copied tag 'has a notochord' must be copied now. | ||||
expected_tags = [ | ||||
{ | ||||
"value": "has a notochord", | ||||
"taxonomy": self.free_text_taxonomy, | ||||
"copied": True, | ||||
}, | ||||
{ | ||||
"value": "DPANN", | ||||
"taxonomy": self.taxonomy, | ||||
"copied": True, | ||||
}, | ||||
{ | ||||
"value": "Chordata", | ||||
"taxonomy": self.taxonomy, | ||||
"copied": False, | ||||
}, | ||||
] | ||||
assert len(object_tags) == 3 | ||||
for index, object_tag in enumerate(object_tags): | ||||
assert object_tag.value == expected_tags[index]["value"] | ||||
assert not object_tag.is_deleted | ||||
assert object_tag.taxonomy == expected_tags[index]["taxonomy"] | ||||
assert object_tag.object_id == obj2 | ||||
assert object_tag.is_copied == expected_tags[index]["copied"] |
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.
Did you confirm this is working? (That
_value
and_export_id
are getting set automatically?)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.
Yes, I confirm that 👍
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 comment: 6395019