localcosmos-app-kit 0.9.18__py3-none-any.whl → 0.10.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (23) hide show
  1. app_kit/appbuilder/AppReleaseBuilder.py +111 -53
  2. app_kit/appbuilder/JSONBuilders/TaxonProfilesJSONBuilder.py +38 -15
  3. app_kit/appbuilder/JSONBuilders/__pycache__/TaxonProfilesJSONBuilder.cpython-313.pyc +0 -0
  4. app_kit/appbuilder/TaxonBuilder.py +35 -28
  5. app_kit/appbuilder/__pycache__/AppReleaseBuilder.cpython-313.pyc +0 -0
  6. app_kit/appbuilder/__pycache__/TaxonBuilder.cpython-313.pyc +0 -0
  7. app_kit/features/backbonetaxonomy/templates/backbonetaxonomy/manage_taxon.html +1 -1
  8. app_kit/features/taxon_profiles/forms.py +12 -37
  9. app_kit/features/taxon_profiles/models.py +29 -36
  10. app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/create_taxon_profile.html +1 -1
  11. app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/manage_taxon_profile_form.html +35 -54
  12. app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/manage_taxon_profile_morphotype.html +2 -1
  13. app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/nature_guide_taxonlist.html +2 -2
  14. app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/non_nature_guide_taxonlist.html +1 -1
  15. app_kit/features/taxon_profiles/templates/taxon_profiles/manage_taxon_profile.html +4 -4
  16. app_kit/features/taxon_profiles/urls.py +3 -0
  17. app_kit/features/taxon_profiles/views.py +44 -32
  18. {localcosmos_app_kit-0.9.18.dist-info → localcosmos_app_kit-0.10.0.dist-info}/METADATA +1 -1
  19. {localcosmos_app_kit-0.9.18.dist-info → localcosmos_app_kit-0.10.0.dist-info}/RECORD +22 -23
  20. app_kit/tests/TESTS_ROOT/media_for_tests/test/imagestore/31/a6a11b61d65ee19c4c22caa0682288ff.jpg +0 -0
  21. {localcosmos_app_kit-0.9.18.dist-info → localcosmos_app_kit-0.10.0.dist-info}/WHEEL +0 -0
  22. {localcosmos_app_kit-0.9.18.dist-info → localcosmos_app_kit-0.10.0.dist-info}/licenses/LICENCE +0 -0
  23. {localcosmos_app_kit-0.9.18.dist-info → localcosmos_app_kit-0.10.0.dist-info}/top_level.txt +0 -0
@@ -1959,6 +1959,63 @@ class AppReleaseBuilder(AppBuilderBase):
1959
1959
  localized_long_text = self.get_localized_taxonprofile_text(text_dict['longTextKey'], glossarized_locale, app_locale)
1960
1960
 
1961
1961
  return localized_short_text, localized_long_text
1962
+
1963
+ def get_localized_taxon_profile(self, profile_json, language_code):
1964
+
1965
+ glossarized_locale_filepath = self._app_glossarized_locale_filepath(language_code)
1966
+
1967
+ glossarized_locale = {}
1968
+
1969
+ if os.path.isfile(glossarized_locale_filepath):
1970
+ with open(glossarized_locale_filepath, 'r') as f:
1971
+ glossarized_locale = json.loads(f.read())
1972
+
1973
+ app_locale = self.meta_app.localizations[language_code]
1974
+
1975
+ localized_profile_json = profile_json.copy()
1976
+
1977
+ localized_short_profile = self.get_localized_taxonprofile_text(localized_profile_json['shortProfile'], glossarized_locale, app_locale)
1978
+ localized_profile_json['shortProfile'] = localized_short_profile
1979
+
1980
+ for index, text_dict in enumerate(profile_json['texts'], 0):
1981
+
1982
+ localized_short_text, localized_long_text = self.get_localized_taxonprofile_taxon_text(text_dict, glossarized_locale, app_locale)
1983
+
1984
+ localized_profile_json['texts'][index]['shortText'] = localized_short_text
1985
+ localized_profile_json['texts'][index]['longText'] = localized_long_text
1986
+
1987
+
1988
+ for c_index, category in enumerate(profile_json['categorizedTexts'], 0):
1989
+
1990
+ localized_category = category.copy()
1991
+
1992
+ localized_category_name = self.get_localized_taxonprofile_text(category['category'], glossarized_locale, app_locale)
1993
+
1994
+ if localized_category:
1995
+ localized_category['category'] = localized_category_name
1996
+
1997
+ for index, text_dict in enumerate(category['texts'], 0):
1998
+ localized_short_text, localized_long_text = self.get_localized_taxonprofile_taxon_text(text_dict, glossarized_locale, app_locale)
1999
+
2000
+ localized_category['texts'][index]['shortText'] = localized_short_text
2001
+ localized_category['texts'][index]['longText'] = localized_long_text
2002
+
2003
+ localized_profile_json['categorizedTexts'][c_index] = localized_category
2004
+
2005
+ # localize seo, no glossarized locale
2006
+ localized_seo = localized_profile_json['seo'].copy()
2007
+ title = localized_seo['title']
2008
+ meta_description = localized_seo['metaDescription']
2009
+
2010
+ if title and title in app_locale:
2011
+ localized_seo = app_locale[title]
2012
+
2013
+ if meta_description and meta_description in app_locale:
2014
+ localized_seo['metaDescription'] = app_locale[meta_description]
2015
+
2016
+ localized_profile_json['seo'] = localized_seo
2017
+
2018
+ return localized_profile_json
1962
2019
 
1963
2020
  def _build_TaxonProfiles(self, app_generic_content):
1964
2021
 
@@ -1993,6 +2050,11 @@ class AppReleaseBuilder(AppBuilderBase):
1993
2050
 
1994
2051
  if not os.path.isdir(app_absolute_taxonprofiles_path):
1995
2052
  os.makedirs(app_absolute_taxonprofiles_path)
2053
+
2054
+ # morphotype paths
2055
+ app_relative_morphotype_profiles_folder = os.path.join(app_relative_taxonprofiles_folder, 'morphotypes')
2056
+ self.build_features[generic_content_type]['localizedMorphotypeFiles'] = {}
2057
+ app_absolute_morphotype_profiles_path = os.path.join(app_absolute_taxonprofiles_path, 'morphotypes')
1996
2058
 
1997
2059
 
1998
2060
  collected_taxa = taxon_profiles.collected_taxa(published_only=True)
@@ -2081,8 +2143,10 @@ class AppReleaseBuilder(AppBuilderBase):
2081
2143
  self.build_features[generic_content_type]['localizedFiles'] = {}
2082
2144
 
2083
2145
  for profile_taxon in active_collected_taxa:
2146
+
2147
+ morphotype = None
2084
2148
 
2085
- profile_json = jsonbuilder.build_taxon_profile(profile_taxon,
2149
+ profile_json = jsonbuilder.build_taxon_profile(profile_taxon, morphotype,
2086
2150
  languages=self.meta_app.languages())
2087
2151
 
2088
2152
  if profile_json is not None:
@@ -2101,64 +2165,13 @@ class AppReleaseBuilder(AppBuilderBase):
2101
2165
  # localized taxon profiles for faster language load
2102
2166
  for language_code in self.meta_app.languages():
2103
2167
 
2104
- glossarized_locale_filepath = self._app_glossarized_locale_filepath(language_code)
2105
-
2106
- glossarized_locale = {}
2107
-
2108
- if os.path.isfile(glossarized_locale_filepath):
2109
- with open(glossarized_locale_filepath, 'r') as f:
2110
- glossarized_locale = json.loads(f.read())
2168
+ localized_profile_json = self.get_localized_taxon_profile(profile_json, language_code)
2111
2169
 
2112
2170
  relative_localized_taxonprofiles_folder = os.path.join(
2113
2171
  app_relative_taxonprofiles_folder, language_code)
2114
2172
 
2115
2173
  if language_code not in self.build_features[generic_content_type]['localizedFiles']:
2116
2174
  self.build_features[generic_content_type]['localizedFiles'][language_code] = '/{0}'.format(relative_localized_taxonprofiles_folder)
2117
-
2118
- app_locale = self.meta_app.localizations[language_code]
2119
-
2120
- localized_profile_json = profile_json.copy()
2121
-
2122
- localized_short_profile = self.get_localized_taxonprofile_text(localized_profile_json['shortProfile'], glossarized_locale, app_locale)
2123
- localized_profile_json['shortProfile'] = localized_short_profile
2124
-
2125
- for index, text_dict in enumerate(profile_json['texts'], 0):
2126
-
2127
- localized_short_text, localized_long_text = self.get_localized_taxonprofile_taxon_text(text_dict, glossarized_locale, app_locale)
2128
-
2129
- localized_profile_json['texts'][index]['shortText'] = localized_short_text
2130
- localized_profile_json['texts'][index]['longText'] = localized_long_text
2131
-
2132
-
2133
- for c_index, category in enumerate(profile_json['categorizedTexts'], 0):
2134
-
2135
- localized_category = category.copy()
2136
-
2137
- localized_category_name = self.get_localized_taxonprofile_text(category['category'], glossarized_locale, app_locale)
2138
-
2139
- if localized_category:
2140
- localized_category['category'] = localized_category_name
2141
-
2142
- for index, text_dict in enumerate(category['texts'], 0):
2143
- localized_short_text, localized_long_text = self.get_localized_taxonprofile_taxon_text(text_dict, glossarized_locale, app_locale)
2144
-
2145
- localized_category['texts'][index]['shortText'] = localized_short_text
2146
- localized_category['texts'][index]['longText'] = localized_long_text
2147
-
2148
- localized_profile_json['categorizedTexts'][c_index] = localized_category
2149
-
2150
- # localize seo, no glossarized locale
2151
- localized_seo = localized_profile_json['seo'].copy()
2152
- title = localized_seo['title']
2153
- meta_description = localized_seo['metaDescription']
2154
-
2155
- if title and title in app_locale:
2156
- localized_seo = app_locale[title]
2157
-
2158
- if meta_description and meta_description in app_locale:
2159
- localized_seo['metaDescription'] = app_locale[meta_description]
2160
-
2161
- localized_profile_json['seo'] = localized_seo
2162
2175
 
2163
2176
  absolute_localized_taxonprofiles_folder = os.path.join(
2164
2177
  app_absolute_taxonprofiles_path, language_code)
@@ -2177,7 +2190,52 @@ class AppReleaseBuilder(AppBuilderBase):
2177
2190
 
2178
2191
  with open(localized_profile_filepath, 'w', encoding='utf-8') as f:
2179
2192
  json.dump(localized_profile_json, f, indent=4, ensure_ascii=False)
2193
+
2194
+ # build morphotype profiles
2195
+ morphotypes = []
2196
+ taxon_profile = TaxonProfile.objects.filter(taxon_profiles=taxon_profiles,
2197
+ taxon_source=profile_taxon.taxon_source, taxon_latname=profile_taxon.taxon_latname,
2198
+ taxon_author=profile_taxon.taxon_author).first()
2199
+
2200
+ if taxon_profile and taxon_profile.morphotype_profiles:
2201
+ morphotypes = taxon_profile.morphotype_profiles.values_list('morphotype', flat=True)
2180
2202
 
2203
+
2204
+ for morphotype in morphotypes:
2205
+
2206
+ morphotype_profile_json = jsonbuilder.build_taxon_profile(profile_taxon, morphotype,
2207
+ languages=self.meta_app.languages())
2208
+
2209
+ if morphotype_profile_json is not None:
2210
+
2211
+ for language_code in self.meta_app.languages():
2212
+
2213
+ localized_profile_json = self.get_localized_taxon_profile(morphotype_profile_json, language_code)
2214
+
2215
+ relative_localized_morphotype_profiles_folder = os.path.join(
2216
+ app_relative_morphotype_profiles_folder, language_code)
2217
+
2218
+ if language_code not in self.build_features[generic_content_type]['localizedMorphotypeFiles']:
2219
+ self.build_features[generic_content_type]['localizedMorphotypeFiles'][language_code] = '/{0}'.format(relative_localized_morphotype_profiles_folder)
2220
+
2221
+
2222
+ absolute_localized_morphotype_profiles_folder = os.path.join(
2223
+ app_absolute_morphotype_profiles_path, language_code)
2224
+
2225
+ if not os.path.isdir(absolute_localized_morphotype_profiles_folder):
2226
+ os.makedirs(absolute_localized_morphotype_profiles_folder)
2227
+
2228
+ localized_source_folder = os.path.join(absolute_localized_morphotype_profiles_folder,
2229
+ profile_taxon.taxon_source)
2230
+
2231
+ if not os.path.isdir(localized_source_folder):
2232
+ os.makedirs(localized_source_folder)
2233
+
2234
+ localized_morphotype_profile_filepath = os.path.join(localized_source_folder,
2235
+ '{0}_{1}.json'.format(profile_taxon.name_uuid, morphotype))
2236
+
2237
+ with open(localized_morphotype_profile_filepath, 'w', encoding='utf-8') as f:
2238
+ json.dump(morphotype_profile_json, f, indent=4, ensure_ascii=False)
2181
2239
 
2182
2240
 
2183
2241
  # build search index and registry
@@ -52,7 +52,7 @@ class TaxonProfilesJSONBuilder(JSONBuilder):
52
52
  installed_taxonomic_sources = [s[0] for s in settings.TAXONOMY_DATABASES]
53
53
  return installed_taxonomic_sources
54
54
 
55
-
55
+ '''
56
56
  def collect_node_traits(self, node):
57
57
 
58
58
  #self.app_release_builder.logger.info('collecting node traits for {0}'.format(node.meta_node.name))
@@ -95,6 +95,7 @@ class TaxonProfilesJSONBuilder(JSONBuilder):
95
95
  #self.app_release_builder.logger.info('finished collecting')
96
96
 
97
97
  return node_traits
98
+ '''
98
99
 
99
100
 
100
101
  def get_vernacular_name_from_nature_guides(self, lazy_taxon):
@@ -109,7 +110,7 @@ class TaxonProfilesJSONBuilder(JSONBuilder):
109
110
  return template_contents
110
111
 
111
112
  # languages is for the vernacular name only, the rest are keys for translation
112
- def build_taxon_profile(self, profile_taxon, languages):
113
+ def build_taxon_profile(self, profile_taxon, morphotype, languages):
113
114
 
114
115
  lazy_taxon = LazyTaxon(instance=profile_taxon)
115
116
 
@@ -118,7 +119,7 @@ class TaxonProfilesJSONBuilder(JSONBuilder):
118
119
  # get the profile
119
120
  db_profile = TaxonProfile.objects.filter(taxon_profiles=self.generic_content,
120
121
  taxon_source=profile_taxon.taxon_source, taxon_latname=profile_taxon.taxon_latname,
121
- taxon_author=profile_taxon.taxon_author).first()
122
+ taxon_author=profile_taxon.taxon_author, morphotype=morphotype).first()
122
123
 
123
124
 
124
125
  taxon_profile_json = self.app_release_builder.taxa_builder.serialize_taxon_extended(lazy_taxon)
@@ -126,8 +127,9 @@ class TaxonProfilesJSONBuilder(JSONBuilder):
126
127
  # if the taxonomic db got updated, still use the old taxon latname and author here
127
128
  taxon_profile_json['taxonLatname'] = lazy_taxon.taxon_latname
128
129
  taxon_profile_json['taxonAuthor'] = lazy_taxon.taxon_author
130
+ images = []
129
131
 
130
- images = self.app_release_builder.taxa_builder.serialize_taxon_images(lazy_taxon)
132
+ images = self.app_release_builder.taxa_builder.serialize_taxon_images(lazy_taxon, morphotype=morphotype)
131
133
 
132
134
  is_featured = False
133
135
  if db_profile:
@@ -139,6 +141,7 @@ class TaxonProfilesJSONBuilder(JSONBuilder):
139
141
 
140
142
  taxon_profile_json.update({
141
143
  'taxonProfileId': db_profile.id if db_profile else None,
144
+ 'morphotype': db_profile.morphotype if db_profile else None,
142
145
  'vernacular' : {},
143
146
  'allVernacularNames' : {},
144
147
  'nodeNames' : [], # if the taxon occurs in a nature guide, primary_language only
@@ -151,7 +154,7 @@ class TaxonProfilesJSONBuilder(JSONBuilder):
151
154
  'synonyms' : [],
152
155
  'templateContents' : [],
153
156
  'genericForms' : self.collect_usable_generic_forms(profile_taxon),
154
- 'taxonRelationships': self.collect_taxon_relationships(profile_taxon),
157
+ 'taxonRelationships': self.collect_taxon_relationships(profile_taxon) if not morphotype else [],
155
158
  'tags' : [],
156
159
  'seo': {
157
160
  'title': None,
@@ -162,14 +165,15 @@ class TaxonProfilesJSONBuilder(JSONBuilder):
162
165
  'isFeatured': is_featured,
163
166
  })
164
167
 
165
- synonyms = profile_taxon.synonyms()
166
- for synonym in synonyms:
167
- synonym_entry = {
168
- 'taxonLatname' : synonym.taxon_latname,
169
- 'taxonAuthor' : synonym.taxon_author,
170
- }
168
+ if not morphotype:
169
+ synonyms = profile_taxon.synonyms()
170
+ for synonym in synonyms:
171
+ synonym_entry = {
172
+ 'taxonLatname' : synonym.taxon_latname,
173
+ 'taxonAuthor' : synonym.taxon_author,
174
+ }
171
175
 
172
- taxon_profile_json['synonyms'].append(synonym_entry)
176
+ taxon_profile_json['synonyms'].append(synonym_entry)
173
177
 
174
178
  for language_code in languages:
175
179
 
@@ -186,6 +190,24 @@ class TaxonProfilesJSONBuilder(JSONBuilder):
186
190
 
187
191
  # template contents
188
192
  taxon_profile_json['templateContents'] = self.get_taxon_profile_template_content_links(profile_taxon, language_code)
193
+
194
+ # respect additional languages for vernacular names as defined in taxon profiles options
195
+ include_vernacular_names_languages_option = self.generic_content.get_option(self.meta_app,
196
+ 'include_vernacular_names_languages')
197
+ if include_vernacular_names_languages_option:
198
+ additional_languages = [lang.strip() for lang in include_vernacular_names_languages_option.split(',') if lang.strip()]
199
+ for language_code in additional_languages:
200
+ if language_code not in languages:
201
+ preferred_vernacular_name = lazy_taxon.get_preferred_vernacular_name(language_code,
202
+ self.meta_app)
203
+
204
+ taxon_profile_json['vernacular'][language_code] = preferred_vernacular_name
205
+
206
+ all_vernacular_names = profile_taxon.all_vernacular_names(self.meta_app,
207
+ languages=[language_code])
208
+
209
+ names_list = [name_reference['name'] for name_reference in all_vernacular_names]
210
+ taxon_profile_json['allVernacularNames'][language_code] = names_list
189
211
 
190
212
  # get taxon_profile_images
191
213
  if db_profile:
@@ -207,7 +229,7 @@ class TaxonProfilesJSONBuilder(JSONBuilder):
207
229
  # get information (traits, node_names) from nature guides if possible
208
230
  # collect node images
209
231
  # only use occurrences in nature guides of this app
210
- node_occurrences = self.app_release_builder.taxa_builder.get_nature_guide_occurrences(lazy_taxon)
232
+ node_occurrences = self.app_release_builder.taxa_builder.get_nature_guide_occurrences(lazy_taxon, morphotype=morphotype)
211
233
 
212
234
  # collect traits of upward branch in tree (higher taxa)
213
235
  parent_nuids = set([])
@@ -287,7 +309,8 @@ class TaxonProfilesJSONBuilder(JSONBuilder):
287
309
 
288
310
  if db_profile:
289
311
 
290
- taxon_profile_json['morphotypeProfiles'] = self.collect_morphotype_profiles(db_profile, languages)
312
+ if not morphotype:
313
+ taxon_profile_json['morphotypeProfiles'] = self.collect_morphotype_profiles(db_profile, languages)
291
314
 
292
315
  taxon_profile_json['shortProfile'] = db_profile.short_profile
293
316
 
@@ -469,7 +492,7 @@ class TaxonProfilesJSONBuilder(JSONBuilder):
469
492
  'taxonProfileId': morphotype.id,
470
493
  'parentTaxonProfileId': taxon_profile.id,
471
494
  'morphotype': morphotype.morphotype,
472
- 'taxon': self.app_release_builder.taxa_builder.serialize_taxon(lazy_taxon),
495
+ 'taxon': self.app_release_builder.taxa_builder.serialize_taxon_extended(lazy_taxon),
473
496
  'vernacular' : {},
474
497
  'image': image_entry,
475
498
  }
@@ -41,8 +41,7 @@ class TaxaBuilder(ContentImagesJSONBuilder):
41
41
 
42
42
  def serialize_taxon(self, lazy_taxon):
43
43
  taxon_serializer = TaxonSerializer(lazy_taxon, self)
44
- return taxon_serializer.serialize()
45
-
44
+ return taxon_serializer.serialize()
46
45
 
47
46
  def serialize_taxon_extended(self, lazy_taxon):
48
47
  taxon_serializer = TaxonSerializer(lazy_taxon, self)
@@ -66,9 +65,9 @@ class TaxaBuilder(ContentImagesJSONBuilder):
66
65
  accepted_name_uuid)
67
66
 
68
67
 
69
- def serialize_taxon_images(self, lazy_taxon):
68
+ def serialize_taxon_images(self, lazy_taxon, morphotype=None):
70
69
  taxon_serializer = TaxonSerializer(lazy_taxon, self)
71
- return taxon_serializer.serialize_images()
70
+ return taxon_serializer.serialize_images(morphotype=morphotype)
72
71
 
73
72
 
74
73
  def get_nature_guide_ids(self):
@@ -80,7 +79,7 @@ class TaxaBuilder(ContentImagesJSONBuilder):
80
79
  return self.nature_guide_ids
81
80
 
82
81
 
83
- def get_nature_guide_occurrences(self, lazy_taxon):
82
+ def get_nature_guide_occurrences(self, lazy_taxon, morphotype=None):
84
83
  nature_guide_ids = self.get_nature_guide_ids()
85
84
 
86
85
  if lazy_taxon.taxon_source in self.installed_taxonomic_sources:
@@ -88,6 +87,7 @@ class TaxaBuilder(ContentImagesJSONBuilder):
88
87
  meta_nodes = MetaNode.objects.filter(
89
88
  nature_guide_id__in=nature_guide_ids,
90
89
  node_type='result',
90
+ morphotype=morphotype,
91
91
  name_uuid = lazy_taxon.name_uuid).values_list('pk', flat=True)
92
92
 
93
93
  node_occurrences = NatureGuidesTaxonTree.objects.filter(nature_guide_id__in=nature_guide_ids,
@@ -211,12 +211,13 @@ class TaxonSerializer:
211
211
 
212
212
  return taxon_json_copy
213
213
 
214
- def get_taxon_profile(self):
214
+ def get_taxon_profile(self, morphotype=None):
215
215
  taxon_profile = None
216
216
 
217
217
  taxon_profile_qry = TaxonProfile.objects.filter(
218
218
  taxon_profiles=self.taxa_builder.taxon_profiles,
219
- name_uuid=self.lazy_taxon.name_uuid).first()
219
+ name_uuid=self.lazy_taxon.name_uuid,
220
+ morphotype=morphotype).first()
220
221
 
221
222
  if taxon_profile_qry and taxon_profile_qry.publication_status != 'draft':
222
223
  taxon_profile = taxon_profile_qry
@@ -224,19 +225,23 @@ class TaxonSerializer:
224
225
  return taxon_profile
225
226
 
226
227
 
227
- def serialize_images(self):
228
+ def serialize_images(self, morphotype=None):
228
229
 
229
230
  name_uuid_str = str(self.lazy_taxon.name_uuid)
231
+ cache_key=name_uuid_str
232
+
233
+ if morphotype:
234
+ cache_key = name_uuid_str + '_' + morphotype
230
235
 
231
- if name_uuid_str in self.taxa_builder.cache['images']:
232
- taxon_images = self.taxa_builder.cache['images'][name_uuid_str]
236
+ if cache_key in self.taxa_builder.cache['images']:
237
+ taxon_images = self.taxa_builder.cache['images'][cache_key]
233
238
 
234
239
  else:
235
240
 
236
241
  collected_content_image_ids = set([])
237
242
  collected_image_store_ids = set([])
238
243
 
239
- taxon_profile = self.get_taxon_profile()
244
+ taxon_profile = self.get_taxon_profile(morphotype=morphotype)
240
245
 
241
246
  taxon_images = {
242
247
  'primary': None,
@@ -272,8 +277,9 @@ class TaxonSerializer:
272
277
  taxon_images['primary'] = image_entry
273
278
 
274
279
 
280
+
275
281
  # images from nature guides
276
- node_occurrences = self.taxa_builder.get_nature_guide_occurrences(self.lazy_taxon)
282
+ node_occurrences = self.taxa_builder.get_nature_guide_occurrences(self.lazy_taxon, morphotype=morphotype)
277
283
 
278
284
  for node in node_occurrences:
279
285
 
@@ -297,30 +303,31 @@ class TaxonSerializer:
297
303
 
298
304
  if taxon_images['primary'] == None:
299
305
  taxon_images['primary'] = image_entry
300
-
306
+
301
307
 
302
308
  # get taxonomic images
303
- content_images_taxon = ContentImage.objects.filter(image_store__taxon_source=self.lazy_taxon.taxon_source,
304
- image_store__taxon_latname=self.lazy_taxon.taxon_latname,
305
- image_store__taxon_author=self.lazy_taxon.taxon_author).exclude(
306
- pk__in=list(collected_content_image_ids))
309
+ if not morphotype:
310
+ content_images_taxon = ContentImage.objects.filter(image_store__taxon_source=self.lazy_taxon.taxon_source,
311
+ image_store__taxon_latname=self.lazy_taxon.taxon_latname,
312
+ image_store__taxon_author=self.lazy_taxon.taxon_author).exclude(
313
+ pk__in=list(collected_content_image_ids))
307
314
 
308
- #self.app_release_builder.logger.info('Found {0} images for {1}'.format(taxon_images.count(), profile_taxon.taxon_latname))
315
+ #self.app_release_builder.logger.info('Found {0} images for {1}'.format(taxon_images.count(), profile_taxon.taxon_latname))
309
316
 
310
- for taxon_image in content_images_taxon:
317
+ for taxon_image in content_images_taxon:
311
318
 
312
- if taxon_image is not None and taxon_image.id not in collected_content_image_ids and taxon_image.image_store.id not in collected_image_store_ids:
319
+ if taxon_image is not None and taxon_image.id not in collected_content_image_ids and taxon_image.image_store.id not in collected_image_store_ids:
313
320
 
314
- image_entry = self.taxa_builder.get_image_json(taxon_image)
315
- taxon_images['taxonImages'].append(image_entry)
316
-
317
- if taxon_images['primary'] == None:
318
- taxon_images['primary'] = image_entry
321
+ image_entry = self.taxa_builder.get_image_json(taxon_image)
322
+ taxon_images['taxonImages'].append(image_entry)
323
+
324
+ if taxon_images['primary'] == None:
325
+ taxon_images['primary'] = image_entry
319
326
 
320
- collected_content_image_ids.add(taxon_image.id)
321
- collected_image_store_ids.add(taxon_image.image_store.id)
327
+ collected_content_image_ids.add(taxon_image.id)
328
+ collected_image_store_ids.add(taxon_image.image_store.id)
322
329
 
323
- self.taxa_builder.cache['images'][name_uuid_str] = taxon_images
330
+ self.taxa_builder.cache['images'][cache_key] = taxon_images
324
331
 
325
332
  taxon_images_copy = copy.deepcopy(taxon_images)
326
333
 
@@ -29,7 +29,7 @@
29
29
  <div class="mt-5">
30
30
  <h3>{% trans 'Taxon Profile' %}</h3>
31
31
  {% if taxon_profile %}
32
- <a href="{% url 'manage_taxon_profile' meta_app.id taxon_profiles.id taxon.taxon_source taxon.name_uuid %}">{{ taxon }}</a>
32
+ <a href="{% url 'manage_taxon_profile' meta_app.id taxon_profile.id %}">{{ taxon }}</a>
33
33
  {% else %}
34
34
  {% trans 'This taxon does not have a taxon profile' %}
35
35
  {% endif %}
@@ -29,6 +29,9 @@ class TaxonProfilesOptionsForm(GenericFormChoicesMixin, GenericContentOptionsFor
29
29
 
30
30
  enable_taxonomic_navigation = forms.BooleanField(required=False, label=_('Enable Taxonomic Navigation'))
31
31
 
32
+ include_vernacular_names_languages = forms.CharField(required=False, label=_('Include Vernacular Names Languages'),
33
+ help_text=_('A comma-separated list of language codes (e.g. "en,de,fr") to include vernacular names from. Leave empty to include all available languages.'))
34
+
32
35
  version = forms.CharField(help_text=_('You can manually set you own version here. This will not affect the automated versioning.'), required=False)
33
36
 
34
37
 
@@ -94,8 +97,6 @@ class ManageTaxonTextsForm(LocalizeableForm):
94
97
 
95
98
  self.layoutable_simple_fields = []
96
99
 
97
- self.has_categories = False
98
-
99
100
  super().__init__(*args, **kwargs)
100
101
 
101
102
  categories = [None] + list(TaxonTextTypeCategory.objects.filter(taxon_profiles=taxon_profiles))
@@ -105,34 +106,12 @@ class ManageTaxonTextsForm(LocalizeableForm):
105
106
  if taxon_profile.taxon_text_set:
106
107
  allowed_text_types = taxon_profile.taxon_text_set.text_types.values_list('pk', flat=True)
107
108
 
108
- if len(categories) > 1:
109
- self.has_categories = True
110
-
111
- for category_index, category in enumerate(categories, 1):
112
-
113
- types = TaxonTextType.objects.filter(taxon_profiles=taxon_profiles, category=category, pk__in=allowed_text_types).order_by('category', 'position')
114
-
115
- category_label = 'uncategorized'
116
- if category:
117
- category_label = category.name
118
-
119
- category_helper_field = forms.CharField(widget=forms.HiddenInput(), label=category_label, required=False)
120
- category_helper_field.category = category
121
- category_helper_field.is_category_field = True
122
- category_helper_field.text_type_count = types.count()
123
- category_helper_field.is_first_category = False
124
- category_helper_field.is_last = False
125
-
126
- if category_index == 2:
127
- category_helper_field.is_first_category = True
128
-
129
- if not types:
130
- category_helper_field.is_last = True
109
+ for category in categories:
131
110
 
132
- self.fields[category_label] = category_helper_field
111
+ types = TaxonTextType.objects.filter(taxon_profiles=taxon_profiles, category=category, pk__in=allowed_text_types).order_by('category', 'position')
133
112
 
134
113
  for field_index, text_type in enumerate(types, 1):
135
-
114
+
136
115
  short_text_field_name = text_type.text_type
137
116
 
138
117
  self.text_type_map[short_text_field_name] = text_type
@@ -143,14 +122,17 @@ class ManageTaxonTextsForm(LocalizeableForm):
143
122
  required=False, label=short_text_field_label, validators=[json_compatible])
144
123
  short_text_field.taxon_text_type = text_type
145
124
  short_text_field.is_short_version = True
146
- short_text_field.is_last = False
147
125
  short_text_field.taxon_text = None
126
+ short_text_field.category = None
148
127
 
149
128
  self.fields[short_text_field_name] = short_text_field
150
129
  self.localizeable_fields.append(short_text_field_name)
151
130
  self.fields[short_text_field_name].language = self.language
152
131
  self.layoutable_simple_fields.append(short_text_field_name)
153
132
 
133
+ if field_index == 1:
134
+ short_text_field.category = category
135
+
154
136
 
155
137
  if settings.APP_KIT_ENABLE_TAXON_PROFILES_LONG_TEXTS == True:
156
138
  long_text_field_name = self.get_long_text_form_field_name(text_type)
@@ -162,19 +144,12 @@ class ManageTaxonTextsForm(LocalizeableForm):
162
144
  required=False, label=long_text_field_label, validators=[json_compatible])
163
145
  long_text_field.taxon_text_type = text_type
164
146
  long_text_field.is_short_version = False
165
- long_text_field.is_last = False
166
147
 
167
148
  self.fields[long_text_field_name] = long_text_field
168
149
  self.localizeable_fields.append(long_text_field_name)
169
150
  self.fields[long_text_field_name].language = self.language
170
151
  self.layoutable_simple_fields.append(long_text_field_name)
171
-
172
- if field_index == len(types):
173
- if settings.APP_KIT_ENABLE_TAXON_PROFILES_LONG_TEXTS == True:
174
- long_text_field.is_last = True
175
- else:
176
- short_text_field.is_last = True
177
-
152
+
178
153
  if taxon_profile:
179
154
  content = TaxonText.objects.filter(taxon_text_type=text_type,
180
155
  taxon_profile=taxon_profile).first()
@@ -185,7 +160,7 @@ class ManageTaxonTextsForm(LocalizeableForm):
185
160
  if settings.APP_KIT_ENABLE_TAXON_PROFILES_LONG_TEXTS == True:
186
161
  long_text_field.initial = content.long_text
187
162
  long_text_field.taxon_text = content
188
-
163
+
189
164
 
190
165
  def get_long_text_form_field_name(self, text_type):
191
166
 
@@ -87,51 +87,44 @@ class TaxonProfiles(GenericContent):
87
87
  def get_primary_localization(self, meta_app=None):
88
88
  locale = super().get_primary_localization(meta_app)
89
89
 
90
- taxon_query = TaxonProfile.objects.filter(taxon_profiles=self)
91
- taxa = LazyTaxonList(queryset=taxon_query)
92
- for lazy_taxon in taxa:
93
-
94
- taxon_query = {
95
- 'taxon_source' : lazy_taxon.taxon_source,
96
- 'taxon_latname' : lazy_taxon.taxon_latname,
97
- 'taxon_author' : lazy_taxon.taxon_author,
98
- }
99
-
100
- taxon_profile = TaxonProfile.objects.filter(taxon_profiles=self, **taxon_query).first()
101
-
102
- if taxon_profile:
90
+ all_taxon_profiles = TaxonProfile.objects.filter(taxon_profiles=self)
91
+ for taxon_profile in all_taxon_profiles:
92
+
93
+ if taxon_profile.publication_status == 'draft':
94
+ continue
103
95
 
104
- if taxon_profile.morphotype:
105
- locale[taxon_profile.morphotype] = taxon_profile.morphotype
96
+ if taxon_profile.morphotype:
97
+ locale[taxon_profile.morphotype] = taxon_profile.morphotype
106
98
 
107
- for text in taxon_profile.texts():
99
+ for text in taxon_profile.texts():
108
100
 
109
- # text_type_key = 'taxon_text_{0}'.format(text.taxon_text_type.id)
110
- # short: use name as key (-> no duplicates in translation matrix)
111
- text_type_key = text.taxon_text_type.text_type
112
- locale[text_type_key] = text.taxon_text_type.text_type
113
-
114
- # text.text is a bad key, because if text.text changes, the translation is gone
115
- # text.text are long texts, so use a different key which survives text changes
116
- # locale[text.text] = text.text
101
+ # text_type_key = 'taxon_text_{0}'.format(text.taxon_text_type.id)
102
+ # short: use name as key (-> no duplicates in translation matrix)
103
+ text_type_key = text.taxon_text_type.text_type
104
+ locale[text_type_key] = text.taxon_text_type.text_type
105
+
106
+ # text.text is a bad key, because if text.text changes, the translation is gone
107
+ # text.text are long texts, so use a different key which survives text changes
108
+ # locale[text.text] = text.text
117
109
 
118
- short_text_key = self.get_short_text_key(text)
110
+ short_text_key = self.get_short_text_key(text)
119
111
 
120
- if text.text:
121
- locale[short_text_key] = text.text
112
+ if text.text:
113
+ locale[short_text_key] = text.text
122
114
 
123
- long_text_key = self.get_long_text_key(text)
115
+ long_text_key = self.get_long_text_key(text)
124
116
 
125
- if text.long_text:
126
- locale[long_text_key] = text.long_text
117
+ if text.long_text:
118
+ locale[long_text_key] = text.long_text
127
119
 
128
- content_images_primary_localization = taxon_profile.get_content_images_primary_localization()
129
- locale.update(content_images_primary_localization)
120
+ content_images_primary_localization = taxon_profile.get_content_images_primary_localization()
121
+ locale.update(content_images_primary_localization)
122
+
123
+ short_profile = taxon_profile.short_profile
124
+ if short_profile:
125
+ locale[short_profile] = short_profile
130
126
 
131
- short_profile = taxon_profile.short_profile
132
- if short_profile:
133
- locale[short_profile] = short_profile
134
-
127
+
135
128
  navigation = TaxonProfilesNavigation.objects.filter(taxon_profiles=self).first()
136
129
 
137
130
  if navigation:
@@ -32,7 +32,7 @@
32
32
  <script>
33
33
  var modal = $("#Modal");
34
34
  modal.modal("hide");
35
- window.location = "{% url 'manage_taxon_profile' meta_app.id taxon_profiles.id taxon.taxon_source taxon.name_uuid %}";
35
+ window.location = "{% url 'manage_taxon_profile' meta_app.id taxon_profile.id %}";
36
36
  </script>
37
37
  {% endif %}
38
38
  {% endblock %}
@@ -1,70 +1,51 @@
1
1
  {% load i18n static localcosmos_tags %}
2
2
  {% if text_types %}
3
- <form id="taxon-text-types-form" method="POST" action="{% url 'manage_taxon_profile' meta_app.id taxon_profiles.id taxon.taxon_source taxon.name_uuid %}">{% csrf_token %}
3
+ <form id="taxon-text-types-form" method="POST" action="{% url 'manage_taxon_profile' meta_app.id taxon_profile.id %}"
4
+ >{% csrf_token %}
4
5
  <div id="text-types-form-fields">
5
6
  {% for field in form %}
6
- {% if field.field.is_category_field %}
7
- {% if field.field.is_first_category %}
8
- <div id="order-ctype-{{ field.field.category|ctype_id }}-container" class="object-order-flex mb-3">
9
- {% endif %}
10
- <div id="order-ctype-{{ text_type_content_type.id }}{% if field.field.category %}-{{ field.field.category.id }}{% endif %}-container" {% if field.field.category %}data-object-id="{{ field.field.category.id }}"{% endif %} class="text-type-category-container">
7
+ {% if field.field.category %}
8
+ <h2>
9
+ {{ field.field.category }}
10
+ </h2>
11
11
  {% endif %}
12
- <div {% if field.name in form.text_type_map %}id="ctype-{{ field.field.taxon_text_type|ctype_id }}-{{ field.field.taxon_text_type.id }}" data-object-id="{{ field.field.taxon_text_type.id }}" {% endif %} class="row">
13
- <div class="col-12">
14
- {% if field.is_hidden %}
15
- {% if field.field.category %}
16
- <h2>
17
- {{ field.field.category }}
18
- </h2>
12
+ <div class="row">
13
+ <div class="col-12">
19
14
 
20
- {% if not field.field.text_type_count %}
21
- {% if taxon_profile.taxon_text_set %}
22
- <div class="alert alert-info">{% trans 'The selected Text Set does not include any text types for this category.' %}</div>
23
- {% else %}
24
- <div class="alert alert-info">{% trans 'No text types for this this category yet.' %}</div>
25
- {% endif %}
26
- {% endif %}
27
- {% else %}
15
+ {% if field.is_hidden %}
16
+ {{ field }}
17
+ {% else %}
18
+ <div class="form-group {% if field.errors %}has-error{% endif %}">
19
+
20
+ <h4>
21
+ {{ field.label }}
22
+ {% if field.field.taxon_text_type %}
23
+ {% if show_text_length_badges %}{% if field.field.is_short_version %}<span class="badge badge-info">{% trans 'short version' %}</span>{% else %}<span class="badge badge-primary">{% trans 'long version' %}</span>{% endif %} {% endif %}
28
24
  {% endif %}
29
- {{ field }}
30
- {% else %}
31
- <div class="form-group {% if field.errors %}has-error{% endif %}">
25
+ </h4>
32
26
 
33
- <h4>
34
- {{ field.label }}
35
- {% if field.field.taxon_text_type %}
36
- {% if show_text_length_badges %}{% if field.field.is_short_version %}<span class="badge badge-info">{% trans 'short version' %}</span>{% else %}<span class="badge badge-primary">{% trans 'long version' %}</span>{% endif %} {% endif %}
37
- {% endif %}
38
- </h4>
27
+ {% if field.field.language %}
28
+ <img src="{% static 'localcosmos_server/images/countries/' %}{{ field.field.language }}.gif" /> {{ field.field.language }}
29
+ {% endif %}
39
30
 
40
- {% if field.field.language %}
41
- <img src="{% static 'localcosmos_server/images/countries/' %}{{ field.field.language }}.gif" /> {{ field.field.language }}
42
- {% endif %}
31
+ {{ field }}
32
+ {% if field.help_text %}
33
+ <small class="form-text text-muted">{{ field.help_text }}</small>
34
+ {% endif %}
35
+ </div>
43
36
 
44
- {{ field }}
45
- {% if field.help_text %}
46
- <small class="form-text text-muted">{{ field.help_text }}</small>
47
- {% endif %}
37
+ {% if field.field.taxon_text and field.field.is_short_version %}
38
+ {% with content_instance=field.field.taxon_text %}
39
+ <div id="content-images-list-{{ content_instance|ctype_id }}-{{ content_instance.id }}" class="taxon-text-images-container">
40
+ {% include 'app_kit/ajax/content_images_list.html' %}
48
41
  </div>
49
-
50
- {% if field.field.taxon_text and field.field.is_short_version %}
51
- {% with content_instance=field.field.taxon_text %}
52
- <div id="content-images-list-{{ content_instance|ctype_id }}-{{ content_instance.id }}" class="taxon-text-images-container">
53
- {% include 'app_kit/ajax/content_images_list.html' %}
54
- </div>
55
- {% endwith %}
56
- {% endif %}
57
- <br><br>
58
- {% endif %}
59
- </div>
60
- </div>
61
- {% if field.field.is_last %}
42
+ {% endwith %}
43
+ {% endif %}
44
+ <br><br>
45
+ {% endif %}
62
46
  </div>
63
- {% endif %}
47
+ </div>
64
48
  {% endfor %}
65
- {% if form.has_categories %}
66
- <!--</div>-->
67
- {% endif %}
68
49
  </div>
69
50
 
70
51
  <div class="row">
@@ -23,7 +23,8 @@
23
23
  {% if success %}
24
24
  <script>
25
25
  {% if created %}
26
- window.location.href = "{% url 'manage_taxon_profile' meta_app.id taxon_profiles.id taxon_profile.taxon.taxon_source taxon_profile.taxon.name_uuid taxon_profile.morphotype %}";
26
+ // taxon_profile is the created morphotype profile
27
+ window.location.href = "{% url 'manage_taxon_profile' meta_app.id taxon_profile.id %}";
27
28
  {% else %}
28
29
  // Reload the page to show the updated morphotype
29
30
  $('#Modal').modal('hide');
@@ -7,7 +7,7 @@
7
7
  {% if meta_node.taxon %}
8
8
  {% get_taxon_profile meta_app meta_node.taxon as profile %}
9
9
  {% if profile %}
10
- <a href="{% url 'manage_taxon_profile' meta_app.id generic_content.id profile.taxon_source profile.name_uuid %}">
10
+ <a href="{% url 'manage_taxon_profile' meta_app.id profile.id %}">
11
11
  {{ meta_node.name }} <i>{{ meta_node.taxon_latname }} {{ meta_node.taxon_author }}</i>
12
12
  </a>
13
13
  {% if profile.publication_status == 'draft' %}
@@ -23,7 +23,7 @@
23
23
  {% get_nature_guide_taxon meta_node nature_guide as taxon %}
24
24
  {% get_taxon_profile meta_app taxon as non_taxon_profile %}
25
25
  {% if non_taxon_profile %}
26
- <a href="{% url 'manage_taxon_profile' meta_app.id generic_content.id non_taxon_profile.taxon_source non_taxon_profile.name_uuid %}">
26
+ <a href="{% url 'manage_taxon_profile' meta_app.id non_taxon_profile.id %}">
27
27
  {{ meta_node.name }}
28
28
  </a>
29
29
  {% if non_taxon_profile.publication_status == 'draft' %}
@@ -3,7 +3,7 @@
3
3
  <ul>
4
4
  {% for profile in non_nature_guide_taxon_profiles %}
5
5
  <li>
6
- <a href="{% url 'manage_taxon_profile' meta_app.id generic_content.id profile.taxon_source profile.name_uuid %}">
6
+ <a href="{% url 'manage_taxon_profile' meta_app.id profile.id %}">
7
7
  <i>{{ profile.taxon_latname }} {{ profile.taxon_author }}</i>
8
8
  </a>
9
9
  {% if profile.publication_status == 'draft' %}
@@ -92,7 +92,7 @@
92
92
  </div>
93
93
  {% for duplicate in possible_duplicates %}
94
94
  <i>
95
- <a href="{% url 'manage_taxon_profile' meta_app.id taxon_profiles.id duplicate.taxon_source duplicate.name_uuid %}">{{ duplicate.taxon_latname }} {{ duplicate.taxon_author }}</a>
95
+ <a href="{% url 'manage_taxon_profile' meta_app.id duplicate.id %}">{{ duplicate.taxon_latname }} {{ duplicate.taxon_author }}</a>
96
96
  </i>
97
97
  {% endfor %}
98
98
  </div>
@@ -111,10 +111,10 @@
111
111
  </div>
112
112
  </div>
113
113
  {% endif %}
114
- {% if taxon_profile.morphotype %}
114
+ {% if taxon_profile.morphotype and taxon_profile.parent_profile %}
115
115
  <div class="row">
116
116
  <div class="col-12">
117
- {% trans 'This is a morphotype of:' %} <a href="{% url 'manage_taxon_profile' meta_app.id taxon_profiles.id taxon.taxon_source taxon.name_uuid %}">
117
+ {% trans 'This is a morphotype of:' %} <a href="{% url 'manage_taxon_profile' meta_app.id taxon_profile.parent_profile.id %}">
118
118
  {{ taxon }}
119
119
  </a>
120
120
  </div>
@@ -131,7 +131,7 @@
131
131
  {% if taxon_profile.morphotype_profiles %}
132
132
  {% for morphotype in taxon_profile.morphotype_profiles %}
133
133
  <div>
134
- <a href="{% url 'manage_taxon_profile' meta_app.id taxon_profiles.id taxon_profile.taxon.taxon_source taxon_profile.taxon.name_uuid morphotype.morphotype %}">
134
+ <a href="{% url 'manage_taxon_profile' meta_app.id morphotype.id %}">
135
135
  {{ morphotype.morphotype }}
136
136
  </a>
137
137
  </div>
@@ -10,6 +10,9 @@ urlpatterns = [
10
10
  views.CreateTaxonProfile.as_view(), name='create_taxon_profile'),
11
11
  path('manage-taxon-profile/<int:meta_app_id>/<int:taxon_profiles_id>/<str:taxon_source>/<uuid:name_uuid>/',
12
12
  views.ManageTaxonProfile.as_view(), name='manage_taxon_profile'),
13
+ # this should be the future wherever possible, as it is more robust (does not rely on taxon_source and name_uuid to be unchanged)
14
+ path('manage-taxon-profile/<int:meta_app_id>/<int:taxon_profile_id>/',
15
+ views.ManageTaxonProfile.as_view(), name='manage_taxon_profile'),
13
16
  path('delete-taxon-profile/<int:meta_app_id>/<int:pk>/',
14
17
  views.DeleteTaxonProfile.as_view(), name='delete_taxon_profile'),
15
18
  # morphotypes
@@ -298,16 +298,22 @@ class ManageTaxonProfile(CreateTaxonProfileMixin, MetaAppFormLanguageMixin, Form
298
298
 
299
299
  def set_taxon(self, request, **kwargs):
300
300
 
301
- self.taxon_profiles = TaxonProfiles.objects.get(pk=kwargs['taxon_profiles_id'])
302
-
303
- taxon_source = kwargs['taxon_source']
304
- name_uuid = kwargs['name_uuid']
301
+ if 'taxon_profile_id' in kwargs:
302
+ self.taxon_profile = TaxonProfile.objects.get(pk=kwargs['taxon_profile_id'])
303
+ self.taxon_profiles = self.taxon_profile.taxon_profiles
304
+
305
+ else:
305
306
 
306
- morphotype = kwargs.get('morphotype', None)
307
+ self.taxon_profiles = TaxonProfiles.objects.get(pk=kwargs['taxon_profiles_id'])
307
308
 
308
- self.taxon_profile = TaxonProfile.objects.get(taxon_profiles=self.taxon_profiles,
309
- taxon_source=taxon_source, name_uuid=name_uuid,
310
- morphotype=morphotype)
309
+ taxon_source = kwargs['taxon_source']
310
+ name_uuid = kwargs['name_uuid']
311
+
312
+ morphotype = kwargs.get('morphotype', None)
313
+
314
+ self.taxon_profile = TaxonProfile.objects.get(taxon_profiles=self.taxon_profiles,
315
+ taxon_source=taxon_source, name_uuid=name_uuid,
316
+ morphotype=morphotype)
311
317
 
312
318
  self.taxon = LazyTaxon(instance=self.taxon_profile)
313
319
 
@@ -744,44 +750,50 @@ class CollectTaxonImages(MetaAppFormLanguageMixin, TemplateView):
744
750
  return images
745
751
 
746
752
  def get_taxon_images(self, exclude=[]):
747
- images = ContentImage.objects.filter(image_store__taxon_source=self.taxon.taxon_source,
748
- image_store__taxon_latname=self.taxon.taxon_latname).exclude(pk__in=exclude)
753
+
754
+ images = []
755
+
756
+ if not self.taxon_profile.morphotype:
757
+ images = ContentImage.objects.filter(image_store__taxon_source=self.taxon.taxon_source,
758
+ image_store__taxon_latname=self.taxon.taxon_latname).exclude(pk__in=exclude)
749
759
 
750
760
  return images
751
761
 
752
762
  # images can be on MetNode or NatureGuidesTaxonTree
753
763
  def get_nature_guide_images(self, exclude=[]):
754
764
 
755
- meta_nodes = MetaNode.objects.filter(taxon_source=self.taxon.taxon_source,
756
- taxon_latname=self.taxon.taxon_latname, taxon_author=self.taxon.taxon_author, morphotype=self.morphotype)
757
-
758
765
  nature_guide_images = []
766
+
767
+ if not self.taxon_profile.morphotype:
768
+
769
+ meta_nodes = MetaNode.objects.filter(taxon_source=self.taxon.taxon_source,
770
+ taxon_latname=self.taxon.taxon_latname, taxon_author=self.taxon.taxon_author, morphotype=self.morphotype)
759
771
 
760
- if meta_nodes:
772
+ if meta_nodes:
761
773
 
762
- meta_node_ids = meta_nodes.values_list('id', flat=True)
774
+ meta_node_ids = meta_nodes.values_list('id', flat=True)
763
775
 
764
- meta_node_content_type = ContentType.objects.get_for_model(MetaNode)
765
- meta_node_images = ContentImage.objects.filter(content_type=meta_node_content_type,
766
- object_id__in=meta_node_ids).exclude(pk__in=exclude)
767
-
768
- exclude += list(meta_node_images.values_list('id', flat=True))
769
- nature_guide_images += list(meta_node_images)
776
+ meta_node_content_type = ContentType.objects.get_for_model(MetaNode)
777
+ meta_node_images = ContentImage.objects.filter(content_type=meta_node_content_type,
778
+ object_id__in=meta_node_ids).exclude(pk__in=exclude)
779
+
780
+ exclude += list(meta_node_images.values_list('id', flat=True))
781
+ nature_guide_images += list(meta_node_images)
770
782
 
771
-
772
- nodes = NatureGuidesTaxonTree.objects.filter(meta_node__taxon_source=self.taxon.taxon_source,
773
- meta_node__taxon_latname=self.taxon.taxon_latname,
774
- meta_node__taxon_author=self.taxon.taxon_author)
783
+
784
+ nodes = NatureGuidesTaxonTree.objects.filter(meta_node__taxon_source=self.taxon.taxon_source,
785
+ meta_node__taxon_latname=self.taxon.taxon_latname,
786
+ meta_node__taxon_author=self.taxon.taxon_author)
775
787
 
776
- if nodes:
788
+ if nodes:
777
789
 
778
- node_ids = nodes.values_list('id', flat=True)
790
+ node_ids = nodes.values_list('id', flat=True)
779
791
 
780
- node_content_type = ContentType.objects.get_for_model(NatureGuidesTaxonTree)
781
- node_images = ContentImage.objects.filter(content_type=node_content_type,
782
- object_id__in=node_ids).exclude(pk__in=exclude)
783
-
784
- nature_guide_images += list(node_images)
792
+ node_content_type = ContentType.objects.get_for_model(NatureGuidesTaxonTree)
793
+ node_images = ContentImage.objects.filter(content_type=node_content_type,
794
+ object_id__in=node_ids).exclude(pk__in=exclude)
795
+
796
+ nature_guide_images += list(node_images)
785
797
 
786
798
 
787
799
  return nature_guide_images
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: localcosmos_app_kit
3
- Version: 0.9.18
3
+ Version: 0.10.0
4
4
  Summary: LocalCosmos App Kit. Web Portal to build Android and iOS apps
5
5
  Home-page: https://github.com/localcosmos/app-kit
6
6
  Author: Thomas Uher
@@ -37,10 +37,10 @@ app_kit/app_kit_api/tests/__pycache__/test_serializers.cpython-311.pyc,sha256=Xv
37
37
  app_kit/app_kit_api/tests/__pycache__/test_views.cpython-311.pyc,sha256=jzyuIXHjnoubiVjdoa5h2YxGSTAomhTxhyxfZBqVf1o,10161
38
38
  app_kit/appbuilder/AppBuilderBase.py,sha256=mDwmMd0Fdl-wedTYWEK8AcHfiAhvjxFBGOkLrGavwTs,29160
39
39
  app_kit/appbuilder/AppPreviewBuilder.py,sha256=C0oSh_i1Cx4vLW01T0qJeo-MrtqqjD72Hh43k4kG5EI,6845
40
- app_kit/appbuilder/AppReleaseBuilder.py,sha256=Xh1G8DI5azLLA1_uE-S_4HQDACs2xqxbA87bBGhdBeo,131151
40
+ app_kit/appbuilder/AppReleaseBuilder.py,sha256=up6NEc5l46FdPBWH2iW6XZKMET_s1PEJ4Jq2J0Wiges,134050
41
41
  app_kit/appbuilder/ContentImageBuilder.py,sha256=k9YdH2d5oIyfbeoA9H_DaUigc1SQ69WnXFy9e00DdfA,7332
42
42
  app_kit/appbuilder/GBIFlib.py,sha256=iGj01hrk0iG-qjEkPM8ez_lNKL_zJedPTS3oUZDd8vg,989
43
- app_kit/appbuilder/TaxonBuilder.py,sha256=4c9tDVxWoHIXiy3z-hHku2OXceQDJDjrehvm8spXtuE,15983
43
+ app_kit/appbuilder/TaxonBuilder.py,sha256=BQcu1EWn-eGrTZhrbVCDdRsjBQ9nsjpUKaJMIXgbA8A,16390
44
44
  app_kit/appbuilder/__init__.py,sha256=PIqSBvR4NFND1zb_KOryk3PFZ5yhiGwaZIZSRSTp1JY,152
45
45
  app_kit/appbuilder/precompile_fulltree.py,sha256=Lrf5j0xGY2FgpuuWdUrfef1ZlLs-GntFYpngtZ5pTF0,2005
46
46
  app_kit/appbuilder/JSONBuilders/BackboneTaxonomyJSONBuilder.py,sha256=worozLAgqxKJSdBzQ45zlCL3l4BnpZAYX-Dl4SfmwUs,6488
@@ -52,7 +52,7 @@ app_kit/appbuilder/JSONBuilders/GlossaryJSONBuilder.py,sha256=7pITMctTmEVRbyb7Dl
52
52
  app_kit/appbuilder/JSONBuilders/JSONBuilder.py,sha256=BssXm7ueXghCmHHmWsnQekQdbE4g0UIIQ59a6k0Bzts,6010
53
53
  app_kit/appbuilder/JSONBuilders/MapJSONBuilder.py,sha256=NgP5g_H0sfq5VRkoHdMzkQUGLgUofcwG1R2xe6vUS9U,2792
54
54
  app_kit/appbuilder/JSONBuilders/NatureGuideJSONBuilder.py,sha256=LZgyfc0e2xhTB9XES6fgm_vmL-O7VBBXsRdNDapgu5E,25498
55
- app_kit/appbuilder/JSONBuilders/TaxonProfilesJSONBuilder.py,sha256=XNtRAQ31UPSghcFPUR1-RQLdzDpDxmkITb_paYP4uxQ,34716
55
+ app_kit/appbuilder/JSONBuilders/TaxonProfilesJSONBuilder.py,sha256=tvHz0--awo5Rvsc_nPNGvwbPKLAuNXUh4RX0erZOTZM,36345
56
56
  app_kit/appbuilder/JSONBuilders/TemplateContentJSONBuilder.py,sha256=zWF7SNeRosbOi876boXp0tpIYXVs04fKtauK9Fr_DRs,7382
57
57
  app_kit/appbuilder/JSONBuilders/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
58
58
  app_kit/appbuilder/JSONBuilders/generic_forms_JSON_specification,sha256=dFabBHtkfzJqB2zNSRR2OaIyroYr1nEw_qY6VFZF7dQ,6720
@@ -74,7 +74,7 @@ app_kit/appbuilder/JSONBuilders/__pycache__/NatureGuideJSONBuilder.cpython-311.p
74
74
  app_kit/appbuilder/JSONBuilders/__pycache__/NatureGuideJSONBuilder.cpython-313.pyc,sha256=jF5kdrd9eYsIuLJtophN4ptZB67MM1poI4Oao2aY8RU,25376
75
75
  app_kit/appbuilder/JSONBuilders/__pycache__/TaxonJSONBuilder.cpython-311.pyc,sha256=nEt3jd6Pf4lb0QnFpU7QPg9bsKa68z0Vh8C85t4CMO0,9663
76
76
  app_kit/appbuilder/JSONBuilders/__pycache__/TaxonProfilesJSONBuilder.cpython-311.pyc,sha256=bffiRE-WzCN3s0sz00rFuuu8c0qFL7kRq97XwtuRnoo,22862
77
- app_kit/appbuilder/JSONBuilders/__pycache__/TaxonProfilesJSONBuilder.cpython-313.pyc,sha256=--E2Ix4-WlvKe_BPIWLnqoNmEnkfWop0ZDn2FWJu1Ew,29536
77
+ app_kit/appbuilder/JSONBuilders/__pycache__/TaxonProfilesJSONBuilder.cpython-313.pyc,sha256=y3XVQ4f5zXWVClaO6vQLNXKklpt7K4ymnix51Xnu5Ok,29288
78
78
  app_kit/appbuilder/JSONBuilders/__pycache__/TemplateContentJSONBuilder.cpython-311.pyc,sha256=7fGagTetGK129h057h6dPXMSwggBX03uHOm3_dr3ueE,5932
79
79
  app_kit/appbuilder/JSONBuilders/__pycache__/TemplateContentJSONBuilder.cpython-313.pyc,sha256=lXf1kZuOMRWsHmnP1aN7UJIPEfWF-PhiMyyZ9FfY1Tg,6501
80
80
  app_kit/appbuilder/JSONBuilders/__pycache__/__init__.cpython-311.pyc,sha256=MxwSyVkGIkNVrjjMZzXCHh9k7_ytM6tzgpNTaCtDNn4,211
@@ -84,13 +84,13 @@ app_kit/appbuilder/__pycache__/AppBuilderBase.cpython-313.pyc,sha256=GTLt_n208ej
84
84
  app_kit/appbuilder/__pycache__/AppPreviewBuilder.cpython-311.pyc,sha256=5kKHNjUuOfp31cqB_ZO175x-wGgVVhqX8YkHWSlX--k,8245
85
85
  app_kit/appbuilder/__pycache__/AppPreviewBuilder.cpython-313.pyc,sha256=C7-mLN6yGvDrknbBamjKkI9fxjfT3djrdr3-8Fhc7HQ,7526
86
86
  app_kit/appbuilder/__pycache__/AppReleaseBuilder.cpython-311.pyc,sha256=ZAHDJfyKvQzTsyFHIjvRjCiCn1dzObCPp6XYWCGHZmI,126739
87
- app_kit/appbuilder/__pycache__/AppReleaseBuilder.cpython-313.pyc,sha256=8bJrshzvJDUlDowgZ96tnBvNx6h9zh96m12mAekOwCQ,129137
87
+ app_kit/appbuilder/__pycache__/AppReleaseBuilder.cpython-313.pyc,sha256=_88iSOHywr1q1eKR6zJLdemnjwvIrL2kldxx0mZcrT0,131779
88
88
  app_kit/appbuilder/__pycache__/ContentImageBuilder.cpython-311.pyc,sha256=EyL2LamJkdU_7O_F0j3vwtTYjInblFSPKmlPLyXvSuE,8920
89
89
  app_kit/appbuilder/__pycache__/ContentImageBuilder.cpython-313.pyc,sha256=K6b-GlHYhM0SWlniDyyFfKdK_QF7kHN8yFahn2ETCa8,8737
90
90
  app_kit/appbuilder/__pycache__/GBIFlib.cpython-311.pyc,sha256=NNB_AHGQnN0ld82WuJHxGn5RthLO_fGkpVAfAHaDyMU,1945
91
91
  app_kit/appbuilder/__pycache__/GBIFlib.cpython-313.pyc,sha256=13SE5Ayqrg8n90KGWbLE7rQ-UPaU2Q0XbY5dQENpXTA,1962
92
92
  app_kit/appbuilder/__pycache__/TaxonBuilder.cpython-311.pyc,sha256=7JVnCo4-CVmaX_EIzU05is5ySaqWPA86QBlFM-B4Trw,16273
93
- app_kit/appbuilder/__pycache__/TaxonBuilder.cpython-313.pyc,sha256=mxUE3vbiXd4R9F3iFOdPIAuZySRhBJ6KIeGllVJp4Uw,16957
93
+ app_kit/appbuilder/__pycache__/TaxonBuilder.cpython-313.pyc,sha256=fNSv6AE_6jLLNiXE4SFVpSHv6_hVkeSUIGmaFJxLkao,17166
94
94
  app_kit/appbuilder/__pycache__/__init__.cpython-311.pyc,sha256=KkcyxSIx1hiGZkOwMG8qWGJQ-RPacWMKpfpnP-naNv4,388
95
95
  app_kit/appbuilder/__pycache__/__init__.cpython-313.pyc,sha256=iHwg7gUn2XzOOz0SNmIeY6GVMxTcc5NKM3gzSz4pLnA,329
96
96
  app_kit/appbuilder/app/frontends/Multiverse/settings.json,sha256=dCcy0ZGor57YhlrPUJVj-IADrF413gBBWFUfletZW6g,2026
@@ -154,7 +154,7 @@ app_kit/features/backbonetaxonomy/templates/backbonetaxonomy/add_taxon_form.html
154
154
  app_kit/features/backbonetaxonomy/templates/backbonetaxonomy/manage_backbone_taxa_form.html,sha256=wVUAExurrDbck2SD9pwL4IWdOx0Z-QHWU9idNbnc5VY,1529
155
155
  app_kit/features/backbonetaxonomy/templates/backbonetaxonomy/manage_backbonetaxonomy.html,sha256=0EehuPUlE6-g7miYOycv_j2aZPqmU-Ykwd_bpC3LdMM,4101
156
156
  app_kit/features/backbonetaxonomy/templates/backbonetaxonomy/manage_fulltree_form.html,sha256=uqw8OL3dGy7_iZzGxgGc3KHNSsGHVBniBx2FQSrM8h0,622
157
- app_kit/features/backbonetaxonomy/templates/backbonetaxonomy/manage_taxon.html,sha256=vkQjHX7K9OGPB3lrBFnJguWpCXKzbvLmKrnwAPgOG34,1882
157
+ app_kit/features/backbonetaxonomy/templates/backbonetaxonomy/manage_taxon.html,sha256=Rsn0XHwq4n_Zk4iPVi_MKb3sB6z6L2KeaZPP82tZi4Y,1846
158
158
  app_kit/features/backbonetaxonomy/templates/backbonetaxonomy/remove_backbone_taxon.html,sha256=-9t83d771KmyoeENWqvxrxyoI7zOK5-sHL_rLdHxsP0,1206
159
159
  app_kit/features/backbonetaxonomy/templates/backbonetaxonomy/swap_taxon.html,sha256=6soId42pD0s-vxCSNE8RNNotSfSWOINmMk3Eyo9hlMM,7469
160
160
  app_kit/features/backbonetaxonomy/templates/backbonetaxonomy/taxon_relationships.html,sha256=jBFcbS1CJnd0b9IqSMGcfDFR-tmHygOs4wSBfFekPEo,5503
@@ -398,10 +398,10 @@ app_kit/features/nature_guides/tests/__pycache__/test_views.cpython-311.pyc,sha2
398
398
  app_kit/features/taxon_profiles/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
399
399
  app_kit/features/taxon_profiles/admin.py,sha256=suMo4x8I3JBxAFBVIdE-5qnqZ6JAZV0FESABHOSc-vg,63
400
400
  app_kit/features/taxon_profiles/apps.py,sha256=c0nynglV50B8qvXTnu7v6LZHT6N5nOTayOasKICAAJE,119
401
- app_kit/features/taxon_profiles/forms.py,sha256=T5mU0QGhG_fSNppzuzTxjxb078VA4IckOPOaP7nM5fE,16998
402
- app_kit/features/taxon_profiles/models.py,sha256=xYDHT_KI_xatFUwYYnkogXeqd70kr9Dp8YVum8hzvRw,24214
403
- app_kit/features/taxon_profiles/urls.py,sha256=wamGUfN5cpCvYEfNnTTbdqBt1GeFQbybmzsG7_KtpvA,10814
404
- app_kit/features/taxon_profiles/views.py,sha256=WCA2C8D6eyghFg42CRBQZlyvcy_UWf2iDcZPwOcRzSc,61245
401
+ app_kit/features/taxon_profiles/forms.py,sha256=jBvYFgKAG9_gpCG3dfE97KQTnTiKjTIOQenmeXVE62g,16131
402
+ app_kit/features/taxon_profiles/models.py,sha256=kllsA7VTgD5a8KVyHAUV0udMcv7Keg5hd5x1LcrmR3I,23855
403
+ app_kit/features/taxon_profiles/urls.py,sha256=IhJOF7HIPOw-VanBzJtSanKOdAgWL1vKy9evcHD3Bzw,11098
404
+ app_kit/features/taxon_profiles/views.py,sha256=gIZTKT7bdnHOBhNgLqpLsTtkAjARbMPDnHC4Y1lXoBQ,61750
405
405
  app_kit/features/taxon_profiles/zip_import.py,sha256=aYFEtaMjn5Qebj0eaOeM-WVdvMUDymH4wUOnhAItN9I,29883
406
406
  app_kit/features/taxon_profiles/migrations/0001_initial.py,sha256=aknHwoaZMBwDWMnp7dftXToVGuyN4f9xy3epQSqGkxQ,3659
407
407
  app_kit/features/taxon_profiles/migrations/0002_taxontext_long_text.py,sha256=FN2GAdO4paIgX8FpREoLk7cihlHRRaehVY7_Ve0K97w,383
@@ -418,7 +418,7 @@ app_kit/features/taxon_profiles/migrations/0012_taxonprofile_updated_at.py,sha25
418
418
  app_kit/features/taxon_profiles/migrations/0013_alter_taxonprofile_options_and_more.py,sha256=03fp39qqKjBJOiUspog7BzgxVg80lZJ8vq8dZhq8K98,596
419
419
  app_kit/features/taxon_profiles/migrations/0014_alter_taxonprofile_unique_together_and_more.py,sha256=wPO0TfoU_I9_BBLOSe3gvzMzEeGpxP5exnwuGT_ngUU,2501
420
420
  app_kit/features/taxon_profiles/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
421
- app_kit/features/taxon_profiles/templates/taxon_profiles/manage_taxon_profile.html,sha256=9uqOz0oQuA8Yxyg1yTSZs0RCWpjASOS6mIZgJm6uJFQ,11184
421
+ app_kit/features/taxon_profiles/templates/taxon_profiles/manage_taxon_profile.html,sha256=i04Bvrb5fKgxnD4oCUaqTcTf2D3RsQElmg7LHUe8HEE,11059
422
422
  app_kit/features/taxon_profiles/templates/taxon_profiles/manage_taxon_profiles.html,sha256=NJGnmoa5da40e-hUpZAG2V-UZGqf_oxAd8bIABfuaKw,9304
423
423
  app_kit/features/taxon_profiles/templates/taxon_profiles/manage_taxon_texts.html,sha256=q1Do_NKTwkQ8sHWY4Zx4CXaWbpfFBGxn6_8Uc3N4EVA,1353
424
424
  app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/backbone_taxa_taxonlist.html,sha256=6zEHqwPnU0bJJmyQqkXxWw90D0IQ1WPtm4sCCKXFJMQ,656
@@ -427,7 +427,7 @@ app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/change_navigation_
427
427
  app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/change_taxon_profile_publication_status.html,sha256=zuDHrJc77sAVLCmFmhvUMyJSYVQu8zQT_RC0PwavTiI,596
428
428
  app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/collected_taxon_images.html,sha256=a6HQJ6p4QMSpDqYraentxFyGmIxs-5uypFbWIyoR4q8,3654
429
429
  app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/collected_taxon_traits.html,sha256=PkA7sGNPBFQ_t1Pb4X1avCd_n9SVFKedN0BIsYyB0Eg,2470
430
- app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/create_taxon_profile.html,sha256=TylM_rq_aARbxzBgLZ8iGO6BNMFiGCue9-4saUZdS4c,1092
430
+ app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/create_taxon_profile.html,sha256=jbyin1419LNIbBltUmvN4S02K9jq2vgdJwGz3Dh8dSs,1056
431
431
  app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/delete_all_manually_added_images.html,sha256=_zOaLGeVD3AKPmIzwRTr-eHi0Lo38dOTsSzYI-Oz_rE,1022
432
432
  app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/delete_navigation_entry.html,sha256=kCNgH9qiAvF5Y3XP6UPA-XZeFb0Uw2CZakkYY-JjZD0,226
433
433
  app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/delete_navigation_entry_taxon.html,sha256=xn3CFCzn1qZS5tM76GeQn4-2_WL4zLo5OxUTAD47XiQ,410
@@ -438,19 +438,19 @@ app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/delete_taxon_text_
438
438
  app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/delete_taxon_text_type_category.html,sha256=mIgqNz2dcZyl-6U2bClztlERrSCzct5RhOnY_KB51tA,381
439
439
  app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/manage_navigation_entry.html,sha256=a_Cydkty0fWKIOzcnXOa0US-eLrjKI_y8LaI4unxeC0,2497
440
440
  app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/manage_navigation_image.html,sha256=9uAZLbs5Rs4Xew3ua-0BOT4MzLXjW25XjgO73vPJxP8,872
441
- app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/manage_taxon_profile_form.html,sha256=RZ-7jxCk-gxW7Ozzm_5sX7SlhG9N-LL80yYAq1iB0QY,4432
441
+ app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/manage_taxon_profile_form.html,sha256=VbfbX5xrfhzjBealfy49tbzZf4Z0wFXc7UvujzuMvnw,3089
442
442
  app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/manage_taxon_profile_image.html,sha256=TORQADZVRluI4VN3D_0cKJsKhEJu7y8JgOR-sDv6INU,1141
443
- app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/manage_taxon_profile_morphotype.html,sha256=uB_yzjW_cKFO32dqwaKtSUw-jLRfrzl2Aerf7cP66Fo,1071
443
+ app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/manage_taxon_profile_morphotype.html,sha256=eVyORlAKHmHjB3crC1uTusXhmYOz72Fo2Hd3fwT00nA,1049
444
444
  app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/manage_taxon_text_set.html,sha256=E98YJtky7fBZxPiP_gkT6LxaRHtN5BDPgc0ow3mU93I,1148
445
445
  app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/manage_text_type.html,sha256=XFkHIQsxGFndUCMK5U-b0E48Fibbod2mlYw51DUcbWk,1404
446
446
  app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/manage_text_type_category.html,sha256=5aS1gI4kXOms7TWBiGIOp37Z56TzC4QyhHBuoJlkBCs,1391
447
447
  app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/move_image_to_section.html,sha256=IVpYDx7oLL16auz9D5rSXA6PMChPLhT6IsmQsuYkELg,585
448
448
  app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/move_navigation_entry.html,sha256=mZ-e8N8j-XhFaueIOpJSGv8knL2iX20i_FvQSeqS5uE,2158
449
- app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/nature_guide_taxonlist.html,sha256=tFbBXh60iJPOB7hWDxSr83yvfjL1DF8MfHuVGle3iZQ,2015
449
+ app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/nature_guide_taxonlist.html,sha256=dXtTcymXITUEoBsGe2XoTSbifyacPLjD0NX539cVyRU,1911
450
450
  app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/navigation_entry_taxa.html,sha256=6UeTMqrtUCU7WEzZBK_yT9HquxxFWONRekiwoj7jh5U,2063
451
451
  app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/navigation_entry_taxon_profiles.html,sha256=m3IaC1yd4lvpRTV8CnSOM60pFxZukIndmCw_Yv-Yorw,910
452
452
  app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/navigation_entry_taxon_profiles_list.html,sha256=DrSBBxOOMSUYBZj7-XCPvmDkWB_Y8587AVlrCLPVrxE,431
453
- app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/non_nature_guide_taxonlist.html,sha256=dGz2NdCx38ACm3lixNHsOJsedImGs7D2oLfds6iMq1U,629
453
+ app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/non_nature_guide_taxonlist.html,sha256=4sLthyIACNopPz7ev1A4866M3nxRpkrhZEgR3eT3Smo,582
454
454
  app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/set_taxon_text_set_for_taxon_profile.html,sha256=M92q0Qh2RB-Lxi717_EctdZbrp7v7kd1BMdrclkaQ8Q,611
455
455
  app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/taxon_profiles_navigation.html,sha256=a098AWlYiJae0V23YMwXx1JsPW0D_4DI1ASMn4E9Sx4,980
456
456
  app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/taxon_profiles_navigation_level.html,sha256=GY0KFR7BPiLsiMIVy8xRukZpbsQ6q7RBE3QiaR7506s,6204
@@ -1903,7 +1903,6 @@ app_kit/tests/TESTS_ROOT/images/app-background.jpg,sha256=bmW6cudSfmcRqGSK9P2Sc5
1903
1903
  app_kit/tests/TESTS_ROOT/images/localcosmos-logo.svg,sha256=4-MHj0FjED9eTgmUHnAP-DHCQRqc557HH9akHaoQxs0,409549
1904
1904
  app_kit/tests/TESTS_ROOT/images/test-image-2560-1440.jpg,sha256=BOP-1ZlA9wq-E1sUkOpyqUowpFCdSoF965oKgajjSq0,156278
1905
1905
  app_kit/tests/TESTS_ROOT/ipa_for_tests/TestApp.ipa,sha256=YdGWqMepeBwvpkch3DSVMlnNkf8RuGwENWuwHtoY1Do,78900
1906
- app_kit/tests/TESTS_ROOT/media_for_tests/test/imagestore/31/a6a11b61d65ee19c4c22caa0682288ff.jpg,sha256=dXT6yUqaMJ_91rwQMHT22VjDGb69KRCmm4eboxjtnxM,49349
1907
1906
  app_kit/tests/TESTS_ROOT/templates/neobiota.html,sha256=3ag2VGCuaZ-FoAu25GMUb3s4qMsY7AyhNoDf7CSZJ_w,147
1908
1907
  app_kit/tests/TESTS_ROOT/xlsx_for_testing/BackboneTaxonomy/invalid/Backbone taxonomy.xlsx,sha256=cMkmCtGBR1wwhpDSbjrscNSvLMGnb6YbaliQqws-l7M,8121
1909
1908
  app_kit/tests/TESTS_ROOT/xlsx_for_testing/BackboneTaxonomy/invalid_content_type/Backbone taxonomy.xlsx,sha256=aYRrPI-UABxQUZF-bWvbrD_31ZQgEijdKCzBGOXzGRk,7996
@@ -1939,8 +1938,8 @@ app_kit/tests/__pycache__/test_models.cpython-313.pyc,sha256=Lmv3BfjLs5Fg-olJeMl
1939
1938
  app_kit/tests/__pycache__/test_utils.cpython-313.pyc,sha256=GX3REqZygi2eO_A2F2_KtYi7hg54X5QPtCTCGWuxGpM,14054
1940
1939
  app_kit/tests/__pycache__/test_views.cpython-311.pyc,sha256=NDJR40TcMm-bXXC-wV7OgH1sGR3N7psSWYiUirkkrjU,133242
1941
1940
  app_kit/tests/__pycache__/test_views.cpython-313.pyc,sha256=q851UqIZFCCTfQb1lF4SVxV1j_Vu1hJdOlpckmrGX28,125363
1942
- localcosmos_app_kit-0.9.18.dist-info/licenses/LICENCE,sha256=VnxALPSxXoU59rlNeRdJtwS_nU79IFpVWsZZCQUM4Mw,1086
1943
- localcosmos_app_kit-0.9.18.dist-info/METADATA,sha256=wC25Ke7ekb_Rf0l-tcIN2Ih3__GSe64Z0SNNQwGQVSg,1388
1944
- localcosmos_app_kit-0.9.18.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
1945
- localcosmos_app_kit-0.9.18.dist-info/top_level.txt,sha256=F6H4pEBkCvUR_iwQHIy4K1iby-jzfWg3CTym5XJKeys,8
1946
- localcosmos_app_kit-0.9.18.dist-info/RECORD,,
1941
+ localcosmos_app_kit-0.10.0.dist-info/licenses/LICENCE,sha256=VnxALPSxXoU59rlNeRdJtwS_nU79IFpVWsZZCQUM4Mw,1086
1942
+ localcosmos_app_kit-0.10.0.dist-info/METADATA,sha256=pVHi86lhY2n4lU4kKq5TLikiIHOxHWFiEerAaFnNzqw,1388
1943
+ localcosmos_app_kit-0.10.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
1944
+ localcosmos_app_kit-0.10.0.dist-info/top_level.txt,sha256=F6H4pEBkCvUR_iwQHIy4K1iby-jzfWg3CTym5XJKeys,8
1945
+ localcosmos_app_kit-0.10.0.dist-info/RECORD,,