You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
As a Platform Administrator, I want the taxonomy retrieval API to report each taxonomy's type ("tags" or "competency"), so that the Taxonomies page can support displaying a badge for Competency Taxonomies and correctly gate access to the Competency Management page.
Description
Current behavior
GET /api/tagging/v1/taxonomies/{id}/ and GET /api/tagging/v1/taxonomies/ (TaxonomySerializer, src/openedx_tagging/rest_api/v1/serializers.py) return taxonomy fields including system_defined, but nothing identifies whether a taxonomy is a Competency Taxonomy.
Requested change
Add a read-only taxonomy_type field to TaxonomySerializer, returned on both the single-taxonomy and list GET endpoints.
Depends on:#614 (Create/Import endpoint) merging first, since the CompetencyTaxonomy model this ticket detects doesn't exist until then.
Explicitly out of scope
No "competency only" / "non-competency only" filter or query parameter on Get/List. The list endpoint keeps returning all taxonomy types together, undifferentiated.
No change to content-tagging surfaces (Course Outline, Libraries). Tagging content with a Competency Taxonomy without linking Competency Criteria must stay possible; this ticket adds no restriction there.
No change to the existing system-level taxonomy indication.
Acceptance Criteria
These scenarios are verifiable via Postman.
Scenario: Get a single Competency Taxonomy
Given a Competency Taxonomy exists (created via the #614 Create endpoint with taxonomy_type="competency")
When a client sends GET /api/tagging/v1/taxonomies/{id}/ for that taxonomy
Then the response has status code 200
And the response body's "taxonomy_type" field equals "competency"
Scenario: Get a single standard tag taxonomy
Given a standard (non-competency) taxonomy exists
When a client sends GET /api/tagging/v1/taxonomies/{id}/ for that taxonomy
Then the response has status code 200
And the response body's "taxonomy_type" field equals "tags"
And the field is never null
Scenario: Get a system-defined taxonomy
Given a system-defined taxonomy exists (e.g. the built-in Language taxonomy, system_defined=true)
When a client sends GET /api/tagging/v1/taxonomies/{id}/ for that taxonomy
Then the response has status code 200
And the response body's "taxonomy_type" field equals "tags"
And "system_defined" is unchanged and still equals true
Scenario: List taxonomies of mixed type
Given at least one Competency Taxonomy and at least one standard taxonomy exist
When a client sends GET /api/tagging/v1/taxonomies/
Then every Competency Taxonomy entry has "taxonomy_type" equal to "competency"
And every other entry has "taxonomy_type" equal to "tags"
And no entry's "taxonomy_type" is null
And entries of both types are returned together, unfiltered
Add coverage for base, system-defined, and overridden get_type() across detail + list
Recommended Approach
Add an overridable model method rather than probing for the CBE applet's model by name — mirroring the already-shipped system_defined pattern (Taxonomy.system_defined base property, overridden by SystemDefinedTaxonomy in src/openedx_tagging/models/system_defined.py:29-35). It’s also the pattern #614's implementer will already be reading when they subclass Taxonomy for CompetencyTaxonomy.
# src/openedx_tagging/models/base.py, above the Taxonomy modelclassTaxonomyType(models.TextChoices):
TAGS="tags"COMPETENCY="competency"classTaxonomy(...):
...
defget_type(self) ->str:
""" Returns this taxonomy's type as one of the TaxonomyType values. The base Taxonomy always returns TaxonomyType.TAGS. Subclasses (for example, a future CBE applet's CompetencyTaxonomy) override this to report their own type. openedx_tagging has no knowledge of what subclasses exist or what they override this to. """returnTaxonomyType.TAGS
TaxonomySerializer.get_taxonomy_type() calls instance.get_type() on the already-.cast()ed instance (the serializer already casts before running field getters — reuse that seam, don't duplicate it).
Layering:openedx_tagging never references CompetencyTaxonomy or the competencytaxonomy relation name anywhere in its source. The default get_type() is an unconditional constant; only a class defined and owned outside this package can ever make it return something else.
Example Resolution Prompt
In openedx-core, add a taxonomy_type read-only field to the taxonomy Get endpoints. In src/openedx_tagging/models/base.py, add TaxonomyType(models.TextChoices) with TAGS = "tags" and COMPETENCY = "competency", placed above the Taxonomy class, and add a Taxonomy.get_type() method returning TaxonomyType.TAGS unconditionally — this mirrors the existing system_defined base/override pattern (system_defined.py:29-35) and must not reference CompetencyTaxonomy or the competencytaxonomy relation name anywhere. In src/openedx_tagging/rest_api/v1/serializers.py, add taxonomy_type = serializers.SerializerMethodField() to TaxonomySerializer, with get_taxonomy_type(self, obj) returning obj.get_type() (call this after the serializer's existing .cast() step), and add "taxonomy_type" to Meta.fields. Add test cases covering a base Taxonomy → "tags", a SystemDefinedTaxonomy → "tags", and a test-only Taxonomy subclass overriding get_type() → confirms polymorphism flows through both the detail and list endpoints. Import TaxonomyType from models/base.py for both this serializer field and #614's write-side ChoiceField, so the two can never drift.
Use Case
As a Platform Administrator, I want the taxonomy retrieval API to report each taxonomy's type ("tags" or "competency"), so that the Taxonomies page can support displaying a badge for Competency Taxonomies and correctly gate access to the Competency Management page.
Description
Current behavior
GET /api/tagging/v1/taxonomies/{id}/andGET /api/tagging/v1/taxonomies/(TaxonomySerializer,src/openedx_tagging/rest_api/v1/serializers.py) return taxonomy fields includingsystem_defined, but nothing identifies whether a taxonomy is a Competency Taxonomy.Requested change
taxonomy_typefield toTaxonomySerializer, returned on both the single-taxonomy and list GET endpoints."competency"for Competency Taxonomies (the model introduced by [BE] Update taxonomy Create & Import endpoints to accept Taxonomy Type #614 and its data-model dependency) and"tags"for every other taxonomy, including allsystem_definedtaxonomies. Nevernull.taxonomy_typefield ([BE] Update taxonomy Create & Import endpoints to accept Taxonomy Type #614) accepts, and both draw from one sharedTaxonomyTypeenum so they cannot drift apart.Depends on: #614 (Create/Import endpoint) merging first, since the
CompetencyTaxonomymodel this ticket detects doesn't exist until then.Explicitly out of scope
Acceptance Criteria
These scenarios are verifiable via Postman.
Technical Details
Files to create and modify
Modified files
src/openedx_tagging/models/base.pyTaxonomyType(models.TextChoices); addTaxonomy.get_type()returningTaxonomyType.TAGSsrc/openedx_tagging/rest_api/v1/serializers.pytaxonomy_typeSerializerMethodFieldtoTaxonomySerializer; add toMeta.fieldssrc/openedx_tagging/rest_api/v1/tests/test_views.py(confirm exact path)get_type()across detail + listRecommended Approach
Add an overridable model method rather than probing for the CBE applet's model by name — mirroring the already-shipped
system_definedpattern (Taxonomy.system_definedbase property, overridden bySystemDefinedTaxonomyinsrc/openedx_tagging/models/system_defined.py:29-35). It’s also the pattern #614's implementer will already be reading when they subclassTaxonomyforCompetencyTaxonomy.TaxonomySerializer.get_taxonomy_type()callsinstance.get_type()on the already-.cast()ed instance (the serializer already casts before running field getters — reuse that seam, don't duplicate it).Layering:
openedx_taggingnever referencesCompetencyTaxonomyor thecompetencytaxonomyrelation name anywhere in its source. The defaultget_type()is an unconditional constant; only a class defined and owned outside this package can ever make it return something else.Example Resolution Prompt
In
openedx-core, add ataxonomy_typeread-only field to the taxonomy Get endpoints. Insrc/openedx_tagging/models/base.py, addTaxonomyType(models.TextChoices)withTAGS = "tags"andCOMPETENCY = "competency", placed above theTaxonomyclass, and add aTaxonomy.get_type()method returningTaxonomyType.TAGSunconditionally — this mirrors the existingsystem_definedbase/override pattern (system_defined.py:29-35) and must not referenceCompetencyTaxonomyor thecompetencytaxonomyrelation name anywhere. Insrc/openedx_tagging/rest_api/v1/serializers.py, addtaxonomy_type = serializers.SerializerMethodField()toTaxonomySerializer, withget_taxonomy_type(self, obj)returningobj.get_type()(call this after the serializer's existing.cast()step), and add"taxonomy_type"toMeta.fields. Add test cases covering a baseTaxonomy→"tags", aSystemDefinedTaxonomy→"tags", and a test-onlyTaxonomysubclass overridingget_type()→ confirms polymorphism flows through both the detail and list endpoints. ImportTaxonomyTypefrommodels/base.pyfor both this serializer field and #614's write-sideChoiceField, so the two can never drift.