diff --git a/INSTALL.md b/INSTALL.md index 3a99f4d..820b4a1 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -100,6 +100,15 @@ user@host:szuru/server$ source python_modules/bin/activate # enters the sandbox `alembic` should have been installed during installation of `szurubooru`'s dependencies. +4. Run the tests: + + ```console + (python_modules) user@host:szuru/server$ green + ``` + + `green` should have been installed during installation of `szurubooru`'s + dependencies. + It is recommended to rebuild the frontend after each change to configuration. diff --git a/server/requirements.txt b/server/requirements.txt index 0122fa6..614cf9c 100644 --- a/server/requirements.txt +++ b/server/requirements.txt @@ -3,3 +3,4 @@ configobj>=5.0.6 falcon>=0.3.0 psycopg2>=2.6.1 SQLAlchemy>=1.0.12 +green>=2.4.0 diff --git a/server/szurubooru/util.py b/server/szurubooru/util.py index 929957d..90677d2 100644 --- a/server/szurubooru/util.py +++ b/server/szurubooru/util.py @@ -1,4 +1,8 @@ -''' Exports dotdict. ''' +''' Exports miscellaneous functions and data structures. ''' + +import datetime +import re +from szurubooru.errors import ValidationError class dotdict(dict): # pylint: disable=invalid-name '''dot.notation access to dictionary attributes''' @@ -6,3 +10,52 @@ class dotdict(dict): # pylint: disable=invalid-name return self.get(attr) __setattr__ = dict.__setitem__ __delattr__ = dict.__delitem__ + +def parse_time_range(value, timezone=datetime.timezone(datetime.timedelta())): + ''' Returns tuple containing min/max time for given text representation. ''' + one_day = datetime.timedelta(days=1) + one_second = datetime.timedelta(seconds=1) + + value = value.lower() + if not value: + raise ValidationError('Empty date format.') + + if value == 'today': + now = datetime.datetime.now(tz=timezone) + return ( + datetime.datetime(now.year, now.month, now.day, 0, 0, 0), + datetime.datetime(now.year, now.month, now.day, 0, 0, 0) + + one_day - one_second) + + if value == 'yesterday': + now = datetime.datetime.now(tz=timezone) + return ( + datetime.datetime(now.year, now.month, now.day, 0, 0, 0) - one_day, + datetime.datetime(now.year, now.month, now.day, 0, 0, 0) + - one_second) + + match = re.match('^(\d{4})$', value) + if match: + year = int(match.group(1)) + return ( + datetime.datetime(year, 1, 1), + datetime.datetime(year + 1, 1, 1) - one_second) + + match = re.match('^(\d{4})-(\d{1,2})$', value) + if match: + year = int(match.group(1)) + month = int(match.group(2)) + return ( + datetime.datetime(year, month, 1), + datetime.datetime(year, month + 1, 1) - one_second) + + match = re.match('^(\d{4})-(\d{1,2})-(\d{1,2})$', value) + if match: + year = int(match.group(1)) + month = int(match.group(2)) + day = int(match.group(3)) + return ( + datetime.datetime(year, month, day), + datetime.datetime(year, month, day + 1) - one_second) + + raise ValidationError('Invalid date format: %r.' % value) diff --git a/server/tests/test_util.py b/server/tests/test_util.py new file mode 100644 index 0000000..bfa5218 --- /dev/null +++ b/server/tests/test_util.py @@ -0,0 +1,42 @@ +import unittest +from datetime import datetime +import szurubooru.util +from szurubooru.util import parse_time_range +from szurubooru.errors import ValidationError + +class FakeDatetime(datetime): + def now(tz=None): + return datetime(1997, 1, 2, 3, 4, 5, tzinfo=tz) + +class TestParseTime(unittest.TestCase): + def test_empty(self): + self.assertRaises(ValidationError, parse_time_range, '') + + def test_today(self): + szurubooru.util.datetime.datetime = FakeDatetime + date_min, date_max = parse_time_range('today') + self.assertEquals(date_min, datetime(1997, 1, 2, 0, 0, 0)) + self.assertEquals(date_max, datetime(1997, 1, 2, 23, 59, 59)) + + def test_yesterday(self): + szurubooru.util.datetime.datetime = FakeDatetime + date_min, date_max = parse_time_range('yesterday') + self.assertEquals(date_min, datetime(1997, 1, 1, 0, 0, 0)) + self.assertEquals(date_max, datetime(1997, 1, 1, 23, 59, 59)) + + def test_year(self): + date_min, date_max = parse_time_range('1999') + self.assertEquals(date_min, datetime(1999, 1, 1, 0, 0, 0)) + self.assertEquals(date_max, datetime(1999, 12, 31, 23, 59, 59)) + + def test_month(self): + for text in ['1999-2', '1999-02']: + date_min, date_max = parse_time_range(text) + self.assertEquals(date_min, datetime(1999, 2, 1, 0, 0, 0)) + self.assertEquals(date_max, datetime(1999, 2, 28, 23, 59, 59)) + + def test_day(self): + for text in ['1999-2-6', '1999-02-6', '1999-2-06', '1999-02-06']: + date_min, date_max = parse_time_range(text) + self.assertEquals(date_min, datetime(1999, 2, 6, 0, 0, 0)) + self.assertEquals(date_max, datetime(1999, 2, 6, 23, 59, 59))