openedx / openedx/openedx-core
[FE] Treat an archived tag as no longer part of its taxonomy on create, import, and export
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 10
- Forks
- 32
- Avg merge
- 2d 17h
- Merged PRs (30d)
- 12
Description
User Story
As a platform administrator, I want a tag value that belongs to an archived tag to explain why it’s unavailable rather than failing with a generic duplicate error, in order to understand what happened and pick a value I can actually use.
Acceptance Criteria
This ticket covers three surfaces, not one: adding a tag interactively through the Taxonomy Editing UI (and the API/model method it calls), importing a file, and exporting a taxonomy.
Adding a tag via the Taxonomy Editing UI
Scenario: Adding a tag whose value belongs to an archived tag explains what happened
Given a taxonomy with an archived tag whose value is "Photosynthesis"
When an administrator adds a tag with the value "Photosynthesis"
Then the tag is not created
And the error says the value belongs to an archived tag and that a different value should be used
Scenario: Adding a tag whose value is genuinely taken still reports a duplicate
Given a taxonomy with an unarchived tag whose value is "Photosynthesis"
When an administrator adds a tag with the value "Photosynthesis"
Then the tag is not created
And the error reports the duplicate as it does today
Scenario: Adding a tag whose value is free succeeds
Given a taxonomy with no tag of any kind holding the value "Respiration"
When an administrator adds a tag with the value "Respiration"
Then the tag is created
Importing a file
Scenario: Importing a value that belongs to an archived tag is refused
Given a taxonomy with an archived tag whose value is "Photosynthesis"
When a file containing that value is imported into that taxonomy
Then the archived tag is not updated or revived by the import
And the import reports that the value belongs to an archived tag and a different value should be used
Scenario: Importing an external identifier that belongs to an archived tag is refused
Given a taxonomy with an archived tag holding a given external identifier
When a file containing that external identifier is imported into that taxonomy
Then the archived tag is not updated or revived by the import
And the import reports that the identifier belongs to an archived tag
Scenario: An import that collides changes nothing else
Given an import file containing one colliding value and several valid new tags
When the file is imported
Then the collision is reported
And the taxonomy is left as it was before the import
Exporting a taxonomy
Scenario: An archived tag is absent from an export
Given a taxonomy with one archived tag and two that are not archived
When the taxonomy is exported
Then only the two unarchived tags appear in the exported output
Scenario: Re-importing an export of a taxonomy containing archived tags is clean
Given a taxonomy containing archived tags
When it is exported and the result imported into an empty taxonomy
Then the import succeeds
And the resulting taxonomy contains only the tags that were not archived
Description
Once tags can be archived, a taxonomy contains rows that are invisible on every read path but still occupy their value and their external identifier. Creating a tag with one of those values fails today with the generic message for a value that already exists, which is confusing: the administrator can see no such tag anywhere and has no way to work out why the value is refused.
Import has the same problem and a worse failure mode. Its usual behavior on encountering an existing value or external identifier is to update the matching row, so without a change it would silently write to an archived tag and effectively revive it as a side effect of an import.
The decision is that an archived tag is treated as no longer part of the taxonomy, on every surface that can encounter one: the Taxonomy Editing UI, import, and export. Export omits it entirely, and any attempt to create or import over its value or external identifier is refused with a message explaining why and telling the administrator to use a different value.
Technical Details
This section is background and a suggested approach, not the ticket's source of truth. The User Story and Acceptance Criteria define what must be true when the work is done.
Implementation specifics
- Create path (Taxonomy Editing UI and its API):
add_tag_to_taxonomyinsrc/openedx_tagging/api.py, and whatever validation raises the existing "value already exists" error. Distinguish the archived case before raising and use a distinct message naming the problem and pointing at using a different value Keep the unarchived duplicate message exactly as it is today, so existing callers and tests are unaffected. - Match on both keys. A collision can be on the tag value or on the external identifier, and both must produce the archived-specific message when the matching row is archived.
- Import path: the parsers and the import plan under
src/openedx_tagging/import_export/. Whatever step resolves an incoming row to an existing tag must not resolve it to an archived one and must not update it. Raise the same archived-specific error. - Report the collision as an import error, not a warning, and leave the taxonomy unchanged, so a partly-applied import cannot revive some tags and not others. Confirm how the existing import plan reports and rolls back before choosing where to raise.
- Export path: already excludes archived tags via #778; this ticket adds the round-trip test proving export and import agree with each other, it does not change export's own behavior.
- Do not add a restore action in this ticket. No restore path exists yet beyond direct database access; do not invent an endpoint or a UI affordance here.
- Wording should be reviewed rather than invented in code review. The message is administrator-facing text; "that value belongs to an archived tag, restore it instead" is a starting point, not final copy.
- Tests in the existing
openedx_taggingAPI and import and export test modules, one per scenario, plus a round-trip test exporting a taxonomy containing archived tags and importing the result into an empty taxonomy. - Out of scope: a restore endpoint or UI, the archive branches themselves (#779, #780), and read-path exclusion (#778). Also out of scope: the frontend's lack of translation for backend-sourced error text on either the Taxonomy Editing UI or the import wizard (confirmed pre-existing, not something this ticket changes) — this message inherits that same limitation, consistently with every other error on those pages today.
Files to create and modify
Modified files
| File | Nature of modification |
|---|---|
| src/openedx_tagging/api.py | distinguish the archived collision in add_tag_to_taxonomy (the Taxonomy Editing UI's create path) and raise a message pointing at using a different value |
| src/openedx_tagging/import_export/ | refuse to resolve an incoming row to an archived tag on value or external identifier, and report it as an import error |
| tests/openedx_tagging/ | one test per scenario plus an export-then-import round-trip test |
Context
- The approved implementation approach on #655, and the decision that an archived tag is treated as no longer part of its taxonomy.
- #778 excludes archived tags from read paths and from export; this ticket relies on that and adds the round-trip check.
- #776 adds the
archivedfield these paths inspect. src/openedx_tagging/api.py,add_tag_to_taxonomy, andsrc/openedx_tagging/import_export/for the two paths involved.- #758 implements the non-nullable external identifier work whose auto-generation must also treat archived rows as occupying their slot; see the prerequisite note for that issue.
- Restoring an archived tag today means a direct database change (SQL, or the Django admin if a later ticket happens to register these models there) — there is no application-level restore path, and this ticket does not add one. This is why the administrator-facing message points at choosing a different value rather than at restoring the archived one.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with src/openedx_tagging/api.py and add_tag_to_taxonomy, then trace the import plan and row matching under src/openedx_tagging/import_export/. Read the existing API, import, and export tests under tests/openedx_tagging/ before adding coverage for archived value and external-identifier collisions, atomic imports, and export round-tripping. Done means archived rows are never revived, collisions are reported as import errors, and exports contain only unarchived tags.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- django, python
- Domain
- api, backend, databases, testing
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100