#!/usr/bin/env perl use strict; use v5.10; # ====================[ autolock.pl ]==================== =head1 NAME autolock - An Oddmuse module for locking pages via regular expression matching on page names. =head1 SYNOPSIS autolock automatically locks pages whose page name matches some regular expression from edits, creation, and deletion by non-privileged visitors (but not by password-verified editors or administrators). autolock thus "augments" the built-in, manual method for locking existing pages against page edits and page deletions, by providing an automated alternative; and provides a new method - which has no built-in, manual analogue - for locking against page creations. =head1 INSTALLATION autolock is easily installable: move this file into the B directory of your Oddmuse Wiki. =cut AddModuleDescription('autolock.pl', 'Autolock Extension'); our (@MyInitVariables, $CommentsPrefix, $EditAllowed, $NoEditFile, %LockOnCreation); # ....................{ CONFIGURATION }.................... =head1 CONFIGURATION autolock is easily configurable: set these variables in the B file for your Oddmuse Wiki. =cut our ($AutoLockPagesMatching, $AutoLockCommentsPagesMatching, $AutoLockSeverity, $AutoLockUserCanEditEditorFix); =head2 $AutoLockPagesMatching A regular expression matching page names to be automatically locked against page edits, creations, and deletions; e.g., this regular expression prevents page edits, creations, and deletions for page names resembling "Red Apple Falls--1997-02-16": $AutoLockPagesMatching = '^Red_Apple_Falls--\d\d\d\d-\d\d-\d\d'; This regular expression is left undefined, by default. (Thus, this module does nothing, by default.) When redefined, this regular expression: =over =item ...should not be a quoted regular expression (i.e., "qr/.../"); and =item ...should not be prefixed with the contents of the C<$CommentsPrefix> regular expression. (This module does that for you, as need be.) =back That aside, the limitless sky is yours. =cut $AutoLockPagesMatching = undef; =head2 $AutoLockSeverity A quadstate boolean specifying "how much" automatic locking to apply to pages whose names match the regular expression, above. This boolean, being "quadstate," may take any of four values, mirroring the C<$EditAllowed> site- wide setting as follows (where "visitors" are users who are neither password- verified administrators or password-verified editors): =over =item 0. B Do not allow visitors to edit, create, or delete any autolock-matched pages or page comments. =item 1. B Permissively allow visitors to edit, create, or delete any autolock-matched pages or page comments, so long as the C function also allows that. (This disables autolock, effectively.) =item 2. B Do not allow visitors to edit, create, or delete any autolock-matched pages but do allow visitors to edit, create, or delete autolock-matched page comments. (This is the default.) =item 3. B Do not allow visitors to edit, create, or delete any autolock-matched pages or edit or delete autolock-matched page comments, but do allow visitors to create new page comments. =back =cut $AutoLockSeverity = 2; =head2 $AutoLockUserCanEditEditorFix A boolean that, if true, prompts this module to overwrite the C Oddmuse function with a "fix" to Oddmuse's page-locking logic. By default, the Oddmuse script (v1.865, as of this writing) allows administrators but not editors to edit locked pages; however, this contravenes explicit Oddmuse documentation to the contrary. "If you have the admin or the edit password, you may edit locked pages." http://www.oddmuse.org/cgi-bin/oddmuse/Page_Locking This minor "fix" amends that, by allowing both administrators and editors to edit locked pages. By default, this boolean is true; and therefore implements this fix. =cut $AutoLockUserCanEditEditorFix = 1; # ....................{ INITIALIZATION }.................... push(@MyInitVariables, \&AutoLockInit); sub AutoLockInit { # Set "$AutoLockCommentsPagesMatching", if not already set (and relevant). if ( defined($AutoLockPagesMatching) && !defined($AutoLockCommentsPagesMatching) && $CommentsPrefix) { if ($AutoLockPagesMatching =~ m/^\^/) { $AutoLockCommentsPagesMatching = $AutoLockPagesMatching; $AutoLockCommentsPagesMatching =~ s/^\^/^${CommentsPrefix}/; } else { $AutoLockCommentsPagesMatching = "^${CommentsPrefix}.*${AutoLockPagesMatching}"; } } if ($AutoLockUserCanEditEditorFix) { *UserCanEditAutoLockOld = \&UserCanEditAutoLockFix; } } # ....................{ REDEFINITIONS }.................... *UserCanEditAutoLockOld = \&UserCanEdit; *UserCanEdit = \&UserCanEditAutoLock; sub UserCanEditAutoLock { my ($page_name, $is_editing, $is_comment) = @_; my $user_can_edit = UserCanEditAutoLockOld(@_); if ($user_can_edit && $AutoLockSeverity != 1 && !(UserIsAdmin() || UserIsEditor())) { my $is_page_locked = defined($AutoLockPagesMatching) && $page_name =~ m/$AutoLockPagesMatching/; my $is_comments_page_locked = defined($AutoLockCommentsPagesMatching) && $page_name =~ m/$AutoLockCommentsPagesMatching/; if ( ($AutoLockSeverity == 0 && ($is_page_locked || $is_comments_page_locked)) || ($AutoLockSeverity == 2 && $is_page_locked && ! $is_comments_page_locked) || ($AutoLockSeverity == 3 && $is_page_locked && !($is_comments_page_locked && ($is_comment || (GetParam('aftertext', '') && !GetParam('text', '')))))) { return 0; } } return $user_can_edit; } sub UserCanEditAutoLockFix { my ($id, $editing, $comment) = @_; return 0 if $id eq 'SampleUndefinedPage' or $id eq T('SampleUndefinedPage') or $id eq 'Sample_Undefined_Page' or $id eq T('Sample_Undefined_Page'); return 1 if UserIsAdmin() || UserIsEditor(); return 0 if $id ne '' and IsFile(GetLockedPageFile($id)); return 0 if $LockOnCreation{$id} and not IsFile(GetPageFile($id)); # new page return 0 if !$EditAllowed or IsFile($NoEditFile); return 0 if $editing and UserIsBanned(); # this call is more expensive return 0 if $EditAllowed >= 2 and (not $CommentsPrefix or $id !~ /^$CommentsPrefix/); return 1 if $EditAllowed >= 3 and ($comment or (GetParam('aftertext', '') and not GetParam('text', ''))); return 0 if $EditAllowed >= 3; return 1; } =head1 MOTIVATION Oddmuse does provide a built-in, manual method for locking existing pages against page edits and page deletions: for each such page, manually browse to the "Administration" page and then "Lock ${PAGE_NAME}" page for that page. (This is, needless to say, a clumsy means of bulk-locking some series of similarly named pages.) Oddmuse does not, however, provide a built-in method for preventatively locking against page creations. Ergo, autolock. =head1 SEE ALSO Jorge Arroyo's B module, from which this module was (marginally) inspired and which this module (largely) replaces. =head1 COPYRIGHT AND LICENSE The information below applies to everything in this distribution, except where noted. Copyleft 2008 by B.w.Curry . This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . =cut