mirror of
https://github.com/jazzband/django-avatar.git
synced 2026-05-22 06:11:53 +00:00
Compare commits
16 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
12e4745f29 | ||
|
|
0f725788c9 | ||
|
|
80a7c95583 | ||
|
|
7cb55334c1 | ||
|
|
d1801edc64 | ||
|
|
4955d2d959 | ||
|
|
14495e8106 | ||
|
|
45e741a342 | ||
|
|
a6cafaa7f0 | ||
|
|
981187a9de | ||
|
|
ebeb6d5e64 | ||
|
|
da3615203d | ||
|
|
3343c51e2e | ||
|
|
d81495f50c | ||
|
|
fa54411351 | ||
|
|
28a8173b35 |
14 changed files with 132 additions and 57 deletions
4
.github/workflows/release.yml
vendored
4
.github/workflows/release.yml
vendored
|
|
@ -11,12 +11,12 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v6
|
||||||
with:
|
with:
|
||||||
python-version: 3.11
|
python-version: 3.11
|
||||||
|
|
||||||
|
|
|
||||||
23
.github/workflows/test.yml
vendored
23
.github/workflows/test.yml
vendored
|
|
@ -5,17 +5,26 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
python-version: ['3.8', '3.9', '3.10', '3.11']
|
python-version: ['3.10', '3.11', '3.12', '3.13', '3.14']
|
||||||
django-version: ['3.2', '4.1', '4.2']
|
django-version: ['4.2', '5.2', '6.0.*']
|
||||||
exclude:
|
exclude:
|
||||||
|
- python-version: 3.13
|
||||||
|
django-version: 4.2
|
||||||
|
|
||||||
|
- python-version: 3.14
|
||||||
|
django-version: 4.2
|
||||||
|
|
||||||
|
- python-version: 3.10
|
||||||
|
django-version: 6.0.*
|
||||||
|
|
||||||
- python-version: 3.11
|
- python-version: 3.11
|
||||||
django-version: 3.2
|
django-version: 6.0.*
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v6
|
||||||
- name: 'Set up Python ${{ matrix.python-version }}'
|
- name: 'Set up Python ${{ matrix.python-version }}'
|
||||||
uses: actions/setup-python@v3
|
uses: actions/setup-python@v6
|
||||||
with:
|
with:
|
||||||
python-version: '${{ matrix.python-version }}'
|
python-version: '${{ matrix.python-version }}'
|
||||||
cache: 'pip'
|
cache: 'pip'
|
||||||
|
|
@ -23,7 +32,7 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
pip install -r requirements.txt
|
pip install -r requirements.txt
|
||||||
pip install -r tests/requirements.txt
|
pip install -r tests/requirements.txt
|
||||||
pip install "Django~=${{ matrix.django-version }}.0" .
|
pip install "Django==${{ matrix.django-version }}" .
|
||||||
- name: Run Tests
|
- name: Run Tests
|
||||||
run: |
|
run: |
|
||||||
echo "$(python --version) / Django $(django-admin --version)"
|
echo "$(python --version) / Django $(django-admin --version)"
|
||||||
|
|
@ -33,4 +42,4 @@ jobs:
|
||||||
coverage report
|
coverage report
|
||||||
coverage xml
|
coverage xml
|
||||||
- name: Upload coverage reports to Codecov with GitHub Action
|
- name: Upload coverage reports to Codecov with GitHub Action
|
||||||
uses: codecov/codecov-action@v3
|
uses: codecov/codecov-action@v5
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,24 @@
|
||||||
repos:
|
repos:
|
||||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
rev: v4.5.0
|
rev: v6.0.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: end-of-file-fixer
|
- id: end-of-file-fixer
|
||||||
- id: trailing-whitespace
|
- id: trailing-whitespace
|
||||||
|
|
||||||
- repo: https://github.com/pycqa/isort
|
- repo: https://github.com/pycqa/isort
|
||||||
rev: "5.12.0"
|
rev: "7.0.0"
|
||||||
hooks:
|
hooks:
|
||||||
- id: isort
|
- id: isort
|
||||||
args: ["--profile", "black"]
|
args: ["--profile", "black"]
|
||||||
|
|
||||||
- repo: https://github.com/psf/black
|
- repo: https://github.com/psf/black
|
||||||
rev: 23.9.1
|
rev: 25.12.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: black
|
- id: black
|
||||||
args: [--target-version=py310]
|
args: [--target-version=py310]
|
||||||
|
|
||||||
- repo: https://github.com/pycqa/flake8
|
- repo: https://github.com/pycqa/flake8
|
||||||
rev: '6.1.0'
|
rev: '7.3.0'
|
||||||
hooks:
|
hooks:
|
||||||
- id: flake8
|
- id: flake8
|
||||||
additional_dependencies:
|
additional_dependencies:
|
||||||
|
|
|
||||||
35
.readthedocs.yaml
Normal file
35
.readthedocs.yaml
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
# Read the Docs configuration file for Sphinx projects
|
||||||
|
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
|
||||||
|
|
||||||
|
# Required
|
||||||
|
version: 2
|
||||||
|
|
||||||
|
# Set the OS, Python version and other tools you might need
|
||||||
|
build:
|
||||||
|
os: ubuntu-22.04
|
||||||
|
tools:
|
||||||
|
python: "3.12"
|
||||||
|
# You can also specify other tool versions:
|
||||||
|
# nodejs: "20"
|
||||||
|
# rust: "1.70"
|
||||||
|
# golang: "1.20"
|
||||||
|
|
||||||
|
# Build documentation in the "docs/" directory with Sphinx
|
||||||
|
sphinx:
|
||||||
|
configuration: docs/conf.py
|
||||||
|
# You can configure Sphinx to use a different builder, for instance use the dirhtml builder for simpler URLs
|
||||||
|
# builder: "dirhtml"
|
||||||
|
# Fail on all warnings to avoid broken references
|
||||||
|
# fail_on_warning: true
|
||||||
|
|
||||||
|
# Optionally build your docs in additional formats such as PDF and ePub
|
||||||
|
# formats:
|
||||||
|
# - pdf
|
||||||
|
# - epub
|
||||||
|
|
||||||
|
# Optional but recommended, declare the Python requirements required
|
||||||
|
# to build your documentation
|
||||||
|
# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
|
||||||
|
# python:
|
||||||
|
# install:
|
||||||
|
# - requirements: docs/requirements.txt
|
||||||
|
|
@ -1,6 +1,15 @@
|
||||||
Changelog
|
Changelog
|
||||||
=========
|
=========
|
||||||
* 8.0.0
|
* 9.0.0
|
||||||
|
* Fix files not closed in `create_thumbnail`
|
||||||
|
* Add Django 5.2 and 6.0 support
|
||||||
|
* Add Python 3.13, 3.14 support
|
||||||
|
* Drop Python 3.8, 3.9 support
|
||||||
|
|
||||||
|
* 8.0.1
|
||||||
|
* Fix Django 5.1 compatibility
|
||||||
|
|
||||||
|
* 8.0.0 (October 16, 2023)
|
||||||
* Add Django 4.2 support
|
* Add Django 4.2 support
|
||||||
* Remove Python 3.7 support
|
* Remove Python 3.7 support
|
||||||
* Use path and path converters (changes all url names from prefix `avatar_` to `avatar:`.)
|
* Use path and path converters (changes all url names from prefix `avatar_` to `avatar:`.)
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
__version__ = "8.0.0"
|
__version__ = "9.0.0"
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,8 @@ class AvatarConf(AppConf):
|
||||||
ALLOWED_FILE_EXTS = None
|
ALLOWED_FILE_EXTS = None
|
||||||
ALLOWED_MIMETYPES = None
|
ALLOWED_MIMETYPES = None
|
||||||
CACHE_TIMEOUT = 60 * 60
|
CACHE_TIMEOUT = 60 * 60
|
||||||
STORAGE = settings.DEFAULT_FILE_STORAGE
|
if hasattr(settings, "DEFAULT_FILE_STORAGE"):
|
||||||
|
STORAGE = settings.DEFAULT_FILE_STORAGE # deprecated settings
|
||||||
STORAGE_ALIAS = "default"
|
STORAGE_ALIAS = "default"
|
||||||
CLEANUP_DELETED = True
|
CLEANUP_DELETED = True
|
||||||
AUTO_GENERATE_SIZES = (DEFAULT_SIZE,)
|
AUTO_GENERATE_SIZES = (DEFAULT_SIZE,)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import binascii
|
import binascii
|
||||||
import hashlib
|
import hashlib
|
||||||
import os
|
import os
|
||||||
|
from contextlib import closing
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
from django.core.files import File
|
from django.core.files import File
|
||||||
|
|
@ -142,38 +143,38 @@ class Avatar(models.Model):
|
||||||
orig = self.avatar.storage.open(self.avatar.name, "rb")
|
orig = self.avatar.storage.open(self.avatar.name, "rb")
|
||||||
except IOError:
|
except IOError:
|
||||||
return # What should we do here? Render a "sorry, didn't work" img?
|
return # What should we do here? Render a "sorry, didn't work" img?
|
||||||
try:
|
|
||||||
image = Image.open(orig)
|
with closing(orig):
|
||||||
image = self.transpose_image(image)
|
try:
|
||||||
quality = quality or settings.AVATAR_THUMB_QUALITY
|
image = Image.open(orig)
|
||||||
w, h = image.size
|
except IOError:
|
||||||
if w != width or h != height:
|
|
||||||
ratioReal = 1.0 * w / h
|
|
||||||
ratioWant = 1.0 * width / height
|
|
||||||
if ratioReal > ratioWant:
|
|
||||||
diff = int((w - (h * ratioWant)) / 2)
|
|
||||||
image = image.crop((diff, 0, w - diff, h))
|
|
||||||
elif ratioReal < ratioWant:
|
|
||||||
diff = int((h - (w / ratioWant)) / 2)
|
|
||||||
image = image.crop((0, diff, w, h - diff))
|
|
||||||
if settings.AVATAR_THUMB_FORMAT == "JPEG" and image.mode == "RGBA":
|
|
||||||
image = image.convert("RGB")
|
|
||||||
elif image.mode not in (settings.AVATAR_THUMB_MODES):
|
|
||||||
image = image.convert(settings.AVATAR_THUMB_MODES[0])
|
|
||||||
image = image.resize((width, height), settings.AVATAR_RESIZE_METHOD)
|
|
||||||
thumb = BytesIO()
|
|
||||||
image.save(thumb, settings.AVATAR_THUMB_FORMAT, quality=quality)
|
|
||||||
thumb_file = ContentFile(thumb.getvalue())
|
|
||||||
else:
|
|
||||||
thumb_file = File(orig)
|
thumb_file = File(orig)
|
||||||
|
else:
|
||||||
|
image = self.transpose_image(image)
|
||||||
|
quality = quality or settings.AVATAR_THUMB_QUALITY
|
||||||
|
w, h = image.size
|
||||||
|
if w != width or h != height:
|
||||||
|
ratioReal = 1.0 * w / h
|
||||||
|
ratioWant = 1.0 * width / height
|
||||||
|
if ratioReal > ratioWant:
|
||||||
|
diff = int((w - (h * ratioWant)) / 2)
|
||||||
|
image = image.crop((diff, 0, w - diff, h))
|
||||||
|
elif ratioReal < ratioWant:
|
||||||
|
diff = int((h - (w / ratioWant)) / 2)
|
||||||
|
image = image.crop((0, diff, w, h - diff))
|
||||||
|
if settings.AVATAR_THUMB_FORMAT == "JPEG" and image.mode == "RGBA":
|
||||||
|
image = image.convert("RGB")
|
||||||
|
elif image.mode not in (settings.AVATAR_THUMB_MODES):
|
||||||
|
image = image.convert(settings.AVATAR_THUMB_MODES[0])
|
||||||
|
image = image.resize((width, height), settings.AVATAR_RESIZE_METHOD)
|
||||||
|
thumb = BytesIO()
|
||||||
|
image.save(thumb, settings.AVATAR_THUMB_FORMAT, quality=quality)
|
||||||
|
thumb_file = ContentFile(thumb.getvalue())
|
||||||
|
else:
|
||||||
|
thumb_file = File(orig)
|
||||||
thumb_name = self.avatar_name(width, height)
|
thumb_name = self.avatar_name(width, height)
|
||||||
thumb = self.avatar.storage.save(thumb_name, thumb_file)
|
thumb = self.avatar.storage.save(thumb_name, thumb_file)
|
||||||
except IOError:
|
invalidate_cache(self.user, width, height)
|
||||||
thumb_file = File(orig)
|
|
||||||
thumb = self.avatar.storage.save(
|
|
||||||
self.avatar_name(width, height), thumb_file
|
|
||||||
)
|
|
||||||
invalidate_cache(self.user, width, height)
|
|
||||||
|
|
||||||
def avatar_url(self, width, height=None):
|
def avatar_url(self, width, height=None):
|
||||||
return self.avatar.storage.url(self.avatar_name(width, height))
|
return self.avatar.storage.url(self.avatar_name(width, height))
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@ class GravatarAvatarProvider(object):
|
||||||
|
|
||||||
class LibRAvatarProvider:
|
class LibRAvatarProvider:
|
||||||
"""
|
"""
|
||||||
Returns the url of an avatar by the Ravatar service.
|
Returns the url of an avatar by the LibRavatar service.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|
@ -87,8 +87,17 @@ class LibRAvatarProvider:
|
||||||
baseurl = "http://" + hostname + ":" + port + "/avatar/"
|
baseurl = "http://" + hostname + ":" + port + "/avatar/"
|
||||||
except Exception:
|
except Exception:
|
||||||
baseurl = "https://seccdn.libravatar.org/avatar/"
|
baseurl = "https://seccdn.libravatar.org/avatar/"
|
||||||
hash = hashlib.md5(email.strip().lower()).hexdigest()
|
|
||||||
return baseurl + hash
|
params = {"s": str(width)}
|
||||||
|
if settings.AVATAR_GRAVATAR_DEFAULT:
|
||||||
|
params["d"] = settings.AVATAR_GRAVATAR_DEFAULT
|
||||||
|
if settings.AVATAR_GRAVATAR_FORCEDEFAULT:
|
||||||
|
params["f"] = "y"
|
||||||
|
path = "%s/?%s" % (
|
||||||
|
hashlib.md5(force_bytes(email.strip().lower())).hexdigest(),
|
||||||
|
urlencode(params),
|
||||||
|
)
|
||||||
|
return urljoin(baseurl, path)
|
||||||
|
|
||||||
|
|
||||||
class FacebookAvatarProvider(object):
|
class FacebookAvatarProvider(object):
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% if not avatars %}
|
{% if not avatars %}
|
||||||
{% url 'avatar_change' as avatar_change_url %}
|
{% url 'avatar:change' as avatar_change_url %}
|
||||||
<p>{% blocktrans %}You have no avatars to delete. Please <a href="{{ avatar_change_url }}">upload one</a> now.{% endblocktrans %}</p>
|
<p>{% blocktrans %}You have no avatars to delete. Please <a href="{{ avatar_change_url }}">upload one</a> now.{% endblocktrans %}</p>
|
||||||
{% else %}
|
{% else %}
|
||||||
<p>{% trans "Please select the avatars that you would like to delete." %}</p>
|
<p>{% trans "Please select the avatars that you would like to delete." %}</p>
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ extensions = []
|
||||||
templates_path = ["_templates"]
|
templates_path = ["_templates"]
|
||||||
|
|
||||||
# The suffix of source filenames.
|
# The suffix of source filenames.
|
||||||
source_suffix = ".txt"
|
source_suffix = ".rst"
|
||||||
|
|
||||||
# The encoding of source files.
|
# The encoding of source files.
|
||||||
# source_encoding = 'utf-8-sig'
|
# source_encoding = 'utf-8-sig'
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ that are required. A minimal integration can work like this:
|
||||||
4. Somewhere in your template navigation scheme, link to the change avatar
|
4. Somewhere in your template navigation scheme, link to the change avatar
|
||||||
page::
|
page::
|
||||||
|
|
||||||
<a href="{% url 'avatar_change' %}">Change your avatar</a>
|
<a href="{% url 'avatar:change' %}">Change your avatar</a>
|
||||||
|
|
||||||
5. Wherever you want to display an avatar for a user, first load the avatar
|
5. Wherever you want to display an avatar for a user, first load the avatar
|
||||||
template tags::
|
template tags::
|
||||||
|
|
@ -263,6 +263,11 @@ appear on the site. Listed below are those settings:
|
||||||
Suggested safe setting: ``("image/png", "image/gif", "image/jpeg")``.
|
Suggested safe setting: ``("image/png", "image/gif", "image/jpeg")``.
|
||||||
When enabled you'll get the following error on the form upload *File content is invalid. Detected: image/tiff Allowed content types are: image/png, image/gif, image/jpg*.
|
When enabled you'll get the following error on the form upload *File content is invalid. Detected: image/tiff Allowed content types are: image/png, image/gif, image/jpg*.
|
||||||
|
|
||||||
|
.. py:data:: AVATAR_STORAGE_ALIAS
|
||||||
|
|
||||||
|
Default: 'default'
|
||||||
|
Alias of the storage backend (from STORAGES settings) to use for storing avatars.
|
||||||
|
|
||||||
|
|
||||||
Management Commands
|
Management Commands
|
||||||
-------------------
|
-------------------
|
||||||
|
|
|
||||||
|
|
@ -13,20 +13,20 @@ keywords=["avatar", "django"]
|
||||||
classifiers=[
|
classifiers=[
|
||||||
"Development Status :: 5 - Production/Stable",
|
"Development Status :: 5 - Production/Stable",
|
||||||
"Environment :: Web Environment",
|
"Environment :: Web Environment",
|
||||||
"Framework :: Django",
|
|
||||||
"Intended Audience :: Developers",
|
"Intended Audience :: Developers",
|
||||||
"Framework :: Django",
|
"Framework :: Django",
|
||||||
"Framework :: Django :: 3.2",
|
|
||||||
"Framework :: Django :: 4.1",
|
|
||||||
"Framework :: Django :: 4.2",
|
"Framework :: Django :: 4.2",
|
||||||
|
"Framework :: Django :: 5.0",
|
||||||
|
"Framework :: Django :: 5.2",
|
||||||
|
"Framework :: Django :: 6.0",
|
||||||
"License :: OSI Approved :: BSD License",
|
"License :: OSI Approved :: BSD License",
|
||||||
"Operating System :: OS Independent",
|
"Operating System :: OS Independent",
|
||||||
"Programming Language :: Python",
|
"Programming Language :: Python",
|
||||||
"Programming Language :: Python :: 3.7",
|
|
||||||
"Programming Language :: Python :: 3.8",
|
|
||||||
"Programming Language :: Python :: 3.9",
|
|
||||||
"Programming Language :: Python :: 3.10",
|
"Programming Language :: Python :: 3.10",
|
||||||
"Programming Language :: Python :: 3.11",
|
"Programming Language :: Python :: 3.11",
|
||||||
|
"Programming Language :: Python :: 3.12",
|
||||||
|
"Programming Language :: Python :: 3.13",
|
||||||
|
"Programming Language :: Python :: 3.14",
|
||||||
]
|
]
|
||||||
dynamic = ["version", "dependencies"]
|
dynamic = ["version", "dependencies"]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
import math
|
import math
|
||||||
import os.path
|
import os.path
|
||||||
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from shutil import rmtree
|
from shutil import rmtree
|
||||||
|
from unittest import skipIf
|
||||||
|
|
||||||
from django.contrib.admin.sites import AdminSite
|
from django.contrib.admin.sites import AdminSite
|
||||||
from django.core import management
|
from django.core import management
|
||||||
|
|
@ -118,6 +120,7 @@ class AvatarTests(TestCase):
|
||||||
self.assertTrue(avatar.primary)
|
self.assertTrue(avatar.primary)
|
||||||
|
|
||||||
# We allow the .tiff file extension but not the mime type
|
# We allow the .tiff file extension but not the mime type
|
||||||
|
@skipIf(sys.platform == "win32", "Skipping test on Windows platform")
|
||||||
@override_settings(AVATAR_ALLOWED_FILE_EXTS=(".png", ".gif", ".jpg", ".tiff"))
|
@override_settings(AVATAR_ALLOWED_FILE_EXTS=(".png", ".gif", ".jpg", ".tiff"))
|
||||||
@override_settings(
|
@override_settings(
|
||||||
AVATAR_ALLOWED_MIMETYPES=("image/png", "image/gif", "image/jpeg")
|
AVATAR_ALLOWED_MIMETYPES=("image/png", "image/gif", "image/jpeg")
|
||||||
|
|
@ -130,6 +133,7 @@ class AvatarTests(TestCase):
|
||||||
self.assertNotEqual(response.context["upload_avatar_form"].errors, {})
|
self.assertNotEqual(response.context["upload_avatar_form"].errors, {})
|
||||||
|
|
||||||
# We allow the .tiff file extension and the mime type
|
# We allow the .tiff file extension and the mime type
|
||||||
|
@skipIf(sys.platform == "win32", "Skipping test on Windows platform")
|
||||||
@override_settings(AVATAR_ALLOWED_FILE_EXTS=(".png", ".gif", ".jpg", ".tiff"))
|
@override_settings(AVATAR_ALLOWED_FILE_EXTS=(".png", ".gif", ".jpg", ".tiff"))
|
||||||
@override_settings(
|
@override_settings(
|
||||||
AVATAR_ALLOWED_MIMETYPES=("image/png", "image/gif", "image/jpeg", "image/tiff")
|
AVATAR_ALLOWED_MIMETYPES=("image/png", "image/gif", "image/jpeg", "image/tiff")
|
||||||
|
|
@ -141,6 +145,7 @@ class AvatarTests(TestCase):
|
||||||
self.assertEqual(len(response.redirect_chain), 1) # Redirect only if it worked
|
self.assertEqual(len(response.redirect_chain), 1) # Redirect only if it worked
|
||||||
self.assertEqual(response.context["upload_avatar_form"].errors, {})
|
self.assertEqual(response.context["upload_avatar_form"].errors, {})
|
||||||
|
|
||||||
|
@skipIf(sys.platform == "win32", "Skipping test on Windows platform")
|
||||||
@override_settings(AVATAR_ALLOWED_FILE_EXTS=(".jpg", ".png"))
|
@override_settings(AVATAR_ALLOWED_FILE_EXTS=(".jpg", ".png"))
|
||||||
def test_image_without_wrong_extension(self):
|
def test_image_without_wrong_extension(self):
|
||||||
response = upload_helper(self, "imagefilewithoutext")
|
response = upload_helper(self, "imagefilewithoutext")
|
||||||
|
|
@ -148,6 +153,7 @@ class AvatarTests(TestCase):
|
||||||
self.assertEqual(len(response.redirect_chain), 0) # Redirect only if it worked
|
self.assertEqual(len(response.redirect_chain), 0) # Redirect only if it worked
|
||||||
self.assertNotEqual(response.context["upload_avatar_form"].errors, {})
|
self.assertNotEqual(response.context["upload_avatar_form"].errors, {})
|
||||||
|
|
||||||
|
@skipIf(sys.platform == "win32", "Skipping test on Windows platform")
|
||||||
@override_settings(AVATAR_ALLOWED_FILE_EXTS=(".jpg", ".png"))
|
@override_settings(AVATAR_ALLOWED_FILE_EXTS=(".jpg", ".png"))
|
||||||
def test_image_with_wrong_extension(self):
|
def test_image_with_wrong_extension(self):
|
||||||
response = upload_helper(self, "imagefilewithwrongext.ogg")
|
response = upload_helper(self, "imagefilewithwrongext.ogg")
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue