autolock.pl 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. #!/usr/bin/env perl
  2. use strict;
  3. use v5.10;
  4. # ====================[ autolock.pl ]====================
  5. =head1 NAME
  6. autolock - An Oddmuse module for locking pages via regular expression matching
  7. on page names.
  8. =head1 SYNOPSIS
  9. autolock automatically locks pages whose page name matches some regular
  10. expression from edits, creation, and deletion by non-privileged visitors (but
  11. not by password-verified editors or administrators).
  12. autolock thus "augments" the built-in, manual method for locking existing pages
  13. against page edits and page deletions, by providing an automated alternative;
  14. and provides a new method - which has no built-in, manual analogue - for locking
  15. against page creations.
  16. =head1 INSTALLATION
  17. autolock is easily installable: move this file into the B<wiki/modules/>
  18. directory of your Oddmuse Wiki.
  19. =cut
  20. AddModuleDescription('autolock.pl', 'Autolock Extension');
  21. our (@MyInitVariables, $CommentsPrefix, $EditAllowed, $NoEditFile, %LockOnCreation);
  22. # ....................{ CONFIGURATION }....................
  23. =head1 CONFIGURATION
  24. autolock is easily configurable: set these variables in the B<wiki/config.pl>
  25. file for your Oddmuse Wiki.
  26. =cut
  27. our ($AutoLockPagesMatching,
  28. $AutoLockCommentsPagesMatching,
  29. $AutoLockSeverity,
  30. $AutoLockUserCanEditEditorFix);
  31. =head2 $AutoLockPagesMatching
  32. A regular expression matching page names to be automatically locked against
  33. page edits, creations, and deletions; e.g., this regular expression prevents
  34. page edits, creations, and deletions for page names resembling
  35. "Red Apple Falls--1997-02-16":
  36. $AutoLockPagesMatching = '^Red_Apple_Falls--\d\d\d\d-\d\d-\d\d';
  37. This regular expression is left undefined, by default. (Thus, this module does
  38. nothing, by default.) When redefined, this regular expression:
  39. =over
  40. =item ...should not be a quoted regular expression (i.e., "qr/.../"); and
  41. =item ...should not be prefixed with the contents of the C<$CommentsPrefix>
  42. regular expression. (This module does that for you, as need be.)
  43. =back
  44. That aside, the limitless sky is yours.
  45. =cut
  46. $AutoLockPagesMatching = undef;
  47. =head2 $AutoLockSeverity
  48. A quadstate boolean specifying "how much" automatic locking to apply to pages
  49. whose names match the regular expression, above. This boolean, being
  50. "quadstate," may take any of four values, mirroring the C<$EditAllowed> site-
  51. wide setting as follows (where "visitors" are users who are neither password-
  52. verified administrators or password-verified editors):
  53. =over
  54. =item 0. B<Highest severity.> Do not allow visitors to edit, create, or delete any
  55. autolock-matched pages or page comments.
  56. =item 1. B<No severity.> Permissively allow visitors to edit, create, or delete any
  57. autolock-matched pages or page comments, so long as the C<UserCanEdit>
  58. function also allows that. (This disables autolock, effectively.)
  59. =item 2. B<Low severity.> Do not allow visitors to edit, create, or delete any
  60. autolock-matched pages but do allow visitors to edit, create, or delete
  61. autolock-matched page comments. (This is the default.)
  62. =item 3. B<Medium severity.> Do not allow visitors to edit, create, or delete any
  63. autolock-matched pages or edit or delete autolock-matched page comments,
  64. but do allow visitors to create new page comments.
  65. =back
  66. =cut
  67. $AutoLockSeverity = 2;
  68. =head2 $AutoLockUserCanEditEditorFix
  69. A boolean that, if true, prompts this module to overwrite the C<UserCanEdit>
  70. Oddmuse function with a "fix" to Oddmuse's page-locking logic. By default, the
  71. Oddmuse script (v1.865, as of this writing) allows administrators but not
  72. editors to edit locked pages; however, this contravenes explicit Oddmuse
  73. documentation to the contrary.
  74. "If you have the admin or the edit password, you may edit locked pages."
  75. http://www.oddmuse.org/cgi-bin/oddmuse/Page_Locking
  76. This minor "fix" amends that, by allowing both administrators and editors to
  77. edit locked pages.
  78. By default, this boolean is true; and therefore implements this fix.
  79. =cut
  80. $AutoLockUserCanEditEditorFix = 1;
  81. # ....................{ INITIALIZATION }....................
  82. push(@MyInitVariables, \&AutoLockInit);
  83. sub AutoLockInit {
  84. # Set "$AutoLockCommentsPagesMatching", if not already set (and relevant).
  85. if ( defined($AutoLockPagesMatching) &&
  86. !defined($AutoLockCommentsPagesMatching) && $CommentsPrefix) {
  87. if ($AutoLockPagesMatching =~ m/^\^/) {
  88. $AutoLockCommentsPagesMatching = $AutoLockPagesMatching;
  89. $AutoLockCommentsPagesMatching =~ s/^\^/^${CommentsPrefix}/;
  90. }
  91. else {
  92. $AutoLockCommentsPagesMatching =
  93. "^${CommentsPrefix}.*${AutoLockPagesMatching}";
  94. }
  95. }
  96. if ($AutoLockUserCanEditEditorFix) {
  97. *UserCanEditAutoLockOld = \&UserCanEditAutoLockFix;
  98. }
  99. }
  100. # ....................{ REDEFINITIONS }....................
  101. *UserCanEditAutoLockOld = \&UserCanEdit;
  102. *UserCanEdit = \&UserCanEditAutoLock;
  103. sub UserCanEditAutoLock {
  104. my ($page_name, $is_editing, $is_comment) = @_;
  105. my $user_can_edit = UserCanEditAutoLockOld(@_);
  106. if ($user_can_edit && $AutoLockSeverity != 1 && !(UserIsAdmin() || UserIsEditor())) {
  107. my $is_page_locked = defined($AutoLockPagesMatching) &&
  108. $page_name =~ m/$AutoLockPagesMatching/;
  109. my $is_comments_page_locked = defined($AutoLockCommentsPagesMatching) &&
  110. $page_name =~ m/$AutoLockCommentsPagesMatching/;
  111. if (
  112. ($AutoLockSeverity == 0 && ($is_page_locked || $is_comments_page_locked)) ||
  113. ($AutoLockSeverity == 2 && $is_page_locked && ! $is_comments_page_locked) ||
  114. ($AutoLockSeverity == 3 && $is_page_locked && !($is_comments_page_locked &&
  115. ($is_comment || (GetParam('aftertext', '') && !GetParam('text', '')))))) {
  116. return 0;
  117. }
  118. }
  119. return $user_can_edit;
  120. }
  121. sub UserCanEditAutoLockFix {
  122. my ($id, $editing, $comment) = @_;
  123. return 0 if $id eq 'SampleUndefinedPage' or $id eq T('SampleUndefinedPage')
  124. or $id eq 'Sample_Undefined_Page' or $id eq T('Sample_Undefined_Page');
  125. return 1 if UserIsAdmin() || UserIsEditor();
  126. return 0 if $id ne '' and IsFile(GetLockedPageFile($id));
  127. return 0 if $LockOnCreation{$id} and not IsFile(GetPageFile($id)); # new page
  128. return 0 if !$EditAllowed or IsFile($NoEditFile);
  129. return 0 if $editing and UserIsBanned(); # this call is more expensive
  130. return 0 if $EditAllowed >= 2 and (not $CommentsPrefix or $id !~ /^$CommentsPrefix/);
  131. return 1 if $EditAllowed >= 3 and ($comment or (GetParam('aftertext', '') and not GetParam('text', '')));
  132. return 0 if $EditAllowed >= 3;
  133. return 1;
  134. }
  135. =head1 MOTIVATION
  136. Oddmuse does provide a built-in, manual method for locking existing pages
  137. against page edits and page deletions: for each such page, manually browse to
  138. the "Administration" page and then "Lock ${PAGE_NAME}" page for that page. (This
  139. is, needless to say, a clumsy means of bulk-locking some series of similarly
  140. named pages.)
  141. Oddmuse does not, however, provide a built-in method for preventatively locking
  142. against page creations.
  143. Ergo, autolock.
  144. =head1 SEE ALSO
  145. Jorge Arroyo's B<lock-expression.pl> module, from which this module was
  146. (marginally) inspired and which this module (largely) replaces.
  147. =head1 COPYRIGHT AND LICENSE
  148. The information below applies to everything in this distribution,
  149. except where noted.
  150. Copyleft 2008 by B.w.Curry <http://www.raiazome.com>.
  151. This program is free software; you can redistribute it and/or modify
  152. it under the terms of the GNU General Public License as published by
  153. the Free Software Foundation; either version 3 of the License, or
  154. (at your option) any later version.
  155. This program is distributed in the hope that it will be useful,
  156. but WITHOUT ANY WARRANTY; without even the implied warranty of
  157. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  158. GNU General Public License for more details.
  159. You should have received a copy of the GNU General Public License
  160. along with this program. If not, see <http://www.gnu.org/licenses/>.
  161. =cut