def test_categories_to_string(self): categories = [{"title": "Business"}, {"title": "Education"}] out = model_access.categories_to_string(categories) self.assertEqual(out, "['Business', 'Education']") categories = models.Category.objects.filter(title__istartswith='b') out = model_access.categories_to_string(categories, True) self.assertEqual(out, "['Books and Reference', 'Business']")
def test_categories_to_string(self): categories = [ {"title": "Business"}, {"title": "Education"} ] out = model_access.categories_to_string(categories) self.assertEqual(out, "['Business', 'Education']") categories = models.Category.objects.filter(title__istartswith='b') out = model_access.categories_to_string(categories, True) self.assertEqual(out, "['Books and Reference', 'Business']")
def test_categories_to_string_dict(self): categories = [ {"title": "Business"}, {"title": "Education"} ] out = model_access.categories_to_string(categories) self.assertEqual(out, str(['Business', 'Education']))
def update(self, instance, validated_data): logger.debug('inside ListingSerializer.update') user = generic_model_access.get_profile( self.context['request'].user.username) if user.highest_role() not in ['APPS_MALL_STEWARD', 'ORG_STEWARD']: if user not in instance.owners.all(): raise errors.PermissionDenied( 'User is not an owner of this listing') change_details = [] simple_fields = ['title', 'description', 'description_short', 'launch_url', 'version_name', 'requirements', 'unique_name', 'what_is_new', 'security_marking'] for i in simple_fields: if getattr(instance, i) != validated_data[i]: change_details.append({'old_value': getattr(instance, i), 'new_value': validated_data[i], 'field_name': i}) setattr(instance, i, validated_data[i]) if validated_data['is_enabled'] != instance.is_enabled: if validated_data['is_enabled']: model_access.enable_listing(user, instance) change_details.append({'field_name': 'is_enabled', 'old_value': 'false', 'new_value': 'true'}) else: model_access.disable_listing(user, instance) change_details.append({'field_name': 'is_enabled', 'old_value': 'true', 'new_value': 'false'}) instance.is_enabled = validated_data['is_enabled'] if validated_data['is_private'] != instance.is_private: change_details.append({'old_value': model_access.bool_to_string(instance.is_private), 'new_value': model_access.bool_to_string(validated_data['is_private']), 'field_name': 'is_private'}) instance.is_private = validated_data['is_private'] if validated_data['is_featured'] != instance.is_featured: if user.highest_role() not in ['APPS_MALL_STEWARD', 'ORG_STEWARD']: raise errors.PermissionDenied('Only stewards can change is_featured setting of a listing') change_details.append({'old_value': model_access.bool_to_string(instance.is_featured), 'new_value': model_access.bool_to_string(validated_data['is_featured']), 'field_name': 'is_featured'}) instance.is_featured = validated_data['is_featured'] s = validated_data['approval_status'] if s and s != instance.approval_status: if s == models.Listing.APPROVED and user.highest_role() != 'APPS_MALL_STEWARD': raise errors.PermissionDenied('Only an APPS_MALL_STEWARD can mark a listing as APPROVED') if s == models.Listing.APPROVED_ORG and user.highest_role() not in ['APPS_MALL_STEWARD', 'ORG_STEWARD']: raise errors.PermissionDenied('Only stewards can mark a listing as APPROVED_ORG') if s == models.Listing.PENDING: model_access.submit_listing(user, instance) if s == models.Listing.APPROVED_ORG: model_access.approve_listing_by_org_steward(user, instance) if s == models.Listing.APPROVED: model_access.approve_listing(user, instance) if s == models.Listing.REJECTED: # TODO: need to get the rejection text from somewhere model_access.reject_listing(user, instance, 'TODO: rejection reason') if instance.listing_type != validated_data['listing_type']: if instance.listing_type: old_value = instance.listing_type.title else: old_value = None if validated_data['listing_type']: new_value = validated_data['listing_type'].title else: new_value = None change_details.append({'old_value': old_value, 'new_value': new_value, 'field_name': 'listing_type'}) instance.listing_type = validated_data['listing_type'] image_keys = ['small_icon', 'large_icon', 'banner_icon', 'large_banner_icon'] for image_key in image_keys: if validated_data[image_key]: old_value = model_access.image_to_string(getattr(instance, image_key), True, 'old_value(%s)'%image_key) new_value = model_access.image_to_string(validated_data[image_key], False, 'new_value(%s)'%image_key) if old_value != new_value: new_value_image = None old_image_id = None if old_value is not None: old_image_id = getattr(instance, image_key).id if validated_data[image_key].get('id') == old_image_id: new_value_image = getattr(instance, image_key) new_value_image.security_marking = validated_data[image_key].get('security_marking') new_value_image.save() else: new_value_image = image_model_access.get_image_by_id(validated_data[image_key].get('id')) if new_value_image is None: raise errors.InvalidInput('Error while saving, can not find image by id') change_details.append({'old_value': old_value, 'new_value': new_value, 'field_name': image_key}) if image_key == 'small_icon': instance.small_icon = new_value_image elif image_key == 'large_icon': instance.large_icon = new_value_image elif image_key == 'banner_icon': instance.banner_icon = new_value_image elif image_key == 'large_banner_icon': instance.large_banner_icon = new_value_image if 'contacts' in validated_data: old_contact_instances = instance.contacts.all() old_contacts = model_access.contacts_to_string( old_contact_instances, True) new_contacts = model_access.contacts_to_string( validated_data['contacts']) if old_contacts != new_contacts: change_details.append({'old_value': old_contacts, 'new_value': new_contacts, 'field_name': 'contacts'}) instance.contacts.clear() for contact in validated_data['contacts']: # TODO: Smarter Handling of Duplicates Contact Records # A contact with the same name and email should be the same contact # in the backend. # Person1(name='N1',email='*****@*****.**') and # Person1' (name='N1',email='*****@*****.**',secure_phone = '414-444-444') # The two people above should be one contact # if approval_status: "IN_PROGRESS" then it should be using # contact model ids' since it is temporary contacts obj, created = models.Contact.objects.get_or_create( name=contact['name'], email=contact['email'], secure_phone=contact['secure_phone'], unsecure_phone=contact['unsecure_phone'], organization=contact.get('organization', None), contact_type=contact_type_model_access.get_contact_type_by_name( contact['contact_type']['name']) ) instance.contacts.add(obj) if 'categories' in validated_data: old_category_instances = instance.categories.all() old_categories = model_access.categories_to_string( old_category_instances, True) new_categories = model_access.categories_to_string( validated_data['categories'], True) if old_categories != new_categories: change_details.append({'old_value': old_categories, 'new_value': new_categories, 'field_name': 'categories'}) instance.categories.clear() for category in validated_data['categories']: instance.categories.add(category) if 'owners' in validated_data: old_owner_instances = instance.owners.all() old_owners = model_access.owners_to_string( old_owner_instances, True) new_owners = model_access.owners_to_string( validated_data['owners'], True) if old_owners != new_owners: change_details.append({'old_value': old_owners, 'new_value': new_owners, 'field_name': 'owners'}) instance.owners.clear() for owner in validated_data['owners']: instance.owners.add(owner) # tags will be automatically created if necessary if 'tags' in validated_data: old_tag_instances = instance.tags.all() old_tags = model_access.tags_to_string(old_tag_instances, True) new_tags = model_access.tags_to_string(validated_data['tags']) if old_tags != new_tags: change_details.append({'old_value': old_tags, 'new_value': new_tags, 'field_name': 'tags'}) instance.tags.clear() for tag in validated_data['tags']: obj, created = models.Tag.objects.get_or_create( name=tag['name']) instance.tags.add(obj) if 'intents' in validated_data: old_intent_instances = instance.intents.all() old_intents = model_access.intents_to_string(old_intent_instances, True) new_intents = model_access.intents_to_string( validated_data['intents'], True) if old_intents != new_intents: change_details.append({'old_value': old_intents, 'new_value': new_intents, 'field_name': 'intents'}) instance.intents.clear() for intent in validated_data['intents']: instance.intents.add(intent) # doc_urls will be automatically created if 'doc_urls' in validated_data: old_doc_url_instances = model_access.get_doc_urls_for_listing(instance) old_doc_urls = model_access.doc_urls_to_string( old_doc_url_instances, True) new_doc_urls = model_access.doc_urls_to_string( validated_data['doc_urls']) if old_doc_urls != new_doc_urls: change_details.append({ 'old_value': old_doc_urls, 'new_value': new_doc_urls, 'field_name': 'doc_urls'}) new_doc_url_instances = [] for d in validated_data['doc_urls']: obj, created = models.DocUrl.objects.get_or_create( name=d['name'], url=d['url'], listing=instance) new_doc_url_instances.append(obj) for i in old_doc_url_instances: if i not in new_doc_url_instances: logger.info('Deleting doc_url: %s' % i.id) i.delete() # screenshots will be automatically created if 'screenshots' in validated_data: old_screenshot_instances = model_access.get_screenshots_for_listing(instance) old_screenshots = model_access.screenshots_to_string(old_screenshot_instances, True) new_screenshots = model_access.screenshots_to_string(validated_data['screenshots']) if old_screenshots != new_screenshots: change_details.append({'old_value': old_screenshots, 'new_value': new_screenshots, 'field_name': 'screenshots'}) new_screenshot_instances = [] for s in validated_data['screenshots']: new_small_image = image_model_access.get_image_by_id(s['small_image']['id']) new_small_image.security_marking = s['small_image']['security_marking'] new_small_image.save() new_large_image = image_model_access.get_image_by_id(s['large_image']['id']) new_large_image.security_marking = s['large_image']['security_marking'] new_large_image.save() obj, created = models.Screenshot.objects.get_or_create( small_image=new_small_image, large_image=new_large_image, listing=instance) new_screenshot_instances.append(obj) for i in old_screenshot_instances: if i not in new_screenshot_instances: logger.info('Deleting screenshot: %s' % i.id) i.delete() if 'agency' in validated_data: if instance.agency != validated_data['agency']: change_details.append({'old_value': instance.agency.title, 'new_value': validated_data['agency'].title, 'field_name': 'agency'}) instance.agency = validated_data['agency'] instance.save() model_access.log_listing_modification(user, instance, change_details) instance.edited_date = datetime.datetime.now(pytz.utc) return instance
def test_update_listing_full(self): user = generic_model_access.get_profile('julia').user self.client.force_authenticate(user=user) url = '/api/listing/1/' title = 'julias app 2' data = { "title": title, "description": "description of app", "launch_url": "http://www.google.com/launch", "version_name": "2.1.8", "unique_name": "org.apps.julia-one", "what_is_new": "nothing is new", "description_short": "a shorter description", "requirements": "Many new things", "is_private": "true", "is_enabled": "false", "is_featured": "false", "contacts": [ {"email": "*****@*****.**", "secure_phone": "111-222-3434", "unsecure_phone": "444-555-4545", "name": "me", "contact_type": {"name": "Government"} }, {"email": "*****@*****.**", "secure_phone": "222-222-3333", "unsecure_phone": "555-555-5555", "name": "you", "contact_type": {"name": "Military"} } ], "security_marking": "SECRET", "listing_type": {"title": "widget"}, "small_icon": {"id": 1}, "large_icon": {"id": 2}, "banner_icon": {"id": 3}, "large_banner_icon": {"id": 4}, "categories": [ {"title": "Business"}, {"title": "Education"} ], "owners": [ {"user": {"username": "******"}}, {"user": {"username": "******"}} ], "tags": [ {"name": "demo"}, {"name": "map"} ], "intents": [ {"action": "/application/json/view"}, {"action": "/application/json/edit"} ], "doc_urls": [ {"name": "wiki", "url": "http://www.google.com/wiki2"}, {"name": "guide", "url": "http://www.google.com/guide2"} ], "screenshots": [ {"small_image": {"id": 1}, "large_image": {"id": 2}}, {"small_image": {"id": 3}, "large_image": {"id": 4}} ] } # for checking Activity status later on old_listing_data = self.client.get(url, format='json').data response = self.client.put(url, data, format='json') self.assertEqual(response.status_code, status.HTTP_200_OK) # title self.assertEqual(response.data['title'], data['title']) # description self.assertEqual(response.data['description'], data['description']) # launch_url self.assertEqual(response.data['launch_url'], data['launch_url']) # version_name self.assertEqual(response.data['version_name'], data['version_name']) # unique_name self.assertEqual(response.data['unique_name'], data['unique_name']) # what_is_new self.assertEqual(response.data['what_is_new'], data['what_is_new']) # description_short self.assertEqual(response.data['description_short'], data['description_short']) # requirements self.assertEqual(response.data['requirements'], data['requirements']) # is_private self.assertEqual(response.data['is_private'], True) # contacts self.assertEqual(len(response.data['contacts']), 2) names = [] for c in response.data['contacts']: names.append(c['name']) self.assertTrue('me' in names) self.assertTrue('you' in names) # security_marking self.assertEqual(response.data['security_marking'], 'SECRET') # listing_type self.assertEqual(response.data['listing_type']['title'], 'widget') # icons self.assertEqual(response.data['small_icon']['id'], 1) self.assertEqual(response.data['large_icon']['id'], 2) self.assertEqual(response.data['banner_icon']['id'], 3) self.assertEqual(response.data['large_banner_icon']['id'], 4) # categories categories = [] for c in response.data['categories']: categories.append(c['title']) self.assertEqual(len(response.data['categories']), 2) self.assertTrue('Business' in categories) self.assertTrue('Education' in categories) # owners owners = [] for o in response.data['owners']: owners.append(o['user']['username']) self.assertEqual(len(response.data['owners']), 2) self.assertTrue('wsmith' in owners) self.assertTrue('julia' in owners) # tags tags = [] for t in response.data['tags']: tags.append(t['name']) self.assertEqual(len(response.data['tags']), 2) self.assertTrue('demo' in tags) self.assertTrue('map' in tags) # intents intents = [] for i in response.data['intents']: intents.append(i['action']) self.assertEqual(len(response.data['intents']), 2) self.assertTrue('/application/json/view' in intents) self.assertTrue('/application/json/edit' in intents) # doc_urls doc_urls = [] for d in response.data['doc_urls']: doc_urls.append(d['url']) self.assertEqual(len(response.data['doc_urls']), 2) self.assertTrue('http://www.google.com/wiki2' in doc_urls) self.assertTrue('http://www.google.com/guide2' in doc_urls) # screenshots screenshots_small = [] self.assertEqual(len(response.data['screenshots']), 2) for s in response.data['screenshots']: screenshots_small.append(s['small_image']['id']) self.assertTrue(1 in screenshots_small) self.assertTrue(3 in screenshots_small) screenshots_large = [] for s in response.data['screenshots']: screenshots_large.append(s['large_image']['id']) self.assertTrue(2 in screenshots_large) self.assertTrue(4 in screenshots_large) self.assertTrue(response.data['approved_date']) self.assertEqual(response.data['approval_status'], models.Listing.APPROVED) self.assertEqual(response.data['is_enabled'], False) self.assertEqual(response.data['is_featured'], False) self.assertEqual(response.data['avg_rate'], 3.0) self.assertEqual(response.data['total_votes'], 3) self.assertEqual(response.data['total_rate5'], 1) self.assertEqual(response.data['total_rate4'], 0) self.assertEqual(response.data['total_rate3'], 1) self.assertEqual(response.data['total_rate2'], 0) self.assertEqual(response.data['total_rate1'], 1) self.assertEqual(response.data['total_reviews'], 3) self.assertEqual(response.data['iframe_compatible'], False) self.assertEqual(response.data['required_listings'], None) self.assertTrue(response.data['edited_date']) self.assertEquals(self._validate_listing_map_keys(response.data), []) # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # verify change_details # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - activity_url = url + 'activity/' activity_response = self.client.get(activity_url, format='json') activity_data = activity_response.data fields = ['title', 'description', 'description_short', 'version_name', 'requirements', 'unique_name', 'what_is_new', 'launch_url', 'is_enabled', 'is_featured', 'is_private', 'doc_urls', 'contacts', 'screenshots', 'categories', 'owners', 'tags', 'small_icon', 'large_icon', 'banner_icon', 'large_banner_icon', 'security_marking', 'listing_type', 'approval_status', 'intents'] total_found = 0 for activity in activity_data: if activity['action'] == 'MODIFIED': for change in activity['change_details']: if change['field_name'] == 'title': self.assertEqual(change['new_value'], data['title']) self.assertEqual(change['old_value'], old_listing_data['title']) total_found += 1 if change['field_name'] == 'description': self.assertEqual(change['new_value'], data['description']) self.assertEqual(change['old_value'], old_listing_data['description']) total_found += 1 if change['field_name'] == 'description_short': self.assertEqual(change['new_value'], data['description_short']) self.assertEqual(change['old_value'], old_listing_data['description_short']) total_found += 1 if change['field_name'] == 'version_name': self.assertEqual(change['new_value'], data['version_name']) self.assertEqual(change['old_value'], old_listing_data['version_name']) total_found += 1 if change['field_name'] == 'requirements': self.assertEqual(change['new_value'], data['requirements']) self.assertEqual(change['old_value'], old_listing_data['requirements']) total_found += 1 if change['field_name'] == 'what_is_new': self.assertEqual(change['new_value'], data['what_is_new']) self.assertEqual(change['old_value'], old_listing_data['what_is_new']) total_found += 1 if change['field_name'] == 'unique_name': self.assertEqual(change['new_value'], data['unique_name']) self.assertEqual(change['old_value'], old_listing_data['unique_name']) total_found += 1 if change['field_name'] == 'launch_url': self.assertEqual(change['new_value'], data['launch_url']) self.assertEqual(change['old_value'], old_listing_data['launch_url']) total_found += 1 if change['field_name'] == 'is_private': self.assertEqual(change['new_value'], data['is_private']) self.assertEqual(change['old_value'], model_access.bool_to_string(old_listing_data['is_private'])) total_found += 1 if change['field_name'] == 'is_featured': self.assertEqual(change['new_value'], data['is_featured']) self.assertEqual(change['old_value'], model_access.bool_to_string(old_listing_data['is_featured'])) total_found += 1 if change['field_name'] == 'listing_type': self.assertEqual(change['new_value'], data['listing_type']['title']) self.assertEqual(change['old_value'], old_listing_data['listing_type']['title']) total_found += 1 if change['field_name'] == 'security_marking': self.assertEqual(change['new_value'], data['security_marking']) self.assertEqual(change['old_value'], old_listing_data['security_marking']) total_found += 1 if change['field_name'] == 'small_icon': self.assertEqual(change['new_value'], str(data['small_icon']['id']) + '.UNCLASSIFIED') self.assertEqual(change['old_value'], str(old_listing_data['small_icon']['id']) + '.UNCLASSIFIED') total_found += 1 if change['field_name'] == 'large_icon': self.assertEqual(change['new_value'], str(data['large_icon']['id']) + '.UNCLASSIFIED') self.assertEqual(change['old_value'], str(old_listing_data['large_icon']['id']) + '.UNCLASSIFIED') total_found += 1 if change['field_name'] == 'banner_icon': self.assertEqual(change['new_value'], str(data['banner_icon']['id']) + '.UNCLASSIFIED') self.assertEqual(change['old_value'], str(old_listing_data['banner_icon']['id']) + '.UNCLASSIFIED') total_found += 1 if change['field_name'] == 'large_banner_icon': self.assertEqual(change['new_value'], str(data['large_banner_icon']['id']) + '.UNCLASSIFIED') self.assertEqual(change['old_value'], str(old_listing_data['large_banner_icon']['id']) + '.UNCLASSIFIED') total_found += 1 if change['field_name'] == 'doc_urls': self.assertEqual(change['new_value'], model_access.doc_urls_to_string(data['doc_urls'])) self.assertEqual(change['old_value'], model_access.doc_urls_to_string(old_listing_data['doc_urls'])) total_found += 1 if change['field_name'] == 'screenshots': self.assertEqual(change['new_value'], model_access.screenshots_to_string(data['screenshots'])) self.assertEqual(change['old_value'], model_access.screenshots_to_string(old_listing_data['screenshots'])) total_found += 1 if change['field_name'] == 'contacts': self.assertEqual(change['new_value'], model_access.contacts_to_string(data['contacts'])) self.assertEqual(change['old_value'], model_access.contacts_to_string(old_listing_data['contacts'])) total_found += 1 if change['field_name'] == 'intents': self.assertEqual(change['new_value'], model_access.intents_to_string(data['intents'])) self.assertEqual(change['old_value'], model_access.intents_to_string(old_listing_data['intents'])) total_found += 1 if change['field_name'] == 'categories': self.assertEqual(change['new_value'], model_access.categories_to_string(data['categories'])) self.assertEqual(change['old_value'], model_access.categories_to_string(old_listing_data['categories'])) total_found += 1 if change['field_name'] == 'tags': self.assertEqual(change['new_value'], model_access.tags_to_string(data['tags'])) self.assertEqual(change['old_value'], model_access.tags_to_string(old_listing_data['tags'])) total_found += 1 if change['field_name'] == 'owners': self.assertEqual(change['new_value'], model_access.owners_to_string(data['owners'])) self.assertEqual(change['old_value'], model_access.owners_to_string(old_listing_data['owners'])) total_found += 1 self.assertEqual(total_found, len(fields) - 2) # (-1 for approved_status) + (-1 for is_enabled)
def update(self, instance, validated_data): user = generic_model_access.get_profile( self.context['request'].user.username) if user.highest_role() not in ['APPS_MALL_STEWARD', 'ORG_STEWARD']: if user not in instance.owners.all(): raise errors.PermissionDenied( 'User is not an owner of this listing') change_details = [] simple_fields = ['title', 'description', 'description_short', 'launch_url', 'version_name', 'requirements', 'unique_name', 'what_is_new', 'security_marking'] for i in simple_fields: if getattr(instance, i) != validated_data[i]: change_details.append({'old_value': getattr(instance, i), 'new_value': validated_data[i], 'field_name': i}) setattr(instance, i, validated_data[i]) if validated_data['is_enabled'] != instance.is_enabled: if validated_data['is_enabled']: model_access.enable_listing(user, instance) change_details.append({'field_name': 'is_enabled', 'old_value': 'false', 'new_value': 'true'}) else: model_access.disable_listing(user, instance) change_details.append({'field_name': 'is_enabled', 'old_value': 'true', 'new_value': 'false'}) instance.is_enabled = validated_data['is_enabled'] if validated_data['is_private'] != instance.is_private: change_details.append({'old_value': model_access.bool_to_string(instance.is_private), 'new_value': model_access.bool_to_string(validated_data['is_private']), 'field_name': 'is_private'}) instance.is_private = validated_data['is_private'] if validated_data['is_featured'] != instance.is_featured: if user.highest_role() not in ['APPS_MALL_STEWARD', 'ORG_STEWARD']: raise errors.PermissionDenied('Only stewards can change is_featured setting of a listing') change_details.append({'old_value': model_access.bool_to_string(instance.is_featured), 'new_value': model_access.bool_to_string(validated_data['is_featured']), 'field_name': 'is_featured'}) instance.is_featured = validated_data['is_featured'] s = validated_data['approval_status'] if s and s != instance.approval_status: if s == models.Listing.APPROVED and user.highest_role() != 'APPS_MALL_STEWARD': raise errors.PermissionDenied('Only an APPS_MALL_STEWARD can mark a listing as APPROVED') if s == models.Listing.APPROVED_ORG and user.highest_role() not in ['APPS_MALL_STEWARD', 'ORG_STEWARD']: raise errors.PermissionDenied('Only stewards can mark a listing as APPROVED_ORG') if s == models.Listing.PENDING: model_access.submit_listing(user, instance) if s == models.Listing.APPROVED_ORG: model_access.approve_listing_by_org_steward(user, instance) if s == models.Listing.APPROVED: model_access.approve_listing(user, instance) if s == models.Listing.REJECTED: # TODO: need to get the rejection text from somewhere model_access.reject_listing(user, instance, 'TODO: rejection reason') if instance.listing_type != validated_data['listing_type']: if instance.listing_type: old_value = instance.listing_type.title else: old_value = None if validated_data['listing_type']: new_value = validated_data['listing_type'].title else: new_value = None change_details.append({'old_value': old_value, 'new_value': new_value, 'field_name': 'listing_type'}) instance.listing_type = validated_data['listing_type'] if instance.small_icon != validated_data['small_icon']: if instance.small_icon: old_value = instance.small_icon.id else: old_value = None if validated_data['small_icon']: new_value = validated_data['small_icon'].id else: new_value = None change_details.append({'old_value': old_value, 'new_value': new_value, 'field_name': 'small_icon'}) instance.small_icon = validated_data['small_icon'] if instance.large_icon != validated_data['large_icon']: if instance.large_icon: old_value = instance.large_icon.id else: old_value = None if validated_data['large_icon']: new_value = validated_data['large_icon'].id else: new_value = None change_details.append({'old_value': old_value, 'new_value': new_value, 'field_name': 'large_icon'}) instance.large_icon = validated_data['large_icon'] if instance.banner_icon != validated_data['banner_icon']: if instance.banner_icon: old_value = instance.banner_icon.id else: old_value = None if validated_data['banner_icon']: new_value = validated_data['banner_icon'].id else: new_value = None change_details.append({'old_value': old_value, 'new_value': new_value, 'field_name': 'banner_icon'}) instance.banner_icon = validated_data['banner_icon'] if instance.large_banner_icon != validated_data['large_banner_icon']: if instance.large_banner_icon: old_value = instance.large_banner_icon.id else: old_value = None if validated_data['large_banner_icon']: new_value = validated_data['large_banner_icon'].id else: new_value = None change_details.append({'old_value': old_value, 'new_value': new_value, 'field_name': 'large_banner_icon'}) instance.large_banner_icon = validated_data['large_banner_icon'] if 'contacts' in validated_data: old_contact_instances = instance.contacts.all() old_contacts = model_access.contacts_to_string( old_contact_instances, True) new_contacts = model_access.contacts_to_string( validated_data['contacts']) if old_contacts != new_contacts: change_details.append({'old_value': old_contacts, 'new_value': new_contacts, 'field_name': 'contacts'}) instance.contacts.clear() for contact in validated_data['contacts']: obj, created = models.Contact.objects.get_or_create( name=contact['name'], email=contact['email'], secure_phone=contact['secure_phone'], unsecure_phone=contact['unsecure_phone'], organization=contact.get('organization', None), contact_type=contact_type_model_access.get_contact_type_by_name( contact['contact_type']['name']) ) instance.contacts.add(obj) if 'categories' in validated_data: old_category_instances = instance.categories.all() old_categories = model_access.categories_to_string( old_category_instances, True) new_categories = model_access.categories_to_string( validated_data['categories'], True) if old_categories != new_categories: change_details.append({'old_value': old_categories, 'new_value': new_categories, 'field_name': 'categories'}) instance.categories.clear() for category in validated_data['categories']: instance.categories.add(category) if 'owners' in validated_data: old_owner_instances = instance.owners.all() old_owners = model_access.owners_to_string( old_owner_instances, True) new_owners = model_access.owners_to_string( validated_data['owners'], True) if old_owners != new_owners: change_details.append({'old_value': old_owners, 'new_value': new_owners, 'field_name': 'owners'}) instance.owners.clear() for owner in validated_data['owners']: instance.owners.add(owner) # tags will be automatically created if necessary if 'tags' in validated_data: old_tag_instances = instance.tags.all() old_tags = model_access.tags_to_string(old_tag_instances, True) new_tags = model_access.tags_to_string(validated_data['tags']) if old_tags != new_tags: change_details.append({'old_value': old_tags, 'new_value': new_tags, 'field_name': 'tags'}) instance.tags.clear() for tag in validated_data['tags']: obj, created = models.Tag.objects.get_or_create( name=tag['name']) instance.tags.add(obj) if 'intents' in validated_data: old_intent_instances = instance.intents.all() old_intents = model_access.intents_to_string(old_intent_instances, True) new_intents = model_access.intents_to_string( validated_data['intents'], True) if old_intents != new_intents: change_details.append({'old_value': old_intents, 'new_value': new_intents, 'field_name': 'intents'}) instance.intents.clear() for intent in validated_data['intents']: instance.intents.add(intent) # doc_urls will be automatically created if 'doc_urls' in validated_data: old_doc_url_instances = model_access.get_doc_urls_for_listing(instance) old_doc_urls = model_access.doc_urls_to_string( old_doc_url_instances, True) new_doc_urls = model_access.doc_urls_to_string( validated_data['doc_urls']) if old_doc_urls != new_doc_urls: change_details.append({ 'old_value': old_doc_urls, 'new_value': new_doc_urls, 'field_name': 'doc_urls'}) new_doc_url_instances = [] for d in validated_data['doc_urls']: obj, created = models.DocUrl.objects.get_or_create( name=d['name'], url=d['url'], listing=instance) new_doc_url_instances.append(obj) for i in old_doc_url_instances: if i not in new_doc_url_instances: logger.info('Deleting doc_url: %s' % i.id) i.delete() # screenshots will be automatically created if 'screenshots' in validated_data: old_screenshot_instances = model_access.get_screenshots_for_listing(instance) old_screenshots = model_access.screenshots_to_string(old_screenshot_instances, True) new_screenshots = model_access.screenshots_to_string( validated_data['screenshots']) if old_screenshots != new_screenshots: change_details.append({'old_value': old_screenshots, 'new_value': new_screenshots, 'field_name': 'screenshots'}) new_screenshot_instances = [] for s in validated_data['screenshots']: obj, created = models.Screenshot.objects.get_or_create( small_image=image_model_access.get_image_by_id( s['small_image']['id']), large_image=image_model_access.get_image_by_id( s['large_image']['id']), listing=instance) new_screenshot_instances.append(obj) for i in old_screenshot_instances: if i not in new_screenshot_instances: logger.info('Deleting screenshot: %s' % i.id) i.delete() if 'agency' in validated_data: if instance.agency != validated_data['agency']: change_details.append({'old_value': instance.agency.title, 'new_value': validated_data['agency'].title, 'field_name': 'agency'}) instance.agency = validated_data['agency'] instance.save() model_access.log_listing_modification(user, instance, change_details) instance.edited_date = datetime.datetime.now(pytz.utc) return instance
def test_categories_to_string_object(self): categories = models.Category.objects.filter(title__istartswith='b') out = model_access.categories_to_string(categories, True) self.assertEqual(out, str(['Books and Reference', 'Business']))
def update_listing(serializer_instance, instance, validated_data): # TODO Put in listing model_access.py user = generic_model_access.get_profile(serializer_instance.context['request'].user.username) if user.highest_role() not in ['APPS_MALL_STEWARD', 'ORG_STEWARD']: if user not in instance.owners.all(): raise errors.PermissionDenied( 'User ({0!s}) is not an owner of this listing'.format(user.username)) if instance.is_deleted: raise errors.PermissionDenied('Cannot update a previously deleted listing') change_details = [] simple_fields = ['title', 'description', 'description_short', 'launch_url', 'version_name', 'usage_requirements', 'system_requirements', 'unique_name', 'what_is_new', 'security_marking'] for i in simple_fields: if getattr(instance, i) != validated_data[i]: if validated_data[i] is not None: change_details.append({'old_value': getattr(instance, i), 'new_value': validated_data[i], 'field_name': i}) setattr(instance, i, validated_data[i]) if validated_data['is_enabled'] is not None and validated_data['is_enabled'] != instance.is_enabled: if validated_data['is_enabled']: model_access.enable_listing(user, instance) else: model_access.disable_listing(user, instance) instance.is_enabled = validated_data['is_enabled'] if validated_data['approval_status'] == models.Listing.APPROVED: dispatcher.publish('listing_enabled_status_changed', listing=instance, profile=user, is_enabled=validated_data['is_enabled']) if validated_data['is_508_compliant'] is not None and validated_data['is_508_compliant'] != instance.is_508_compliant: changeset = {'old_value': model_access.bool_to_string(instance.is_508_compliant), 'new_value': model_access.bool_to_string(validated_data['is_508_compliant']), 'field_name': 'is_508_compliant'} change_details.append(changeset) instance.is_508_compliant = validated_data['is_508_compliant'] if validated_data['is_private'] is not None and validated_data['is_private'] != instance.is_private: changeset = {'old_value': model_access.bool_to_string(instance.is_private), 'new_value': model_access.bool_to_string(validated_data['is_private']), 'field_name': 'is_private'} change_details.append(changeset) instance.is_private = validated_data['is_private'] if validated_data['approval_status'] == models.Listing.APPROVED: dispatcher.publish('listing_private_status_changed', listing=instance, profile=user, is_private=validated_data['is_private']) if validated_data['is_featured'] is not None and validated_data['is_featured'] != instance.is_featured: if user.highest_role() not in ['APPS_MALL_STEWARD', 'ORG_STEWARD']: raise errors.PermissionDenied('Only stewards can change is_featured setting of a listing') change_details.append({'old_value': model_access.bool_to_string(instance.is_featured), 'new_value': model_access.bool_to_string(validated_data['is_featured']), 'field_name': 'is_featured'}) instance.is_featured = validated_data['is_featured'] instance.featured_date = datetime.datetime.now(pytz.utc) if validated_data['is_featured'] else None s = validated_data['approval_status'] if s and s != instance.approval_status: # Check to see if approval_status has changed old_approval_status = instance.approval_status if s == models.Listing.APPROVED and user.highest_role() != 'APPS_MALL_STEWARD': raise errors.PermissionDenied('Only an APPS_MALL_STEWARD can mark a listing as APPROVED') if s == models.Listing.APPROVED_ORG and user.highest_role() not in ['APPS_MALL_STEWARD', 'ORG_STEWARD']: raise errors.PermissionDenied('Only stewards can mark a listing as APPROVED_ORG') if s == models.Listing.PENDING: model_access.submit_listing(user, instance) if s == models.Listing.PENDING_DELETION: # pending deletion should be handled through ListingPendingDeletionViewSet # keeping this here for now for backwards compatibility model_access.pending_delete_listing(user, instance, 'Unknown reason') if s == models.Listing.APPROVED_ORG: model_access.approve_listing_by_org_steward(user, instance) if s == models.Listing.APPROVED: model_access.approve_listing(user, instance) if s == models.Listing.REJECTED: # TODO: need to get the rejection text from somewhere model_access.reject_listing(user, instance, 'TODO: rejection reason') dispatcher.publish('listing_approval_status_changed', listing=instance, profile=user, old_approval_status=old_approval_status, new_approval_status=instance.approval_status) if instance.listing_type != validated_data['listing_type']: if instance.listing_type: old_value = instance.listing_type.title else: old_value = None if validated_data['listing_type']: new_value = validated_data['listing_type'].title else: new_value = None change_details.append({'old_value': old_value, 'new_value': new_value, 'field_name': 'listing_type'}) instance.listing_type = validated_data['listing_type'] image_keys = ['small_icon', 'large_icon', 'banner_icon', 'large_banner_icon'] for image_key in image_keys: if validated_data[image_key]: old_value = model_access.image_to_string(getattr(instance, image_key), True, 'old_value({0!s})'.format(image_key)) new_value = model_access.image_to_string(validated_data[image_key], False, 'new_value({0!s})'.format(image_key)) if old_value != new_value: new_value_image = None old_image_id = None if old_value is not None: old_image_id = getattr(instance, image_key).id if validated_data[image_key].get('id') == old_image_id: new_value_image = getattr(instance, image_key) new_value_image.security_marking = validated_data[image_key].get('security_marking') new_value_image.save() else: new_value_image = image_model_access.get_image_by_id(validated_data[image_key].get('id')) if new_value_image is None: raise errors.InvalidInput('Error while saving, can not find image by id') change_details.append({'old_value': old_value, 'new_value': new_value, 'field_name': image_key}) if image_key == 'small_icon': instance.small_icon = new_value_image elif image_key == 'large_icon': instance.large_icon = new_value_image elif image_key == 'banner_icon': instance.banner_icon = new_value_image elif image_key == 'large_banner_icon': instance.large_banner_icon = new_value_image if 'contacts' in validated_data: old_contact_instances = instance.contacts.all() old_contacts = model_access.contacts_to_string(old_contact_instances, True) new_contacts = model_access.contacts_to_string(validated_data['contacts']) if old_contacts != new_contacts: change_details.append({'old_value': old_contacts, 'new_value': new_contacts, 'field_name': 'contacts'}) instance.contacts.clear() for contact in validated_data['contacts']: # TODO: Smarter Handling of Duplicates Contact Records # A contact with the same name and email should be the same contact # in the backend. # Person1(name='N1',email='*****@*****.**') and # Person1' (name='N1',email='*****@*****.**',secure_phone = '414-444-444') # The two people above should be one contact # if approval_status: "IN_PROGRESS" then it should be using # contact model ids' since it is temporary contacts obj, created = models.Contact.objects.get_or_create( name=contact['name'], email=contact['email'], secure_phone=contact['secure_phone'], unsecure_phone=contact['unsecure_phone'], organization=contact.get('organization', None), contact_type=contact_type_model_access.get_contact_type_by_name( contact['contact_type']['name']) ) instance.contacts.add(obj) if 'categories' in validated_data: old_category_instances = instance.categories.all() old_categories = model_access.categories_to_string(old_category_instances, True) new_categories = model_access.categories_to_string(validated_data['categories'], True) if old_categories != new_categories: changeset = {'old_value': old_categories, 'new_value': new_categories, 'field_name': 'categories'} change_details.append(changeset) instance.categories.clear() for category in validated_data['categories']: instance.categories.add(category) dispatcher.publish('listing_categories_changed', listing=instance, profile=user, old_categories=old_category_instances, new_categories=validated_data['categories']) if 'owners' in validated_data: old_owner_instances = instance.owners.all() old_owners = model_access.owners_to_string(old_owner_instances, True) new_owners = model_access.owners_to_string(validated_data['owners'], True) if old_owners != new_owners: change_details.append({'old_value': old_owners, 'new_value': new_owners, 'field_name': 'owners'}) instance.owners.clear() for owner in validated_data['owners']: instance.owners.add(owner) # tags will be automatically created if necessary if 'tags' in validated_data: old_tag_instances = instance.tags.all() old_tags = model_access.tags_to_string(old_tag_instances, True) new_tags = model_access.tags_to_string(validated_data['tags']) if old_tags != new_tags: changeset = {'old_value': old_tags, 'new_value': new_tags, 'field_name': 'tags'} change_details.append(changeset) instance.tags.clear() new_tags_instances = [] for tag in validated_data['tags']: obj, created = models.Tag.objects.get_or_create( name=tag['name']) instance.tags.add(obj) new_tags_instances.append(obj) dispatcher.publish('listing_tags_changed', listing=instance, profile=user, old_tags=old_tag_instances, new_tags=new_tags_instances) if 'intents' in validated_data: old_intent_instances = instance.intents.all() old_intents = model_access.intents_to_string(old_intent_instances, True) new_intents = model_access.intents_to_string(validated_data['intents'], True) if old_intents != new_intents: change_details.append({'old_value': old_intents, 'new_value': new_intents, 'field_name': 'intents'}) instance.intents.clear() for intent in validated_data['intents']: instance.intents.add(intent) # doc_urls will be automatically created if 'doc_urls' in validated_data: old_doc_url_instances = model_access.get_doc_urls_for_listing(instance) old_doc_urls = model_access.doc_urls_to_string(old_doc_url_instances, True) new_doc_urls = model_access.doc_urls_to_string(validated_data['doc_urls']) if old_doc_urls != new_doc_urls: change_details.append({ 'old_value': old_doc_urls, 'new_value': new_doc_urls, 'field_name': 'doc_urls'}) new_doc_url_instances = [] for d in validated_data['doc_urls']: obj, created = models.DocUrl.objects.get_or_create( name=d['name'], url=d['url'], listing=instance) new_doc_url_instances.append(obj) for i in old_doc_url_instances: if i not in new_doc_url_instances: logger.info('Deleting doc_url: {0!s}'.format(i.id), extra={'request': serializer_instance.context.get('request')}) i.delete() # screenshots will be automatically created if 'screenshots' in validated_data: old_screenshot_instances = model_access.get_screenshots_for_listing(instance) old_screenshots = model_access.screenshots_to_string(old_screenshot_instances, True) new_screenshots = model_access.screenshots_to_string(validated_data['screenshots']) if old_screenshots != new_screenshots: change_details.append({'old_value': old_screenshots, 'new_value': new_screenshots, 'field_name': 'screenshots'}) new_screenshot_instances = [] for s in validated_data['screenshots']: new_small_image = image_model_access.get_image_by_id(s['small_image']['id']) new_small_image.security_marking = s['small_image']['security_marking'] new_small_image.save() new_large_image = image_model_access.get_image_by_id(s['large_image']['id']) new_large_image.security_marking = s['large_image']['security_marking'] new_large_image.save() obj, created = models.Screenshot.objects.get_or_create( order=s.get('order'), small_image=new_small_image, large_image=new_large_image, description=s.get('description'), listing=instance) new_screenshot_instances.append(obj) for i in old_screenshot_instances: if i not in new_screenshot_instances: logger.info('Deleting screenshot: {0!s}'.format(i.id), extra={'request': serializer_instance.context.get('request')}) i.delete() if 'agency' in validated_data: if instance.agency != validated_data['agency']: change_details.append({'old_value': instance.agency.title, 'new_value': validated_data['agency'].title, 'field_name': 'agency'}) instance.agency = validated_data['agency'] instance.save() # If the listing was modified add an entry showing changes if change_details: model_access.log_listing_modification(user, instance, change_details) new_change_details = [] field_to_exclude = ['is_private', 'categories', 'tags'] for change_detail in change_details: if change_detail['field_name'] not in field_to_exclude: new_change_details.append(change_detail) if new_change_details: dispatcher.publish('listing_changed', listing=instance, profile=user, change_details=new_change_details) instance.edited_date = datetime.datetime.now(pytz.utc) return instance
def update(self, instance, validated_data): # logger.debug('inside ListingSerializer.update', extra={'request':self.context.get('request')}) user = generic_model_access.get_profile( self.context['request'].user.username) if user.highest_role() not in ['APPS_MALL_STEWARD', 'ORG_STEWARD']: if user not in instance.owners.all(): raise errors.PermissionDenied( 'User ({0!s}) is not an owner of this listing'.format( user.username)) if instance.is_deleted: raise errors.PermissionDenied( 'Cannot update a previously deleted listing') change_details = [] simple_fields = [ 'title', 'description', 'description_short', 'launch_url', 'version_name', 'requirements', 'unique_name', 'what_is_new', 'security_marking' ] for i in simple_fields: if getattr(instance, i) != validated_data[i]: change_details.append({ 'old_value': getattr(instance, i), 'new_value': validated_data[i], 'field_name': i }) setattr(instance, i, validated_data[i]) if validated_data['is_enabled'] != instance.is_enabled: if validated_data['is_enabled']: model_access.enable_listing(user, instance) else: model_access.disable_listing(user, instance) instance.is_enabled = validated_data['is_enabled'] if validated_data['is_private'] != instance.is_private: change_details.append({ 'old_value': model_access.bool_to_string(instance.is_private), 'new_value': model_access.bool_to_string(validated_data['is_private']), 'field_name': 'is_private' }) instance.is_private = validated_data['is_private'] if validated_data['is_featured'] != instance.is_featured: if user.highest_role() not in ['APPS_MALL_STEWARD', 'ORG_STEWARD']: raise errors.PermissionDenied( 'Only stewards can change is_featured setting of a listing' ) change_details.append({ 'old_value': model_access.bool_to_string(instance.is_featured), 'new_value': model_access.bool_to_string(validated_data['is_featured']), 'field_name': 'is_featured' }) instance.is_featured = validated_data['is_featured'] s = validated_data['approval_status'] if s and s != instance.approval_status: if s == models.Listing.APPROVED and user.highest_role( ) != 'APPS_MALL_STEWARD': raise errors.PermissionDenied( 'Only an APPS_MALL_STEWARD can mark a listing as APPROVED') if s == models.Listing.APPROVED_ORG and user.highest_role( ) not in ['APPS_MALL_STEWARD', 'ORG_STEWARD']: raise errors.PermissionDenied( 'Only stewards can mark a listing as APPROVED_ORG') if s == models.Listing.PENDING: model_access.submit_listing(user, instance) if s == models.Listing.APPROVED_ORG: model_access.approve_listing_by_org_steward(user, instance) if s == models.Listing.APPROVED: model_access.approve_listing(user, instance) if s == models.Listing.REJECTED: # TODO: need to get the rejection text from somewhere model_access.reject_listing(user, instance, 'TODO: rejection reason') if instance.listing_type != validated_data['listing_type']: if instance.listing_type: old_value = instance.listing_type.title else: old_value = None if validated_data['listing_type']: new_value = validated_data['listing_type'].title else: new_value = None change_details.append({ 'old_value': old_value, 'new_value': new_value, 'field_name': 'listing_type' }) instance.listing_type = validated_data['listing_type'] image_keys = [ 'small_icon', 'large_icon', 'banner_icon', 'large_banner_icon' ] for image_key in image_keys: if validated_data[image_key]: old_value = model_access.image_to_string( getattr(instance, image_key), True, 'old_value({0!s})'.format(image_key)) new_value = model_access.image_to_string( validated_data[image_key], False, 'new_value({0!s})'.format(image_key)) if old_value != new_value: new_value_image = None old_image_id = None if old_value is not None: old_image_id = getattr(instance, image_key).id if validated_data[image_key].get('id') == old_image_id: new_value_image = getattr(instance, image_key) new_value_image.security_marking = validated_data[ image_key].get('security_marking') new_value_image.save() else: new_value_image = image_model_access.get_image_by_id( validated_data[image_key].get('id')) if new_value_image is None: raise errors.InvalidInput( 'Error while saving, can not find image by id') change_details.append({ 'old_value': old_value, 'new_value': new_value, 'field_name': image_key }) if image_key == 'small_icon': instance.small_icon = new_value_image elif image_key == 'large_icon': instance.large_icon = new_value_image elif image_key == 'banner_icon': instance.banner_icon = new_value_image elif image_key == 'large_banner_icon': instance.large_banner_icon = new_value_image if 'contacts' in validated_data: old_contact_instances = instance.contacts.all() old_contacts = model_access.contacts_to_string( old_contact_instances, True) new_contacts = model_access.contacts_to_string( validated_data['contacts']) if old_contacts != new_contacts: change_details.append({ 'old_value': old_contacts, 'new_value': new_contacts, 'field_name': 'contacts' }) instance.contacts.clear() for contact in validated_data['contacts']: # TODO: Smarter Handling of Duplicates Contact Records # A contact with the same name and email should be the same contact # in the backend. # Person1(name='N1',email='*****@*****.**') and # Person1' (name='N1',email='*****@*****.**',secure_phone = '414-444-444') # The two people above should be one contact # if approval_status: "IN_PROGRESS" then it should be using # contact model ids' since it is temporary contacts obj, created = models.Contact.objects.get_or_create( name=contact['name'], email=contact['email'], secure_phone=contact['secure_phone'], unsecure_phone=contact['unsecure_phone'], organization=contact.get('organization', None), contact_type=contact_type_model_access. get_contact_type_by_name( contact['contact_type']['name'])) instance.contacts.add(obj) if 'categories' in validated_data: old_category_instances = instance.categories.all() old_categories = model_access.categories_to_string( old_category_instances, True) new_categories = model_access.categories_to_string( validated_data['categories'], True) if old_categories != new_categories: change_details.append({ 'old_value': old_categories, 'new_value': new_categories, 'field_name': 'categories' }) instance.categories.clear() for category in validated_data['categories']: instance.categories.add(category) if 'owners' in validated_data: old_owner_instances = instance.owners.all() old_owners = model_access.owners_to_string(old_owner_instances, True) new_owners = model_access.owners_to_string( validated_data['owners'], True) if old_owners != new_owners: change_details.append({ 'old_value': old_owners, 'new_value': new_owners, 'field_name': 'owners' }) instance.owners.clear() for owner in validated_data['owners']: instance.owners.add(owner) # tags will be automatically created if necessary if 'tags' in validated_data: old_tag_instances = instance.tags.all() old_tags = model_access.tags_to_string(old_tag_instances, True) new_tags = model_access.tags_to_string(validated_data['tags']) if old_tags != new_tags: change_details.append({ 'old_value': old_tags, 'new_value': new_tags, 'field_name': 'tags' }) instance.tags.clear() for tag in validated_data['tags']: obj, created = models.Tag.objects.get_or_create( name=tag['name']) instance.tags.add(obj) if 'intents' in validated_data: old_intent_instances = instance.intents.all() old_intents = model_access.intents_to_string( old_intent_instances, True) new_intents = model_access.intents_to_string( validated_data['intents'], True) if old_intents != new_intents: change_details.append({ 'old_value': old_intents, 'new_value': new_intents, 'field_name': 'intents' }) instance.intents.clear() for intent in validated_data['intents']: instance.intents.add(intent) # doc_urls will be automatically created if 'doc_urls' in validated_data: old_doc_url_instances = model_access.get_doc_urls_for_listing( instance) old_doc_urls = model_access.doc_urls_to_string( old_doc_url_instances, True) new_doc_urls = model_access.doc_urls_to_string( validated_data['doc_urls']) if old_doc_urls != new_doc_urls: change_details.append({ 'old_value': old_doc_urls, 'new_value': new_doc_urls, 'field_name': 'doc_urls' }) new_doc_url_instances = [] for d in validated_data['doc_urls']: obj, created = models.DocUrl.objects.get_or_create( name=d['name'], url=d['url'], listing=instance) new_doc_url_instances.append(obj) for i in old_doc_url_instances: if i not in new_doc_url_instances: logger.info( 'Deleting doc_url: {0!s}'.format(i.id), extra={'request': self.context.get('request')}) i.delete() # screenshots will be automatically created if 'screenshots' in validated_data: old_screenshot_instances = model_access.get_screenshots_for_listing( instance) old_screenshots = model_access.screenshots_to_string( old_screenshot_instances, True) new_screenshots = model_access.screenshots_to_string( validated_data['screenshots']) if old_screenshots != new_screenshots: change_details.append({ 'old_value': old_screenshots, 'new_value': new_screenshots, 'field_name': 'screenshots' }) new_screenshot_instances = [] for s in validated_data['screenshots']: new_small_image = image_model_access.get_image_by_id( s['small_image']['id']) new_small_image.security_marking = s['small_image'][ 'security_marking'] new_small_image.save() new_large_image = image_model_access.get_image_by_id( s['large_image']['id']) new_large_image.security_marking = s['large_image'][ 'security_marking'] new_large_image.save() obj, created = models.Screenshot.objects.get_or_create( small_image=new_small_image, large_image=new_large_image, listing=instance) new_screenshot_instances.append(obj) for i in old_screenshot_instances: if i not in new_screenshot_instances: logger.info('Deleting screenshot: {0!s}'.format(i.id), extra={'request': self.context.get('request')}) i.delete() if 'agency' in validated_data: if instance.agency != validated_data['agency']: change_details.append({ 'old_value': instance.agency.title, 'new_value': validated_data['agency'].title, 'field_name': 'agency' }) instance.agency = validated_data['agency'] instance.save() # If the listing was modified add an entry showing changes if change_details: model_access.log_listing_modification(user, instance, change_details) instance.edited_date = datetime.datetime.now(pytz.utc) return instance