localcosmos-app-kit 0.9.17__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.
- app_kit/appbuilder/AppReleaseBuilder.py +111 -53
- app_kit/appbuilder/JSONBuilders/TaxonProfilesJSONBuilder.py +38 -15
- app_kit/appbuilder/JSONBuilders/__pycache__/TaxonProfilesJSONBuilder.cpython-313.pyc +0 -0
- app_kit/appbuilder/TaxonBuilder.py +35 -28
- app_kit/appbuilder/__pycache__/AppReleaseBuilder.cpython-313.pyc +0 -0
- app_kit/appbuilder/__pycache__/TaxonBuilder.cpython-313.pyc +0 -0
- app_kit/features/backbonetaxonomy/templates/backbonetaxonomy/manage_taxon.html +1 -1
- app_kit/features/taxon_profiles/forms.py +12 -37
- app_kit/features/taxon_profiles/models.py +29 -36
- app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/create_taxon_profile.html +1 -1
- app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/manage_taxon_profile_form.html +35 -54
- app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/manage_taxon_profile_morphotype.html +2 -1
- app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/nature_guide_taxonlist.html +2 -2
- app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/non_nature_guide_taxonlist.html +1 -1
- app_kit/features/taxon_profiles/templates/taxon_profiles/manage_taxon_profile.html +4 -4
- app_kit/features/taxon_profiles/urls.py +3 -0
- app_kit/features/taxon_profiles/views.py +44 -32
- app_kit/taxonomy/sources/custom/management/commands/__pycache__/import_custom_species_csv.cpython-313.pyc +0 -0
- app_kit/taxonomy/sources/custom/management/commands/__pycache__/import_custom_taxonomy_csv.cpython-313.pyc +0 -0
- app_kit/taxonomy/sources/custom/management/commands/import_custom_species_csv.py +177 -0
- app_kit/taxonomy/sources/custom/management/commands/import_custom_taxonomy_csv.py +177 -0
- {localcosmos_app_kit-0.9.17.dist-info → localcosmos_app_kit-0.10.0.dist-info}/METADATA +1 -1
- {localcosmos_app_kit-0.9.17.dist-info → localcosmos_app_kit-0.10.0.dist-info}/RECORD +26 -23
- app_kit/tests/TESTS_ROOT/media_for_tests/test/imagestore/31/a6a11b61d65ee19c4c22caa0682288ff.jpg +0 -0
- {localcosmos_app_kit-0.9.17.dist-info → localcosmos_app_kit-0.10.0.dist-info}/WHEEL +0 -0
- {localcosmos_app_kit-0.9.17.dist-info → localcosmos_app_kit-0.10.0.dist-info}/licenses/LICENCE +0 -0
- {localcosmos_app_kit-0.9.17.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
|
-
|
|
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
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
495
|
+
'taxon': self.app_release_builder.taxa_builder.serialize_taxon_extended(lazy_taxon),
|
|
473
496
|
'vernacular' : {},
|
|
474
497
|
'image': image_entry,
|
|
475
498
|
}
|
|
Binary file
|
|
@@ -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
|
|
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
|
|
232
|
-
taxon_images = self.taxa_builder.cache['images'][
|
|
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
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
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
|
-
|
|
315
|
+
#self.app_release_builder.logger.info('Found {0} images for {1}'.format(taxon_images.count(), profile_taxon.taxon_latname))
|
|
309
316
|
|
|
310
|
-
|
|
317
|
+
for taxon_image in content_images_taxon:
|
|
311
318
|
|
|
312
|
-
|
|
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
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
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
|
-
|
|
321
|
-
|
|
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'][
|
|
330
|
+
self.taxa_builder.cache['images'][cache_key] = taxon_images
|
|
324
331
|
|
|
325
332
|
taxon_images_copy = copy.deepcopy(taxon_images)
|
|
326
333
|
|
|
Binary file
|
|
Binary file
|
|
@@ -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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|