If we delete project by naively calling project.delete() then checks
can receive pings during the deletion, causing the deletion operation
to fail with an IntegrityError.
So instead do it like so:
* iterate over project's checks, call Check.lock_and_delete() on each
* in the end, call project.delete()
* Instead of check.n_pings (int) use last_ping().n
* Instead of check.last_ping (datetime) use last_ping().created
There is a time gap from creating a flip object to processing
it (sending out an alert). We want the notification to reflect
the check's state at the moment the flip was created. To do this,
we use the Transport.last_ping() helper method which retrieves
the last ping *that is not newer than the flip*.
This commit updates transport classes and templates to use
Transport.last_ping() consistently everywhere.
... and pass it to Transport.notify_flip().
This allows us to pass flip-specific information (the flip timestamp,
the new status) to transport classes.
I'm planning to change Channel.notify() signature to take a Flip
object as an argument instead of a Check object. This change is
in preparation for these changes.
If timestamps are equal, put flips chronologically after pings.
We are showing events in reverse chronological order (newer
events at the top), so the flips will now display
*above* the pings that caused them.
The live-updating code still needs float timestamps, but
we only need them for the most recent event (so we know
the lower threshold for fetching new events). We now send
the float timestamp separately:
* in the `/log/` view, we put it in HTML content, in a <script> tag
* in the `/log_events/` view we put it in response header
The main benefit of this is smaller response sizes for the
`/log/` and `/log_events/` views.