|
@@ -1,16 +1,17 @@
|
|
-from datetime import timedelta
|
|
|
|
import re
|
|
import re
|
|
|
|
|
|
from django.conf import settings
|
|
from django.conf import settings
|
|
from django.db import models
|
|
from django.db import models
|
|
from django.utils import timezone
|
|
from django.utils import timezone
|
|
-from django.utils.translation import ugettext_lazy as _
|
|
|
|
|
|
+from django.utils.translation import ugettext_lazy as _, ungettext, pgettext
|
|
|
|
|
|
from misago.core import cachebuster
|
|
from misago.core import cachebuster
|
|
|
|
+from misago.core.utils import date_format
|
|
|
|
|
|
|
|
|
|
__all__ = [
|
|
__all__ = [
|
|
- 'BAN_USERNAME', 'BAN_EMAIL', 'BAN_IP', 'BANS_CHOICES', 'Ban', 'BanCache'
|
|
|
|
|
|
+ 'BAN_USERNAME', 'BAN_EMAIL', 'BAN_IP', 'BANS_CHOICES',
|
|
|
|
+ 'Ban', 'BanCache', 'format_expiration_date'
|
|
]
|
|
]
|
|
|
|
|
|
|
|
|
|
@@ -29,68 +30,89 @@ BANS_CHOICES = (
|
|
)
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
+def format_expiration_date(expiration_date):
|
|
|
|
+ if not expiration_date:
|
|
|
|
+ return _("Never")
|
|
|
|
+
|
|
|
|
+ now = timezone.now()
|
|
|
|
+ diff = (expiration_date - now).total_seconds()
|
|
|
|
+
|
|
|
|
+ if diff and diff < (3600 * 24):
|
|
|
|
+ format = pgettext("ban expiration hour minute",
|
|
|
|
+ "h:i a")
|
|
|
|
+ elif now.year == expiration_date.year:
|
|
|
|
+ format = pgettext("ban expiration hour minute day month",
|
|
|
|
+ "jS F, h:i a")
|
|
|
|
+ else:
|
|
|
|
+ format = pgettext("ban expiration hour minute day month year",
|
|
|
|
+ "jS F Y, h:i a")
|
|
|
|
+
|
|
|
|
+ return date_format(expiration_date, format)
|
|
|
|
+
|
|
|
|
+
|
|
class BansManager(models.Manager):
|
|
class BansManager(models.Manager):
|
|
- def is_ip_banned(self, ip):
|
|
|
|
- return self.check_ban(ip=ip)
|
|
|
|
|
|
+ def get_ip_ban(self, ip):
|
|
|
|
+ return self.get_ban(ip=ip)
|
|
|
|
|
|
- def is_username_banned(self, username):
|
|
|
|
- return self.check_ban(username=username)
|
|
|
|
|
|
+ def get_username_ban(self, username):
|
|
|
|
+ return self.get_ban(username=username)
|
|
|
|
|
|
- def is_email_banned(self, email):
|
|
|
|
- return self.check_ban(email=email)
|
|
|
|
|
|
+ def get_email_ban(self, email):
|
|
|
|
+ return self.get_ban(email=email)
|
|
|
|
|
|
def invalidate_cache(self):
|
|
def invalidate_cache(self):
|
|
cachebuster.invalidate(BAN_CACHEBUSTER)
|
|
cachebuster.invalidate(BAN_CACHEBUSTER)
|
|
|
|
|
|
- def find_ban(self, username=None, email=None, ip=None):
|
|
|
|
- tests = []
|
|
|
|
|
|
+ def get_ban(self, username=None, email=None, ip=None):
|
|
|
|
+ checks = []
|
|
|
|
|
|
if username:
|
|
if username:
|
|
username = username.lower()
|
|
username = username.lower()
|
|
- tests.append(BAN_USERNAME)
|
|
|
|
|
|
+ checks.append(BAN_USERNAME)
|
|
if email:
|
|
if email:
|
|
email = email.lower()
|
|
email = email.lower()
|
|
- tests.append(BAN_EMAIL)
|
|
|
|
|
|
+ checks.append(BAN_EMAIL)
|
|
if ip:
|
|
if ip:
|
|
- tests.append(BAN_IP)
|
|
|
|
|
|
+ checks.append(BAN_IP)
|
|
|
|
|
|
- queryset = self.filter(is_valid=True)
|
|
|
|
- if len(tests) == 1:
|
|
|
|
- queryset = queryset.filter(test=tests[0])
|
|
|
|
- elif tests:
|
|
|
|
- queryset = queryset.filter(test__in=tests)
|
|
|
|
|
|
+ queryset = self.filter(is_checked=True)
|
|
|
|
+ if len(checks) == 1:
|
|
|
|
+ queryset = queryset.filter(check_type=checks[0])
|
|
|
|
+ elif checks:
|
|
|
|
+ queryset = queryset.filter(check_type__in=checks)
|
|
|
|
|
|
for ban in queryset.order_by('-id').iterator():
|
|
for ban in queryset.order_by('-id').iterator():
|
|
- if (ban.test == BAN_USERNAME and username and
|
|
|
|
- ban.test_value(username)):
|
|
|
|
|
|
+ if (ban.check_type == BAN_USERNAME and username and
|
|
|
|
+ ban.check_value(username)):
|
|
return ban
|
|
return ban
|
|
- elif ban.test == BAN_EMAIL and email and ban.test_value(email):
|
|
|
|
|
|
+ elif (ban.check_type == BAN_EMAIL and email and
|
|
|
|
+ ban.check_value(email)):
|
|
return ban
|
|
return ban
|
|
- elif ban.test == BAN_IP and ip and ban.test_value(ip):
|
|
|
|
|
|
+ elif ban.check_type == BAN_IP and ip and ban.check_value(ip):
|
|
return ban
|
|
return ban
|
|
else:
|
|
else:
|
|
- raise Ban.DoesNotExist('no valid ban for values has been found')
|
|
|
|
|
|
+ raise Ban.DoesNotExist('specified values are not banned')
|
|
|
|
|
|
|
|
|
|
class Ban(models.Model):
|
|
class Ban(models.Model):
|
|
- test = models.PositiveIntegerField(default=BAN_USERNAME, db_index=True)
|
|
|
|
|
|
+ check_type = models.PositiveIntegerField(default=BAN_USERNAME, db_index=True)
|
|
banned_value = models.CharField(max_length=255, db_index=True)
|
|
banned_value = models.CharField(max_length=255, db_index=True)
|
|
user_message = models.TextField(null=True, blank=True)
|
|
user_message = models.TextField(null=True, blank=True)
|
|
staff_message = models.TextField(null=True, blank=True)
|
|
staff_message = models.TextField(null=True, blank=True)
|
|
- valid_until = models.DateField(null=True, blank=True, db_index=True)
|
|
|
|
- is_valid = models.BooleanField(default=True, db_index=True)
|
|
|
|
|
|
+ expires_on = models.DateTimeField(null=True, blank=True, db_index=True)
|
|
|
|
+ is_checked = models.BooleanField(default=True, db_index=True)
|
|
|
|
|
|
objects = BansManager()
|
|
objects = BansManager()
|
|
|
|
|
|
def save(self, *args, **kwargs):
|
|
def save(self, *args, **kwargs):
|
|
self.banned_value = self.banned_value.lower()
|
|
self.banned_value = self.banned_value.lower()
|
|
- self.is_valid = not self.is_expired
|
|
|
|
|
|
+ self.is_checked = not self.is_expired
|
|
|
|
|
|
return super(Ban, self).save(*args, **kwargs)
|
|
return super(Ban, self).save(*args, **kwargs)
|
|
|
|
|
|
@property
|
|
@property
|
|
- def test_name(self):
|
|
|
|
- return BANS_CHOICES[self.test][1]
|
|
|
|
|
|
+ def check_name(self):
|
|
|
|
+ return BANS_CHOICES[self.check_type][1]
|
|
|
|
|
|
@property
|
|
@property
|
|
def name(self):
|
|
def name(self):
|
|
@@ -98,12 +120,16 @@ class Ban(models.Model):
|
|
|
|
|
|
@property
|
|
@property
|
|
def is_expired(self):
|
|
def is_expired(self):
|
|
- if self.valid_until:
|
|
|
|
- return self.valid_until < timezone.now().date()
|
|
|
|
|
|
+ if self.expires_on:
|
|
|
|
+ return self.expires_on < timezone.now()
|
|
else:
|
|
else:
|
|
return False
|
|
return False
|
|
|
|
|
|
- def test_value(self, value):
|
|
|
|
|
|
+ @property
|
|
|
|
+ def formatted_expiration_date(self):
|
|
|
|
+ return format_expiration_date(self.expires_on)
|
|
|
|
+
|
|
|
|
+ def check_value(self, value):
|
|
if '*' in self.banned_value:
|
|
if '*' in self.banned_value:
|
|
regex = re.escape(self.banned_value).replace('\*', '(.*?)')
|
|
regex = re.escape(self.banned_value).replace('\*', '(.*?)')
|
|
return re.search('^%s$' % regex, value) is not None
|
|
return re.search('^%s$' % regex, value) is not None
|
|
@@ -111,7 +137,7 @@ class Ban(models.Model):
|
|
return self.banned_value == value
|
|
return self.banned_value == value
|
|
|
|
|
|
def lift(self):
|
|
def lift(self):
|
|
- self.valid_until = (timezone.now() - timedelta(days=1)).date()
|
|
|
|
|
|
+ self.expires_on = timezone.now()
|
|
|
|
|
|
|
|
|
|
class BanCache(models.Model):
|
|
class BanCache(models.Model):
|
|
@@ -122,7 +148,11 @@ class BanCache(models.Model):
|
|
bans_version = models.PositiveIntegerField(default=0)
|
|
bans_version = models.PositiveIntegerField(default=0)
|
|
user_message = models.TextField(null=True, blank=True)
|
|
user_message = models.TextField(null=True, blank=True)
|
|
staff_message = models.TextField(null=True, blank=True)
|
|
staff_message = models.TextField(null=True, blank=True)
|
|
- valid_until = models.DateField(null=True, blank=True)
|
|
|
|
|
|
+ expires_on = models.DateTimeField(null=True, blank=True)
|
|
|
|
+
|
|
|
|
+ @property
|
|
|
|
+ def formatted_expiration_date(self):
|
|
|
|
+ return format_expiration_date(self.expires_on)
|
|
|
|
|
|
@property
|
|
@property
|
|
def is_banned(self):
|
|
def is_banned(self):
|
|
@@ -132,7 +162,6 @@ class BanCache(models.Model):
|
|
def is_valid(self):
|
|
def is_valid(self):
|
|
version_is_valid = cachebuster.is_valid(BAN_CACHEBUSTER,
|
|
version_is_valid = cachebuster.is_valid(BAN_CACHEBUSTER,
|
|
self.bans_version)
|
|
self.bans_version)
|
|
- date_today = timezone.now().date()
|
|
|
|
- not_expired = not self.valid_until or self.valid_until > date_today
|
|
|
|
|
|
+ expired = self.expires_on and self.expires_on < timezone.now()
|
|
|
|
|
|
- return version_is_valid and not_expired
|
|
|
|
|
|
+ return version_is_valid and not expired
|