paul@0 | 1 | # -*- coding: iso-8859-1 -*- |
paul@0 | 2 | """ |
paul@0 | 3 | MoinMoin - Check the speed of page editing |
paul@0 | 4 | |
paul@0 | 5 | Check to see how quickly the user wanted to edit a page after previous |
paul@0 | 6 | actions. Prevent them from saving a page if they were too fast. |
paul@0 | 7 | |
paul@0 | 8 | @copyright: 2016 Paul Boddie <paul@boddie.org.uk> |
paul@0 | 9 | @license: GNU GPL, see COPYING for details. |
paul@0 | 10 | """ |
paul@0 | 11 | |
paul@0 | 12 | from MoinMoin.events import PagePreSaveEvent, Abort |
paul@0 | 13 | from MoinMoin.logfile.eventlog import EventLog |
paul@0 | 14 | from MoinMoin import wikiutil |
paul@0 | 15 | import time |
paul@0 | 16 | |
paul@0 | 17 | # The default editing delay where no configuration setting has been provided. |
paul@0 | 18 | # Value expressed in seconds. |
paul@0 | 19 | |
paul@0 | 20 | editing_delay_default = "10" |
paul@0 | 21 | |
paul@0 | 22 | # Event handling. |
paul@0 | 23 | |
paul@0 | 24 | def handle_presave(event): |
paul@0 | 25 | request = event.request |
paul@0 | 26 | _ = request.getText |
paul@0 | 27 | |
paul@0 | 28 | # Obtain user details. If no user is identified, nothing can be done. |
paul@0 | 29 | |
paul@0 | 30 | username = request.user.name |
paul@0 | 31 | if not username: |
paul@0 | 32 | return None |
paul@0 | 33 | |
paul@0 | 34 | # Obtain the required delay between viewing and editing. This is expressed |
paul@0 | 35 | # in seconds. |
paul@0 | 36 | |
paul@0 | 37 | delay = float(getattr(request.cfg, "editing_delay", editing_delay_default)) |
paul@0 | 38 | |
paul@0 | 39 | # Obtain the current time. |
paul@0 | 40 | |
paul@0 | 41 | time_now = time.time() |
paul@0 | 42 | |
paul@0 | 43 | # Check in the log for the last action by the user. This requires the |
paul@0 | 44 | # recording of the username in the log. |
paul@0 | 45 | |
paul@0 | 46 | log = EventLog(request) |
paul@0 | 47 | log.set_filter(["VIEWPAGE", "SAVEPAGE", "SAVENEW"]) |
paul@0 | 48 | |
paul@0 | 49 | pagename = event.page_editor.page_name |
paul@0 | 50 | last_viewed = None |
paul@0 | 51 | last_saved = None |
paul@0 | 52 | |
paul@0 | 53 | for event in log.reverse(): |
paul@0 | 54 | event_usecs, event_type, event_attr = event[:3] |
paul@0 | 55 | |
paul@0 | 56 | # Convert to seconds and determine if the start of the delay period has |
paul@0 | 57 | # been reached. |
paul@0 | 58 | |
paul@0 | 59 | event_secs = wikiutil.version2timestamp(event_usecs) |
paul@0 | 60 | if time_now - event_secs >= delay: |
paul@0 | 61 | break |
paul@0 | 62 | |
paul@0 | 63 | event_page = event_attr.get("pagename") |
paul@0 | 64 | event_user = event_attr.get("username") |
paul@0 | 65 | |
paul@0 | 66 | # Stop when encountering the latest event entry for this page and user. |
paul@0 | 67 | |
paul@0 | 68 | if event_page == pagename and event_user == username: |
paul@0 | 69 | if event_type == "VIEWPAGE": |
paul@0 | 70 | last_viewed = event_secs |
paul@0 | 71 | else: |
paul@0 | 72 | last_saved = event_secs |
paul@0 | 73 | break |
paul@0 | 74 | |
paul@0 | 75 | # Any attempt to save occurring too soon after VIEWPAGE is possibly an |
paul@0 | 76 | # automated edit. |
paul@0 | 77 | |
paul@0 | 78 | if last_viewed: |
paul@0 | 79 | return Abort(_("Page not changed: the page was saved too quickly after viewing.")) |
paul@0 | 80 | |
paul@0 | 81 | # Any attempt to save without any previous VIEWPAGE, but after a SAVENEW or |
paul@0 | 82 | # SAVEPAGE may also be an automated edit. |
paul@0 | 83 | |
paul@0 | 84 | elif last_saved: |
paul@0 | 85 | return Abort(_("Page not changed: the page was saved again too soon or saved without viewing the page.")) |
paul@0 | 86 | |
paul@0 | 87 | return None |
paul@0 | 88 | |
paul@0 | 89 | def handle(event): |
paul@0 | 90 | if isinstance(event, PagePreSaveEvent): |
paul@0 | 91 | return handle_presave(event) |
paul@0 | 92 | |
paul@0 | 93 | # vim: tabstop=4 expandtab shiftwidth=4 |