Exemplo n.º 1
0
    def test_change_without_any_cache_should_save_but_not_have_file_changes(self):
        item = self.item
        # Load the Change Item Page
        ItemAdmin.save_as_continue = False

        # Request.POST
        data = {
            "id": item.id,
            "name": "name",
            "price": 2.0,
            "file": "",
            "file-clear": "on",
            "currency": Item.VALID_CURRENCIES[0][0],
            "_confirm_change": True,
            "_saveasnew": True,
        }

        # Ensure no cache
        cache.delete(CACHE_KEYS["object"])
        cache.delete(CACHE_KEYS["post"])

        # Click "Yes, I'm Sure"
        del data["_confirm_change"]
        data[CONFIRMATION_RECEIVED] = True

        with mock.patch.object(ItemAdmin, "message_user") as message_user:
            response = self.client.post(
                f"/admin/market/item/{self.item.id}/change/", data=data
            )
            # Should show message to user with correct obj and path
            message_user.assert_called_once()
            message = message_user.call_args[0][1]
            self.assertIn("/admin/market/item/2/change/", message)
            self.assertIn(data["name"], message)
            self.assertNotIn("You may edit it again below.", message)

        # Should have redirected to changelist
        self.assertEqual(response.url, "/admin/market/item/")

        # Should not have changed existing item
        item.refresh_from_db()
        self.assertEqual(item.name, "Not name")
        self.assertEqual(item.file.name.count("test_file"), 1)
        self.assertEqual(item.image.name.count("test_image2"), 0)
        self.assertEqual(item.image.name.count("test_image"), 1)

        # Should have saved new item
        self.assertEqual(Item.objects.count(), 2)
        new_item = Item.objects.filter(id=item.id + 1).first()
        self.assertIsNotNone(new_item)
        self.assertEqual(new_item.name, data["name"])
        self.assertEqual(new_item.price, data["price"])
        self.assertEqual(new_item.currency, data["currency"])
        self.assertFalse(new_item.file)
        # FAILED to save image
        self.assertFalse(new_item.image)

        # Should have cleared cache
        for key in CACHE_KEYS.values():
            self.assertIsNone(cache.get(key))
    def test_simple_change(self):
        item = ItemFactory(name="Not name")

        # Load the Change Item Page
        ItemAdmin.confirm_change = True
        response = self.client.get(f"/admin/market/item/{item.id}/change/")

        # Should be asked for confirmation
        self.assertTrue(response.context_data.get("confirm_change"))
        self.assertIn("_confirm_change", response.rendered_content)

        # Click "Save And Continue"
        data = {
            "id": item.id,
            "name": "name",
            "price": 2.0,
            "currency": Item.VALID_CURRENCIES[0][0],
            "_confirm_change": True,
            "_continue": True,
        }
        response = self.client.post(f"/admin/market/item/{item.id}/change/",
                                    data=data)

        # Should be shown confirmation page
        self._assertSubmitHtml(
            rendered_content=response.rendered_content,
            save_action="_continue",
            multipart_form=True,
        )

        # Should have cached the unsaved item
        cached_item = cache.get(CACHE_KEYS["object"])
        self.assertIsNotNone(cached_item)

        # Should not have saved the changes yet
        self.assertEqual(Item.objects.count(), 1)
        item.refresh_from_db()
        self.assertEqual(item.name, "Not name")

        # Click "Yes, I'm Sure"
        del data["_confirm_change"]
        data[CONFIRMATION_RECEIVED] = True
        response = self.client.post(f"/admin/market/item/{item.id}/change/",
                                    data=data)

        # Should not have redirected to changelist
        self.assertEqual(response.url, f"/admin/market/item/{item.id}/change/")

        # Should have saved item
        self.assertEqual(Item.objects.count(), 1)
        saved_item = Item.objects.all().first()
        self.assertEqual(saved_item.name, data["name"])
        self.assertEqual(saved_item.price, data["price"])
        self.assertEqual(saved_item.currency, data["currency"])

        # Should have cleared cache
        for key in CACHE_KEYS.values():
            self.assertIsNone(cache.get(key))
    def test_simple_add(self):
        # Load the Add Item Page
        ItemAdmin.confirm_add = True
        response = self.client.get(reverse("admin:market_item_add"))

        # Should be asked for confirmation
        self.assertTrue(response.context_data.get("confirm_add"))
        self.assertIn("_confirm_add", response.rendered_content)

        # Click "Save"
        data = {
            "name": "name",
            "price": 2.0,
            "currency": Item.VALID_CURRENCIES[0][0],
            "_confirm_add": True,
            "_save": True,
        }
        response = self.client.post(reverse("admin:market_item_add"),
                                    data=data)

        # Should be shown confirmation page
        self._assertSubmitHtml(
            rendered_content=response.rendered_content,
            save_action="_save",
            multipart_form=True,
        )

        # Should have cached the unsaved item
        cached_item = cache.get(CACHE_KEYS["object"])
        self.assertIsNotNone(cached_item)
        self.assertIsNone(cached_item.id)
        self.assertEqual(cached_item.name, data["name"])
        self.assertEqual(cached_item.price, data["price"])
        self.assertEqual(cached_item.currency, data["currency"])

        # Should not have saved the item yet
        self.assertEqual(Item.objects.count(), 0)

        # Click "Yes, I'm Sure"
        del data["_confirm_add"]
        data[CONFIRMATION_RECEIVED] = True
        response = self.client.post(reverse("admin:market_item_add"),
                                    data=data)

        # Should have redirected to changelist
        self.assertEqual(response.status_code, 302)
        self.assertEqual(response.url, "/admin/market/item/")

        # Should have saved item
        self.assertEqual(Item.objects.count(), 1)
        saved_item = Item.objects.all().first()
        self.assertEqual(saved_item.name, data["name"])
        self.assertEqual(saved_item.price, data["price"])
        self.assertEqual(saved_item.currency, data["currency"])

        # Should have cleared cache
        for key in CACHE_KEYS.values():
            self.assertIsNone(cache.get(key))
Exemplo n.º 4
0
    def test_form_without_files_should_not_use_cache(self):
        cache.delete_many(CACHE_KEYS.values())
        shop = ShopFactory()
        # Click "Save And Continue"
        data = {
            "id": shop.id,
            "name": "name",
            "_confirm_change": True,
            "_continue": True,
        }
        response = self.client.post(f"/admin/market/shop/{shop.id}/change/", data=data)

        # Should be shown confirmation page
        self._assertSubmitHtml(
            rendered_content=response.rendered_content, save_action="_continue"
        )

        # Should not have set cache since not multipart form
        for key in CACHE_KEYS.values():
            self.assertIsNone(cache.get(key))
Exemplo n.º 5
0
    def test_cache_with_incorrect_model_should_not_be_used(self):
        item = self.item
        # Load the Change Item Page
        ItemAdmin.save_as_continue = False

        # Request.POST
        data = {
            "id": item.id,
            "name": "name",
            "price": 2.0,
            "file": "",
            "file-clear": "on",
            "currency": Item.VALID_CURRENCIES[0][0],
            "_confirm_change": True,
            "_save": True,
        }

        # Set cache to incorrect model
        cache_obj = Shop(name="ShopName")

        cache.set(CACHE_KEYS["object"], cache_obj)
        cache.set(CACHE_KEYS["post"], data)

        # Click "Yes, I'm Sure"
        del data["_confirm_change"]
        data[CONFIRMATION_RECEIVED] = True

        with mock.patch.object(ItemAdmin, "message_user") as message_user:
            response = self.client.post(
                f"/admin/market/item/{self.item.id}/change/", data=data
            )
            # Should show message to user with correct obj and path
            message_user.assert_called_once()
            message = message_user.call_args[0][1]
            self.assertIn("/admin/market/item/1/change/", message)
            self.assertIn(data["name"], message)
            self.assertNotIn("You may edit it again below.", message)

        # Should have redirected to changelist
        self.assertEqual(response.url, "/admin/market/item/")

        # Should have changed existing item
        self.assertEqual(Item.objects.count(), 1)
        item.refresh_from_db()
        self.assertEqual(item.name, "name")
        # Should have cleared if requested
        self.assertFalse(item.file.name)
        self.assertEqual(item.image.name.count("test_image2"), 0)
        self.assertEqual(item.image.name.count("test_image"), 1)

        # Should have cleared cache
        for key in CACHE_KEYS.values():
            self.assertIsNone(cache.get(key))
Exemplo n.º 6
0
    def changeform_view(self,
                        request,
                        object_id=None,
                        form_url="",
                        extra_context=None):
        if request.method == "POST":
            if (not object_id and CONFIRM_ADD in request.POST) or (
                    object_id and CONFIRM_CHANGE in request.POST):
                log("confirmation is asked for")
                self._file_cache.delete_all()
                cache.delete_many(CACHE_KEYS.values())
                return self._change_confirmation_view(request, object_id,
                                                      form_url, extra_context)
            elif CONFIRMATION_RECEIVED in request.POST:
                return self._confirmation_received_view(
                    request, object_id, form_url, extra_context)
            else:
                self._file_cache.delete_all()
                cache.delete_many(CACHE_KEYS.values())

        extra_context = self._add_confirmation_options_to_extra_context(
            extra_context)
        return super().changeform_view(request, object_id, form_url,
                                       extra_context)
Exemplo n.º 7
0
    def test_old_cache_should_not_be_used(self):
        item = self.item

        # Upload new image and remove file
        i2 = SimpleUploadedFile(
            name="test_image2.jpg",
            content=open(self.image_path, "rb").read(),
            content_type="image/jpeg",
        )
        # Click "Save And Continue"
        data = {
            "id": item.id,
            "name": "name",
            "price": 2.0,
            "image": i2,
            "file": "",
            "file-clear": "on",
            "currency": Item.VALID_CURRENCIES[0][0],
            "_confirm_change": True,
            "_continue": True,
        }
        response = self.client.post(f"/admin/market/item/{item.id}/change/", data=data)

        # Should be shown confirmation page
        self._assertSubmitHtml(
            rendered_content=response.rendered_content,
            save_action="_continue",
            multipart_form=True,
        )

        # Should have cached the unsaved item
        cached_item = cache.get(CACHE_KEYS["object"])
        self.assertIsNotNone(cached_item)

        # Should not have saved the changes yet
        self.assertEqual(Item.objects.count(), 1)
        item.refresh_from_db()
        self.assertEqual(item.name, "Not name")
        self.assertIsNotNone(item.file)
        self.assertIsNotNone(item.image)

        # Wait for cache to time out

        time.sleep(1)

        # Check that it did time out
        cached_item = cache.get(CACHE_KEYS["object"])
        self.assertIsNone(cached_item)

        # Click "Yes, I'm Sure"
        del data["_confirm_change"]
        data["image"] = ""
        data[CONFIRMATION_RECEIVED] = True
        response = self.client.post(f"/admin/market/item/{item.id}/change/", data=data)

        # Should not have redirected to changelist
        self.assertEqual(response.url, f"/admin/market/item/{item.id}/change/")

        # Should have saved item
        self.assertEqual(Item.objects.count(), 1)
        saved_item = Item.objects.all().first()
        self.assertEqual(saved_item.name, data["name"])
        self.assertEqual(saved_item.price, data["price"])
        self.assertEqual(saved_item.currency, data["currency"])
        self.assertFalse(saved_item.file)

        # SHOULD not have saved image since it was in the old cache
        self.assertNotIn("test_image2", saved_item.image)

        # Should have cleared cache
        for key in CACHE_KEYS.values():
            self.assertIsNone(cache.get(key))
Exemplo n.º 8
0
    def test_save_as_continue_true_should_not_redirect_to_changelist(self):
        item = self.item
        # Load the Change Item Page
        ItemAdmin.save_as_continue = True

        # Upload new image and remove file
        i2 = SimpleUploadedFile(
            name="test_image2.jpg",
            content=open(self.image_path, "rb").read(),
            content_type="image/jpeg",
        )
        # Request.POST
        data = {
            "id": item.id,
            "name": "name",
            "price": 2.0,
            "file": "",
            "file-clear": "on",
            "currency": Item.VALID_CURRENCIES[0][0],
            "_confirm_change": True,
            "_saveasnew": True,
        }

        # Set cache
        cache_item = Item(
            name=data["name"],
            price=data["price"],
            currency=data["currency"],
            image=i2,
        )
        file_cache = FileCache()
        file_cache.set(format_cache_key(model="Item", field="image"), i2)

        cache.set(CACHE_KEYS["object"], cache_item)
        cache.set(CACHE_KEYS["post"], data)

        # Click "Yes, I'm Sure"
        del data["_confirm_change"]
        data[CONFIRMATION_RECEIVED] = True

        with mock.patch.object(ItemAdmin, "message_user") as message_user:
            response = self.client.post(
                f"/admin/market/item/{self.item.id}/change/", data=data
            )
            # Should show message to user with correct obj and path
            message_user.assert_called_once()
            message = message_user.call_args[0][1]
            self.assertIn("/admin/market/item/2/change/", message)
            self.assertIn(data["name"], message)
            self.assertIn("You may edit it again below.", message)

        # Should not have redirected to changelist
        self.assertEqual(response.url, f"/admin/market/item/{self.item.id + 1}/change/")

        # Should not have changed existing item
        item.refresh_from_db()
        self.assertEqual(item.name, "Not name")
        self.assertEqual(item.file.name.count("test_file"), 1)
        self.assertEqual(item.image.name.count("test_image2"), 0)
        self.assertEqual(item.image.name.count("test_image"), 1)

        # Should have saved new item
        self.assertEqual(Item.objects.count(), 2)
        new_item = Item.objects.filter(id=item.id + 1).first()
        self.assertIsNotNone(new_item)
        self.assertEqual(new_item.name, data["name"])
        self.assertEqual(new_item.price, data["price"])
        self.assertEqual(new_item.currency, data["currency"])
        self.assertFalse(new_item.file)
        self.assertEqual(new_item.image.name.count("test_image2"), 1)

        # Should have cleared cache
        for key in CACHE_KEYS.values():
            self.assertIsNone(cache.get(key))
Exemplo n.º 9
0
    def test_add_without_cached_post_should_save_new_instance_with_file(self):
        # Upload new file
        f2 = SimpleUploadedFile(
            name="test_file2.jpg",
            content=open(self.image_path, "rb").read(),
            content_type="image/jpeg",
        )

        # Request.POST
        data = {
            "name": "name",
            "price": 2.0,
            "image": "",
            "file": f2,
            "currency": Item.VALID_CURRENCIES[0][0],
            "_confirm_add": True,
            "_save": True,
        }

        # Set cache
        cache_item = Item(
            name=data["name"], price=data["price"], currency=data["currency"], file=f2
        )

        cache.set(CACHE_KEYS["object"], cache_item)
        # Make sure there's no post cached post
        cache.delete(CACHE_KEYS["post"])

        # Click "Yes, I'm Sure"
        del data["_confirm_add"]
        data[CONFIRMATION_RECEIVED] = True

        with mock.patch.object(ItemAdmin, "message_user") as message_user:
            response = self.client.post("/admin/market/item/add/", data=data)
            # Should show message to user with correct obj and path
            message_user.assert_called_once()
            message = message_user.call_args[0][1]
            self.assertIn("/admin/market/item/2/change/", message)
            self.assertIn(data["name"], message)
            self.assertNotIn("You may edit it again below.", message)

        # Should not have redirected to changelist
        self.assertEqual(response.url, "/admin/market/item/")

        # Should not have changed existing item
        self.item.refresh_from_db()
        self.assertEqual(self.item.name, "Not name")
        self.assertEqual(self.item.file.name.count("test_file"), 1)
        self.assertEqual(self.item.image.name.count("test_image2"), 0)
        self.assertEqual(self.item.image.name.count("test_image"), 1)

        # Should have saved new item
        self.assertEqual(Item.objects.count(), 2)
        new_item = Item.objects.filter(id=self.item.id + 1).first()
        self.assertIsNotNone(new_item)
        self.assertEqual(new_item.name, data["name"])
        self.assertEqual(new_item.price, data["price"])
        self.assertEqual(new_item.currency, data["currency"])
        self.assertFalse(new_item.image)

        # Able to save the cached file since cached object was there even though cached post was not
        self.assertRegex(new_item.file.name, r"test_file2.*\.jpg$")

        # Should have cleared cache
        for key in CACHE_KEYS.values():
            self.assertIsNone(cache.get(key))
Exemplo n.º 10
0
    def test_saveasnew_without_any_file_changes_should_save_new_instance_without_files(
        self,
    ):
        item = self.item

        # Request.POST
        data = {
            "id": item.id,
            "name": "name",
            "price": 2.0,
            "file": "",
            "image": "",
            "currency": Item.VALID_CURRENCIES[0][0],
            "_confirm_change": True,
            "_saveasnew": True,
        }

        # Set cache
        cache_item = Item(
            name=data["name"],
            price=data["price"],
            currency=data["currency"],
        )

        cache.set(CACHE_KEYS["object"], cache_item)
        cache.set(CACHE_KEYS["post"], data)

        # Click "Yes, I'm Sure"
        del data["_confirm_change"]
        data[CONFIRMATION_RECEIVED] = True

        with mock.patch.object(ItemAdmin, "message_user") as message_user:
            response = self.client.post(
                f"/admin/market/item/{self.item.id}/change/", data=data
            )
            # Should show message to user with correct obj and path
            message_user.assert_called_once()
            message = message_user.call_args[0][1]
            self.assertIn("/admin/market/item/2/change/", message)
            self.assertIn(data["name"], message)
            self.assertIn("You may edit it again below.", message)

        # Should not have redirected to changelist
        self.assertEqual(response.url, f"/admin/market/item/{self.item.id + 1}/change/")

        # Should not have changed existing item
        item.refresh_from_db()
        self.assertEqual(item.name, "Not name")
        self.assertEqual(item.file.name.count("test_file"), 1)
        self.assertEqual(item.image.name.count("test_image2"), 0)
        self.assertEqual(item.image.name.count("test_image"), 1)

        # Should have saved new item
        self.assertEqual(Item.objects.count(), 2)
        new_item = Item.objects.filter(id=item.id + 1).first()
        self.assertIsNotNone(new_item)
        self.assertEqual(new_item.name, data["name"])
        self.assertEqual(new_item.price, data["price"])
        self.assertEqual(new_item.currency, data["currency"])
        # In Django (by default), the save as new does not transfer over the files
        self.assertFalse(new_item.file)
        self.assertFalse(new_item.image)

        # Should have cleared cache
        for key in CACHE_KEYS.values():
            self.assertIsNone(cache.get(key))
Exemplo n.º 11
0
    def test_when_m2m_field_in_exclude_changes_to_field_should_not_be_saved(
            self):
        gm = GeneralManager.objects.create(name="gm")
        shops = [ShopFactory() for i in range(3)]
        town = Town.objects.create(name="town")
        mall = ShoppingMall.objects.create(name="mall",
                                           general_manager=gm,
                                           town=town)
        mall.shops.set(shops)

        # new values
        gm2 = GeneralManager.objects.create(name="gm2")
        town2 = Town.objects.create(name="town2")

        data = {
            "id": mall.id,
            "name": "name",
            "general_manager": gm2.id,
            "shops": [1],
            "town": town2.id,
            "_confirm_change": True,
            "_continue": True,
        }
        response = self.client.post(
            f"/admin/market/shoppingmall/{mall.id}/change/", data=data)
        # Should be shown confirmation page
        self._assertSubmitHtml(rendered_content=response.rendered_content,
                               save_action="_continue")

        # Should not have cached the unsaved obj
        cached_item = cache.get(CACHE_KEYS["object"])
        self.assertIsNone(cached_item)

        # Should not have saved changes yet
        self.assertEqual(ShoppingMall.objects.count(), 1)
        mall.refresh_from_db()
        self.assertEqual(mall.name, "mall")
        self.assertEqual(mall.general_manager, gm)
        self.assertEqual(mall.town, town)
        for shop in mall.shops.all():
            self.assertIn(shop, shops)

        # Click "Yes, I'm Sure"
        confirmation_received_data = data
        del confirmation_received_data["_confirm_change"]

        response = self.client.post(
            f"/admin/market/shoppingmall/{mall.id}/change/",
            data=confirmation_received_data,
        )

        # Should not have redirected to changelist
        self.assertEqual(response.url,
                         f"/admin/market/shoppingmall/{mall.id}/change/")

        # Should have saved obj
        self.assertEqual(ShoppingMall.objects.count(), 1)
        saved_item = ShoppingMall.objects.all().first()
        # should have updated fields that were in form
        self.assertEqual(saved_item.name, data["name"])
        self.assertEqual(saved_item.town, town2)
        self.assertEqual(saved_item.general_manager, gm2)
        # should have presevered the fields that are not in form (exclude)
        for shop in saved_item.shops.all():
            self.assertIn(shop, shops)

        # Should have cleared cache
        for key in CACHE_KEYS.values():
            self.assertIsNone(cache.get(key))
    def test_relation_change(self):
        gm = GeneralManager.objects.create(name="gm")
        shops = [ShopFactory() for i in range(3)]
        town = Town.objects.create(name="town")
        mall = ShoppingMall.objects.create(name="mall",
                                           general_manager=gm,
                                           town=town)
        mall.shops.set(shops)

        # new values
        gm2 = GeneralManager.objects.create(name="gm2")
        shops2 = [ShopFactory() for i in range(3)]
        town2 = Town.objects.create(name="town2")

        # Load the Change ShoppingMall Page
        ShoppingMallAdmin.confirm_change = True
        response = self.client.get(
            f"/admin/market/shoppingmall/{mall.id}/change/")

        # Should be asked for confirmation
        self.assertTrue(response.context_data.get("confirm_change"))
        self.assertIn("_confirm_change", response.rendered_content)

        # Click "Save"
        data = {
            "id": mall.id,
            "name": "name",
            "shops": [s.id for s in shops2],
            "general_manager": gm2.id,
            "town": town2.id,
            "_confirm_change": True,
            "_continue": True,
        }
        response = self.client.post(
            f"/admin/market/shoppingmall/{mall.id}/change/", data=data)

        # Should be shown confirmation page
        self._assertManyToManyFormHtml(
            rendered_content=response.rendered_content,
            options=shops,
            selected_ids=data["shops"],
        )
        self._assertSubmitHtml(rendered_content=response.rendered_content,
                               save_action="_continue")

        # Should not have cached the unsaved obj
        cached_item = cache.get(CACHE_KEYS["object"])
        self.assertIsNone(cached_item)

        # Should not have saved changes yet
        self.assertEqual(ShoppingMall.objects.count(), 1)
        mall.refresh_from_db()
        self.assertEqual(mall.name, "mall")
        self.assertEqual(mall.general_manager, gm)
        self.assertEqual(mall.town, town)
        for shop in mall.shops.all():
            self.assertIn(shop, shops)

        # Click "Yes, I'm Sure"
        confirmation_received_data = data
        del confirmation_received_data["_confirm_change"]
        confirmation_received_data[CONFIRMATION_RECEIVED] = True

        response = self.client.post(
            f"/admin/market/shoppingmall/{mall.id}/change/",
            data=confirmation_received_data,
        )

        # Should not have redirected to changelist
        self.assertEqual(response.url,
                         f"/admin/market/shoppingmall/{mall.id}/change/")

        # Should have saved obj
        self.assertEqual(ShoppingMall.objects.count(), 1)
        saved_item = ShoppingMall.objects.all().first()
        self.assertEqual(saved_item.name, data["name"])
        self.assertEqual(saved_item.general_manager, gm2)
        self.assertEqual(saved_item.town, town2)

        for shop in saved_item.shops.all():
            self.assertIn(shop, shops2)

        # Should have cleared cache
        for key in CACHE_KEYS.values():
            self.assertIsNone(cache.get(key))
    def test_relations_add(self):
        gm = GeneralManager.objects.create(name="gm")
        shops = [ShopFactory() for i in range(3)]
        town = Town.objects.create(name="town")

        # Load the Add ShoppingMall Page
        ShoppingMallAdmin.confirm_add = True
        response = self.client.get(reverse("admin:market_shoppingmall_add"))

        # Should be asked for confirmation
        self.assertTrue(response.context_data.get("confirm_add"))
        self.assertIn("_confirm_add", response.rendered_content)

        # Click "Save"
        data = {
            "name": "name",
            "shops": [s.id for s in shops],
            "general_manager": gm.id,
            "town": town.id,
            "_confirm_add": True,
            "_save": True,
        }
        response = self.client.post(reverse("admin:market_shoppingmall_add"),
                                    data=data)

        # Should be shown confirmation page
        self._assertManyToManyFormHtml(
            rendered_content=response.rendered_content,
            options=shops,
            selected_ids=data["shops"],
        )
        self._assertSubmitHtml(rendered_content=response.rendered_content,
                               save_action="_save")

        # Should not have cached the unsaved object
        cached_item = cache.get(CACHE_KEYS["object"])
        self.assertIsNone(cached_item)

        # Should not have saved the object yet
        self.assertEqual(ShoppingMall.objects.count(), 0)

        # Click "Yes, I'm Sure"
        confirmation_received_data = data
        del confirmation_received_data["_confirm_add"]

        response = self.client.post(reverse("admin:market_shoppingmall_add"),
                                    data=confirmation_received_data)

        # Should have redirected to changelist
        self.assertEqual(response.status_code, 302)
        self.assertEqual(response.url, "/admin/market/shoppingmall/")

        # Should have saved object
        self.assertEqual(ShoppingMall.objects.count(), 1)
        saved_item = ShoppingMall.objects.all().first()
        self.assertEqual(saved_item.name, data["name"])
        self.assertEqual(saved_item.general_manager, gm)
        self.assertEqual(saved_item.town, town)
        for shop in saved_item.shops.all():
            self.assertIn(shop, shops)

        # Should have cleared cache
        for key in CACHE_KEYS.values():
            self.assertIsNone(cache.get(key))
    def test_file_and_image_change(self):
        item = ItemFactory(name="Not name")
        # Select files
        image_path = "screenshot.png"
        f = SimpleUploadedFile(
            name="test_file.jpg",
            content=open(image_path, "rb").read(),
            content_type="image/jpeg",
        )
        i = SimpleUploadedFile(
            name="test_image.jpg",
            content=open(image_path, "rb").read(),
            content_type="image/jpeg",
        )
        item.file = f
        item.image = i
        item.save()

        # Load the Change Item Page
        ItemAdmin.confirm_change = True
        ItemAdmin.fields = ["name", "price", "file", "image", "currency"]
        response = self.client.get(f"/admin/market/item/{item.id}/change/")

        # Should be asked for confirmation
        self.assertTrue(response.context_data.get("confirm_change"))
        self.assertIn("_confirm_change", response.rendered_content)

        # Upload new image and remove file
        i2 = SimpleUploadedFile(
            name="test_image2.jpg",
            content=open(image_path, "rb").read(),
            content_type="image/jpeg",
        )
        # Click "Save And Continue"
        data = {
            "id": item.id,
            "name": "name",
            "price": 2.0,
            "image": i2,
            "file": "",
            "file-clear": "on",
            "currency": Item.VALID_CURRENCIES[0][0],
            "_confirm_change": True,
            "_continue": True,
        }
        response = self.client.post(f"/admin/market/item/{item.id}/change/",
                                    data=data)

        # Should be shown confirmation page
        self._assertSubmitHtml(
            rendered_content=response.rendered_content,
            save_action="_continue",
            multipart_form=True,
        )

        # Should have cached the unsaved item
        cached_item = cache.get(CACHE_KEYS["object"])
        self.assertIsNotNone(cached_item)

        # Should not have saved the changes yet
        self.assertEqual(Item.objects.count(), 1)
        item.refresh_from_db()
        self.assertEqual(item.name, "Not name")
        self.assertIsNotNone(item.file)
        self.assertIsNotNone(item.image)

        # Click "Yes, I'm Sure"
        del data["_confirm_change"]
        data["image"] = ""
        data[CONFIRMATION_RECEIVED] = True
        response = self.client.post(f"/admin/market/item/{item.id}/change/",
                                    data=data)

        # Should not have redirected to changelist
        self.assertEqual(response.url, f"/admin/market/item/{item.id}/change/")

        # Should have saved item
        self.assertEqual(Item.objects.count(), 1)
        saved_item = Item.objects.all().first()
        self.assertEqual(saved_item.name, data["name"])
        self.assertEqual(saved_item.price, data["price"])
        self.assertEqual(saved_item.currency, data["currency"])
        self.assertFalse(saved_item.file)
        self.assertIsNotNone(saved_item.image)

        self.assertRegex(saved_item.image.name, r"test_image2.*\.jpg$")

        # Should have cleared cache
        for key in CACHE_KEYS.values():
            self.assertIsNone(cache.get(key))
    def test_file_and_image_add(self):
        # Load the Add Item Page
        ItemAdmin.confirm_add = True
        response = self.client.get(reverse("admin:market_item_add"))

        # Should be asked for confirmation
        self.assertTrue(response.context_data.get("confirm_add"))
        self.assertIn("_confirm_add", response.rendered_content)

        # Select files
        image_path = "screenshot.png"
        f = SimpleUploadedFile(
            name="test_file.jpg",
            content=open(image_path, "rb").read(),
            content_type="image/jpeg",
        )
        i = SimpleUploadedFile(
            name="test_image.jpg",
            content=open(image_path, "rb").read(),
            content_type="image/jpeg",
        )
        # Click "Save"
        data = {
            "name": "name",
            "price": 2.0,
            "currency": Item.VALID_CURRENCIES[0][0],
            "file": f,
            "image": i,
            "_confirm_add": True,
            "_save": True,
        }
        response = self.client.post(reverse("admin:market_item_add"),
                                    data=data)

        # Should be shown confirmation page
        self._assertSubmitHtml(
            rendered_content=response.rendered_content,
            save_action="_save",
            multipart_form=True,
        )

        # Should have cached the unsaved item
        cached_item = cache.get(CACHE_KEYS["object"])
        self.assertIsNotNone(cached_item)
        self.assertIsNone(cached_item.id)
        self.assertEqual(cached_item.name, data["name"])
        self.assertEqual(cached_item.price, data["price"])
        self.assertEqual(cached_item.currency, data["currency"])
        self.assertEqual(cached_item.file, data["file"])
        self.assertEqual(cached_item.image, data["image"])

        # Should not have saved the item yet
        self.assertEqual(Item.objects.count(), 0)

        # Click "Yes, I'm Sure"
        confirmation_data = data.copy()
        del confirmation_data["_confirm_add"]
        del confirmation_data["image"]
        del confirmation_data["file"]
        confirmation_data[CONFIRMATION_RECEIVED] = True
        response = self.client.post(reverse("admin:market_item_add"),
                                    data=confirmation_data)

        # Should have redirected to changelist
        self.assertEqual(response.status_code, 302)
        self.assertEqual(response.url, "/admin/market/item/")

        # Should have saved item
        self.assertEqual(Item.objects.count(), 1)
        saved_item = Item.objects.all().first()
        self.assertEqual(saved_item.name, data["name"])
        self.assertEqual(saved_item.price, data["price"])
        self.assertEqual(saved_item.currency, data["currency"])
        self.assertIsNotNone(saved_item.file)
        self.assertIsNotNone(saved_item.image)

        self.assertRegex(saved_item.file.name, r"test_file.*\.jpg$")
        self.assertRegex(saved_item.image.name, r"test_image.*\.jpg$")

        # Should have cleared cache
        for key in CACHE_KEYS.values():
            self.assertIsNone(cache.get(key))
Exemplo n.º 16
0
    def _confirmation_received_view(self, request, object_id, form_url,
                                    extra_context):
        """
        When the form is a multipart form, the object and POST are cached
        This is required because file(s) cannot be programmically uploaded
        ie. There is no way to set a file on the html form

        If the form isn't multipart, this function would not be called.
        If there are no file changes, do nothing to the request and send to Django.

        If there are files uploaded, save the files from cached object to either:
        - the object instance if already exists
        - or save the new object and modify the request from `add` to `change`
        and pass the request to Django
        """
        log("Confirmation has been received")

        def _reconstruct_request_files():
            """
            Reconstruct the file(s) from the file cache (if any).
            Returns a dictionary of field name to cached file
            """
            reconstructed_files = {}

            cached_object = cache.get(CACHE_KEYS["object"])
            # Reconstruct the files from cached object
            if not cached_object:
                log("Warning: no cached_object")
                return

            if type(cached_object) != self.model:
                # Do not use cache if the model doesn't match this model
                log(f"Warning: cached_object is not of type {self.model}")
                return

            query_dict = request.POST

            for field in self.model._meta.get_fields():
                if not (isinstance(field, FileField)
                        or isinstance(field, ImageField)):
                    continue

                cached_file = self._file_cache.get(
                    format_cache_key(model=self.model.__name__,
                                     field=field.name))

                # If a file was uploaded, the field is omitted from the POST since it's in request.FILES
                if not query_dict.get(field.name):
                    if not cached_file:
                        log(f"Warning: Could not find file cached for field {field.name}"
                            )
                    else:
                        reconstructed_files[field.name] = cached_file

            return reconstructed_files

        reconstructed_files = _reconstruct_request_files()
        if reconstructed_files:
            log(f"Found reconstructed files for fields: {reconstructed_files.keys()}"
                )
            obj = None

            # remove the _confirm_add and _confirm_change from post
            modified_post = request.POST.copy()
            if CONFIRM_ADD in modified_post:
                del modified_post[CONFIRM_ADD]  # pragma: no cover
            if CONFIRM_CHANGE in modified_post:
                del modified_post[CONFIRM_CHANGE]  # pragma: no cover

            if object_id and SAVE_AS_NEW not in request.POST:
                # Update the obj with the new uploaded files
                # then pass rest of changes to Django
                obj = self.model.objects.filter(id=object_id).first()
            else:
                # Create the obj and pass the rest as changes to Django
                # (Since we are not handling the formsets/inlines)
                # Note that this results in the "Yes, I'm Sure" submission
                #   act as a `change` not an `add`
                obj = cache.get(CACHE_KEYS["object"])

            # No cover: __reconstruct_request_files currently checks for cached obj so obj won't be None
            if obj:  # pragma: no cover
                for field, file in reconstructed_files.items():
                    log(f"Setting file field {field} to file {file}")
                    setattr(obj, field, file)
                obj.save()
                object_id = str(obj.id)
                # Update the request path, used in the message to user and redirect
                # Used in `self.response_change`
                request.path = get_admin_change_url(obj)

                if SAVE_AS_NEW in request.POST:
                    # We have already saved the new object
                    # So change action to _continue
                    del modified_post[SAVE_AS_NEW]
                    if self.save_as_continue:
                        modified_post[SAVE_AND_CONTINUE] = True
                    else:
                        modified_post[SAVE] = True
                    if "id" in modified_post:
                        del modified_post["id"]
                        modified_post["id"] = object_id

            request.POST = modified_post

        self._file_cache.delete_all()
        cache.delete_many(CACHE_KEYS.values())

        return super()._changeform_view(request, object_id, form_url,
                                        extra_context)