Merge branch 'devel' into gandi-sponsor

This commit is contained in:
Oliver Falk
2021-09-10 11:45:18 +02:00
12 changed files with 125 additions and 18 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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

View 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),
),
]

View 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'),
),
]

View File

@@ -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):

View File

@@ -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()

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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 :)