diff --git a/ivatar/ivataraccount/migrations/0016_auto_20210413_0904.py b/ivatar/ivataraccount/migrations/0016_auto_20210413_0904.py new file mode 100644 index 0000000..d1cc066 --- /dev/null +++ b/ivatar/ivataraccount/migrations/0016_auto_20210413_0904.py @@ -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), + ), + ] diff --git a/ivatar/ivataraccount/models.py b/ivatar/ivataraccount/models.py index bc51d64..3f73fb1 100644 --- a/ivatar/ivataraccount/models.py +++ b/ivatar/ivataraccount/models.py @@ -347,6 +347,8 @@ class UnconfirmedEmail(BaseAccountModel): ''' email = models.EmailField(max_length=MAX_LENGTH_EMAIL) 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 ''' @@ -382,11 +384,17 @@ class UnconfirmedEmail(BaseAccountModel): 'verification_link': link, 'site_name': SITE_NAME, }) + self.last_send_date = timezone.now() + self.last_status = 'OK' # if settings.DEBUG: # print('DEBUG: %s' % link) - send_mail( - email_subject, email_body, DEFAULT_FROM_EMAIL, - [self.email]) + try: + send_mail( + email_subject, email_body, DEFAULT_FROM_EMAIL, + [self.email]) + except Exception as e: + self.last_status = "%s" % e + self.save() return True def __str__(self): diff --git a/ivatar/ivataraccount/views.py b/ivatar/ivataraccount/views.py index 4b4ecb3..2035816 100644 --- a/ivatar/ivataraccount/views.py +++ b/ivatar/ivataraccount/views.py @@ -1000,7 +1000,7 @@ class PasswordResetView(PasswordResetViewOriginal): # ResetPasswordView class will silently ignore the password # reset request if user: - if not user.password or user.password == '!': + if not user.password or user.password.startswith('!'): random_pass = User.objects.make_random_password() user.set_password(random_pass) user.save() diff --git a/ivatar/urls.py b/ivatar/urls.py index df3b450..96b4d22 100644 --- a/ivatar/urls.py +++ b/ivatar/urls.py @@ -7,7 +7,7 @@ from django.conf.urls import url from django.conf.urls.static import static from django.views.generic import TemplateView, RedirectView from ivatar import settings -from . views import AvatarImageView, GravatarProxyView +from . views import AvatarImageView, GravatarProxyView, StatsView urlpatterns = [ # pylint: disable=invalid-name 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('contact/', TemplateView.as_view(template_name='contact.html'), name='contact'), path('talk_to_us/', RedirectView.as_view(url='/contact'), name='talk_to_us'), + url('stats/', StatsView.as_view(), name='stats'), ] MAINTENANCE = False diff --git a/ivatar/views.py b/ivatar/views.py index fb79958..d3de012 100644 --- a/ivatar/views.py +++ b/ivatar/views.py @@ -8,12 +8,14 @@ from urllib.request import urlopen from urllib.error import HTTPError, URLError from ssl import SSLError 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.cache import cache, caches from django.utils.translation import ugettext_lazy as _ from django.urls import reverse_lazy from django.db.models import Q +from django.contrib.auth.models import User from PIL import Image @@ -23,7 +25,8 @@ from pydenticon5 import Pydenticon5 import pagan 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 . ivataraccount.models import ConfirmedEmail, ConfirmedOpenId from . ivataraccount.models import pil_format, file_format @@ -60,7 +63,8 @@ class CachingHttpResponse(HttpResponse): ''' 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: caches['filesystem'].set(uri, { 'content': content, @@ -394,3 +398,20 @@ class GravatarProxyView(View): # We shouldn't reach this point... But make sure we do something 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 + } + + if request.content_type == 'application/json': + return JsonResponse(retval) + + return HttpResponseRedirect(reverse_lazy('home'))