irongit

Enhanced time synchronization for drf views.

added raise_exception boolean to simplify some other cases

huncholanehuncholaneauthored
parent 47d6292commit 4c831fadd4d13f81733b35d9c7cbf472977d0b41Browse files

5 files changed, +45 -19

+6-3README.md
@@ -65,11 +65,12 @@ TimeCheck(request, ...) has the following arguments:
6565 - `continue` allows the view to continue processing data when the client does not provide a timestamp
6666 - **noupdate_code** `int` The response code for exceptions raised to indicate the view should stop processing
6767 - **dt_fmt** `str` The datetime format used to normalize timestamps. Useful when the client and server use mismatched time depths (defaults to config)
68+- **raise_exception** `bool` Raises and exception if the process should stop (defaults to config)
6869
6970 ### TimeCheck Methods
7071
71-- `check_get` Raises a `NoUpdate` exception when the client timestamp is newer than or equal to the server timestamp
72-- `raise_update` Raises a `NoUpdate` exception when the client timestamp is older than or equal to the server timestamp
72+- `check_get` Raises a `NoUpdate` exception when the client timestamp is newer than or equal to the server timestamp. Returns a True if the client should receive data.
73+- `check_update` Raises a `NoUpdate` exception when the client timestamp is older than or equal to the server timestamp. Returns a True if the update should continue.
7374
7475 ---
7576
@@ -77,7 +78,7 @@ TimeCheck(request, ...) has the following arguments:
7778
7879 TimeCheck is customizable through the django settings, env, and on a per usage basis.
7980
80-### Django Settings Dictionairy Defaults
81+### Django Settings Dictionairy (Defaults)
8182
8283 ```python
8384 TIMECHECK_CONF = {
@@ -87,6 +88,7 @@ TIMECHECK_CONF = {
8788 "instance_field": "lastUpdated",
8889 "missing_action": "noupdate",
8990 "noupdate_code": 418,
91+ "raise_exception": True,
9092 }
9193 ```
9294
@@ -102,6 +104,7 @@ Set via environment variables or in `settings.TIMECHECK_CONF`:
102104 | `TIMECHECK_NOUPDATE_CODE` | `418` | Error code raised when update is unnecessary (int) |
103105 | `TIMECHECK_MISSING_ACTION` | `noupdate` | Action if timestamp is missing (`continue`, `noupdate`) |
104106 | `TIMECHECK_DT_FMT` | `%Y-%m-%dT%H:%M:%S%z` | Timestamp parsing format (str) |
107+| RAISE_EXCEPTION | True | Raises exceptions by default (bool) |
105108
106109 ---
107110
+1-0timecheck/settings.py
@@ -24,5 +24,6 @@ conf = TimeCheckConf(
2424 "instance_field": getval(str, "instance_field", "lastUpdated"),
2525 "missing_action": getval(str, "missing_action", "noupdate"),
2626 "noupdate_code": getval(int, "noupdate_code", 418),
27+ "raise_exception": getval(bool, "raise_exception", True),
2728 }
2829 )
+4-0timecheck/tests.py
@@ -19,8 +19,12 @@ class TimeCheckTests(TestCase):
1919
2020 def test_get_client_is_newer(self):
2121 client_time = fmt_dt(self.later)
22+ conf["raise_exception"] = True
2223 response = self.client.get("/", HTTP_LASTUPDATED=client_time)
2324 self.assertEqual(response.status_code, conf["noupdate_code"])
25+ conf["raise_exception"] = False
26+ response = self.client.get("/", HTTP_LASTUPDATED=client_time)
27+ self.assertEqual(response.status_code, 200)
2428
2529 def test_get_client_is_older(self):
2630 client_time = fmt_dt(self.earlier)
+32-16timecheck/timecheck.py
@@ -30,20 +30,23 @@ class TimeCheckPrivate:
3030 instance: models.Model | None = None,
3131 server_timestamp: dt.datetime | None = None,
3232 client_timestamp: dt.datetime | None = None,
33- header_field=conf["header_field"],
34- body_field=conf["body_field"],
35- instance_field=conf["instance_field"],
36- missing_action: MissingAction = conf["missing_action"],
37- noupdate_code=conf["noupdate_code"],
38- dt_fmt=conf["dt_fmt"],
33+ header_field: str | None = None,
34+ body_field: str | None = None,
35+ instance_field: str | None = None,
36+ missing_action: MissingAction | None = None,
37+ noupdate_code: int | None = None,
38+ dt_fmt: str | None = None,
39+ raise_exception: bool | None = None,
3940 ):
4041 self.request = request
41- self._header_field = header_field
42- self._body_field = body_field
43- self._instance_field = instance_field
44- self._noupdate_code = noupdate_code
45- self._missing_action = missing_action
46- self._dt_fmt = dt_fmt
42+ self._header_field = header_field or conf["header_field"]
43+ self._body_field = body_field or conf["body_field"]
44+ self._instance_field = instance_field or conf["instance_field"]
45+ self._noupdate_code = noupdate_code or conf["noupdate_code"]
46+ self._missing_action = missing_action or conf["missing_action"]
47+ self._dt_fmt = dt_fmt or conf["dt_fmt"]
48+ self._raise_exception = raise_exception or conf["raise_exception"]
49+ logger.debug(f"raise_exception={raise_exception}, {conf['raise_exception']}")
4750 self.client_timestamp = client_timestamp
4851
4952 if server_timestamp:
@@ -79,9 +82,16 @@ class TimeCheckPrivate:
7982 )
8083 if not self.client_timestamp:
8184 if self._missing_action == "noupdate":
82- raise NoUpdate(self.request.method, self._noupdate_code)
85+ if self._raise_exception:
86+ raise NoUpdate(self.request.method, self._noupdate_code)
87+ else:
88+ return False
8389 elif self.client_timestamp >= self.server_timestamp:
84- raise NoUpdate(self.request.method, self._noupdate_code)
90+ if self._raise_exception:
91+ raise NoUpdate(self.request.method, self._noupdate_code)
92+ else:
93+ return False
94+ return True
8595
8696 def check_update(self):
8797 """Raises a drf exception `NoUpdate` which provides details that there is no need to update the server."""
@@ -90,6 +100,12 @@ class TimeCheckPrivate:
90100 )
91101 if not self.client_timestamp:
92102 if self._missing_action == "noupdate":
93- raise NoUpdate(self.request.method, self._noupdate_code)
103+ if self._raise_exception:
104+ raise NoUpdate(self.request.method, self._noupdate_code)
105+ else:
106+ return False
94107 elif self.client_timestamp <= self.server_timestamp:
95- raise NoUpdate(self.request.method, self._noupdate_code)
108+ if self._raise_exception:
109+ raise NoUpdate(self.request.method, self._noupdate_code)
110+ else:
111+ return False
+2-0timecheck/types.py
@@ -18,3 +18,5 @@ class TimeCheckConf(TypedDict):
1818 """What do do when the client does not provide a timestamp"""
1919 dt_fmt: str
2020 """Format used to normalize datetimes."""
21+ raise_exception: bool
22+ """Raise an exception or just store the should update value"""