def test_concepts_should_have_unique_fully_specified_name_per_locale(self): name_fully_specified1 = LocalizedTextFactory.build( name='FullySpecifiedName1') source = OrganizationSourceFactory( custom_validation_schema=CUSTOM_VALIDATION_SCHEMA_OPENMRS, version=HEAD) concept1_data = { **factory.build(dict, FACTORY_CLASS=ConceptFactory), 'mnemonic': 'c1', 'parent': source, 'names': [name_fully_specified1] } concept2_data = { **factory.build(dict, FACTORY_CLASS=ConceptFactory), 'mnemonic': 'c2', 'parent': source, 'names': [name_fully_specified1] } concept1 = Concept.persist_new(concept1_data) concept2 = Concept.persist_new(concept2_data) self.assertEqual(concept1.errors, {}) self.assertEqual( concept2.errors, dict(names=[ OPENMRS_FULLY_SPECIFIED_NAME_UNIQUE_PER_SOURCE_LOCALE + ': FullySpecifiedName1 (locale: en, preferred: no)' ]))
def test_unretire(self): source = OrganizationSourceFactory(version=HEAD) concept = Concept.persist_new({ **factory.build(dict, FACTORY_CLASS=ConceptFactory), 'mnemonic': 'c1', 'parent': source, 'retired': True, 'names': [LocalizedTextFactory.build(locale='en', name='English', locale_preferred=True)] }) Concept.persist_clone(concept.clone(), concept.created_by) concept_v1 = Concept.objects.order_by('-created_at').first() concept.refresh_from_db() self.assertEqual(concept.versions.count(), 2) self.assertTrue(concept.retired) self.assertFalse(concept.is_latest_version) self.assertTrue(concept.is_versioned_object) self.assertTrue(concept_v1.is_latest_version) concept_v1.unretire(concept.created_by, 'World needs you!') # concept will become old/prev version concept.refresh_from_db() concept_v1.refresh_from_db() self.assertFalse(concept_v1.is_latest_version) self.assertEqual(concept.versions.count(), 3) self.assertFalse(concept.retired) latest_version = concept.get_latest_version() self.assertFalse(latest_version.retired) self.assertEqual(latest_version.comment, 'World needs you!') self.assertEqual( concept.unretire(concept.created_by), {'__all__': CONCEPT_IS_ALREADY_NOT_RETIRED} )
def test_duplicate_preferred_name_per_source_should_fail(self): source = SourceFactory(custom_validation_schema=CUSTOM_VALIDATION_SCHEMA_OPENMRS, version=HEAD) concept1 = Concept.persist_new( dict( mnemonic='concept1', version=HEAD, name='concept1', parent=source, concept_class='Diagnosis', datatype='None', names=[ LocalizedTextFactory.build( name='Concept Non Unique Preferred Name', locale='en', locale_preferred=True, type='Fully Specified' ), ] ) ) concept2 = Concept.persist_new( dict( mnemonic='concept2', version=HEAD, name='concept2', parent=source, concept_class='Diagnosis', datatype='None', names=[ LocalizedTextFactory.build( name='Concept Non Unique Preferred Name', locale='en', locale_preferred=True, type='None' ), LocalizedTextFactory.build( name='any name', locale='en', locale_preferred=False, type='Fully Specified' ), ] ) ) self.assertEqual(concept1.errors, {}) self.assertEqual( concept2.errors, dict(names=[OPENMRS_PREFERRED_NAME_UNIQUE_PER_SOURCE_LOCALE + ': Concept Non Unique Preferred Name (locale: en, preferred: yes)']) )
def update(self, instance, validated_data): from core.concepts.models import Concept from core.sources.models import Source instance.extras = validated_data.get('extras', instance.extras) instance.external_id = validated_data.get('external_id', instance.external_id) instance.comment = validated_data.get( 'update_comment') or validated_data.get('comment') instance.retired = validated_data.get('retired', instance.retired) from_concept_url = validated_data.get('from_concept_url', None) to_concept_url = validated_data.get('to_concept_url', None) to_source_url = validated_data.get('to_source_url', None) if from_concept_url: instance.from_concept = Concept.from_uri_queryset( from_concept_url).first() if to_concept_url: instance.to_concept = Concept.from_uri_queryset( to_concept_url).first() if to_source_url: instance.to_source = Source.head_from_uri(to_source_url).first() instance.mnemonic = validated_data.get('mnemonic', instance.mnemonic) instance.map_type = validated_data.get('map_type', instance.map_type) instance.to_concept_code = validated_data.get('to_concept_code', instance.to_concept_code) instance.to_concept_name = validated_data.get('to_concept_name', instance.to_concept_name) errors = Mapping.persist_clone(instance, self.context.get('request').user) if errors: self._errors.update(errors) return instance
def test_get_latest_versions_for_queryset(self): self.assertEqual(Concept.get_latest_versions_for_queryset(Concept.objects.none()).count(), 0) source1 = SourceFactory() concept1_latest = ConceptFactory(parent=source1, mnemonic='common-name-1') ConceptFactory(version='v1', parent=source1, is_latest_version=False, mnemonic=concept1_latest.mnemonic) concept2_latest = ConceptFactory(parent=source1) ConceptFactory(version='v1', parent=source1, is_latest_version=False, mnemonic=concept2_latest.mnemonic) concept3_latest = ConceptFactory(parent=source1, mnemonic='common-name-2') ConceptFactory(version='v1', parent=source1, is_latest_version=False, mnemonic=concept3_latest.mnemonic) source2 = SourceFactory() concept4_latest = ConceptFactory(parent=source2, mnemonic='common-name-1') ConceptFactory(version='v1', parent=source2, is_latest_version=False, mnemonic=concept4_latest.mnemonic) concept5_latest = ConceptFactory(parent=source2) ConceptFactory(version='v1', parent=source2, is_latest_version=False, mnemonic=concept5_latest.mnemonic) concept6_latest = ConceptFactory(parent=source2, mnemonic='common-name-2') ConceptFactory(version='v1', parent=source2, is_latest_version=False, mnemonic=concept6_latest.mnemonic) latest_versions = Concept.get_latest_versions_for_queryset(Concept.objects.filter(parent=source1)) self.assertEqual(latest_versions.count(), 3) self.assertEqual( list(latest_versions.order_by('created_at')), [concept1_latest, concept2_latest, concept3_latest] ) latest_versions = Concept.get_latest_versions_for_queryset(Concept.objects.filter(parent=source2)) self.assertEqual(latest_versions.count(), 3) self.assertEqual( list(latest_versions.order_by('created_at')), [concept4_latest, concept5_latest, concept6_latest] ) latest_versions = Concept.get_latest_versions_for_queryset(Concept.objects.filter(mnemonic='common-name-1')) self.assertEqual(latest_versions.count(), 2) self.assertEqual( list(latest_versions.order_by('created_at')), [concept1_latest, concept4_latest] ) latest_versions = Concept.get_latest_versions_for_queryset( Concept.objects.filter(mnemonic='common-name-2', version='v1') ) self.assertEqual(latest_versions.count(), 2) self.assertEqual( list(latest_versions.order_by('created_at')), [concept3_latest, concept6_latest] )
def process(self): if self.version: instance = self.get_queryset().first().clone() errors = Concept.create_new_version_for(instance, self.data, self.user) return errors or UPDATED instance = Concept.persist_new(self.data, self.user) if instance.id: return CREATED return instance.errors or FAILED
def create_concepts(source, file, user): file = open(file, 'r') lines = file.readlines() for line in lines: data = json.loads(line) mnemonic = data.pop('id', None) if not Concept.objects.filter(parent=source, mnemonic=mnemonic, is_latest_version=True).exists(): data['mnemonic'] = mnemonic data['name'] = mnemonic data['parent'] = source Concept.persist_new(data, user)
def test_get_parent_and_owner_filters_from_uri(self): self.assertEqual(Concept.get_parent_and_owner_filters_from_uri(None), dict()) self.assertEqual(Concept.get_parent_and_owner_filters_from_uri(''), dict()) self.assertEqual( Concept.get_parent_and_owner_filters_from_uri('/bar/'), dict()) self.assertEqual( Concept.get_parent_and_owner_filters_from_uri('/concepts/'), dict()) self.assertEqual( Concept.get_parent_and_owner_filters_from_uri( '/concepts/concept1/'), dict()) self.assertEqual( Concept.get_parent_and_owner_filters_from_uri( '/users/foo/sources/bar/concepts/'), dict(parent__mnemonic='bar', parent__user__username='******')) self.assertEqual( Concept.get_parent_and_owner_filters_from_uri( '/users/foo/sources/bar/concepts/concept1/'), dict(parent__mnemonic='bar', parent__user__username='******')) self.assertEqual( Concept.get_parent_and_owner_filters_from_uri( '/orgs/foo/sources/bar/concepts/concept1/'), dict(parent__mnemonic='bar', parent__organization__mnemonic='foo'))
def update(self, instance, validated_data): errors = Concept.create_new_version_for( instance, validated_data, self.context.get('request').user) if errors: self._errors.update(errors) return instance
def test_no_more_than_one_short_name_per_locale(self): source = OrganizationSourceFactory( custom_validation_schema=CUSTOM_VALIDATION_SCHEMA_OPENMRS, version=HEAD) concept = Concept.persist_new( dict(mnemonic='concept', version=HEAD, name='concept', parent=source, concept_class='Diagnosis', datatype='None', names=[ LocalizedTextFactory.build(name="fully specified name1", locale='en', type='Short'), LocalizedTextFactory.build(name='fully specified name2', locale='en', type='Short'), LocalizedTextFactory.build(name='fully specified name3', locale='fr'), ])) self.assertEqual( concept.errors, dict(names=[ OPENMRS_NO_MORE_THAN_ONE_SHORT_NAME_PER_LOCALE + ': fully specified name2 (locale: en, preferred: no)' ]))
def test_unique_preferred_name_per_locale_within_concept_negative(self): source = OrganizationSourceFactory( custom_validation_schema=CUSTOM_VALIDATION_SCHEMA_OPENMRS, version=HEAD) concept = Concept.persist_new( dict(mnemonic='concept1', version=HEAD, name='concept1', parent=source, concept_class='Diagnosis', datatype='None', names=[ LocalizedTextFactory.build( name='Concept Non Unique Preferred Name', locale='es', locale_preferred=True, type='FULLY_SPECIFIED'), LocalizedTextFactory.build( name='Concept Non Unique Preferred Name', locale='es', locale_preferred=True, type='FULLY_SPECIFIED'), ])) self.assertEqual( concept.errors, { 'names': [ 'A concept may not have more than one preferred name (per locale): ' 'Concept Non Unique Preferred Name (locale: es, preferred: yes)' ] })
def update(self, instance, validated_data): instance.concept_class = validated_data.get('concept_class', instance.concept_class) instance.datatype = validated_data.get('datatype', instance.datatype) instance.extras = validated_data.get('extras', instance.extras) instance.external_id = validated_data.get('external_id', instance.external_id) instance.comment = validated_data.get('update_comment') or validated_data.get('comment') instance.retired = validated_data.get('retired', instance.retired) new_names = [ LocalizedText( **{k: v for k, v in name.items() if k not in ['name_type']} ) for name in validated_data.get('names', []) ] new_descriptions = [ LocalizedText( **{k: v for k, v in desc.items() if k not in ['description_type']} ) for desc in validated_data.get('descriptions', []) ] instance.cloned_names = compact(new_names) instance.cloned_descriptions = compact(new_descriptions) errors = Concept.persist_clone(instance, self.context.get('request').user) if errors: self._errors.update(errors) return instance
def test_a_preferred_name_can_not_be_a_short_name(self): source = OrganizationSourceFactory( custom_validation_schema=CUSTOM_VALIDATION_SCHEMA_OPENMRS, version=HEAD) concept = Concept.persist_new( dict(mnemonic='concept', version=HEAD, name='concept', parent=source, concept_class='Diagnosis', datatype='None', names=[ LocalizedTextFactory.build(name="ShortName", locale_preferred=True, type="Short", locale='fr'), LocalizedTextFactory.build(name='Fully Specified Name'), ])) self.assertEqual( concept.errors, dict(names=[ OPENMRS_SHORT_NAME_CANNOT_BE_PREFERRED + ': ShortName (locale: fr, preferred: yes)' ]))
def test_concept_should_have_exactly_one_preferred_name_per_locale(self): name_en1 = LocalizedTextFactory.build(name='PreferredName1', locale_preferred=True) name_en2 = LocalizedTextFactory.build(name='PreferredName2', locale_preferred=True) name_tr = LocalizedTextFactory.build(name='PreferredName3', locale="tr", locale_preferred=True) source = OrganizationSourceFactory( custom_validation_schema=CUSTOM_VALIDATION_SCHEMA_OPENMRS) concept = Concept.persist_new( dict(mnemonic='concept', version=HEAD, name='concept', parent=source, concept_class='Diagnosis', datatype='None', names=[name_en1, name_en2, name_tr])) self.assertEqual( concept.errors, dict(names=[ OPENMRS_MUST_HAVE_EXACTLY_ONE_PREFERRED_NAME + ': PreferredName2 (locale: en, preferred: yes)' ]))
def test_retire(self): source = SourceFactory(version=HEAD) concept = Concept.persist_new({ **factory.build(dict, FACTORY_CLASS=ConceptFactory), 'mnemonic': 'c1', 'parent': source, 'names': [LocalizedTextFactory.build(locale='en', name='English', locale_preferred=True)] }) self.assertEqual(concept.versions.count(), 1) self.assertFalse(concept.retired) self.assertTrue(concept.is_head) concept.retire(concept.created_by, 'Forceful retirement') # concept will become old/prev version concept.refresh_from_db() self.assertFalse(concept.is_head) self.assertEqual(concept.versions.count(), 2) self.assertFalse(concept.retired) latest_version = concept.get_latest_version() self.assertTrue(latest_version.retired) self.assertEqual(latest_version.comment, 'Forceful retirement') self.assertEqual( concept.retire(concept.created_by), {'__all__': CONCEPT_IS_ALREADY_RETIRED} )
def get_queryset(self): queryset = Concept.global_listing_queryset( self.get_filter_params(), self.request.user).select_related( 'parent__organization', 'parent__user', ).prefetch_related('names', 'descriptions') limit = int(self.request.query_params.get(LIMIT_PARAM, 25)) return queryset[0:limit]
def get_object(self, request, *args, **kwargs): concept = Concept.get_base_queryset(kwargs).first() if not concept: raise Http404() self.source = concept.parent self.updated_since = request.GET.get('updated_since', None) self.limit = request.GET.get('limit', None) return concept
def test_persist_clone(self): es_locale = LocalizedTextFactory(locale='es', name='Not English') en_locale = LocalizedTextFactory(locale='en', name='English') source_head = OrganizationSourceFactory(version=HEAD) source_version0 = OrganizationSourceFactory( version='v0', mnemonic=source_head.mnemonic, organization=source_head.organization) self.assertEqual(source_head.versions.count(), 2) concept = ConceptFactory(descriptions=(es_locale, en_locale), names=(en_locale, ), sources=(source_version0, ), parent=source_version0) cloned_concept = Concept.version_for_concept(concept, 'v1', source_version0) self.assertEqual( Concept.persist_clone(cloned_concept), dict( version_created_by= 'Must specify which user is attempting to create a new concept version.' )) self.assertEqual( Concept.persist_clone(cloned_concept, concept.created_by), {}) persisted_concept = Concept.objects.filter( mnemonic=cloned_concept.mnemonic, version=cloned_concept.version).first() self.assertEqual(persisted_concept.names.count(), 1) self.assertEqual(persisted_concept.descriptions.count(), 2) self.assertEqual(persisted_concept.parent, source_version0) self.assertEqual(persisted_concept.sources.count(), 2) self.assertEqual(source_head.concepts.first().id, persisted_concept.id) self.assertEqual( persisted_concept.uri, '/orgs/{}/sources/{}/{}/concepts/{}/{}/'.format( source_version0.organization.mnemonic, source_version0.mnemonic, source_version0.version, persisted_concept.mnemonic, persisted_concept.version)) self.assertEqual(persisted_concept.version_url, persisted_concept.uri)
def test_hierarchy_one_parent_child(self): parent_concept = ConceptFactory( names=[LocalizedTextFactory(locale='en', name='English', locale_preferred=True)]) source = parent_concept.parent child_concept = Concept.persist_new({ **factory.build(dict, FACTORY_CLASS=ConceptFactory), 'mnemonic': 'c1', 'parent': source, 'names': [LocalizedTextFactory.build(locale='en', name='English', locale_preferred=True)], 'parent_concept_urls': [parent_concept.uri] }) parent_concept_latest_version = parent_concept.get_latest_version() self.assertEqual(child_concept.errors, {}) self.assertIsNotNone(child_concept.id) self.assertEqual(list(child_concept.parent_concept_urls), [parent_concept.uri]) self.assertEqual(list(child_concept.get_latest_version().parent_concept_urls), [parent_concept.uri]) self.assertEqual(list(child_concept.child_concept_urls), []) self.assertEqual(list(parent_concept.child_concept_urls), [child_concept.uri]) self.assertEqual(list(parent_concept_latest_version.child_concept_urls), [child_concept.uri]) self.assertEqual(list(parent_concept_latest_version.prev_version.child_concept_urls), []) another_child_concept = Concept.persist_new({ **factory.build(dict, FACTORY_CLASS=ConceptFactory), 'mnemonic': 'c2', 'parent': source, 'names': [LocalizedTextFactory.build(locale='en', name='English', locale_preferred=True)], 'parent_concept_urls': [parent_concept.uri] }) parent_concept_latest_version = parent_concept.get_latest_version() self.assertEqual(another_child_concept.errors, {}) self.assertIsNotNone(another_child_concept.id) self.assertEqual(list(child_concept.parent_concept_urls), [parent_concept.uri]) self.assertEqual(list(child_concept.get_latest_version().parent_concept_urls), [parent_concept.uri]) self.assertEqual(list(child_concept.child_concept_urls), []) self.assertEqual(list(another_child_concept.parent_concept_urls), [parent_concept.uri]) self.assertEqual(list(another_child_concept.get_latest_version().parent_concept_urls), [parent_concept.uri]) self.assertEqual(list(another_child_concept.child_concept_urls), []) self.assertEqual( sorted(list(parent_concept.child_concept_urls)), sorted([child_concept.uri, another_child_concept.uri]) ) self.assertEqual( sorted(list(parent_concept_latest_version.child_concept_urls)), sorted([child_concept.uri, another_child_concept.uri]) ) self.assertEqual(list(parent_concept_latest_version.prev_version.child_concept_urls), [child_concept.uri])
def __get_children_from_expressions(expressions): concepts = Concept.objects.none() mappings = Mapping.objects.none() for expression in expressions: if is_concept(expression): concepts |= Concept.from_uri_queryset(expression) if is_mapping(expression): mappings |= Mapping.from_uri_queryset(expression) return concepts, mappings
def persist_new(cls, data, user): from core.concepts.models import Concept from_concept_url = data.pop('from_concept_url', None) to_concept_url = data.pop('to_concept_url', None) mapping = Mapping(**data, created_by=user, updated_by=user) if from_concept_url: mapping.from_concept = Concept.from_uri_queryset( from_concept_url).first() if to_concept_url: mapping.to_concept = Concept.from_uri_queryset( to_concept_url).first() mapping.mnemonic = data.get('mnemonic', TEMP) mapping.version = TEMP mapping.errors = dict() try: mapping.full_clean() mapping.save() if mapping.id: mapping.version = str(mapping.id) if mapping.mnemonic == TEMP: mapping.mnemonic = str(mapping.id) mapping.is_latest_version = False mapping.versioned_object_id = mapping.id mapping.save() initial_version = cls.create_initial_version(mapping) parent = mapping.parent parent_head = parent.head initial_version.sources.set([parent, parent_head]) mapping.sources.set([parent, parent_head]) parent.save() parent_head.save() except ValidationError as ex: mapping.errors.update(ex.message_dict) except IntegrityError as ex: mapping.errors.update(dict(__all__=ex.args)) return mapping
def test_version_for_concept(self): concept = ConceptFactory(released=True) source = OrganizationSourceFactory() concept_version = Concept.version_for_concept(concept, 'v1.0', source) self.assertEqual(concept_version.parent, source) self.assertEqual(concept_version.version, 'v1.0') self.assertEqual(concept_version.created_by_id, concept.created_by_id) self.assertEqual(concept_version.updated_by_id, concept.updated_by_id) self.assertEqual(concept_version.mnemonic, concept.mnemonic) self.assertFalse(concept_version.released)
def delete(self, request, *args, **kwargs): key = kwargs.get('extra') new_version = self.get_object().clone() if key in new_version.extras: del new_version.extras[key] new_version.comment = 'Deleted extra %s.' % key errors = Concept.persist_clone(new_version, request.user) if errors: return Response(errors, status=status.HTTP_400_BAD_REQUEST) return Response(status=status.HTTP_204_NO_CONTENT) return Response(dict(detail='Not found.'), status=status.HTTP_404_NOT_FOUND)
def get_object(self, queryset=None): queryset = self.get_queryset() filters = dict(id=F('versioned_object_id')) if 'collection' in self.kwargs: filters = dict(is_latest_version=True) uri_param = self.request.query_params.dict().get('uri') if uri_param: filters.update(Concept.get_parent_and_owner_filters_from_uri(uri_param)) if queryset.count() > 1 and not uri_param: raise Http409() return get_object_or_404(queryset, **filters)
def test_data_type_is_valid_attribute_negative(self): source = SourceFactory(custom_validation_schema=CUSTOM_VALIDATION_SCHEMA_OPENMRS) concept = Concept.persist_new( dict( mnemonic='concept1', version=HEAD, name='concept1', parent=source, concept_class='Diagnosis', datatype='XYZWERRTR', names=[LocalizedTextFactory.build(name='Grip', locale='es', locale_preferred=True)] ) ) self.assertEqual( concept.errors, dict(data_type=[OPENMRS_DATATYPE]) )
def test_locale_preferred_name_uniqueness_doesnt_apply_to_shorts(self): source = SourceFactory(custom_validation_schema=CUSTOM_VALIDATION_SCHEMA_OPENMRS, version=HEAD) concept = Concept.persist_new( dict( mnemonic='concept', version=HEAD, name='concept', parent=source, concept_class='Diagnosis', datatype='None', names=[ LocalizedTextFactory.build(name="mg", locale='en', locale_preferred=True), LocalizedTextFactory.build(name='mg', locale='en', type='Short'), ] ) ) self.assertEqual(concept.errors, {}) self.assertIsNotNone(concept.id)
def test_concept_class_is_valid_attribute_negative(self): source = OrganizationSourceFactory(custom_validation_schema=CUSTOM_VALIDATION_SCHEMA_OPENMRS) concept = Concept.persist_new( dict( mnemonic='concept1', version=HEAD, name='concept1', parent=source, concept_class='XYZQWERT', datatype='None', names=[LocalizedTextFactory.build(name='Grip', locale='es', locale_preferred=True)] ) ) self.assertEqual( concept.errors, dict(concept_class=[OPENMRS_CONCEPT_CLASS]) )
def update(self, request, **kwargs): key = kwargs.get('extra') value = request.data.get(key) if not value: return Response(['Must specify %s param in body.' % key], status=status.HTTP_400_BAD_REQUEST) new_version = self.get_object().clone() new_version.extras[key] = value new_version.comment = 'Updated extras: %s=%s.' % (key, value) errors = Concept.persist_clone(new_version, request.user) if errors: return Response(errors, status=status.HTTP_400_BAD_REQUEST) return Response({key: value})
def test_description_locale_is_valid_attribute_negative(self): source = SourceFactory(custom_validation_schema=CUSTOM_VALIDATION_SCHEMA_OPENMRS) concept = Concept.persist_new( dict( mnemonic='concept1', version=HEAD, name='concept1', parent=source, concept_class='Diagnosis', datatype='None', names=[LocalizedTextFactory.build(locale_preferred=True)], descriptions=[LocalizedTextFactory.build(locale_preferred=True, locale='FOOBAR')] ) ) self.assertEqual( concept.errors, dict(descriptions=[OPENMRS_DESCRIPTION_LOCALE]) )
def delete(self, request, *args, **kwargs): instance = self.get_object() if instance: resource_instance = self.get_resource_object() new_version = resource_instance.clone() subject_label_attr = "cloned_{}".format(self.parent_list_attribute) labels = [name.clone() for name in resource_instance.names.exclude(id=instance.id)] setattr(new_version, subject_label_attr, labels) new_version.comment = 'Deleted %s in %s.' % (instance.name, self.parent_list_attribute) errors = Concept.persist_clone(new_version, request.user) if errors: return Response(errors, status=status.HTTP_400_BAD_REQUEST) return Response(status=status.HTTP_204_NO_CONTENT)