def test_delete_listing(self):
        url = '/api/listing/1/'
        response = APITestHelper.request(self, url, 'GET', username='******', status_code=200)
        self.assertFalse(response.data.get('is_deleted'))
        self.assertEqual(validate_listing_map_keys(response.data), [])

        url = '/api/listing/1/'
        data = {'description': 'deleting listing'}
        response = APITestHelper.request(self, url, 'DELETE', data=data, username='******', status_code=204)

        url = '/api/listing/1/'
        response = APITestHelper.request(self, url, 'GET', username='******', status_code=200)
        self.assertTrue(response.data.get('is_deleted'))
        self.assertEqual(validate_listing_map_keys(response.data), [])
    def test_delete_review(self):
        # test_delete_review
        air_mail_id = models.Listing.objects.get(title='Air Mail').id
        url = '/api/listing/{0!s}/review/'.format(air_mail_id)
        data = {'rate': 4, 'text': 'winston test review'}

        user = generic_model_access.get_profile('wsmith').user
        self.client.force_authenticate(user=user)
        response = self.client.post(url, data, format='json')
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        review_id = response.data['id']

        # trying to delete it as a different user should fail...
        url = '/api/listing/{0!s}/review/{1!s}/'.format(air_mail_id, review_id)
        user = generic_model_access.get_profile('jones').user
        self.client.force_authenticate(user=user)
        response = self.client.delete(url, format='json')
        self.assertEqual(response.data, ExceptionUnitTestHelper.permission_denied("Cannot update another user's review"))

        # ... unless that user is an org steward or apps mall steward
        user = generic_model_access.get_profile('julia').user
        self.client.force_authenticate(user=user)
        response = self.client.delete(url, format='json')
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)

        # Check listing history
        url = '/api/listing/{0!s}/'.format(air_mail_id)
        response = APITestHelper.request(self, url, 'GET', username='******', status_code=200)
        data = response.data

        self.assertEqual(validate_listing_map_keys(data), [])
        self.assertEqual(data['last_activity']['author']['user']['username'], 'julia')
        self.assertEqual(data['last_activity']['action'], 'REVIEW_DELETED')
        self.assertEqual(data['last_activity']['listing']['id'], air_mail_id)
    def test_self_deleted_listing(self):
        url = '/api/self/listing/'
        response = APITestHelper.request(self, url, 'GET', username='******', status_code=200)

        titles = [i['id'] for i in response.data]
        self.assertTrue('1' not in titles)
        for listing_map in response.data:
            self.assertEqual(validate_listing_map_keys(listing_map), [])
    def test_self_listing(self):
        url = '/api/self/listing/'
        response = APITestHelper.request(self, url, 'GET', username='******', status_code=200)

        titles = [i['title'] for i in response.data]
        self.assertTrue('Bread Basket' in titles)
        self.assertTrue('Chatter Box' in titles)
        self.assertTrue('Air Mail' not in titles)
        for listing_map in response.data:
            self.assertEqual(validate_listing_map_keys(listing_map), [])
    def test_create_listing_minimal(self):
        # create a new listing with minimal data (title)
        url = '/api/listing/'
        title = 'julias app'
        data = {'title': title, 'security_marking': 'UNCLASSIFIED'}
        response = APITestHelper.request(self, url, 'POST', data=data, username='******', status_code=201)

        self.assertEqual(response.data['title'], title)
        self.assertEqual(response.data['is_bookmarked'], False)
        self.assertEqual(validate_listing_map_keys(response.data), [])
    def test_self_deleted_listing(self):
        url = '/api/self/listing/'
        response = APITestHelper.request(self,
                                         url,
                                         'GET',
                                         username='******',
                                         status_code=200)

        titles = [i['id'] for i in response.data]
        self.assertTrue('1' not in titles)
        for listing_map in response.data:
            self.assertEqual(validate_listing_map_keys(listing_map), [])
    def test_self_listing(self):
        url = '/api/self/listing/'
        response = APITestHelper.request(self,
                                         url,
                                         'GET',
                                         username='******',
                                         status_code=200)

        titles = [i['title'] for i in response.data]
        self.assertTrue('Bread Basket' in titles)
        self.assertTrue('Chatter Box' in titles)
        self.assertTrue('Air Mail' not in titles)
        for listing_map in response.data:
            self.assertEqual(validate_listing_map_keys(listing_map), [])
    def test_update_listing_approval_status_deny_user(self):
        # a standard user cannot update the approval_status
        url = '/api/listing/'
        data = {
            "title": 'mr jones app',
            "approval_status": "APPROVED",
            "security_marking": "UNCLASSIFIED"
        }

        user = generic_model_access.get_profile('jones').user
        self.client.force_authenticate(user=user)
        response = self.client.post(url, data, format='json')
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        self.assertEqual(response.data['approval_status'], 'IN_PROGRESS')
        self.assertEqual(validate_listing_map_keys(response.data), [])

        data = response.data
        data['approval_status'] = models.Listing.APPROVED
        listing_id = data['id']

        url = '/api/listing/{0!s}/'.format(listing_id)
        response = self.client.put(url, data, format='json')
        self.assertEqual(response.data['error_code'], (ExceptionUnitTestHelper.permission_denied('Only an APPS_MALL_STEWARD can mark a listing as APPROVED')['error_code']))
    def test_update_listing_partial(self):
        """
        This was added to catch the case where a listing that didn't previously
        have an icon was being updated, and the update method in the serializer
        was invoking instance.small_icon.id to get the old value for the
        change_details. There was no previous value, so accessing
        instance.small_icon.id raised an exception. The same problem could exist
        on any property that isn't a simple data type
        """
        listing = models.Listing.objects.get(id=1)
        listing.small_icon = None
        listing.large_icon = None
        listing.banner_icon = None
        listing.large_banner_icon = None
        listing.listing_type = None
        listing.save()

        # now make another change to the listing
        url = '/api/listing/1/'
        data = APITestHelper.request(self, url, 'GET', username='******', status_code=200).data

        data['small_icon'] = {'id': 1}
        data['large_icon'] = {'id': 2}
        data['banner_icon'] = {'id': 3}
        data['large_banner_icon'] = {'id': 4}
        data['listing_type'] = {'title': 'Web Application'}
        # and another update
        response = APITestHelper.request(self, url, 'PUT', data=data, username='******', status_code=200)

        self.assertTrue(response.data['edited_date'])
        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)
        self.assertEqual(response.data['is_bookmarked'], False)
        self.assertEqual(validate_listing_map_keys(response.data), [])
    def test_z_create_listing_full(self):
        url = '/api/listing/'
        title = 'julias app'
        data = {
            "title": title,
            "description": "description of app",
            "launch_url": "http://www.google.com/launch",
            "version_name": "1.0.0",
            "unique_name": "org.apps.julia-one",
            "what_is_new": "nothing is new",
            "description_short": "a shorter description",
            "usage_requirements": "None",
            "system_requirements": "None",
            "is_private": "true",
            "feedback_score": 0,
            "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": "UNCLASSIFIED",
            "listing_type": {"title": "Web Application"},
            "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/wiki"},
                {"name": "guide", "url": "http://www.google.com/guide"}
            ],
            "screenshots": [
                {"small_image": {"id": 1}, "large_image": {"id": 2}},
                {"small_image": {"id": 3}, "large_image": {"id": 4}}
            ]

        }
        response = APITestHelper.request(self, url, 'POST', data=data, username='******', status_code=201)

        compare_keys_data_exclude = [
            {'key': 'title', 'exclude': []},
            {'key': 'description', 'exclude': []},
            {'key': 'launch_url', 'exclude': []},
            {'key': 'version_name', 'exclude': []},
            {'key': 'unique_name', 'exclude': []},
            {'key': 'what_is_new', 'exclude': []},
            {'key': 'description_short', 'exclude': []},
            {'key': 'usage_requirements', 'exclude': []},
            {'key': 'system_requirements', 'exclude': []},
            {'key': 'security_marking', 'exclude': []},
            {'key': 'listing_type', 'exclude': []},
            {'key': 'small_icon', 'exclude': ['security_marking', 'url']},
            {'key': 'large_icon', 'exclude': ['security_marking', 'url']},
            {'key': 'banner_icon', 'exclude': ['security_marking', 'url']},
            {'key': 'large_banner_icon', 'exclude': ['security_marking', 'url']},
            {'key': 'contacts', 'exclude': ['id', 'organization']},
            {'key': 'categories', 'exclude': ['id', 'description']},
            {'key': 'tags', 'exclude': ['id']},
            {'key': 'owners', 'exclude': ['id', 'display_name', 'avatar']},
            {'key': 'intents', 'exclude': ['id', 'icon', 'label', 'media_type']},
            {'key': 'doc_urls', 'exclude': ['id']},
            {'key': 'screenshots', 'exclude': ['small_image.security_marking', 'large_image.security_marking', 'small_image.url', 'large_image.url', 'order', 'description']},
        ]

        for key_to_compare_dict in compare_keys_data_exclude:
            key_to_compare = key_to_compare_dict['key']
            key_exclude = key_to_compare_dict['exclude']

            response_key_value = shorthand_dict(response.data[key_to_compare], exclude_keys=key_exclude)
            data_expected_value = shorthand_dict(data[key_to_compare], exclude_keys=key_exclude)

            # Fix Order for Sqlite/Postgres diffrences
            if isinstance(response_key_value, list):
                response_key_value = sorted(response_key_value)

            if isinstance(data_expected_value, list):
                data_expected_value = sorted(data_expected_value)

            self.assertEqual(response_key_value, data_expected_value, 'Comparing {} key'.format(key_to_compare))

        # fields that should come back with default values
        self.assertEqual(response.data['approved_date'], None)
        self.assertEqual(response.data['approval_status'], models.Listing.IN_PROGRESS)
        self.assertEqual(response.data['is_enabled'], True)
        self.assertEqual(response.data['is_featured'], False)
        self.assertEqual(response.data['avg_rate'], 0.0)
        self.assertEqual(response.data['total_votes'], 0)
        self.assertEqual(response.data['total_rate5'], 0)
        self.assertEqual(response.data['total_rate4'], 0)
        self.assertEqual(response.data['total_rate3'], 0)
        self.assertEqual(response.data['total_rate2'], 0)
        self.assertEqual(response.data['total_rate1'], 0)
        self.assertEqual(response.data['total_reviews'], 0)
        self.assertEqual(response.data['iframe_compatible'], True)
        self.assertEqual(response.data['required_listings'], None)
        self.assertTrue(response.data['edited_date'])
        self.assertEqual(response.data['is_bookmarked'], False)
        self.assertEqual(validate_listing_map_keys(response.data), [])
    def test_z_create_update(self):
        url = '/api/listing/'
        data = {
          "title": "test",
          "screenshots": [],
          "contacts": [
            {
              "name": "test1",
              "email": "*****@*****.**",
              "secure_phone": "240-544-8777",
              "contact_type": {
                "name": "Civilian"
              }
            },
            {
              "name": "test2",
              "email": "*****@*****.**",
              "secure_phone": "240-888-7477",
              "contact_type": {
                "name": "Civilian"
              }
            }
          ],
          "tags": [],
          "owners": [
            {
              "display_name": "Big Brother",
              "id": 4,
              "user": {
                "username": "******"
              }
            }
          ],
          "agency": {
            "short_name": "Miniluv",
            "title": "Ministry of Love"
          },
          "categories": [
            {
              "title": "Books and Reference"
            }
          ],
          "intents": [],
          "doc_urls": [],
          "security_marking": "UNCLASSIFIED",  # //FOR OFFICIAL USE ONLY//ABCDE
          "listing_type": {
            "title": "Web Application"
          },
          "last_activity": {
            "action": "APPROVED"
          },
          "required_listings": None
        }

        user = generic_model_access.get_profile('julia').user
        self.client.force_authenticate(user=user)
        response = self.client.post(url, data, format='json')
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        self.assertEqual(response.data['approval_status'], 'IN_PROGRESS')
        self.assertEqual(validate_listing_map_keys(response.data), [])
        listing_id = response.data['id']

        data = {
          "id": listing_id,
          "title": "test",
          "description": None,
          "description_short": None,
          "screenshots": [],
          "contacts": [
            {
              "id": 4,
              "contact_type": {
                "name": "Government"
              },
              "secure_phone": "240-544-8777",
              "unsecure_phone": None,
              "email": "*****@*****.**",
              "name": "test15",
              "organization": None
            },
            {
              "id": 5,
              "contact_type": {
                "name": "Civilian"
              },
              "secure_phone": "240-888-7477",
              "unsecure_phone": None,
              "email": "*****@*****.**",
              "name": "test2",
              "organization": None
            }
          ],
          "avg_rate": 0,
          "total_votes": 0,
          "feedback_score": 0,
          "tags": [],
          "usage_requirements": None,
          "system_requirements": None,
          "version_name": None,
          "launch_url": None,
          "what_is_new": None,
          "owners": [
            {
              "display_name": "Big Brother",
              "avatar": None,
              "id": 4,
              "user": {
                "username": "******"
              }
            }
          ],
          "agency": {
            "short_name": "Miniluv",
            "title": "Ministry of Love"
          },
          "is_enabled": True,
          "categories": [
            {
              "title": "Books and Reference"
            }
          ],
          "intents": [],
          "doc_urls": [],
          "approval_status": "IN_PROGRESS",
          "is_featured": False,
          "is_private": False,
          "security_marking": "UNCLASSIFIED//FOR OFFICIAL USE ONLY//ABCDE",
          "listing_type": {
            "title": "Web Application"
          },
          "unique_name": None,
          "last_activity": {
            "action": "APPROVED"
          },
          "required_listings": None
        }

        url = '/api/listing/{0!s}/'.format(listing_id)
        response = self.client.put(url, data, format='json')

        contacts = response.data['contacts']
        contact_types = [i['contact_type']['name'] for i in contacts]
        self.assertEqual(str(contact_types), str(['Civilian', 'Government']))
        self.assertEqual(validate_listing_map_keys(response.data), [])
    def test_update_listing_full(self):
        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",
            "usage_requirements": "Many new things",
            "system_requirements": "Good System",
            "is_private": "true",
            "is_enabled": "false",
            "is_featured": "false",
            "feedback_score": 0,
            "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}, "description": "Test Description"},
                {"small_image": {"id": 3}, "large_image": {"id": 4}, "description": "Test Description"}
            ]

        }

        # for checking Activity status later on
        user = generic_model_access.get_profile('julia').user
        self.client.force_authenticate(user=user)
        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)

        compare_keys_data_exclude = [
            {'key': 'title', 'exclude': []},
            {'key': 'description', 'exclude': []},
            {'key': 'launch_url', 'exclude': []},
            {'key': 'version_name', 'exclude': []},
            {'key': 'unique_name', 'exclude': []},
            {'key': 'what_is_new', 'exclude': []},
            {'key': 'description_short', 'exclude': []},
            {'key': 'usage_requirements', 'exclude': []},
            {'key': 'system_requirements', 'exclude': []},
            {'key': 'security_marking', 'exclude': []},
            {'key': 'listing_type', 'exclude': []},
            {'key': 'small_icon', 'exclude': ['security_marking', 'url']},
            {'key': 'large_icon', 'exclude': ['security_marking', 'url']},
            {'key': 'banner_icon', 'exclude': ['security_marking', 'url']},
            {'key': 'large_banner_icon', 'exclude': ['security_marking', 'url']},
            {'key': 'contacts', 'exclude': ['id', 'organization']},
            {'key': 'categories', 'exclude': ['id', 'description']},
            {'key': 'tags', 'exclude': ['id']},
            {'key': 'owners', 'exclude': ['id', 'display_name', 'avatar']},
            {'key': 'intents', 'exclude': ['id', 'icon', 'label', 'media_type']},
            {'key': 'doc_urls', 'exclude': ['id']},
            {'key': 'screenshots', 'exclude': ['small_image.security_marking', 'large_image.security_marking', 'small_image.url', 'large_image.url', 'order']},
        ]

        for key_to_compare_dict in compare_keys_data_exclude:
            key_to_compare = key_to_compare_dict['key']
            key_exclude = key_to_compare_dict['exclude']

            response_key_value = shorthand_dict(response.data[key_to_compare], exclude_keys=key_exclude)
            data_expected_value = shorthand_dict(data[key_to_compare], exclude_keys=key_exclude)

            # Fix Order for Sqlite/Postgres diffrences
            if isinstance(response_key_value, list):
                response_key_value = sorted(response_key_value)

            if isinstance(data_expected_value, list):
                data_expected_value = sorted(data_expected_value)

            self.assertEqual(response_key_value, data_expected_value, 'Comparing {} key'.format(key_to_compare))

        self.assertEqual(response.data['is_private'], True)
        self.assertEqual(response.data['is_enabled'], False)
        self.assertEqual(response.data['is_featured'], False)
        self.assertEqual(response.data['approval_status'], models.Listing.APPROVED)
        self.assertEqual(response.data['avg_rate'], 3.0)
        self.assertEqual(response.data['total_votes'], 4)
        self.assertEqual(response.data['total_rate5'], 1)
        self.assertEqual(response.data['total_rate4'], 0)
        self.assertEqual(response.data['total_rate3'], 2)
        self.assertEqual(response.data['total_rate2'], 0)
        self.assertEqual(response.data['total_rate1'], 1)
        self.assertEqual(response.data['total_reviews'], 4)
        self.assertEqual(response.data['iframe_compatible'], False)
        self.assertEqual(response.data['required_listings'], None)
        self.assertTrue(response.data['edited_date'])
        self.assertTrue(response.data['approved_date'])
        self.assertEqual(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',
            'usage_requirements', 'system_requirements', 'unique_name', 'what_is_new', 'launch_url',
            'is_enabled', 'is_featured', 'is_private', 'feedback_score', 'doc_urls', 'contacts',
            'screenshots', 'categories', 'owners', 'tags', 'small_icon',
            'large_icon', 'banner_icon', 'large_banner_icon', 'security_marking',
            'listing_type', 'approval_status', 'intents']

        changed_found_fields = []

        for activity in activity_data:
            if activity['action'] == 'MODIFIED':
                for change in activity['change_details']:
                    # Field Set 1
                    temp_change_fields = ['title', 'description', 'description_short',
                        'version_name', 'usage_requirements', 'system_requirements', 'what_is_new', 'unique_name', 'launch_url', 'feedback_score',
                        'is_private', 'is_featured', 'listing_type', 'security_marking']

                    for temp_field in temp_change_fields:
                        if change['field_name'] == temp_field:
                            if temp_field == 'listing_type':
                                self.assertEqual(change['new_value'], data[temp_field]['title'], 'new_value assertion for {}'.format(temp_field))
                            else:
                                self.assertEqual(change['new_value'], data[temp_field], 'new_value assertion for {}'.format(temp_field))

                            if temp_field.startswith('is_'):
                                self.assertEqual(change['old_value'], model_access.bool_to_string(old_listing_data[temp_field]), 'old_value assertion for {}'.format(temp_field))
                            elif temp_field == 'listing_type':
                                self.assertEqual(change['old_value'], old_listing_data[temp_field]['title'], 'old_value assertion for {}'.format(temp_field))
                            else:
                                self.assertEqual(change['old_value'], old_listing_data[temp_field], 'old_value assertion for {}'.format(temp_field))
                            changed_found_fields.append(temp_field)

                    # Field Set 2
                    temp_change_fields = ['small_icon', 'large_icon', 'banner_icon', 'large_banner_icon']
                    for temp_field in temp_change_fields:
                        if change['field_name'] == temp_field:
                            self.assertEqual(change['new_value'], str(data[temp_field]['id']) + '.UNCLASSIFIED', 'new_value assertion for {}'.format(temp_field))
                            self.assertEqual(change['old_value'], str(old_listing_data[temp_field]['id']) + '.UNCLASSIFIED', 'old_value assertion for {}'.format(temp_field))
                            changed_found_fields.append(temp_field)

                    # Field Set 3
                    temp_change_fields = ['doc_urls', 'screenshots', 'contacts', 'intents', 'categories', 'tags', 'owners']
                    for temp_field in temp_change_fields:
                        if change['field_name'] == temp_field:
                            temp_field_function = getattr(model_access, '{}_to_string'.format(temp_field))
                            self.assertEqual(change['new_value'], temp_field_function(data[temp_field]))
                            self.assertEqual(change['old_value'], temp_field_function(old_listing_data[temp_field]))
                            changed_found_fields.append(temp_field)

        difference_in_fields = sorted(list(set(fields) - set(changed_found_fields)))  # TODO: Better way to do this
        self.assertEqual(difference_in_fields, ['approval_status', 'feedback_score', 'is_enabled', 'is_featured'])