questionasker.pl 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. # Copyright (C) 2004 Brock Wilcox <awwaiid@thelackthereof.org>
  2. # Copyright (C) 2006–2015 Alex Schroeder <alex@gnu.org>
  3. #
  4. # This program is free software; you can redistribute it and/or modify
  5. # it under the terms of the GNU General Public License as published by
  6. # the Free Software Foundation; either version 3 of the License, or
  7. # (at your option) any later version.
  8. #
  9. # This program is distributed in the hope that it will be useful,
  10. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. # GNU General Public License for more details.
  13. #
  14. # You should have received a copy of the GNU General Public License
  15. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. use strict;
  17. use v5.10;
  18. AddModuleDescription('questionasker.pl', 'QuestionAsker Extension');
  19. our ($q, $bol, $FreeLinks, $FreeLinkPattern, $LinkPattern, $WikiLinks,
  20. @MyInitVariables, %AdminPages, %CookieParameters, @MyFormChanges);
  21. our (@QuestionaskerQuestions,
  22. $QuestionaskerRememberAnswer,
  23. $QuestionaskerSecretKey,
  24. $QuestionaskerRequiredList,
  25. %QuestionaskerProtectedForms);
  26. # A list of arrays. The first element in each array is a string, the
  27. # question to be asked. The second element is a subroutine which is
  28. # passed the answer as the first argument.
  29. @QuestionaskerQuestions =
  30. (['What is the first letter of this question?' => sub { shift =~ /^\s*W\s*$/i }],
  31. ['How many letters are in the word "four"?' => sub { shift =~ /^\s*(4|four)\s*$/i }],
  32. ['Tell me any number between 1 and 10' => sub { shift =~ /^\s*([1-9]|10|one|two|three|four|five|six|seven|eight|nine|ten)\s*$/ }],
  33. ["How many lives does a cat have?" => sub { shift =~ /^\s*(7|seven|9|nine)\s*$/i }],
  34. ["What is 2 + 4?" => sub { shift =~ /^\s*(6|six)\s*$/i }],
  35. );
  36. # The page name for exceptions, if defined. Every page linked to via
  37. # WikiWord or [[free link]] is considered to be a page which needs
  38. # questions asked. All other pages do not require questions asked. If
  39. # not set, then all pages need questions asked.
  40. $QuestionaskerRequiredList = '';
  41. # If a user answers a question correctly, remember this in the cookie
  42. # and don't ask any further questions. The name of the parameter in
  43. # the cookie can be changed should a spam bot target this module
  44. # specifically. Changing the secret key will force all users to answer
  45. # another question.
  46. $QuestionaskerRememberAnswer = 1;
  47. $QuestionaskerSecretKey = 'question';
  48. # Forms using one of the following classes are protected.
  49. %QuestionaskerProtectedForms = ('comment' => 1,
  50. 'edit upload' => 1,
  51. 'edit text' => 1,);
  52. push(@MyInitVariables, \&QuestionaskerInit);
  53. sub QuestionaskerInit {
  54. $QuestionaskerRequiredList = FreeToNormal($QuestionaskerRequiredList);
  55. $AdminPages{$QuestionaskerRequiredList} = 1;
  56. $CookieParameters{$QuestionaskerSecretKey} = '';
  57. }
  58. *OldQuestionaskerDoPost = \&DoPost;
  59. *DoPost = \&NewQuestionaskerDoPost;
  60. sub NewQuestionaskerDoPost {
  61. my(@params) = @_;
  62. my $id = FreeToNormal(GetParam('title', undef));
  63. my $preview = GetParam('Preview', undef); # case matters!
  64. my $question_num = GetParam('question_num', undef);
  65. my $answer = GetParam('answer', undef);
  66. unless (UserIsEditor()
  67. or $QuestionaskerRememberAnswer && GetParam($QuestionaskerSecretKey, 0)
  68. or $preview
  69. or $QuestionaskerQuestions[$question_num][1]($answer)
  70. or QuestionaskerException($id)) {
  71. print GetHeader('', T('Edit Denied'), undef, undef, '403 FORBIDDEN');
  72. print $q->p(T('You did not answer correctly.'));
  73. print GetFormStart(), QuestionaskerGetQuestion(1),
  74. (map { $q->input({-type=>'hidden', -name=>$_,
  75. -value=>UnquoteHtml(GetParam($_))}) }
  76. qw(title text oldtime summary recent_edit aftertext)), $q->end_form;
  77. PrintFooter();
  78. # logging to the error log file of the server
  79. # warn "Q: '$QuestionaskerQuestions[$question_num][0]', A: '$answer'\n";
  80. return;
  81. }
  82. # Set the secret key only if a question has in fact been answered
  83. if (not GetParam($QuestionaskerSecretKey, 0)
  84. and $QuestionaskerQuestions[$question_num][1]($answer)) {
  85. SetParam($QuestionaskerSecretKey, 1)
  86. }
  87. return (OldQuestionaskerDoPost(@params));
  88. }
  89. push(@MyFormChanges, \&QuestionAddTo);
  90. sub QuestionAddTo {
  91. my ($form, $type, $upload) = @_;
  92. if (not $upload
  93. and not QuestionaskerException(GetId())
  94. and not $QuestionaskerRememberAnswer && GetParam($QuestionaskerSecretKey, 0)
  95. and not UserIsEditor()) {
  96. my $question = QuestionaskerGetQuestion();
  97. $form =~ s/(.*)<p>(.*?)<label for="username">/$1$question<p>$2<label for="username">/;
  98. }
  99. return $form;
  100. }
  101. sub QuestionaskerGetQuestion {
  102. my $need_button = shift;
  103. my $button = $need_button ? $q->submit(-value=>T('Go!')) : '';
  104. my $question_number = int(rand(scalar(@QuestionaskerQuestions)));
  105. return $q->div({-class=>'question'},
  106. $q->p(T('To save this page you must answer this question:')),
  107. $q->blockquote($q->p($QuestionaskerQuestions[$question_number][0]),
  108. $q->p($q->input({-type=>'text', -name=>'answer'}),
  109. $q->input({-type=>'hidden', -name=>'question_num',
  110. -value=>$question_number}),
  111. $button)));
  112. }
  113. sub QuestionaskerException {
  114. my $id = shift;
  115. return 0 unless $QuestionaskerRequiredList and $id;
  116. my $data = GetPageContent($QuestionaskerRequiredList);
  117. if ($WikiLinks) {
  118. while ($data =~ /$LinkPattern/g) {
  119. return 0 if FreeToNormal($1) eq $id;
  120. }
  121. }
  122. if ($FreeLinks) {
  123. while ($data =~ /\[\[$FreeLinkPattern\]\]/g) {
  124. return 0 if FreeToNormal($1) eq $id;
  125. }
  126. }
  127. return 1;
  128. }