mirror of
https://git.linux-kernel.at/oliver/ivatar.git
synced 2025-11-18 22:18:02 +00:00
Merge branch 'master' int trust - so it doesn't look stale
This commit is contained in:
@@ -1,12 +1,9 @@
|
||||
image: centos:centos7
|
||||
image: ofalk/centos7-python36
|
||||
|
||||
before_script:
|
||||
- yum install -y -t https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
|
||||
- yum -y -t install python36 python34-pip python36-devel unzip mysql-devel gcc git openldap-devel
|
||||
- pip3 install pip --upgrade
|
||||
- pip install virtualenv --upgrade
|
||||
- virtualenv -p python3.6 /tmp/.virtualenv
|
||||
- source /tmp/.virtualenv/bin/activate
|
||||
- pip install Pillow
|
||||
- pip install -r requirements.txt
|
||||
- pip install python-coveralls
|
||||
- pip install coverage
|
||||
|
||||
@@ -52,7 +52,7 @@ OPENID_CREATE_USERS = True
|
||||
OPENID_UPDATE_DETAILS_FROM_SREG = True
|
||||
|
||||
SITE_NAME = os.environ.get('SITE_NAME', 'libravatar')
|
||||
IVATAR_VERSION = '1.0'
|
||||
IVATAR_VERSION = '1.1'
|
||||
|
||||
SECURE_BASE_URL = os.environ.get('SECURE_BASE_URL', 'https://avatars.linux-kernel.at/avatar/')
|
||||
BASE_URL = os.environ.get('BASE_URL', 'http://avatars.linux-kernel.at/avatar/')
|
||||
@@ -102,11 +102,14 @@ else:
|
||||
if 'test' in sys.argv or 'collectstatic' in sys.argv:
|
||||
EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend'
|
||||
else:
|
||||
try:
|
||||
ANYMAIL = { # pragma: no cover
|
||||
'MAILGUN_API_KEY': os.environ['IVATAR_MAILGUN_API_KEY'],
|
||||
'MAILGUN_SENDER_DOMAIN': os.environ['IVATAR_MAILGUN_SENDER_DOMAIN'],
|
||||
}
|
||||
EMAIL_BACKEND = 'anymail.backends.mailgun.EmailBackend' # pragma: no cover
|
||||
except Exception as exc:
|
||||
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
|
||||
|
||||
SERVER_EMAIL = os.environ.get('SERVER_EMAIL', 'ivatar@mg.linux-kernel.at')
|
||||
DEFAULT_FROM_EMAIL = os.environ.get('DEFAULT_FROM_EMAIL', 'ivatar@mg.linux-kernel.at')
|
||||
|
||||
@@ -1,139 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2018 Oliver Falk <oliver@linux-kernel.at>
|
||||
#
|
||||
# This file is part of Libravatar
|
||||
#
|
||||
# Libravatar is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Libravatar is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with Libravatar. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import base64
|
||||
import gzip
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from xml.sax import saxutils
|
||||
import hashlib
|
||||
|
||||
# pylint: disable=relative-import
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "libravatar.settings")
|
||||
import libravatar.settings as settings
|
||||
from libravatar.utils import create_logger, is_hex
|
||||
import django
|
||||
django.setup()
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
os.umask(022)
|
||||
LOGGER = create_logger('exportaccount')
|
||||
|
||||
SCHEMA_ROOT = 'https://www.libravatar.org/schemas/export/0.2'
|
||||
SCHEMA_XSD = '%s/export.xsd' % SCHEMA_ROOT
|
||||
|
||||
|
||||
def xml_header():
|
||||
return '''<?xml version="1.0" encoding="UTF-8"?>
|
||||
<user xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="%s %s"
|
||||
xmlns="%s">\n''' % (SCHEMA_ROOT, SCHEMA_XSD, SCHEMA_ROOT)
|
||||
|
||||
|
||||
def xml_footer():
|
||||
return '</user>\n'
|
||||
|
||||
|
||||
def xml_account(username, password):
|
||||
escaped_username = saxutils.quoteattr(username)
|
||||
escaped_site_url = saxutils.quoteattr(settings.SITE_URL)
|
||||
escaped_password = saxutils.quoteattr(password)
|
||||
return ' <account username=%s password=%s site=%s/>\n' % (escaped_username, escaped_password, escaped_site_url)
|
||||
|
||||
def xml_email(emails):
|
||||
returnstring = " <emails>\n"
|
||||
for email in emails:
|
||||
returnstring += ' <email photo_id="' + str(email.photo_id) + '">' + email.email.encode('utf-8') + '</email>' + "\n"
|
||||
returnstring += " </emails>\n"
|
||||
return returnstring
|
||||
|
||||
def xml_openid(openids):
|
||||
returnstring = " <openids>\n"
|
||||
for openid in openids:
|
||||
returnstring += ' <openid photo_id="' + str(openid.photo_id) + '">' + openid.openid.encode('utf-8') + '</openid>' + "\n"
|
||||
returnstring += " </openids>\n"
|
||||
return returnstring
|
||||
|
||||
|
||||
def xml_photos(photos):
|
||||
s = ' <photos>\n'
|
||||
for photo in photos:
|
||||
(photo_filename, photo_format, id) = photo
|
||||
encoded_photo = encode_photo(photo_filename, photo_format)
|
||||
if encoded_photo:
|
||||
s += ''' <photo id="%s" encoding="base64" format=%s>
|
||||
%s
|
||||
</photo>\n''' % (id, saxutils.quoteattr(photo_format), encoded_photo)
|
||||
s += ' </photos>\n'
|
||||
return s
|
||||
|
||||
|
||||
def encode_photo(photo_filename, photo_format):
|
||||
filename = settings.USER_FILES_ROOT + photo_filename + '.' + photo_format
|
||||
if not os.path.isfile(filename):
|
||||
LOGGER.warning('Photo not found: %s', filename)
|
||||
return None
|
||||
|
||||
photo_content = None
|
||||
with open(filename) as photo:
|
||||
photo_content = photo.read()
|
||||
|
||||
if not photo_content:
|
||||
LOGGER.warning('Could not read photo: %s', filename)
|
||||
return None
|
||||
|
||||
return base64.b64encode(photo_content)
|
||||
|
||||
|
||||
def main(argv=None):
|
||||
if argv is None:
|
||||
argv = sys.argv
|
||||
|
||||
if(len(sys.argv) > 1):
|
||||
userobjs = User.objects.filter(username=sys.argv[1])
|
||||
else:
|
||||
userobjs = User.objects.all()
|
||||
|
||||
for user in userobjs:
|
||||
hash_object = hashlib.new('sha256')
|
||||
hash_object.update(user.username + user.password)
|
||||
file_hash = hash_object.hexdigest()
|
||||
photos = []
|
||||
for photo in user.photos.all():
|
||||
photo_details = (photo.filename, photo.format, photo.id)
|
||||
photos.append(photo_details)
|
||||
username = user.username
|
||||
|
||||
dest_filename = settings.EXPORT_FILES_ROOT + file_hash + '.xml.gz'
|
||||
|
||||
destination = gzip.open(dest_filename, 'w')
|
||||
destination.write(xml_header())
|
||||
destination.write(xml_account(username, user.password))
|
||||
destination.write(xml_email(user.confirmed_emails.all()))
|
||||
destination.write(xml_openid(user.confirmed_openids.all()))
|
||||
destination.write(xml_photos(photos))
|
||||
destination.write(xml_footer())
|
||||
destination.close()
|
||||
print(dest_filename)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -37,10 +37,10 @@ from .gravatar import get_photo as get_gravatar_photo
|
||||
|
||||
def file_format(image_type):
|
||||
'''
|
||||
Helper method returning a 3 character long image type
|
||||
Helper method returning a short image type
|
||||
'''
|
||||
if image_type == 'JPEG':
|
||||
return 'jpg'
|
||||
return 'jpeg'
|
||||
elif image_type == 'PNG':
|
||||
return 'png'
|
||||
elif image_type == 'GIF':
|
||||
@@ -52,7 +52,7 @@ def pil_format(image_type):
|
||||
'''
|
||||
Helper method returning the 'encoder name' for PIL
|
||||
'''
|
||||
if image_type == 'jpg':
|
||||
if image_type == 'jpg' or image_type == 'jpeg':
|
||||
return 'JPEG'
|
||||
elif image_type == 'png':
|
||||
return 'PNG'
|
||||
|
||||
@@ -358,7 +358,7 @@ class Tester(TestCase): # pylint: disable=too-many-public-methods
|
||||
# Probably not the best way to access the content type
|
||||
self.assertEqual(
|
||||
response['Content-Type'],
|
||||
'image/jpg',
|
||||
'image/jpeg',
|
||||
'Content type wrong!?')
|
||||
|
||||
self.assertEqual(
|
||||
@@ -638,10 +638,10 @@ class Tester(TestCase): # pylint: disable=too-many-public-methods
|
||||
self.assertEqual(
|
||||
str(list(response.context[0]['messages'])[0]),
|
||||
'Successfully uploaded',
|
||||
'JPG upload failed?!')
|
||||
'JPEG upload failed?!')
|
||||
self.assertEqual(
|
||||
self.user.photo_set.first().format, 'jpg',
|
||||
'Format must be jpg, since we uploaded a jpg!')
|
||||
self.user.photo_set.first().format, 'jpeg',
|
||||
'Format must be jpeg, since we uploaded a jpeg!')
|
||||
self.test_confirm_email()
|
||||
self.user.confirmedemail_set.first().photo = self.user.photo_set.first()
|
||||
urlobj = urlsplit(
|
||||
|
||||
@@ -914,6 +914,9 @@ class PasswordResetView(PasswordResetViewOriginal):
|
||||
try:
|
||||
confirmed_email = ConfirmedEmail.objects.get(email=request.POST['email'])
|
||||
confirmed_email.user.email = confirmed_email.email
|
||||
if not confirmed_email.user.password:
|
||||
random_pass = User.objects.make_random_password()
|
||||
confirmed_email.user.set_pasword(random_pass)
|
||||
confirmed_email.user.save()
|
||||
except Exception as exc:
|
||||
pass
|
||||
|
||||
@@ -56,8 +56,10 @@ class CheckForm(forms.Form):
|
||||
required=True,
|
||||
)
|
||||
|
||||
default_url = forms.URLField(
|
||||
default_url = forms.CharField(
|
||||
label=_('Default URL'),
|
||||
min_length=1,
|
||||
max_length=MAX_LENGTH_URL,
|
||||
required=False,
|
||||
)
|
||||
|
||||
|
||||
@@ -8,6 +8,12 @@
|
||||
|
||||
<h1>{% trans 'Check e-mail or openid' %}</h1>
|
||||
|
||||
{% if form.errors %}
|
||||
<p class="error">{% trans "Please correct errors below:" %}<br>
|
||||
{{ form.errors|join:', ' }}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
<div style="max-width:640px">
|
||||
<form method="post" name="check">
|
||||
{% csrf_token %}
|
||||
@@ -17,8 +23,8 @@
|
||||
<input type="text" name="openid" maxlength="255" minlength="11" class="form-control" placeholder="{% trans 'OpenID' %}" {% if openidurl %} value="{{ form.openid.value }}" {% endif %} id="id_openid"></div>
|
||||
<div class="form-group"><label for="id_size">{% trans 'Size' %}</label>
|
||||
<input type="number" name="size" min="5" max="512" class="form-control" placeholder="{% trans 'Size' %}" {% if mailurl or openidurl %} value="{{ form.size.value }}" {% else %} value="100" {% endif %} required id="id_size"></div>
|
||||
<div class="form-group"><label for="id_default_url">{% trans 'Default URL' %}</label>
|
||||
<input type="url" name="default_url" class="form-control" placeholder="{% trans 'Default URL' %}" {% if mailurl or openidurl %} value="{{ form.default_url.value }}" {% endif %} id="id_default_url"></div>
|
||||
<div class="form-group"><label for="id_default_url">{% trans 'Default URL or special keyword' %}</label>
|
||||
<input type="text" name="default_url" class="form-control" placeholder="{% trans 'Default' %}" {% if mailurl or openidurl %} value="{{ form.default_url.value }}" {% endif %} id="id_default_url"></div>
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-default">{% trans 'Check' %}</button>
|
||||
</div>
|
||||
@@ -56,8 +62,8 @@
|
||||
<h3 class="panel-title">SHA256 <i class="fa fa-lock" title="Secure connection (https)"></i> <i class="fa fa-at" title="mail: {{ form.mail.value }}"></i></h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<a href="{{ SECURE_BASE_URL }}{{ mail_hash256 }}?s={{ size }}">
|
||||
<center><img src="{{ SECURE_BASE_URL }}{{ mail_hash256 }}?s={{ size }}" style="max-width: {{ size }}px; max-height: {{ size }}px;"></center>
|
||||
<a href="{{ mailurl_secure_256 }}">
|
||||
<center><img src="{{ mailurl_secure_256 }}" style="max-width: {{ size }}px; max-height: {{ size }}px;"></center>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -37,44 +37,51 @@
|
||||
<!-- TODO TODO TODO: I need better styling -->
|
||||
{% if result %}
|
||||
<hr/>
|
||||
<table>
|
||||
<tr>
|
||||
<td valign="top" style="padding: 0px 10px 0px 10px;">{% trans 'HTTP avatar server:' %}</td>
|
||||
<td>
|
||||
<h2>The following servers will be used for your domain</h2>
|
||||
<div class="panel panel-tortin" style="width:intrinsic;margin-left:30px;float:left">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title"><i class="fa fa-unlock-alt"></i> HTTP Server</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{% if result.avatar_server_http %}
|
||||
<tt>{{result.avatar_server_http}}</tt>
|
||||
<a href="{{result.avatar_server_http}}">
|
||||
<h4>{{result.avatar_server_http}}</h4>
|
||||
</a>
|
||||
{% if result.avatar_server_http_ipv4 %}
|
||||
<br>{{ result.avatar_server_http_ipv4 }}
|
||||
{% else %}
|
||||
<br><strong>{% trans 'Warning: no A record for this hostname' %}</strong>
|
||||
<br><center>{{ result.avatar_server_http_ipv4 }}</center>
|
||||
{% endif %}
|
||||
{% if result.avatar_server_http_ipv6 %}
|
||||
<br>{{ result.avatar_server_http_ipv6 }}
|
||||
<br><center>{{ result.avatar_server_http_ipv6 }}</center>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<i>{% trans 'use <tt>http://cdn.libravatar.org</tt>' %}</i>
|
||||
<a href="http://cdn.libravatar.org">
|
||||
<h4>http://cdn.libravatar.org</h4>
|
||||
</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" style="padding: 0px 10px 0px 10px;">{% trans 'HTTPS avatar server:' %}</td>
|
||||
<td>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-tortin" style="width:intrinsic;margin-left:30px;float:left">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title"><i class="fa fa-lock"></i> HTTPS Server</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{% if result.avatar_server_https %}
|
||||
<tt>{{result.avatar_server_https}}</tt>
|
||||
<a href="{{result.avatar_server_https}}">
|
||||
<h4>{{result.avatar_server_https}}</h4>
|
||||
</a>
|
||||
{% if result.avatar_server_https_ipv4 %}
|
||||
<br>{{ result.avatar_server_https_ipv4 }}
|
||||
{% else %}
|
||||
<br><strong>{% trans 'Warning: no A record for this hostname' %}</strong>
|
||||
<br><center>{{ result.avatar_server_https_ipv4 }}</center>
|
||||
{% endif %}
|
||||
{% if result.avatar_server_https_ipv6 %}
|
||||
<br>{{ result.avatar_server_https_ipv6 }}
|
||||
<br><center>{{ result.avatar_server_https_ipv6 }}</center>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<i>{% trans 'use <tt>https://seccdn.libravatar.org</tt>' %}</i>
|
||||
<a href="https://seccdn.libravatar.org">
|
||||
<h4>https://seccdn.libravatar.org</h4>
|
||||
</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div style="height:40px"></div>
|
||||
|
||||
@@ -66,15 +66,17 @@ class CheckView(FormView):
|
||||
else:
|
||||
default_url = None
|
||||
|
||||
if 'size' in form.cleaned_data:
|
||||
size = form.cleaned_data['size']
|
||||
if form.cleaned_data['mail']:
|
||||
mailurl = libravatar_url(
|
||||
email=form.cleaned_data['mail'],
|
||||
size=form.cleaned_data['size'],
|
||||
size=size,
|
||||
default=default_url)
|
||||
mailurl = mailurl.replace(LIBRAVATAR_BASE_URL, BASE_URL)
|
||||
mailurl_secure = libravatar_url(
|
||||
email=form.cleaned_data['mail'],
|
||||
size=form.cleaned_data['size'],
|
||||
size=size,
|
||||
https=True,
|
||||
default=default_url)
|
||||
mailurl_secure = mailurl_secure.replace(
|
||||
@@ -86,18 +88,20 @@ class CheckView(FormView):
|
||||
hash_obj = hashlib.new('sha256')
|
||||
hash_obj.update(form.cleaned_data['mail'].encode('utf-8'))
|
||||
mail_hash256 = hash_obj.hexdigest()
|
||||
size = form.cleaned_data['size']
|
||||
mailurl_secure_256 = mailurl_secure.replace(
|
||||
mail_hash,
|
||||
mail_hash256)
|
||||
if form.cleaned_data['openid']:
|
||||
if not form.cleaned_data['openid'].startswith('http://') and not form.cleaned_data['openid'].startswith('https://'):
|
||||
form.cleaned_data['openid'] = 'http://%s' % form.cleaned_data['openid']
|
||||
openidurl = libravatar_url(
|
||||
openid=form.cleaned_data['openid'],
|
||||
size=form.cleaned_data['size'],
|
||||
size=size,
|
||||
default=default_url)
|
||||
openidurl = openidurl.replace(LIBRAVATAR_BASE_URL, BASE_URL)
|
||||
openidurl_secure = libravatar_url(
|
||||
openid=form.cleaned_data['openid'],
|
||||
size=form.cleaned_data['size'],
|
||||
size=size,
|
||||
https=True,
|
||||
default=default_url)
|
||||
openidurl_secure = openidurl_secure.replace(
|
||||
@@ -106,13 +110,13 @@ class CheckView(FormView):
|
||||
openid_hash = parse_user_identity(
|
||||
openid=form.cleaned_data['openid'],
|
||||
email=None)[0]
|
||||
size = form.cleaned_data['size']
|
||||
|
||||
return render(self.request, self.template_name, {
|
||||
'form': form,
|
||||
'mailurl': mailurl,
|
||||
'openidurl': openidurl,
|
||||
'mailurl_secure': mailurl_secure,
|
||||
'mailurl_secure_256': mailurl_secure_256,
|
||||
'openidurl_secure': openidurl_secure,
|
||||
'mail_hash': mail_hash,
|
||||
'mail_hash256': mail_hash256,
|
||||
|
||||
@@ -16,7 +16,9 @@ from django.urls import reverse_lazy
|
||||
from PIL import Image
|
||||
|
||||
from monsterid.id import build_monster as BuildMonster
|
||||
from pydenticon import Generator as IdenticonGenerator
|
||||
import Identicon
|
||||
from pydenticon5 import Pydenticon5
|
||||
import pagan
|
||||
from robohash import Robohash
|
||||
|
||||
from ivatar.settings import AVATAR_MAX_SIZE, JPEG_QUALITY, DEFAULT_AVATAR_SIZE
|
||||
@@ -120,6 +122,14 @@ class AvatarImageView(TemplateView):
|
||||
|
||||
# Return the default URL, as specified, or 404 Not Found, if default=404
|
||||
if default:
|
||||
# Proxy to gravatar to generate wavatar - lazy me
|
||||
if str(default) == 'wavatar':
|
||||
url = reverse_lazy('gravatarproxy', args=[kwargs['digest']]) \
|
||||
+ '?s=%i' % size + '&default=%s&f=y' % default
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
|
||||
|
||||
if str(default) == str(404):
|
||||
return HttpResponseNotFound(_('<h1>Image not found</h1>'))
|
||||
|
||||
@@ -145,32 +155,35 @@ class AvatarImageView(TemplateView):
|
||||
data,
|
||||
content_type='image/png')
|
||||
|
||||
if str(default) == 'identicon' or str(default) == 'retro':
|
||||
# Taken from example code
|
||||
foreground = [
|
||||
'rgb(45,79,255)',
|
||||
'rgb(254,180,44)',
|
||||
'rgb(226,121,234)',
|
||||
'rgb(30,179,253)',
|
||||
'rgb(232,77,65)',
|
||||
'rgb(49,203,115)',
|
||||
'rgb(141,69,170)']
|
||||
background = 'rgb(224,224,224)'
|
||||
padwidth = int(size/10)
|
||||
if padwidth < 10:
|
||||
padwidth = 10
|
||||
if size < 60:
|
||||
padwidth = 0
|
||||
padding = (padwidth, padwidth, padwidth, padwidth)
|
||||
# Since padding is _added_ around the generated image, we
|
||||
# need to reduce the image size by padding*2 (left/right, top/bottom)
|
||||
size = size - 2*padwidth
|
||||
generator = IdenticonGenerator(
|
||||
10, 10, digest=hashlib.sha1,
|
||||
foreground=foreground, background=background)
|
||||
data = generator.generate(
|
||||
kwargs['digest'], size, size,
|
||||
output_format='png', padding=padding, inverted=False)
|
||||
if str(default) == 'retro':
|
||||
identicon = Identicon.render(kwargs['digest'])
|
||||
data = BytesIO()
|
||||
img = Image.open(BytesIO(identicon))
|
||||
img = img.resize((size, size), Image.ANTIALIAS)
|
||||
img.save(data, 'PNG', quality=JPEG_QUALITY)
|
||||
data.seek(0)
|
||||
return HttpResponse(
|
||||
data,
|
||||
content_type='image/png')
|
||||
|
||||
if str(default) == 'pagan':
|
||||
paganobj = pagan.Avatar(kwargs['digest'])
|
||||
data = BytesIO()
|
||||
img = paganobj.img.resize((size, size), Image.ANTIALIAS)
|
||||
img.save(data, 'PNG', quality=JPEG_QUALITY)
|
||||
data.seek(0)
|
||||
return HttpResponse(
|
||||
data,
|
||||
content_type='image/png')
|
||||
|
||||
if str(default) == 'identicon':
|
||||
p = Pydenticon5()
|
||||
# In order to make use of the whole 32 bytes digest, we need to redigest them.
|
||||
newdigest = hashlib.md5(bytes(kwargs['digest'], 'utf-8')).hexdigest()
|
||||
img = p.draw(newdigest, size, 0)
|
||||
data = BytesIO()
|
||||
img.save(data, 'PNG', quality=JPEG_QUALITY)
|
||||
data.seek(0)
|
||||
return HttpResponse(
|
||||
data,
|
||||
content_type='image/png')
|
||||
@@ -194,7 +207,11 @@ class AvatarImageView(TemplateView):
|
||||
|
||||
imgformat = obj.photo.format
|
||||
photodata = Image.open(BytesIO(obj.photo.data))
|
||||
|
||||
# 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)
|
||||
else:
|
||||
photodata.thumbnail((size, size), Image.ANTIALIAS)
|
||||
data = BytesIO()
|
||||
photodata.save(data, pil_format(imgformat), quality=JPEG_QUALITY)
|
||||
@@ -235,6 +252,7 @@ class GravatarProxyView(View):
|
||||
except:
|
||||
pass
|
||||
|
||||
if str(default) != 'wavatar':
|
||||
# This part is special/hackish
|
||||
# Check if the image returned by Gravatar is their default image, if so,
|
||||
# redirect to our default instead.
|
||||
@@ -249,7 +267,7 @@ class GravatarProxyView(View):
|
||||
print('Gravatar test url fetch failed: %s' % exc)
|
||||
|
||||
gravatar_url = 'https://secure.gravatar.com/avatar/' + kwargs['digest'] \
|
||||
+ '?s=%i' % size
|
||||
+ '?s=%i' % size + '&d=%s' % default
|
||||
|
||||
try:
|
||||
gravatarimagedata = urlopen(gravatar_url, timeout=URL_TIMEOUT)
|
||||
|
||||
@@ -33,6 +33,8 @@ mysqlclient
|
||||
psycopg2
|
||||
notsetuptools
|
||||
git+https://github.com/ofalk/monsterid.git
|
||||
git+https://github.com/azaghal/pydenticon.git
|
||||
git+https://github.com/ofalk/Robohash.git@devel
|
||||
python-memcached
|
||||
git+https://github.com/ercpe/pydenticon5.git
|
||||
git+https://github.com/flavono123/identicon.git
|
||||
pagan
|
||||
|
||||
@@ -45,8 +45,12 @@
|
||||
</a>
|
||||
<ul class="dropdown-menu" aria-labelledby="tools_dropdown">
|
||||
<li><a id="tools-check" href="{% url 'tools_check' %}">
|
||||
<i class="fa fa-fw fa-check-square" aria-hidden="true"></i> {% trans 'Check' %}
|
||||
<i class="fa fa-fw fa-check-square" aria-hidden="true"></i> {% trans 'Check ID' %}
|
||||
</a></li>
|
||||
<li><a id="tools-check-domain" href="{% url 'tools_check_domain' %}">
|
||||
<i class="fa fa-fw fa-check-square" aria-hidden="true"></i> {% trans 'Check Domain' %}
|
||||
</a></li>
|
||||
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
Reference in New Issue
Block a user