mirror of
https://git.linux-kernel.at/oliver/ivatar.git
synced 2025-11-17 21:48:02 +00:00
Compare commits
37 Commits
1.7.0
...
94-rfe-def
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3a61d519ba | ||
|
|
8dff034f9e | ||
|
|
b58c35e98b | ||
|
|
4f239119d6 | ||
|
|
b7efc60cc0 | ||
|
|
9faf308264 | ||
|
|
b3cfccb9c0 | ||
|
|
5a1dfbc459 | ||
|
|
df0400375d | ||
|
|
50569afc25 | ||
|
|
4385fcc034 | ||
|
|
927083eb58 | ||
|
|
fa4ce5e079 | ||
|
|
a2eea54235 | ||
|
|
01bcc1ee11 | ||
|
|
16f809d8a6 | ||
|
|
f01e49d495 | ||
|
|
fd696ed74c | ||
|
|
021a8de4d8 | ||
|
|
cbdaed28da | ||
|
|
95410f6e43 | ||
|
|
2be7309625 | ||
|
|
6deea2758f | ||
|
|
2bb1f5f26d | ||
|
|
3878554dd9 | ||
|
|
9478177c83 | ||
|
|
47837f4516 | ||
|
|
2276ea962f | ||
|
|
ae3c6beed4 | ||
|
|
ff9af3de9b | ||
|
|
7e46df0c15 | ||
|
|
e1547d14c5 | ||
|
|
8f5bc9653b | ||
|
|
5dbbff49d0 | ||
|
|
5c8da703cb | ||
|
|
3aeb1ba454 | ||
|
|
9e189b3fd2 |
1
.buildpacks
Normal file
1
.buildpacks
Normal file
@@ -0,0 +1 @@
|
||||
https://github.com/heroku/heroku-buildpack-python
|
||||
4
.env
4
.env
@@ -1,6 +1,8 @@
|
||||
if [ ! -d .virtualenv ]; then
|
||||
if [ ! "$(which virtualenv)" == "" ]; then
|
||||
virtualenv -p python3 .virtualenv
|
||||
if [ -f .env ]; then
|
||||
virtualenv -p python3 .virtualenv
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
if [ -f .virtualenv/bin/activate ]; then
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -20,3 +20,4 @@ falko_gravatar.jpg
|
||||
*.egg-info
|
||||
dump_all*.sql
|
||||
dist/
|
||||
.env.local
|
||||
|
||||
134
.gitlab-ci.yml
134
.gitlab-ci.yml
@@ -1,11 +1,16 @@
|
||||
default:
|
||||
image:
|
||||
name: quay.io/rhn_support_ofalk/fedora35-python3
|
||||
entrypoint: [ '/bin/sh', '-c' ]
|
||||
image:
|
||||
name: quay.io/rhn_support_ofalk/fedora36-python3
|
||||
entrypoint:
|
||||
- "/bin/sh"
|
||||
- "-c"
|
||||
|
||||
before_script:
|
||||
test_and_coverage:
|
||||
stage: build
|
||||
coverage: "/^TOTAL.*\\s+(\\d+\\%)$/"
|
||||
before_script:
|
||||
- virtualenv -p python3 /tmp/.virtualenv
|
||||
- source /tmp/.virtualenv/bin/activate
|
||||
- pip install -U pip
|
||||
- pip install Pillow
|
||||
- pip install -r requirements.txt
|
||||
- pip install python-coveralls
|
||||
@@ -13,68 +18,95 @@ before_script:
|
||||
- pip install pycco
|
||||
- pip install django_coverage_plugin
|
||||
|
||||
test_and_coverage:
|
||||
stage: test
|
||||
coverage: '/^TOTAL.*\s+(\d+\%)$/'
|
||||
script:
|
||||
- echo 'from ivatar.settings import TEMPLATES' > config_local.py
|
||||
- echo 'TEMPLATES[0]["OPTIONS"]["debug"] = True' >> config_local.py
|
||||
- echo "DEBUG = True" >> config_local.py
|
||||
- echo "from config import CACHES" >> config_local.py
|
||||
- echo "CACHES['default'] = CACHES['filesystem']" >> config_local.py
|
||||
- python manage.py collectstatic --noinput
|
||||
- coverage run --source . manage.py test -v3
|
||||
- coverage report --fail-under=70
|
||||
- coverage html
|
||||
- echo 'from ivatar.settings import TEMPLATES' > config_local.py
|
||||
- echo 'TEMPLATES[0]["OPTIONS"]["debug"] = True' >> config_local.py
|
||||
- echo "DEBUG = True" >> config_local.py
|
||||
- echo "from config import CACHES" >> config_local.py
|
||||
- echo "CACHES['default'] = CACHES['filesystem']" >> config_local.py
|
||||
- python manage.py collectstatic --noinput
|
||||
- coverage run --source . manage.py test -v3
|
||||
- coverage report --fail-under=70
|
||||
- coverage html
|
||||
artifacts:
|
||||
paths:
|
||||
- htmlcov/
|
||||
|
||||
- htmlcov/
|
||||
pycco:
|
||||
stage: test
|
||||
before_script:
|
||||
- virtualenv -p python3 /tmp/.virtualenv
|
||||
- source /tmp/.virtualenv/bin/activate
|
||||
- pip install -U pip
|
||||
- pip install Pillow
|
||||
- pip install -r requirements.txt
|
||||
- pip install python-coveralls
|
||||
- pip install coverage
|
||||
- pip install pycco
|
||||
- pip install django_coverage_plugin
|
||||
|
||||
script:
|
||||
- /bin/true
|
||||
- find ivatar/ -type f -name "*.py"|grep -v __pycache__|grep -v __init__.py|grep -v /migrations/ | xargs pycco -p -d pycco -i -s
|
||||
- "/bin/true"
|
||||
- find ivatar/ -type f -name "*.py"|grep -v __pycache__|grep -v __init__.py|grep
|
||||
-v /migrations/ | xargs pycco -p -d pycco -i -s
|
||||
artifacts:
|
||||
paths:
|
||||
- pycco/
|
||||
- pycco/
|
||||
expire_in: 14 days
|
||||
|
||||
pages:
|
||||
before_script:
|
||||
- /bin/true
|
||||
- /bin/true
|
||||
stage: deploy
|
||||
dependencies:
|
||||
- test_and_coverage
|
||||
- pycco
|
||||
- test_and_coverage
|
||||
- pycco
|
||||
script:
|
||||
- mv htmlcov/ public/
|
||||
- mv pycco/ public/
|
||||
- mv htmlcov/ public/
|
||||
- mv pycco/ public/
|
||||
artifacts:
|
||||
paths:
|
||||
- public
|
||||
- public
|
||||
expire_in: 14 days
|
||||
only:
|
||||
- master
|
||||
#build-image:
|
||||
# image: docker
|
||||
# only:
|
||||
# - master
|
||||
# - devel
|
||||
# services:
|
||||
# - docker:dind
|
||||
# before_script:
|
||||
# - docker info
|
||||
# - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
|
||||
# script:
|
||||
# - ls -lah
|
||||
# - |
|
||||
# if [[ "$CI_COMMIT_BRANCH" == "$CI_DEFAULT_BRANCH" ]]; then
|
||||
# tag=""
|
||||
# echo "Running on default branch '$CI_DEFAULT_BRANCH': tag = 'latest'"
|
||||
# else
|
||||
# tag=":$CI_COMMIT_REF_SLUG"
|
||||
# echo "Running on branch '$CI_COMMIT_BRANCH': tag = $tag"
|
||||
# fi
|
||||
# - docker build --pull -t "$CI_REGISTRY_IMAGE${tag}" .
|
||||
# - docker push "$CI_REGISTRY_IMAGE${tag}"
|
||||
semgrep:
|
||||
stage: test
|
||||
allow_failure: true
|
||||
image: registry.gitlab.com/gitlab-org/security-products/analyzers/semgrep:latest
|
||||
only:
|
||||
- master
|
||||
|
||||
build-image:
|
||||
image: docker
|
||||
services:
|
||||
- docker:dind
|
||||
before_script:
|
||||
- docker info
|
||||
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
|
||||
|
||||
- devel
|
||||
variables:
|
||||
CI_PROJECT_DIR: "/tmp/app"
|
||||
SECURE_LOG_LEVEL: "debug"
|
||||
script:
|
||||
- ls -lah
|
||||
- |
|
||||
if [[ "$CI_COMMIT_BRANCH" == "$CI_DEFAULT_BRANCH" ]]; then
|
||||
tag=""
|
||||
echo "Running on default branch '$CI_DEFAULT_BRANCH': tag = 'latest'"
|
||||
else
|
||||
tag=":$CI_COMMIT_REF_SLUG"
|
||||
echo "Running on branch '$CI_COMMIT_BRANCH': tag = $tag"
|
||||
fi
|
||||
- docker build --pull -t "$CI_REGISTRY_IMAGE${tag}" .
|
||||
- docker push "$CI_REGISTRY_IMAGE${tag}"
|
||||
- rm -rf .virtualenv
|
||||
- /analyzer run
|
||||
artifacts:
|
||||
paths:
|
||||
- gl-sast-report.json
|
||||
- semgrep.sarif
|
||||
|
||||
include:
|
||||
- template: Jobs/SAST.gitlab-ci.yml
|
||||
- template: Jobs/Dependency-Scanning.gitlab-ci.yml
|
||||
- template: Jobs/Secret-Detection.gitlab-ci.yml
|
||||
|
||||
5
.gitlab/issue_templates/example-template.md
Normal file
5
.gitlab/issue_templates/example-template.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# Dscribe your issue
|
||||
|
||||
# What have you tried to far?
|
||||
|
||||
# Links / Pointer / Resources
|
||||
@@ -9,7 +9,7 @@ repos:
|
||||
- id: prettier
|
||||
files: \.(css|js|md|markdown|json)
|
||||
- repo: https://github.com/python/black
|
||||
rev: 22.10.0
|
||||
rev: 22.12.0
|
||||
hooks:
|
||||
- id: black
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
|
||||
19
Dockerfile
19
Dockerfile
@@ -1,17 +1,22 @@
|
||||
FROM quay.io/rhn_support_ofalk/fedora35-python3
|
||||
FROM quay.io/rhn_support_ofalk/fedora37-python3
|
||||
LABEL maintainer Oliver Falk <oliver@linux-kernel.at>
|
||||
EXPOSE 8081
|
||||
|
||||
RUN pip3 install pip --upgrade
|
||||
|
||||
ADD . /opt/ivatar-devel
|
||||
|
||||
WORKDIR /opt/ivatar-devel
|
||||
|
||||
RUN pip3 install Pillow && pip3 install -r requirements.txt && pip3 install python-coveralls coverage pycco django_coverage_plugin
|
||||
RUN pip3 install pip --upgrade \
|
||||
&& virtualenv .virtualenv \
|
||||
&& source .virtualenv/bin/activate \
|
||||
&& pip3 install Pillow \
|
||||
&& pip3 install -r requirements.txt \
|
||||
&& pip3 install python-coveralls coverage pycco django_coverage_plugin
|
||||
|
||||
RUN echo "DEBUG = True" >> /opt/ivatar-devel/config_local.py
|
||||
RUN echo "EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'" >> /opt/ivatar-devel/config_local.py
|
||||
RUN python3 manage.py migrate && python3 manage.py collectstatic --noinput
|
||||
RUN echo "from django.contrib.auth import get_user_model; User = get_user_model(); User.objects.create_superuser('admin', 'admin@local.tld', 'admin')" | python manage.py shell
|
||||
ENTRYPOINT python3 ./manage.py runserver 0:8081
|
||||
RUN source .virtualenv/bin/activate \
|
||||
&& python3 manage.py migrate \
|
||||
&& python3 manage.py collectstatic --noinput \
|
||||
&& echo "from django.contrib.auth import get_user_model; User = get_user_model(); User.objects.create_superuser('admin', 'admin@local.tld', 'admin')" | python manage.py shell
|
||||
ENTRYPOINT source .virtualenv/bin/activate && python3 ./manage.py runserver 0:8081
|
||||
|
||||
10
MANIFEST.in
Normal file
10
MANIFEST.in
Normal file
@@ -0,0 +1,10 @@
|
||||
include *.py
|
||||
include *.md
|
||||
include COPYING
|
||||
include LICENSE
|
||||
recursive-include templates *
|
||||
recursive-include ivatar *
|
||||
exclude .virtualenv
|
||||
exclude libravatar.egg-info
|
||||
global-exclude *.py[co]
|
||||
global-exclude __pycache__
|
||||
2
attic/debug_toolbar_resources.txt
Normal file
2
attic/debug_toolbar_resources.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
https://django-debug-toolbar.readthedocs.io/en/latest/installation.html
|
||||
https://stackoverflow.com/questions/6548947/how-can-django-debug-toolbar-be-set-to-work-for-just-some-users/6549317#6549317
|
||||
49
attic/encryption_test.py
Executable file
49
attic/encryption_test.py
Executable file
@@ -0,0 +1,49 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
import django
|
||||
import timeit
|
||||
|
||||
os.environ.setdefault(
|
||||
"DJANGO_SETTINGS_MODULE", "ivatar.settings"
|
||||
) # pylint: disable=wrong-import-position
|
||||
django.setup() # pylint: disable=wrong-import-position
|
||||
|
||||
from ivatar.ivataraccount.models import ConfirmedEmail, APIKey
|
||||
from simplecrypt import decrypt
|
||||
from binascii import unhexlify
|
||||
|
||||
digest = None
|
||||
digest_sha256 = None
|
||||
|
||||
|
||||
def get_digest_sha256():
|
||||
digest_sha256 = ConfirmedEmail.objects.first().encrypted_digest_sha256(
|
||||
secret_key=APIKey.objects.first()
|
||||
)
|
||||
return digest_sha256
|
||||
|
||||
|
||||
def get_digest():
|
||||
digest = ConfirmedEmail.objects.first().encrypted_digest(
|
||||
secret_key=APIKey.objects.first()
|
||||
)
|
||||
return digest
|
||||
|
||||
|
||||
def decrypt_digest():
|
||||
return decrypt(APIKey.objects.first().secret_key, unhexlify(digest))
|
||||
|
||||
|
||||
def decrypt_digest_256():
|
||||
return decrypt(APIKey.objects.first().secret_key, unhexlify(digest_sha256))
|
||||
|
||||
|
||||
digest = get_digest()
|
||||
digest_sha256 = get_digest_sha256()
|
||||
|
||||
print("Encrypt digest: %s" % timeit.timeit(get_digest, number=1))
|
||||
print("Encrypt digest_sha256: %s" % timeit.timeit(get_digest_sha256, number=1))
|
||||
print("Decrypt digest: %s" % timeit.timeit(decrypt_digest, number=1))
|
||||
print("Decrypt digest_sha256: %s" % timeit.timeit(decrypt_digest_256, number=1))
|
||||
7
attic/example_mysql_config
Normal file
7
attic/example_mysql_config
Normal file
@@ -0,0 +1,7 @@
|
||||
DATABASES['default'] = {
|
||||
'ENGINE': 'django.db.backends.mysql',
|
||||
'NAME': 'libravatar',
|
||||
'USER': 'libravatar',
|
||||
'PASSWORD': 'libravatar',
|
||||
'HOST': 'localhost',
|
||||
}
|
||||
@@ -232,6 +232,11 @@ TRUSTED_DEFAULT_URLS = [
|
||||
"host_equals": "avatars.dicebear.com",
|
||||
"path_prefix": "/api/",
|
||||
},
|
||||
{
|
||||
"schemes": ["https"],
|
||||
"host_equals": "api.dicebear.com",
|
||||
"path_prefix": "/",
|
||||
},
|
||||
{
|
||||
"schemes": ["https"],
|
||||
"host_equals": "badges.fedoraproject.org",
|
||||
|
||||
@@ -266,7 +266,7 @@ class Photo(BaseAccountModel):
|
||||
cropped_w, cropped_h = cropped.size
|
||||
max_w = AVATAR_MAX_SIZE
|
||||
if cropped_w > max_w or cropped_h > max_w:
|
||||
cropped = cropped.resize((max_w, max_w), Image.ANTIALIAS)
|
||||
cropped = cropped.resize((max_w, max_w), Image.LANCZOS)
|
||||
|
||||
data = BytesIO()
|
||||
cropped.save(data, pil_format(self.format), quality=JPEG_QUALITY)
|
||||
|
||||
@@ -1998,4 +1998,61 @@ class Tester(TestCase): # pylint: disable=too-many-public-methods
|
||||
Test if preferences page works
|
||||
"""
|
||||
|
||||
self.login()
|
||||
self.client.get(reverse("user_preference"))
|
||||
|
||||
def test_delete_user(self):
|
||||
"""
|
||||
Test if deleting user profile works
|
||||
"""
|
||||
|
||||
self.login()
|
||||
self.client.get(reverse("delete"))
|
||||
response = self.client.post(
|
||||
reverse("delete"),
|
||||
data={"password": self.password},
|
||||
follow=True,
|
||||
)
|
||||
self.assertEqual(response.status_code, 200, "Deletion worked")
|
||||
self.assertEqual(User.objects.count(), 0, "No user there any more")
|
||||
|
||||
def test_confirm_already_confirmed(self):
|
||||
"""
|
||||
Try to confirm a mail address that has been confirmed (by another user)
|
||||
"""
|
||||
|
||||
# Add mail address (stays unconfirmed)
|
||||
self.test_add_email()
|
||||
|
||||
# Create a second user that will conflict
|
||||
user2 = User.objects.create_user(
|
||||
username=self.username + "1",
|
||||
password=self.password,
|
||||
first_name=self.first_name,
|
||||
last_name=self.last_name,
|
||||
)
|
||||
ConfirmedEmail.objects.create(
|
||||
email=self.email,
|
||||
user=user2,
|
||||
)
|
||||
|
||||
# Just to be sure
|
||||
self.assertEqual(
|
||||
self.user.unconfirmedemail_set.first().email,
|
||||
user2.confirmedemail_set.first().email,
|
||||
"Mail not the same?",
|
||||
)
|
||||
|
||||
# This needs to be cought
|
||||
try:
|
||||
self.test_confirm_email()
|
||||
except AssertionError:
|
||||
pass
|
||||
|
||||
# Request a random page, so we can access the messages
|
||||
response = self.client.get(reverse("profile"))
|
||||
self.assertEqual(
|
||||
str(list(response.context[0]["messages"])[0]),
|
||||
"This mail address has been taken already and cannot be confirmed",
|
||||
"This should return an error message!",
|
||||
)
|
||||
|
||||
@@ -207,6 +207,13 @@ class ConfirmEmailView(SuccessMessageMixin, TemplateView):
|
||||
messages.error(request, _("Verification key does not exist"))
|
||||
return HttpResponseRedirect(reverse_lazy("profile"))
|
||||
|
||||
if ConfirmedEmail.objects.filter(email=unconfirmed.email).count() > 0:
|
||||
messages.error(
|
||||
request,
|
||||
_("This mail address has been taken already and cannot be confirmed"),
|
||||
)
|
||||
return HttpResponseRedirect(reverse_lazy("profile"))
|
||||
|
||||
# TODO: Check for a reasonable expiration time in unconfirmed email
|
||||
|
||||
(confirmed_id, external_photos) = ConfirmedEmail.objects.create_confirmed_email(
|
||||
|
||||
0
ivatar/tools/__init__.py
Normal file
0
ivatar/tools/__init__.py
Normal file
@@ -48,16 +48,109 @@ class Tester(TestCase): # pylint: disable=too-many-public-methods
|
||||
password=self.password,
|
||||
)
|
||||
|
||||
def test_check(self):
|
||||
def test_check_mail(self):
|
||||
"""
|
||||
Test check page
|
||||
"""
|
||||
self.login()
|
||||
response = self.client.get(reverse("tools_check"))
|
||||
self.assertEqual(response.status_code, 200, "no 200 ok?")
|
||||
response = self.client.post(
|
||||
reverse("tools_check"),
|
||||
data={"mail": "test@test.com", "size": "85"},
|
||||
follow=True,
|
||||
)
|
||||
|
||||
self.assertContains(
|
||||
response,
|
||||
'value="test@test.com"',
|
||||
1,
|
||||
200,
|
||||
"Value not set again!?",
|
||||
)
|
||||
|
||||
self.assertContains(
|
||||
response,
|
||||
"b642b4217b34b1e8d3bd915fc65c4452",
|
||||
3,
|
||||
200,
|
||||
"Wrong md5 hash!?",
|
||||
)
|
||||
self.assertContains(
|
||||
response,
|
||||
"f660ab912ec121d1b1e928a0bb4bc61b15f5ad44d5efdc4e1c92a25e99b8e44a",
|
||||
3,
|
||||
200,
|
||||
"Wrong sha256 hash!?",
|
||||
)
|
||||
self.assertContains(
|
||||
response,
|
||||
'value="85"',
|
||||
1,
|
||||
200,
|
||||
"Size should be set based on post params!?",
|
||||
)
|
||||
|
||||
def test_check_openid(self):
|
||||
"""
|
||||
Test check page
|
||||
"""
|
||||
self.login()
|
||||
response = self.client.get(reverse("tools_check"))
|
||||
self.assertEqual(response.status_code, 200, "no 200 ok?")
|
||||
response = self.client.post(
|
||||
reverse("tools_check"),
|
||||
data={"openid": "https://test.com", "size": "85"},
|
||||
follow=True,
|
||||
)
|
||||
|
||||
self.assertContains(
|
||||
response,
|
||||
'value="https://test.com"',
|
||||
1,
|
||||
200,
|
||||
"Value not set again!?",
|
||||
)
|
||||
|
||||
self.assertContains(
|
||||
response,
|
||||
"396936bd0bf0603d6784b65d03e96dae90566c36b62661f28d4116c516524bcc",
|
||||
3,
|
||||
200,
|
||||
"Wrong sha256 hash!?",
|
||||
)
|
||||
self.assertContains(
|
||||
response,
|
||||
'value="85"',
|
||||
1,
|
||||
200,
|
||||
"Size should be set based on post params!?",
|
||||
)
|
||||
|
||||
def test_check_domain(self):
|
||||
"""
|
||||
Test check domain page
|
||||
"""
|
||||
self.login()
|
||||
response = self.client.get(reverse("tools_check_domain"))
|
||||
self.assertEqual(response.status_code, 200, "no 200 ok?")
|
||||
response = self.client.post(
|
||||
reverse("tools_check_domain"),
|
||||
data={"domain": "linux-kernel.at"},
|
||||
follow=True,
|
||||
)
|
||||
self.assertEqual(response.status_code, 200, "no 200 ok?")
|
||||
self.assertContains(
|
||||
response,
|
||||
"http://avatars.linux-kernel.at",
|
||||
2,
|
||||
200,
|
||||
"Not responing with right URL!?",
|
||||
)
|
||||
self.assertContains(
|
||||
response,
|
||||
"https://avatars.linux-kernel.at",
|
||||
2,
|
||||
200,
|
||||
"Not responing with right URL!?",
|
||||
)
|
||||
|
||||
@@ -256,7 +256,7 @@ class AvatarImageView(TemplateView):
|
||||
identicon = Identicon.render(kwargs["digest"])
|
||||
data = BytesIO()
|
||||
img = Image.open(BytesIO(identicon))
|
||||
img = img.resize((size, size), Image.ANTIALIAS)
|
||||
img = img.resize((size, size), Image.LANCZOS)
|
||||
img.save(data, "PNG", quality=JPEG_QUALITY)
|
||||
data.seek(0)
|
||||
response = CachingHttpResponse(uri, data, content_type="image/png")
|
||||
@@ -266,7 +266,7 @@ class AvatarImageView(TemplateView):
|
||||
if str(default) == "pagan":
|
||||
paganobj = pagan.Avatar(kwargs["digest"])
|
||||
data = BytesIO()
|
||||
img = paganobj.img.resize((size, size), Image.ANTIALIAS)
|
||||
img = paganobj.img.resize((size, size), Image.LANCZOS)
|
||||
img.save(data, "PNG", quality=JPEG_QUALITY)
|
||||
data.seek(0)
|
||||
response = CachingHttpResponse(uri, data, content_type="image/png")
|
||||
@@ -331,9 +331,9 @@ class AvatarImageView(TemplateView):
|
||||
# If the image is smaller than what was requested, we need
|
||||
# to use the function resize
|
||||
if photodata.size[0] < size or photodata.size[1] < size:
|
||||
photodata = photodata.resize((size, size), Image.ANTIALIAS)
|
||||
photodata = photodata.resize((size, size), Image.LANCZOS)
|
||||
else:
|
||||
photodata.thumbnail((size, size), Image.ANTIALIAS)
|
||||
photodata.thumbnail((size, size), Image.LANCZOS)
|
||||
photodata.save(data, pil_format(imgformat), quality=JPEG_QUALITY)
|
||||
|
||||
data.seek(0)
|
||||
|
||||
3
pyproject.toml
Normal file
3
pyproject.toml
Normal file
@@ -0,0 +1,3 @@
|
||||
[build-system]
|
||||
requires = ['setuptools>=40.8.0', 'wheel']
|
||||
build-backend = 'setuptools.build_meta:__legacy__'
|
||||
33
setup.cfg
Normal file
33
setup.cfg
Normal file
@@ -0,0 +1,33 @@
|
||||
[metadata]
|
||||
name = libravatar
|
||||
version = 1.7.0
|
||||
description = A Django application implementing libravatar.org
|
||||
long_description = file: README.md
|
||||
url = https://libravatar.org
|
||||
author = Oliver Falk
|
||||
author_email = oliver@linux-kernel.at
|
||||
license = GPLv3
|
||||
classifiers =
|
||||
Environment :: Web Environment
|
||||
Framework :: Django
|
||||
Framework :: Django :: 3.2
|
||||
Framework :: Django :: 4.0
|
||||
Framework :: Django :: 4.1
|
||||
License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
||||
Operating System :: OS Independent
|
||||
Programming Language :: Python
|
||||
Programming Language :: Python :: 3
|
||||
Programming Language :: Python :: 3 :: Only
|
||||
Programming Language :: Python :: 3.8
|
||||
Programming Language :: Python :: 3.9
|
||||
Programming Language :: Python :: 3.10
|
||||
Programming Language :: Python :: 3.11
|
||||
Topic :: Internet :: WWW/HTTP
|
||||
Topic :: Internet :: WWW/HTTP :: Dynamic Content
|
||||
|
||||
[options]
|
||||
include_package_data = true
|
||||
packages = find:
|
||||
python_requires = >=3.8
|
||||
install_requires =
|
||||
Django >= 3.2
|
||||
Reference in New Issue
Block a user