diff --git a/openedx_learning/__init__.py b/openedx_learning/__init__.py index 574c53b5..6f229c82 100644 --- a/openedx_learning/__init__.py +++ b/openedx_learning/__init__.py @@ -1,4 +1,4 @@ """ Open edX Learning ("Learning Core"). """ -__version__ = "0.2.0" +__version__ = "0.2.1" diff --git a/openedx_tagging/core/tagging/api.py b/openedx_tagging/core/tagging/api.py index 14595a1a..f8106590 100644 --- a/openedx_tagging/core/tagging/api.py +++ b/openedx_tagging/core/tagging/api.py @@ -26,8 +26,7 @@ def create_taxonomy( name: str, description: str | None = None, enabled=True, - required=False, - allow_multiple=False, + allow_multiple=True, allow_free_text=False, taxonomy_class: type[Taxonomy] | None = None, ) -> Taxonomy: @@ -38,7 +37,6 @@ def create_taxonomy( name=name, description=description or "", enabled=enabled, - required=required, allow_multiple=allow_multiple, allow_free_text=allow_free_text, ) @@ -213,11 +211,6 @@ def _check_new_tag_count(new_tag_count: int) -> None: if not taxonomy.allow_multiple and len(tags) > 1: raise ValueError(_(f"Taxonomy ({taxonomy.name}) only allows one tag per object.")) - if taxonomy.required and len(tags) == 0: - raise ValueError( - _(f"Taxonomy ({taxonomy.id}) requires at least one tag per object.") - ) - current_tags = list( ObjectTagClass.objects.filter(taxonomy=taxonomy, object_id=object_id) ) diff --git a/openedx_tagging/core/tagging/fixtures/language_taxonomy.yaml b/openedx_tagging/core/tagging/fixtures/language_taxonomy.yaml deleted file mode 100644 index b300d8ac..00000000 --- a/openedx_tagging/core/tagging/fixtures/language_taxonomy.yaml +++ /dev/null @@ -1,1299 +0,0 @@ -- model: oel_tagging.tag - pk: -1 - fields: - taxonomy: -1 - parent: null - value: Afar - external_id: aa -- model: oel_tagging.tag - pk: -2 - fields: - taxonomy: -1 - parent: null - value: Abkhazian - external_id: ab -- model: oel_tagging.tag - pk: -3 - fields: - taxonomy: -1 - parent: null - value: Avestan - external_id: ae -- model: oel_tagging.tag - pk: -4 - fields: - taxonomy: -1 - parent: null - value: Afrikaans - external_id: af -- model: oel_tagging.tag - pk: -5 - fields: - taxonomy: -1 - parent: null - value: Akan - external_id: ak -- model: oel_tagging.tag - pk: -6 - fields: - taxonomy: -1 - parent: null - value: Amharic - external_id: am -- model: oel_tagging.tag - pk: -7 - fields: - taxonomy: -1 - parent: null - value: Aragonese - external_id: an -- model: oel_tagging.tag - pk: -8 - fields: - taxonomy: -1 - parent: null - value: Arabic - external_id: ar -- model: oel_tagging.tag - pk: -9 - fields: - taxonomy: -1 - parent: null - value: Assamese - external_id: as -- model: oel_tagging.tag - pk: -10 - fields: - taxonomy: -1 - parent: null - value: Avaric - external_id: av -- model: oel_tagging.tag - pk: -11 - fields: - taxonomy: -1 - parent: null - value: Aymara - external_id: ay -- model: oel_tagging.tag - pk: -12 - fields: - taxonomy: -1 - parent: null - value: Azerbaijani - external_id: az -- model: oel_tagging.tag - pk: -13 - fields: - taxonomy: -1 - parent: null - value: Bashkir - external_id: ba -- model: oel_tagging.tag - pk: -14 - fields: - taxonomy: -1 - parent: null - value: Belarusian - external_id: be -- model: oel_tagging.tag - pk: -15 - fields: - taxonomy: -1 - parent: null - value: Bulgarian - external_id: bg -- model: oel_tagging.tag - pk: -16 - fields: - taxonomy: -1 - parent: null - value: Bihari languages - external_id: bh -- model: oel_tagging.tag - pk: -17 - fields: - taxonomy: -1 - parent: null - value: Bislama - external_id: bi -- model: oel_tagging.tag - pk: -18 - fields: - taxonomy: -1 - parent: null - value: Bambara - external_id: bm -- model: oel_tagging.tag - pk: -19 - fields: - taxonomy: -1 - parent: null - value: Bengali - external_id: bn -- model: oel_tagging.tag - pk: -20 - fields: - taxonomy: -1 - parent: null - value: Tibetan - external_id: bo -- model: oel_tagging.tag - pk: -21 - fields: - taxonomy: -1 - parent: null - value: Breton - external_id: br -- model: oel_tagging.tag - pk: -22 - fields: - taxonomy: -1 - parent: null - value: Bosnian - external_id: bs -- model: oel_tagging.tag - pk: -23 - fields: - taxonomy: -1 - parent: null - value: Catalan - external_id: ca -- model: oel_tagging.tag - pk: -24 - fields: - taxonomy: -1 - parent: null - value: Chechen - external_id: ce -- model: oel_tagging.tag - pk: -25 - fields: - taxonomy: -1 - parent: null - value: Chamorro - external_id: ch -- model: oel_tagging.tag - pk: -26 - fields: - taxonomy: -1 - parent: null - value: Corsican - external_id: co -- model: oel_tagging.tag - pk: -27 - fields: - taxonomy: -1 - parent: null - value: Cree - external_id: cr -- model: oel_tagging.tag - pk: -28 - fields: - taxonomy: -1 - parent: null - value: Czech - external_id: cs -- model: oel_tagging.tag - pk: -29 - fields: - taxonomy: -1 - parent: null - value: Church Slavic - external_id: cu -- model: oel_tagging.tag - pk: -30 - fields: - taxonomy: -1 - parent: null - value: Chuvash - external_id: cv -- model: oel_tagging.tag - pk: -31 - fields: - taxonomy: -1 - parent: null - value: Welsh - external_id: cy -- model: oel_tagging.tag - pk: -32 - fields: - taxonomy: -1 - parent: null - value: Danish - external_id: da -- model: oel_tagging.tag - pk: -33 - fields: - taxonomy: -1 - parent: null - value: German - external_id: de -- model: oel_tagging.tag - pk: -34 - fields: - taxonomy: -1 - parent: null - value: Divehi - external_id: dv -- model: oel_tagging.tag - pk: -35 - fields: - taxonomy: -1 - parent: null - value: Dzongkha - external_id: dz -- model: oel_tagging.tag - pk: -36 - fields: - taxonomy: -1 - parent: null - value: Ewe - external_id: ee -- model: oel_tagging.tag - pk: -37 - fields: - taxonomy: -1 - parent: null - value: Greek, Modern (1453-) - external_id: el -- model: oel_tagging.tag - pk: -38 - fields: - taxonomy: -1 - parent: null - value: English - external_id: en -- model: oel_tagging.tag - pk: -39 - fields: - taxonomy: -1 - parent: null - value: Esperanto - external_id: eo -- model: oel_tagging.tag - pk: -40 - fields: - taxonomy: -1 - parent: null - value: Spanish - external_id: es -- model: oel_tagging.tag - pk: -41 - fields: - taxonomy: -1 - parent: null - value: Estonian - external_id: et -- model: oel_tagging.tag - pk: -42 - fields: - taxonomy: -1 - parent: null - value: Basque - external_id: eu -- model: oel_tagging.tag - pk: -43 - fields: - taxonomy: -1 - parent: null - value: Persian - external_id: fa -- model: oel_tagging.tag - pk: -44 - fields: - taxonomy: -1 - parent: null - value: Fulah - external_id: ff -- model: oel_tagging.tag - pk: -45 - fields: - taxonomy: -1 - parent: null - value: Finnish - external_id: fi -- model: oel_tagging.tag - pk: -46 - fields: - taxonomy: -1 - parent: null - value: Fijian - external_id: fj -- model: oel_tagging.tag - pk: -47 - fields: - taxonomy: -1 - parent: null - value: Faroese - external_id: fo -- model: oel_tagging.tag - pk: -48 - fields: - taxonomy: -1 - parent: null - value: French - external_id: fr -- model: oel_tagging.tag - pk: -49 - fields: - taxonomy: -1 - parent: null - value: Western Frisian - external_id: fy -- model: oel_tagging.tag - pk: -50 - fields: - taxonomy: -1 - parent: null - value: Irish - external_id: ga -- model: oel_tagging.tag - pk: -51 - fields: - taxonomy: -1 - parent: null - value: Gaelic - external_id: gd -- model: oel_tagging.tag - pk: -52 - fields: - taxonomy: -1 - parent: null - value: Galician - external_id: gl -- model: oel_tagging.tag - pk: -53 - fields: - taxonomy: -1 - parent: null - value: Guarani - external_id: gn -- model: oel_tagging.tag - pk: -54 - fields: - taxonomy: -1 - parent: null - value: Gujarati - external_id: gu -- model: oel_tagging.tag - pk: -55 - fields: - taxonomy: -1 - parent: null - value: Manx - external_id: gv -- model: oel_tagging.tag - pk: -56 - fields: - taxonomy: -1 - parent: null - value: Hausa - external_id: ha -- model: oel_tagging.tag - pk: -57 - fields: - taxonomy: -1 - parent: null - value: Hebrew - external_id: he -- model: oel_tagging.tag - pk: -58 - fields: - taxonomy: -1 - parent: null - value: Hindi - external_id: hi -- model: oel_tagging.tag - pk: -59 - fields: - taxonomy: -1 - parent: null - value: Hiri Motu - external_id: ho -- model: oel_tagging.tag - pk: -60 - fields: - taxonomy: -1 - parent: null - value: Croatian - external_id: hr -- model: oel_tagging.tag - pk: -61 - fields: - taxonomy: -1 - parent: null - value: Haitian - external_id: ht -- model: oel_tagging.tag - pk: -62 - fields: - taxonomy: -1 - parent: null - value: Hungarian - external_id: hu -- model: oel_tagging.tag - pk: -63 - fields: - taxonomy: -1 - parent: null - value: Armenian - external_id: hy -- model: oel_tagging.tag - pk: -64 - fields: - taxonomy: -1 - parent: null - value: Herero - external_id: hz -- model: oel_tagging.tag - pk: -65 - fields: - taxonomy: -1 - parent: null - value: Interlingua (International Auxiliary Language Association) - external_id: ia -- model: oel_tagging.tag - pk: -66 - fields: - taxonomy: -1 - parent: null - value: Indonesian - external_id: id -- model: oel_tagging.tag - pk: -67 - fields: - taxonomy: -1 - parent: null - value: Interlingue - external_id: ie -- model: oel_tagging.tag - pk: -68 - fields: - taxonomy: -1 - parent: null - value: Igbo - external_id: ig -- model: oel_tagging.tag - pk: -69 - fields: - taxonomy: -1 - parent: null - value: Sichuan Yi - external_id: ii -- model: oel_tagging.tag - pk: -70 - fields: - taxonomy: -1 - parent: null - value: Inupiaq - external_id: ik -- model: oel_tagging.tag - pk: -71 - fields: - taxonomy: -1 - parent: null - value: Ido - external_id: io -- model: oel_tagging.tag - pk: -72 - fields: - taxonomy: -1 - parent: null - value: Icelandic - external_id: is -- model: oel_tagging.tag - pk: -73 - fields: - taxonomy: -1 - parent: null - value: Italian - external_id: it -- model: oel_tagging.tag - pk: -74 - fields: - taxonomy: -1 - parent: null - value: Inuktitut - external_id: iu -- model: oel_tagging.tag - pk: -75 - fields: - taxonomy: -1 - parent: null - value: Japanese - external_id: ja -- model: oel_tagging.tag - pk: -76 - fields: - taxonomy: -1 - parent: null - value: Javanese - external_id: jv -- model: oel_tagging.tag - pk: -77 - fields: - taxonomy: -1 - parent: null - value: Georgian - external_id: ka -- model: oel_tagging.tag - pk: -78 - fields: - taxonomy: -1 - parent: null - value: Kongo - external_id: kg -- model: oel_tagging.tag - pk: -79 - fields: - taxonomy: -1 - parent: null - value: Kikuyu - external_id: ki -- model: oel_tagging.tag - pk: -80 - fields: - taxonomy: -1 - parent: null - value: Kuanyama - external_id: kj -- model: oel_tagging.tag - pk: -81 - fields: - taxonomy: -1 - parent: null - value: Kazakh - external_id: kk -- model: oel_tagging.tag - pk: -82 - fields: - taxonomy: -1 - parent: null - value: Kalaallisut - external_id: kl -- model: oel_tagging.tag - pk: -83 - fields: - taxonomy: -1 - parent: null - value: Central Khmer - external_id: km -- model: oel_tagging.tag - pk: -84 - fields: - taxonomy: -1 - parent: null - value: Kannada - external_id: kn -- model: oel_tagging.tag - pk: -85 - fields: - taxonomy: -1 - parent: null - value: Korean - external_id: ko -- model: oel_tagging.tag - pk: -86 - fields: - taxonomy: -1 - parent: null - value: Kanuri - external_id: kr -- model: oel_tagging.tag - pk: -87 - fields: - taxonomy: -1 - parent: null - value: Kashmiri - external_id: ks -- model: oel_tagging.tag - pk: -88 - fields: - taxonomy: -1 - parent: null - value: Kurdish - external_id: ku -- model: oel_tagging.tag - pk: -89 - fields: - taxonomy: -1 - parent: null - value: Komi - external_id: kv -- model: oel_tagging.tag - pk: -90 - fields: - taxonomy: -1 - parent: null - value: Cornish - external_id: kw -- model: oel_tagging.tag - pk: -91 - fields: - taxonomy: -1 - parent: null - value: Kirghiz - external_id: ky -- model: oel_tagging.tag - pk: -92 - fields: - taxonomy: -1 - parent: null - value: Latin - external_id: la -- model: oel_tagging.tag - pk: -93 - fields: - taxonomy: -1 - parent: null - value: Luxembourgish - external_id: lb -- model: oel_tagging.tag - pk: -94 - fields: - taxonomy: -1 - parent: null - value: Ganda - external_id: lg -- model: oel_tagging.tag - pk: -95 - fields: - taxonomy: -1 - parent: null - value: Limburgan - external_id: li -- model: oel_tagging.tag - pk: -96 - fields: - taxonomy: -1 - parent: null - value: Lingala - external_id: ln -- model: oel_tagging.tag - pk: -97 - fields: - taxonomy: -1 - parent: null - value: Lao - external_id: lo -- model: oel_tagging.tag - pk: -98 - fields: - taxonomy: -1 - parent: null - value: Lithuanian - external_id: lt -- model: oel_tagging.tag - pk: -99 - fields: - taxonomy: -1 - parent: null - value: Luba-Katanga - external_id: lu -- model: oel_tagging.tag - pk: -100 - fields: - taxonomy: -1 - parent: null - value: Latvian - external_id: lv -- model: oel_tagging.tag - pk: -101 - fields: - taxonomy: -1 - parent: null - value: Malagasy - external_id: mg -- model: oel_tagging.tag - pk: -102 - fields: - taxonomy: -1 - parent: null - value: Marshallese - external_id: mh -- model: oel_tagging.tag - pk: -103 - fields: - taxonomy: -1 - parent: null - value: Maori - external_id: mi -- model: oel_tagging.tag - pk: -104 - fields: - taxonomy: -1 - parent: null - value: Macedonian - external_id: mk -- model: oel_tagging.tag - pk: -105 - fields: - taxonomy: -1 - parent: null - value: Malayalam - external_id: ml -- model: oel_tagging.tag - pk: -106 - fields: - taxonomy: -1 - parent: null - value: Mongolian - external_id: mn -- model: oel_tagging.tag - pk: -107 - fields: - taxonomy: -1 - parent: null - value: Marathi - external_id: mr -- model: oel_tagging.tag - pk: -108 - fields: - taxonomy: -1 - parent: null - value: Malay - external_id: ms -- model: oel_tagging.tag - pk: -109 - fields: - taxonomy: -1 - parent: null - value: Maltese - external_id: mt -- model: oel_tagging.tag - pk: -110 - fields: - taxonomy: -1 - parent: null - value: Burmese - external_id: my -- model: oel_tagging.tag - pk: -111 - fields: - taxonomy: -1 - parent: null - value: Nauru - external_id: na -- model: oel_tagging.tag - pk: -112 - fields: - taxonomy: -1 - parent: null - value: Bokmål, Norwegian - external_id: nb -- model: oel_tagging.tag - pk: -113 - fields: - taxonomy: -1 - parent: null - value: Ndebele, North - external_id: nd -- model: oel_tagging.tag - pk: -114 - fields: - taxonomy: -1 - parent: null - value: Nepali - external_id: ne -- model: oel_tagging.tag - pk: -115 - fields: - taxonomy: -1 - parent: null - value: Ndonga - external_id: ng -- model: oel_tagging.tag - pk: -116 - fields: - taxonomy: -1 - parent: null - value: Dutch - external_id: nl -- model: oel_tagging.tag - pk: -117 - fields: - taxonomy: -1 - parent: null - value: Norwegian Nynorsk - external_id: nn -- model: oel_tagging.tag - pk: -118 - fields: - taxonomy: -1 - parent: null - value: Norwegian - external_id: no -- model: oel_tagging.tag - pk: -119 - fields: - taxonomy: -1 - parent: null - value: Ndebele, South - external_id: nr -- model: oel_tagging.tag - pk: -120 - fields: - taxonomy: -1 - parent: null - value: Navajo - external_id: nv -- model: oel_tagging.tag - pk: -121 - fields: - taxonomy: -1 - parent: null - value: Chichewa - external_id: ny -- model: oel_tagging.tag - pk: -122 - fields: - taxonomy: -1 - parent: null - value: Occitan (post 1500) - external_id: oc -- model: oel_tagging.tag - pk: -123 - fields: - taxonomy: -1 - parent: null - value: Ojibwa - external_id: oj -- model: oel_tagging.tag - pk: -124 - fields: - taxonomy: -1 - parent: null - value: Oromo - external_id: om -- model: oel_tagging.tag - pk: -125 - fields: - taxonomy: -1 - parent: null - value: Oriya - external_id: or -- model: oel_tagging.tag - pk: -126 - fields: - taxonomy: -1 - parent: null - value: Ossetian - external_id: os -- model: oel_tagging.tag - pk: -127 - fields: - taxonomy: -1 - parent: null - value: Panjabi - external_id: pa -- model: oel_tagging.tag - pk: -128 - fields: - taxonomy: -1 - parent: null - value: Pali - external_id: pi -- model: oel_tagging.tag - pk: -129 - fields: - taxonomy: -1 - parent: null - value: Polish - external_id: pl -- model: oel_tagging.tag - pk: -130 - fields: - taxonomy: -1 - parent: null - value: Pushto - external_id: ps -- model: oel_tagging.tag - pk: -131 - fields: - taxonomy: -1 - parent: null - value: Portuguese - external_id: pt -- model: oel_tagging.tag - pk: -132 - fields: - taxonomy: -1 - parent: null - value: Quechua - external_id: qu -- model: oel_tagging.tag - pk: -133 - fields: - taxonomy: -1 - parent: null - value: Romansh - external_id: rm -- model: oel_tagging.tag - pk: -134 - fields: - taxonomy: -1 - parent: null - value: Rundi - external_id: rn -- model: oel_tagging.tag - pk: -135 - fields: - taxonomy: -1 - parent: null - value: Romanian - external_id: ro -- model: oel_tagging.tag - pk: -136 - fields: - taxonomy: -1 - parent: null - value: Russian - external_id: ru -- model: oel_tagging.tag - pk: -137 - fields: - taxonomy: -1 - parent: null - value: Kinyarwanda - external_id: rw -- model: oel_tagging.tag - pk: -138 - fields: - taxonomy: -1 - parent: null - value: Sanskrit - external_id: sa -- model: oel_tagging.tag - pk: -139 - fields: - taxonomy: -1 - parent: null - value: Sardinian - external_id: sc -- model: oel_tagging.tag - pk: -140 - fields: - taxonomy: -1 - parent: null - value: Sindhi - external_id: sd -- model: oel_tagging.tag - pk: -141 - fields: - taxonomy: -1 - parent: null - value: Northern Sami - external_id: se -- model: oel_tagging.tag - pk: -142 - fields: - taxonomy: -1 - parent: null - value: Sango - external_id: sg -- model: oel_tagging.tag - pk: -143 - fields: - taxonomy: -1 - parent: null - value: Sinhala - external_id: si -- model: oel_tagging.tag - pk: -144 - fields: - taxonomy: -1 - parent: null - value: Slovak - external_id: sk -- model: oel_tagging.tag - pk: -145 - fields: - taxonomy: -1 - parent: null - value: Slovenian - external_id: sl -- model: oel_tagging.tag - pk: -146 - fields: - taxonomy: -1 - parent: null - value: Samoan - external_id: sm -- model: oel_tagging.tag - pk: -147 - fields: - taxonomy: -1 - parent: null - value: Shona - external_id: sn -- model: oel_tagging.tag - pk: -148 - fields: - taxonomy: -1 - parent: null - value: Somali - external_id: so -- model: oel_tagging.tag - pk: -149 - fields: - taxonomy: -1 - parent: null - value: Albanian - external_id: sq -- model: oel_tagging.tag - pk: -150 - fields: - taxonomy: -1 - parent: null - value: Serbian - external_id: sr -- model: oel_tagging.tag - pk: -151 - fields: - taxonomy: -1 - parent: null - value: Swati - external_id: ss -- model: oel_tagging.tag - pk: -152 - fields: - taxonomy: -1 - parent: null - value: Sotho, Southern - external_id: st -- model: oel_tagging.tag - pk: -153 - fields: - taxonomy: -1 - parent: null - value: Sundanese - external_id: su -- model: oel_tagging.tag - pk: -154 - fields: - taxonomy: -1 - parent: null - value: Swedish - external_id: sv -- model: oel_tagging.tag - pk: -155 - fields: - taxonomy: -1 - parent: null - value: Swahili - external_id: sw -- model: oel_tagging.tag - pk: -156 - fields: - taxonomy: -1 - parent: null - value: Tamil - external_id: ta -- model: oel_tagging.tag - pk: -157 - fields: - taxonomy: -1 - parent: null - value: Telugu - external_id: te -- model: oel_tagging.tag - pk: -158 - fields: - taxonomy: -1 - parent: null - value: Tajik - external_id: tg -- model: oel_tagging.tag - pk: -159 - fields: - taxonomy: -1 - parent: null - value: Thai - external_id: th -- model: oel_tagging.tag - pk: -160 - fields: - taxonomy: -1 - parent: null - value: Tigrinya - external_id: ti -- model: oel_tagging.tag - pk: -161 - fields: - taxonomy: -1 - parent: null - value: Turkmen - external_id: tk -- model: oel_tagging.tag - pk: -162 - fields: - taxonomy: -1 - parent: null - value: Tagalog - external_id: tl -- model: oel_tagging.tag - pk: -163 - fields: - taxonomy: -1 - parent: null - value: Tswana - external_id: tn -- model: oel_tagging.tag - pk: -164 - fields: - taxonomy: -1 - parent: null - value: Tonga (Tonga Islands) - external_id: to -- model: oel_tagging.tag - pk: -165 - fields: - taxonomy: -1 - parent: null - value: Turkish - external_id: tr -- model: oel_tagging.tag - pk: -166 - fields: - taxonomy: -1 - parent: null - value: Tsonga - external_id: ts -- model: oel_tagging.tag - pk: -167 - fields: - taxonomy: -1 - parent: null - value: Tatar - external_id: tt -- model: oel_tagging.tag - pk: -168 - fields: - taxonomy: -1 - parent: null - value: Twi - external_id: tw -- model: oel_tagging.tag - pk: -169 - fields: - taxonomy: -1 - parent: null - value: Tahitian - external_id: ty -- model: oel_tagging.tag - pk: -170 - fields: - taxonomy: -1 - parent: null - value: Uighur - external_id: ug -- model: oel_tagging.tag - pk: -171 - fields: - taxonomy: -1 - parent: null - value: Ukrainian - external_id: uk -- model: oel_tagging.tag - pk: -172 - fields: - taxonomy: -1 - parent: null - value: Urdu - external_id: ur -- model: oel_tagging.tag - pk: -173 - fields: - taxonomy: -1 - parent: null - value: Uzbek - external_id: uz -- model: oel_tagging.tag - pk: -174 - fields: - taxonomy: -1 - parent: null - value: Venda - external_id: ve -- model: oel_tagging.tag - pk: -175 - fields: - taxonomy: -1 - parent: null - value: Vietnamese - external_id: vi -- model: oel_tagging.tag - pk: -176 - fields: - taxonomy: -1 - parent: null - value: Volapük - external_id: vo -- model: oel_tagging.tag - pk: -177 - fields: - taxonomy: -1 - parent: null - value: Walloon - external_id: wa -- model: oel_tagging.tag - pk: -178 - fields: - taxonomy: -1 - parent: null - value: Wolof - external_id: wo -- model: oel_tagging.tag - pk: -179 - fields: - taxonomy: -1 - parent: null - value: Xhosa - external_id: xh -- model: oel_tagging.tag - pk: -180 - fields: - taxonomy: -1 - parent: null - value: Yiddish - external_id: yi -- model: oel_tagging.tag - pk: -181 - fields: - taxonomy: -1 - parent: null - value: Yoruba - external_id: yo -- model: oel_tagging.tag - pk: -182 - fields: - taxonomy: -1 - parent: null - value: Zhuang - external_id: za -- model: oel_tagging.tag - pk: -183 - fields: - taxonomy: -1 - parent: null - value: Chinese - external_id: zh -- model: oel_tagging.tag - pk: -184 - fields: - taxonomy: -1 - parent: null - value: Zulu - external_id: zu -- model: oel_tagging.taxonomy - pk: -1 - fields: - name: Languages - description: ISO 639-1 Languages. Allows tags for any language configured for use on the instance - enabled: true - required: true - allow_multiple: false - allow_free_text: false - visible_to_authors: true - _taxonomy_class: openedx_tagging.core.tagging.models.system_defined.LanguageTaxonomy diff --git a/openedx_tagging/core/tagging/management/commands/__init__.py b/openedx_tagging/core/tagging/management/commands/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/openedx_tagging/core/tagging/management/commands/build_language_fixture.py b/openedx_tagging/core/tagging/management/commands/build_language_fixture.py deleted file mode 100644 index 4901ca9f..00000000 --- a/openedx_tagging/core/tagging/management/commands/build_language_fixture.py +++ /dev/null @@ -1,48 +0,0 @@ -""" -Script that downloads all the ISO 639-1 languages and processes them -to write the fixture for the Language system-defined taxonomy. - -This function is intended to be used only once, -but can be edited in the future if more data needs to be added to the fixture. -""" -import json -import urllib.request - -from django.core.management.base import BaseCommand - -endpoint = "https://pkgstore.datahub.io/core/language-codes/language-codes_json/data/97607046542b532c395cf83df5185246/language-codes_json.json" # noqa -output = "./openedx_tagging/core/tagging/fixtures/language_taxonomy.yaml" - - -class Command(BaseCommand): - def handle(self, **options): - json_data = self.download_json() - self.build_fixture(json_data) - - def download_json(self): - with urllib.request.urlopen(endpoint) as response: - json_data = response.read() - return json.loads(json_data) - - def build_fixture(self, json_data): - tag_pk = -1 - with open(output, "w") as output_file: - for lang_data in json_data: - lang_value = self.get_lang_value(lang_data) - lang_code = lang_data["alpha2"] - output_file.write("- model: oel_tagging.tag\n") - output_file.write(f" pk: {tag_pk}\n") - output_file.write(" fields:\n") - output_file.write(" taxonomy: -1\n") - output_file.write(" parent: null\n") - output_file.write(f" value: {lang_value}\n") - output_file.write(f" external_id: {lang_code}\n") - # System tags are identified with negative numbers to avoid clashing with user-created tags. - tag_pk -= 1 - - def get_lang_value(self, lang_data): - """ - Gets the lang value. Some languages has many values. - """ - lang_list = lang_data["English"].split(";") - return lang_list[0] diff --git a/openedx_tagging/core/tagging/migrations/0005_language_taxonomy.py b/openedx_tagging/core/tagging/migrations/0005_language_taxonomy.py index b6758da1..84d02f8d 100644 --- a/openedx_tagging/core/tagging/migrations/0005_language_taxonomy.py +++ b/openedx_tagging/core/tagging/migrations/0005_language_taxonomy.py @@ -8,15 +8,17 @@ def load_language_taxonomy(apps, schema_editor): """ Load language taxonomy and tags """ - call_command("loaddata", "--app=oel_tagging", "language_taxonomy.yaml") + # Due to changes in the data model this fixture was no longer working and is + # no longer needed anyways - the language taxonomy will be created in + # 0012_language_taxonomy. + pass def revert(apps, schema_editor): # pragma: no cover """ Deletes language taxonomy an tags """ - Taxonomy = apps.get_model("oel_tagging", "Taxonomy") - Taxonomy.objects.filter(id=-1).delete() + pass class Migration(migrations.Migration): diff --git a/openedx_tagging/core/tagging/migrations/0011_remove_required.py b/openedx_tagging/core/tagging/migrations/0011_remove_required.py new file mode 100644 index 00000000..6caf984a --- /dev/null +++ b/openedx_tagging/core/tagging/migrations/0011_remove_required.py @@ -0,0 +1,22 @@ +# Generated by Django 3.2.19 on 2023-10-03 21:53 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('oel_tagging', '0010_cleanups'), + ] + + operations = [ + migrations.RemoveField( + model_name='taxonomy', + name='required', + ), + migrations.AlterField( + model_name='taxonomy', + name='allow_multiple', + field=models.BooleanField(default=True, help_text='Indicates that multiple tags from this taxonomy may be added to an object.'), + ), + ] diff --git a/openedx_tagging/core/tagging/migrations/0012_language_taxonomy.py b/openedx_tagging/core/tagging/migrations/0012_language_taxonomy.py new file mode 100644 index 00000000..5576e83d --- /dev/null +++ b/openedx_tagging/core/tagging/migrations/0012_language_taxonomy.py @@ -0,0 +1,43 @@ +# Generated by Django 3.2.19 on 2023-07-28 13:33 + +from django.core.management import call_command +from django.db import migrations +from django.db.models import Count + + +def create_language_taxonomy(apps, schema_editor): + """ + Create language taxonomy + """ + # Make sure the language taxonomy exists: + Taxonomy = apps.get_model("oel_tagging", "Taxonomy") + lang_taxonomy, _created = Taxonomy.objects.get_or_create(id=-1, defaults={ + "name": "Languages", + "description": "Languages that are enabled on this system.", + "enabled": True, + "allow_multiple": False, + "allow_free_text": False, + "visible_to_authors": True, + "_taxonomy_class": "openedx_tagging.core.tagging.models.system_defined.LanguageTaxonomy", + }) + + # But delete any unused tags created by the old fixture: + lang_taxonomy.tag_set.annotate(usage_count=Count('objecttag')).filter(usage_count=0).delete() + + +def revert(apps, schema_editor): # pragma: no cover + """ + Deletes language taxonomy an tags + """ + Taxonomy = apps.get_model("oel_tagging", "Taxonomy") + Taxonomy.objects.filter(id=-1).delete() + + +class Migration(migrations.Migration): + dependencies = [ + ("oel_tagging", "0011_remove_required"), + ] + + operations = [ + migrations.RunPython(create_language_taxonomy, revert), + ] diff --git a/openedx_tagging/core/tagging/models/base.py b/openedx_tagging/core/tagging/models/base.py index eb4678bd..d24d67d4 100644 --- a/openedx_tagging/core/tagging/models/base.py +++ b/openedx_tagging/core/tagging/models/base.py @@ -131,14 +131,8 @@ class Taxonomy(models.Model): default=True, help_text=_("Only enabled taxonomies will be shown to authors."), ) - required = models.BooleanField( - default=False, - help_text=_( - "Indicates that one or more tags from this taxonomy must be added to an object." - ), - ) allow_multiple = models.BooleanField( - default=False, # TODO: This should be true, or perhaps remove this property altogether + default=True, help_text=_( "Indicates that multiple tags from this taxonomy may be added to an object." ), @@ -260,7 +254,6 @@ def copy(self, taxonomy: Taxonomy) -> Taxonomy: self.name = taxonomy.name self.description = taxonomy.description self.enabled = taxonomy.enabled - self.required = taxonomy.required self.allow_multiple = taxonomy.allow_multiple self.allow_free_text = taxonomy.allow_free_text self.visible_to_authors = taxonomy.visible_to_authors diff --git a/openedx_tagging/core/tagging/rest_api/v1/serializers.py b/openedx_tagging/core/tagging/rest_api/v1/serializers.py index 22878fc7..cf7d6304 100644 --- a/openedx_tagging/core/tagging/rest_api/v1/serializers.py +++ b/openedx_tagging/core/tagging/rest_api/v1/serializers.py @@ -24,7 +24,6 @@ class Meta: "name", "description", "enabled", - "required", "allow_multiple", "allow_free_text", "system_defined", diff --git a/openedx_tagging/core/tagging/rest_api/v1/views.py b/openedx_tagging/core/tagging/rest_api/v1/views.py index 9dbb2cc0..26fcad57 100644 --- a/openedx_tagging/core/tagging/rest_api/v1/views.py +++ b/openedx_tagging/core/tagging/rest_api/v1/views.py @@ -78,10 +78,8 @@ class TaxonomyView(ModelViewSet): applying tags from this taxonomy to an object. * enabled (optional): Only enabled taxonomies will be shown to authors (default: true). - * required (optional): Indicates that one or more tags from this - taxonomy must be added to an object (default: False). * allow_multiple (optional): Indicates that multiple tags from this - taxonomy may be added to an object (default: False). + taxonomy may be added to an object (default: True). * allow_free_text (optional): Indicates that tags in this taxonomy need not be predefined; authors may enter their own tag values (default: False). @@ -92,7 +90,6 @@ class TaxonomyView(ModelViewSet): "name": "Taxonomy Name", "description": "This is a description", "enabled": True, - "required": True, "allow_multiple": True, "allow_free_text": True, } @@ -110,8 +107,6 @@ class TaxonomyView(ModelViewSet): * description (optional): Provides extra information for the user when applying tags from this taxonomy to an object. * enabled (optional): Only enabled taxonomies will be shown to authors. - * required (optional): Indicates that one or more tags from this - taxonomy must be added to an object. * allow_multiple (optional): Indicates that multiple tags from this taxonomy may be added to an object. * allow_free_text (optional): Indicates that tags in this taxonomy need @@ -123,7 +118,6 @@ class TaxonomyView(ModelViewSet): "name": "Taxonomy New Name", "description": "This is a new description", "enabled": False, - "required": False, "allow_multiple": False, "allow_free_text": True, } diff --git a/tests/openedx_tagging/core/fixtures/tagging.yaml b/tests/openedx_tagging/core/fixtures/tagging.yaml index b3c07003..4715b667 100644 --- a/tests/openedx_tagging/core/fixtures/tagging.yaml +++ b/tests/openedx_tagging/core/fixtures/tagging.yaml @@ -207,7 +207,6 @@ name: Life on Earth description: A taxonomy about life on earth. enabled: true - required: false allow_multiple: false allow_free_text: false - model: oel_tagging.taxonomy @@ -216,7 +215,6 @@ name: User Authors description: Allows tags for any User on the instance. enabled: true - required: false allow_multiple: false allow_free_text: false _taxonomy_class: openedx_tagging.core.tagging.models.system_defined.UserSystemDefinedTaxonomy @@ -226,7 +224,6 @@ name: System defined taxonomy description: Generic System defined taxonomy enabled: true - required: false allow_multiple: false allow_free_text: false _taxonomy_class: openedx_tagging.core.tagging.models.system_defined.SystemDefinedTaxonomy @@ -236,7 +233,6 @@ name: Import Taxonomy Test description: "" enabled: true - required: false allow_multiple: false allow_free_text: false diff --git a/tests/openedx_tagging/core/tagging/test_api.py b/tests/openedx_tagging/core/tagging/test_api.py index 182f79c2..6ed0140a 100644 --- a/tests/openedx_tagging/core/tagging/test_api.py +++ b/tests/openedx_tagging/core/tagging/test_api.py @@ -42,7 +42,6 @@ def test_create_taxonomy(self) -> None: # Note: we must specify '-> None' to op "name": "Difficulty", "description": "This taxonomy contains tags describing the difficulty of an activity", "enabled": False, - "required": True, "allow_multiple": True, "allow_free_text": True, } @@ -112,31 +111,61 @@ def test_get_tags(self) -> None: *self.phylum_tags, ] assert tagging_api.get_tags(self.system_taxonomy) == self.system_tags - tags = tagging_api.get_tags(self.language_taxonomy) - langs = [tag.external_id for tag in tags] - expected_langs = [lang[0] for lang in test_languages] - assert langs == expected_langs @override_settings(LANGUAGES=test_languages) def test_get_root_tags(self): assert tagging_api.get_root_tags(self.taxonomy) == self.domain_tags assert tagging_api.get_root_tags(self.system_taxonomy) == self.system_tags - tags = tagging_api.get_root_tags(self.language_taxonomy) - langs = [tag.external_id for tag in tags] - expected_langs = [lang[0] for lang in test_languages] - assert langs == expected_langs @override_settings(LANGUAGES=test_languages) + def test_get_root_language_tags(self): + """ + For the language taxonomy, listing and searching tags will only show + tags that have been used at least once. + """ + before_langs = [ + tag.external_id for tag in + tagging_api.get_root_tags(self.language_taxonomy) + ] + assert before_langs == ["en"] + # Use a few more tags: + for _lang_code, lang_value in test_languages: + tagging_api.tag_object(object_id="foo", taxonomy=self.language_taxonomy, tags=[lang_value]) + # now a search will return matching tags: + after_langs = [ + tag.external_id for tag in + tagging_api.get_root_tags(self.language_taxonomy) + ] + expected_langs = [lang_code for lang_code, _ in test_languages] + assert after_langs == expected_langs + def test_search_tags(self): assert tagging_api.search_tags( self.taxonomy, search_term='eU' ) == self.filtered_tags - tags = tagging_api.search_tags(self.language_taxonomy, search_term='IsH') - langs = [tag.external_id for tag in tags] - expected_langs = [lang[0] for lang in filtered_test_languages] - assert langs == expected_langs + @override_settings(LANGUAGES=test_languages) + def test_search_language_tags(self): + """ + For the language taxonomy, listing and searching tags will only show + tags that have been used at least once. + """ + before_langs = [ + tag.external_id for tag in + tagging_api.search_tags(self.language_taxonomy, search_term='IsH') + ] + assert before_langs == ["en"] + # Use a few more tags: + for _lang_code, lang_value in test_languages: + tagging_api.tag_object(object_id="foo", taxonomy=self.language_taxonomy, tags=[lang_value]) + # now a search will return matching tags: + after_langs = [ + tag.external_id for tag in + tagging_api.search_tags(self.language_taxonomy, search_term='IsH') + ] + expected_langs = [lang_code for lang_code, _ in filtered_test_languages] + assert after_langs == expected_langs def test_get_children_tags(self): assert tagging_api.get_children_tags( @@ -284,12 +313,6 @@ def test_tag_object_no_multiple(self): tagging_api.tag_object(self.taxonomy, ["A", "B"], "biology101") assert "only allows one tag per object" in str(excinfo.value) - def test_tag_object_required(self): - self.taxonomy.required = True - with pytest.raises(ValueError) as excinfo: - tagging_api.tag_object(self.taxonomy, [], "biology101") - assert "requires at least one tag per object" in str(excinfo.value) - def test_tag_object_invalid_tag(self): with pytest.raises(tagging_api.TagDoesNotExist) as excinfo: tagging_api.tag_object(self.taxonomy, ["Eukaryota Xenomorph"], "biology101") diff --git a/tests/openedx_tagging/core/tagging/test_models.py b/tests/openedx_tagging/core/tagging/test_models.py index 6c1d852e..ccc9e6c6 100644 --- a/tests/openedx_tagging/core/tagging/test_models.py +++ b/tests/openedx_tagging/core/tagging/test_models.py @@ -43,7 +43,7 @@ def setUp(self): self.mammalia = get_tag("Mammalia") self.animalia = get_tag("Animalia") self.system_taxonomy_tag = get_tag("System Tag 1") - self.english_tag = get_tag("English") + self.english_tag = self.language_taxonomy.tag_for_external_id("en") self.user_1 = get_user_model()( id=1, username="test_user_1", diff --git a/tests/openedx_tagging/core/tagging/test_views.py b/tests/openedx_tagging/core/tagging/test_views.py index effd6460..b843d204 100644 --- a/tests/openedx_tagging/core/tagging/test_views.py +++ b/tests/openedx_tagging/core/tagging/test_views.py @@ -35,8 +35,7 @@ def check_taxonomy( name, description="", enabled=True, - required=False, - allow_multiple=False, + allow_multiple=True, allow_free_text=False, system_defined=False, visible_to_authors=True, @@ -48,7 +47,6 @@ def check_taxonomy( assert data["name"] == name assert data["description"] == description assert data["enabled"] == enabled - assert data["required"] == required assert data["allow_multiple"] == allow_multiple assert data["allow_free_text"] == allow_free_text assert data["system_defined"] == system_defined @@ -206,7 +204,6 @@ def test_create_taxonomy(self, user_attr: str | None, expected_status: int): "name": "taxonomy_data_2", "description": "This is a description", "enabled": False, - "required": True, "allow_multiple": True, } @@ -227,7 +224,6 @@ def test_create_taxonomy(self, user_attr: str | None, expected_status: int): @ddt.data( {}, - {"name": "Error taxonomy 2", "required": "Invalid value"}, {"name": "Error taxonomy 3", "enabled": "Invalid value"}, ) def test_create_taxonomy_error(self, create_data: dict[str, str]): @@ -260,7 +256,6 @@ def test_update_taxonomy(self, user_attr, expected_status): name="test update taxonomy", description="taxonomy description", enabled=True, - required=False, ) taxonomy.save() @@ -283,7 +278,6 @@ def test_update_taxonomy(self, user_attr, expected_status): "name": "new name", "description": "taxonomy description", "enabled": True, - "required": False, }, ) @@ -320,7 +314,7 @@ def test_update_taxonomy_404(self): ) @ddt.unpack def test_patch_taxonomy(self, user_attr, expected_status): - taxonomy = Taxonomy.objects.create(name="test patch taxonomy", enabled=False, required=True) + taxonomy = Taxonomy.objects.create(name="test patch taxonomy", enabled=False) taxonomy.save() url = TAXONOMY_DETAIL_URL.format(pk=taxonomy.pk) @@ -329,7 +323,7 @@ def test_patch_taxonomy(self, user_attr, expected_status): user = getattr(self, user_attr) self.client.force_authenticate(user=user) - response = self.client.patch(url, {"name": "new name", "required": False}, format="json") + response = self.client.patch(url, {"name": "new name", "enabled": True}, format="json") assert response.status_code == expected_status # If we were able to update the taxonomy, check if the name changed @@ -340,8 +334,7 @@ def test_patch_taxonomy(self, user_attr, expected_status): response.data["id"], **{ "name": "new name", - "enabled": False, - "required": False, + "enabled": True, }, ) @@ -439,8 +432,8 @@ def _object_permission(_user, object_id: str) -> bool: self.language_taxonomy = Taxonomy.objects.get(pk=LANGUAGE_TAXONOMY_ID) # Closed Taxonomies created by taxonomy admins, each with 20 ObjectTags - self.enabled_taxonomy = Taxonomy.objects.create(name="Enabled Taxonomy") - self.disabled_taxonomy = Taxonomy.objects.create(name="Disabled Taxonomy", enabled=False) + self.enabled_taxonomy = Taxonomy.objects.create(name="Enabled Taxonomy", allow_multiple=False) + self.disabled_taxonomy = Taxonomy.objects.create(name="Disabled Taxonomy", enabled=False, allow_multiple=False) self.multiple_taxonomy = Taxonomy.objects.create(name="Multiple Taxonomy", allow_multiple=True) for i in range(20): # Valid ObjectTags @@ -459,9 +452,11 @@ def _object_permission(_user, object_id: str) -> bool: # Free-Text Taxonomies created by taxonomy admins, each linked # to 10 ObjectTags - self.open_taxonomy_enabled = Taxonomy.objects.create(name="Enabled Free-Text Taxonomy", allow_free_text=True) + self.open_taxonomy_enabled = Taxonomy.objects.create( + name="Enabled Free-Text Taxonomy", allow_free_text=True, allow_multiple=False, + ) self.open_taxonomy_disabled = Taxonomy.objects.create( - name="Disabled Free-Text Taxonomy", allow_free_text=True, enabled=False + name="Disabled Free-Text Taxonomy", allow_free_text=True, enabled=False, allow_multiple=False, ) for i in range(10): ObjectTag.objects.create(object_id="abc", taxonomy=self.open_taxonomy_enabled, _value=f"Free Text {i}") @@ -683,10 +678,6 @@ def test_tag_object_invalid(self, user_attr, taxonomy_attr, tag_values, expected (None, "open_taxonomy_disabled", [], status.HTTP_403_FORBIDDEN), ("user", "open_taxonomy_disabled", [], status.HTTP_403_FORBIDDEN), ("staff", "open_taxonomy_disabled", [], status.HTTP_200_OK), - # Users and staff can't clear a taxonomy with required=True - (None, "language_taxonomy", [], status.HTTP_403_FORBIDDEN), - ("user", "language_taxonomy", [], status.HTTP_400_BAD_REQUEST), - ("staff", "language_taxonomy", [], status.HTTP_400_BAD_REQUEST), ) @ddt.unpack def test_tag_object_clear(self, user_attr, taxonomy_attr, tag_values, expected_status):