mirror of
https://git.linux-kernel.at/oliver/ivatar.git
synced 2025-11-14 12:08:04 +00:00
Merge branch 'devel' into gandi-sponsor
This commit is contained in:
@@ -5,6 +5,11 @@ omit =
|
|||||||
node_modules/*
|
node_modules/*
|
||||||
.virtualenv/*
|
.virtualenv/*
|
||||||
import_libravatar.py
|
import_libravatar.py
|
||||||
|
requirements.txt
|
||||||
|
static/admin/*
|
||||||
|
static/humans.txt
|
||||||
|
static/img/robots.txt
|
||||||
|
|
||||||
|
|
||||||
[html]
|
[html]
|
||||||
extra_css = coverage_extra_style.css
|
extra_css = coverage_extra_style.css
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
image: docker.io/ofalk/fedora31-python3
|
image:
|
||||||
|
name: quay.io/rhn_support_ofalk/fedora34-python3
|
||||||
|
entrypoint: [ '/bin/sh', '-c' ]
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
- virtualenv -p python3 /tmp/.virtualenv
|
- virtualenv -p python3 /tmp/.virtualenv
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ cd ivatar
|
|||||||
virtualenv -p python3 .virtualenv
|
virtualenv -p python3 .virtualenv
|
||||||
source .virtualenv/bin/activate
|
source .virtualenv/bin/activate
|
||||||
pip install -r requirements.txt
|
pip install -r requirements.txt
|
||||||
|
pip install pillow
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
## (SQL) Migrations
|
## (SQL) Migrations
|
||||||
|
|||||||
23
ivatar/ivataraccount/migrations/0016_auto_20210413_0904.py
Normal file
23
ivatar/ivataraccount/migrations/0016_auto_20210413_0904.py
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# Generated by Django 3.1.7 on 2021-04-13 09:04
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('ivataraccount', '0015_auto_20200225_0934'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='unconfirmedemail',
|
||||||
|
name='last_send_date',
|
||||||
|
field=models.DateTimeField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='unconfirmedemail',
|
||||||
|
name='last_status',
|
||||||
|
field=models.TextField(blank=True, max_length=2047, null=True),
|
||||||
|
),
|
||||||
|
]
|
||||||
48
ivatar/ivataraccount/migrations/0017_auto_20210528_1314.py
Normal file
48
ivatar/ivataraccount/migrations/0017_auto_20210528_1314.py
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
# Generated by Django 3.2.3 on 2021-05-28 13:14
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('ivataraccount', '0016_auto_20210413_0904'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='confirmedemail',
|
||||||
|
name='id',
|
||||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='confirmedopenid',
|
||||||
|
name='id',
|
||||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='openidassociation',
|
||||||
|
name='id',
|
||||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='openidnonce',
|
||||||
|
name='id',
|
||||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='photo',
|
||||||
|
name='id',
|
||||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='unconfirmedemail',
|
||||||
|
name='id',
|
||||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='unconfirmedopenid',
|
||||||
|
name='id',
|
||||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -347,6 +347,8 @@ class UnconfirmedEmail(BaseAccountModel):
|
|||||||
'''
|
'''
|
||||||
email = models.EmailField(max_length=MAX_LENGTH_EMAIL)
|
email = models.EmailField(max_length=MAX_LENGTH_EMAIL)
|
||||||
verification_key = models.CharField(max_length=64)
|
verification_key = models.CharField(max_length=64)
|
||||||
|
last_send_date = models.DateTimeField(null=True, blank=True)
|
||||||
|
last_status = models.TextField(max_length=2047, null=True, blank=True)
|
||||||
|
|
||||||
class Meta: # pylint: disable=too-few-public-methods
|
class Meta: # pylint: disable=too-few-public-methods
|
||||||
'''
|
'''
|
||||||
@@ -357,11 +359,12 @@ class UnconfirmedEmail(BaseAccountModel):
|
|||||||
|
|
||||||
def save(self, force_insert=False, force_update=False, using=None,
|
def save(self, force_insert=False, force_update=False, using=None,
|
||||||
update_fields=None):
|
update_fields=None):
|
||||||
hash_object = hashlib.new('sha256')
|
if not self.verification_key:
|
||||||
hash_object.update(
|
hash_object = hashlib.new('sha256')
|
||||||
urandom(1024) + self.user.username.encode('utf-8') # pylint: disable=no-member
|
hash_object.update(
|
||||||
) # pylint: disable=no-member
|
urandom(1024) + self.user.username.encode('utf-8') # pylint: disable=no-member
|
||||||
self.verification_key = hash_object.hexdigest()
|
) # pylint: disable=no-member
|
||||||
|
self.verification_key = hash_object.hexdigest()
|
||||||
super(UnconfirmedEmail, self).save(
|
super(UnconfirmedEmail, self).save(
|
||||||
force_insert,
|
force_insert,
|
||||||
force_update,
|
force_update,
|
||||||
@@ -382,11 +385,17 @@ class UnconfirmedEmail(BaseAccountModel):
|
|||||||
'verification_link': link,
|
'verification_link': link,
|
||||||
'site_name': SITE_NAME,
|
'site_name': SITE_NAME,
|
||||||
})
|
})
|
||||||
|
self.last_send_date = timezone.now()
|
||||||
|
self.last_status = 'OK'
|
||||||
# if settings.DEBUG:
|
# if settings.DEBUG:
|
||||||
# print('DEBUG: %s' % link)
|
# print('DEBUG: %s' % link)
|
||||||
send_mail(
|
try:
|
||||||
email_subject, email_body, DEFAULT_FROM_EMAIL,
|
send_mail(
|
||||||
[self.email])
|
email_subject, email_body, DEFAULT_FROM_EMAIL,
|
||||||
|
[self.email])
|
||||||
|
except Exception as e:
|
||||||
|
self.last_status = "%s" % e
|
||||||
|
self.save()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
|||||||
@@ -998,7 +998,7 @@ class PasswordResetView(PasswordResetViewOriginal):
|
|||||||
# ResetPasswordView class will silently ignore the password
|
# ResetPasswordView class will silently ignore the password
|
||||||
# reset request
|
# reset request
|
||||||
if user:
|
if user:
|
||||||
if not user.password or user.password == '!':
|
if not user.password or user.password.startswith('!'):
|
||||||
random_pass = User.objects.make_random_password()
|
random_pass = User.objects.make_random_password()
|
||||||
user.set_password(random_pass)
|
user.set_password(random_pass)
|
||||||
user.save()
|
user.save()
|
||||||
|
|||||||
@@ -118,4 +118,6 @@ PROJECT_ROOT = os.path.abspath(
|
|||||||
STATIC_URL = '/static/'
|
STATIC_URL = '/static/'
|
||||||
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
|
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
|
||||||
|
|
||||||
|
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
||||||
|
|
||||||
from config import * # pylint: disable=wildcard-import,wrong-import-position,unused-wildcard-import
|
from config import * # pylint: disable=wildcard-import,wrong-import-position,unused-wildcard-import
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ from django.conf.urls import url
|
|||||||
from django.conf.urls.static import static
|
from django.conf.urls.static import static
|
||||||
from django.views.generic import TemplateView, RedirectView
|
from django.views.generic import TemplateView, RedirectView
|
||||||
from ivatar import settings
|
from ivatar import settings
|
||||||
from . views import AvatarImageView, GravatarProxyView
|
from . views import AvatarImageView, GravatarProxyView, StatsView
|
||||||
|
|
||||||
urlpatterns = [ # pylint: disable=invalid-name
|
urlpatterns = [ # pylint: disable=invalid-name
|
||||||
path('admin/', admin.site.urls),
|
path('admin/', admin.site.urls),
|
||||||
@@ -36,6 +36,7 @@ urlpatterns = [ # pylint: disable=invalid-name
|
|||||||
url('privacy/', TemplateView.as_view(template_name='privacy.html'), name='privacy'),
|
url('privacy/', TemplateView.as_view(template_name='privacy.html'), name='privacy'),
|
||||||
url('contact/', TemplateView.as_view(template_name='contact.html'), name='contact'),
|
url('contact/', TemplateView.as_view(template_name='contact.html'), name='contact'),
|
||||||
path('talk_to_us/', RedirectView.as_view(url='/contact'), name='talk_to_us'),
|
path('talk_to_us/', RedirectView.as_view(url='/contact'), name='talk_to_us'),
|
||||||
|
url('stats/', StatsView.as_view(), name='stats'),
|
||||||
]
|
]
|
||||||
|
|
||||||
MAINTENANCE = False
|
MAINTENANCE = False
|
||||||
|
|||||||
@@ -8,12 +8,14 @@ from urllib.request import urlopen
|
|||||||
from urllib.error import HTTPError, URLError
|
from urllib.error import HTTPError, URLError
|
||||||
from ssl import SSLError
|
from ssl import SSLError
|
||||||
from django.views.generic.base import TemplateView, View
|
from django.views.generic.base import TemplateView, View
|
||||||
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseNotFound
|
from django.http import HttpResponse, HttpResponseRedirect
|
||||||
|
from django.http import HttpResponseNotFound, JsonResponse
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
from django.core.cache import cache, caches
|
from django.core.cache import cache, caches
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.urls import reverse_lazy
|
from django.urls import reverse_lazy
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
@@ -23,7 +25,8 @@ from pydenticon5 import Pydenticon5
|
|||||||
import pagan
|
import pagan
|
||||||
from robohash import Robohash
|
from robohash import Robohash
|
||||||
|
|
||||||
from ivatar.settings import AVATAR_MAX_SIZE, JPEG_QUALITY, DEFAULT_AVATAR_SIZE, CACHE_RESPONSE
|
from ivatar.settings import AVATAR_MAX_SIZE, JPEG_QUALITY, DEFAULT_AVATAR_SIZE
|
||||||
|
from ivatar.settings import CACHE_RESPONSE
|
||||||
from ivatar.settings import CACHE_IMAGES_MAX_AGE
|
from ivatar.settings import CACHE_IMAGES_MAX_AGE
|
||||||
from . ivataraccount.models import ConfirmedEmail, ConfirmedOpenId
|
from . ivataraccount.models import ConfirmedEmail, ConfirmedOpenId
|
||||||
from . ivataraccount.models import pil_format, file_format
|
from . ivataraccount.models import pil_format, file_format
|
||||||
@@ -60,7 +63,8 @@ class CachingHttpResponse(HttpResponse):
|
|||||||
'''
|
'''
|
||||||
Handle caching of response
|
Handle caching of response
|
||||||
'''
|
'''
|
||||||
def __init__(self, uri, content=b'', content_type=None, status=200, reason=None, charset=None): # pylint: disable=too-many-arguments
|
def __init__(self, uri, content=b'', content_type=None, status=200, # pylint: disable=too-many-arguments
|
||||||
|
reason=None, charset=None):
|
||||||
if CACHE_RESPONSE:
|
if CACHE_RESPONSE:
|
||||||
caches['filesystem'].set(uri, {
|
caches['filesystem'].set(uri, {
|
||||||
'content': content,
|
'content': content,
|
||||||
@@ -394,3 +398,17 @@ class GravatarProxyView(View):
|
|||||||
|
|
||||||
# We shouldn't reach this point... But make sure we do something
|
# We shouldn't reach this point... But make sure we do something
|
||||||
return redir_default(default)
|
return redir_default(default)
|
||||||
|
|
||||||
|
|
||||||
|
class StatsView(TemplateView, JsonResponse):
|
||||||
|
'''
|
||||||
|
Return stats
|
||||||
|
'''
|
||||||
|
def get(self, request, *args, **kwargs): # pylint: disable=too-many-branches,too-many-statements,too-many-locals,no-self-use,unused-argument,too-many-return-statements
|
||||||
|
retval = {
|
||||||
|
'users': User.objects.all().count(),
|
||||||
|
'mails': ConfirmedEmail.objects.all().count(),
|
||||||
|
'openids': ConfirmedOpenId.objects.all().count(), # pylint: disable=no-member
|
||||||
|
}
|
||||||
|
|
||||||
|
return JsonResponse(retval)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
autopep8
|
autopep8
|
||||||
bcrypt
|
bcrypt
|
||||||
defusedxml
|
defusedxml
|
||||||
Django<3.2
|
Django
|
||||||
django-auth-ldap
|
django-auth-ldap
|
||||||
django-bootstrap4
|
django-bootstrap4
|
||||||
django-coverage-plugin
|
django-coverage-plugin
|
||||||
|
|||||||
@@ -14,9 +14,7 @@
|
|||||||
There are a few ways to get in touch with the ivatar/libravatar developers:
|
There are a few ways to get in touch with the ivatar/libravatar developers:
|
||||||
<h4 style="margin-top: 2rem;margin-bottom: 1rem;">IRC</h4>
|
<h4 style="margin-top: 2rem;margin-bottom: 1rem;">IRC</h4>
|
||||||
|
|
||||||
If you have an IRC client already, you can join #libravatar on chat.freenode.net.
|
You can join the Libravatar community chat at <a href="https://matrix.to/#/#libravatar:matrix.org?via=shivering-isles.com&via=matrix.org&via=foad.me.uk" title="Libravatar on Matrix">#libravatar:matrix.org</a>. It is also bridged to #libravatar on irc.<a href="https://libera.chat/">libera.chat</a> for those prefering IRC.
|
||||||
<br/>
|
|
||||||
Otherwise, you can use this <a href="http://webchat.freenode.net/?channels=libravatar" title="http://webchat.freenode.net/?channels=libravatar">simple web interface</a>.
|
|
||||||
<br/>
|
<br/>
|
||||||
Please keep in mind that you may live in a different timezone than most of the developers. So if you do not get a response, it's not because we're ignoring you, it's probably because we're sleeping :)
|
Please keep in mind that you may live in a different timezone than most of the developers. So if you do not get a response, it's not because we're ignoring you, it's probably because we're sleeping :)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user