forked from github/kensanata.oddmuse
Compare commits
41 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
50c9b79858 | ||
|
|
d99f62ea7e | ||
|
|
c11188fd3e | ||
|
|
dd22a852eb | ||
|
|
62b2e22da8 | ||
|
|
5483bbf386 | ||
|
|
8608464863 | ||
|
|
b0d983c817 | ||
|
|
5f58256543 | ||
|
|
c5c088deb1 | ||
|
|
a5b5af9c07 | ||
|
|
0dcf49e2cf | ||
|
|
f3885aa213 | ||
|
|
6136b399a6 | ||
|
|
5cc7d55152 | ||
|
|
4112d2acc4 | ||
|
|
f270a3ced4 | ||
|
|
375c844e37 | ||
|
|
efce35e250 | ||
|
|
cff4f1fd28 | ||
|
|
6f9ded7e41 | ||
|
|
40c01683fd | ||
|
|
08a4861dc3 | ||
|
|
d7c40d4dbe | ||
|
|
f8360bebad | ||
|
|
45a0558fcc | ||
|
|
f4ff56e69f | ||
|
|
0d7236c047 | ||
|
|
686f24251b | ||
|
|
0841c834b9 | ||
|
|
5225bded01 | ||
|
|
e0d18c31e2 | ||
|
|
670b69c118 | ||
|
|
f4d0f300e6 | ||
|
|
53a7a9a80c | ||
|
|
4f675de687 | ||
|
|
dffe5e3053 | ||
|
|
201970ba0b | ||
|
|
7e9137c6f8 | ||
|
|
9d81a1e3d2 | ||
|
|
2f58de9aa4 |
@@ -1,12 +1,12 @@
|
||||
;;; oddmuse-curl.el -- edit pages on an Oddmuse wiki using curl
|
||||
;;
|
||||
;; Copyright (C) 2006–2013 Alex Schroeder <alex@gnu.org>
|
||||
;; Copyright (C) 2006–2014 Alex Schroeder <alex@gnu.org>
|
||||
;; (C) 2007 rubikitch <rubikitch@ruby-lang.org>
|
||||
;;
|
||||
;; Latest version:
|
||||
;; http://git.savannah.gnu.org/cgit/oddmuse.git/plain/contrib/oddmuse-curl.el
|
||||
;; Discussion, feedback:
|
||||
;; http://www.emacswiki.org/cgi-bin/wiki/OddmuseMode
|
||||
;; http://www.emacswiki.org/cgi-bin/wiki/OddmuseCurl
|
||||
;;
|
||||
;; 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
|
||||
@@ -45,22 +45,16 @@
|
||||
(require 'goto-addr)
|
||||
(require 'info)
|
||||
|
||||
(defcustom oddmuse-directory "~/emacs/oddmuse"
|
||||
(defcustom oddmuse-directory "~/.emacs.d/oddmuse"
|
||||
"Directory to store oddmuse pages."
|
||||
:type '(string)
|
||||
:group 'oddmuse)
|
||||
|
||||
(defcustom oddmuse-wikis
|
||||
'(("TestWiki" "http://www.emacswiki.org/cgi-bin/test"
|
||||
utf-8 "question" nil)
|
||||
("EmacsWiki" "http://www.emacswiki.org/cgi-bin/emacs"
|
||||
'(("EmacsWiki" "http://www.emacswiki.org/cgi-bin/emacs"
|
||||
utf-8 "uihnscuskc" nil)
|
||||
("CommunityWiki" "http://www.communitywiki.org/cw"
|
||||
utf-8 "question" nil)
|
||||
("OddmuseWiki" "http://www.oddmuse.org/cgi-bin/oddmuse"
|
||||
utf-8 "question" nil)
|
||||
("CampaignWiki" "http://www.campaignwiki.org/wiki/NameOfYourWiki"
|
||||
utf-8 "ts" nil))
|
||||
utf-8 "question" nil))
|
||||
"Alist mapping wiki names to URLs.
|
||||
|
||||
The elements in this list are:
|
||||
@@ -160,15 +154,15 @@ It must print the RSS 3.0 text format to stdout.
|
||||
|
||||
(defvar oddmuse-post-command
|
||||
(concat "curl --silent --write-out '%{http_code}'"
|
||||
" --form title=%t"
|
||||
" --form summary=%s"
|
||||
" --form username=%u"
|
||||
" --form password=%p"
|
||||
" --form title='%t'"
|
||||
" --form summary='%s'"
|
||||
" --form username='%u'"
|
||||
" --form password='%p'"
|
||||
" --form %q=1"
|
||||
" --form recent_edit=%m"
|
||||
" --form oldtime=%o"
|
||||
" --form text=\"<-\""
|
||||
" %w")
|
||||
" --form text='<-'"
|
||||
" '%w'")
|
||||
"Command to use for publishing pages.
|
||||
It must accept the page on stdin.
|
||||
|
||||
@@ -397,11 +391,11 @@ Font-locking is controlled by `oddmuse-markup-functions'.
|
||||
("%p" . oddmuse-password)
|
||||
("%q" . question)
|
||||
("%o" . oddmuse-revision)
|
||||
("%r" . regexp)
|
||||
("%\\?" . hatena)))
|
||||
(when (and (boundp (cdr pair)) (stringp (symbol-value (cdr pair))))
|
||||
(setq command (replace-regexp-in-string (car pair)
|
||||
(shell-quote-argument
|
||||
(symbol-value (cdr pair)))
|
||||
(symbol-value (cdr pair))
|
||||
command t t))))
|
||||
command))
|
||||
|
||||
@@ -450,13 +444,14 @@ Use a prefix argument to force a reload of the page."
|
||||
(pop-to-buffer (get-buffer name))
|
||||
(let* ((wiki-data (assoc wiki oddmuse-wikis))
|
||||
(url (nth 1 wiki-data))
|
||||
(oddmuse-page-name pagename)
|
||||
(oddmuse-page-name pagename)
|
||||
(command (oddmuse-format-command oddmuse-get-command))
|
||||
(coding (nth 2 wiki-data))
|
||||
(buf (find-file-noselect (concat oddmuse-directory "/" wiki "/"
|
||||
pagename)))
|
||||
(coding-system-for-read coding)
|
||||
(coding-system-for-write coding))
|
||||
;; don't use let for dynamically bound variable
|
||||
(set-buffer buf)
|
||||
(unless (equal name (buffer-name)) (rename-buffer name))
|
||||
(erase-buffer)
|
||||
@@ -474,8 +469,9 @@ Use a prefix argument to force a reload of the page."
|
||||
"Figure out what page we need to visit
|
||||
and call `oddmuse-edit' on it."
|
||||
(interactive "P")
|
||||
(let ((pagename (if arg (oddmuse-read-pagename oddmuse-wiki)
|
||||
(oddmuse-pagename-at-point))))
|
||||
(let ((pagename (or (and arg (oddmuse-read-pagename oddmuse-wiki))
|
||||
(oddmuse-pagename-at-point)
|
||||
(oddmuse-read-pagename oddmuse-wiki))))
|
||||
(oddmuse-edit (or oddmuse-wiki
|
||||
(read-from-minibuffer "URL: "))
|
||||
pagename)))
|
||||
@@ -494,17 +490,17 @@ and call `oddmuse-edit' on it."
|
||||
(defun oddmuse-pagename-at-point ()
|
||||
"Page name at point."
|
||||
(let ((pagename (word-at-point)))
|
||||
(cond ((oddmuse-current-free-link-contents))
|
||||
((oddmuse-wikiname-p pagename)
|
||||
pagename)
|
||||
(t
|
||||
(error "No link found at point")))))
|
||||
(or (oddmuse-current-free-link-contents)
|
||||
(oddmuse-wikiname-p pagename))))
|
||||
|
||||
(defun oddmuse-wikiname-p (pagename)
|
||||
"Whether PAGENAME is WikiName or not."
|
||||
(let (case-fold-search)
|
||||
(string-match (concat "^" oddmuse-link-pattern "$") pagename)))
|
||||
(when pagename
|
||||
(let (case-fold-search)
|
||||
(when (string-match (concat "^" oddmuse-link-pattern "$") pagename)
|
||||
pagename))))
|
||||
|
||||
;; (oddmuse-wikiname-p nil)
|
||||
;; (oddmuse-wikiname-p "WikiName")
|
||||
;; (oddmuse-wikiname-p "not-wikiname")
|
||||
;; (oddmuse-wikiname-p "notWikiName")
|
||||
@@ -519,7 +515,7 @@ Save outpout in BUF and report an appropriate error.
|
||||
ON-REGION indicates whether the commands runs on the region
|
||||
such as when posting, or whether it just runs by itself such
|
||||
as when loading a page."
|
||||
(message "%s..." mesg)
|
||||
(message "%s using %s..." mesg command)
|
||||
;; If ON-REGION, the resulting HTTP CODE is found in BUF, so check
|
||||
;; that, too.
|
||||
(if (and (= 0 (if on-region
|
||||
|
||||
187
contrib/vc-oddmuse.el
Normal file
187
contrib/vc-oddmuse.el
Normal file
@@ -0,0 +1,187 @@
|
||||
;;; vc-oddmuse.el -- add VC support to oddmuse-curl
|
||||
;;
|
||||
;; Copyright (C) 2014 Alex Schroeder <alex@gnu.org>
|
||||
;;
|
||||
;; Latest version:
|
||||
;; http://git.savannah.gnu.org/cgit/oddmuse.git/plain/contrib/vc-oddmuse.el
|
||||
;; Discussion, feedback:
|
||||
;; http://www.emacswiki.org/cgi-bin/wiki/OddmuseCurl
|
||||
;;
|
||||
;; 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 GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; Add the following to your init file:
|
||||
;;
|
||||
;; (add-to-list 'vc-handled-backends 'oddmuse)
|
||||
|
||||
(add-to-list 'vc-handled-backends 'oddmuse)
|
||||
|
||||
(require 'oddmuse)
|
||||
(require 'diff)
|
||||
|
||||
(defun vc-oddmuse-revision-granularity () 'file)
|
||||
|
||||
(defun vc-oddmuse-registered (file)
|
||||
"Handle files in `oddmuse-directory'."
|
||||
(string-match (concat "^" (expand-file-name oddmuse-directory))
|
||||
(file-name-directory file)))
|
||||
|
||||
(defun vc-oddmuse-state (file)
|
||||
"No idea."
|
||||
'up-to-date)
|
||||
|
||||
(defun vc-oddmuse-working-revision (file)
|
||||
"No idea")
|
||||
|
||||
(defun vc-oddmuse-checkout-model (files)
|
||||
"No locking."
|
||||
'implicit)
|
||||
|
||||
(defun vc-oddmuse-create-repo (file)
|
||||
(error "You cannot create Oddmuse wikis using Emacs."))
|
||||
|
||||
(defun vc-oddmuse-register (files &optional rev comment)
|
||||
"This always works.")
|
||||
|
||||
(defun vc-oddmuse-revert (file &optional contents-done)
|
||||
"No idea"
|
||||
nil)
|
||||
|
||||
(defvar vc-oddmuse-log-command
|
||||
"curl --silent %w\"?action=rc;showedit=1;all=1;from=1;raw=1;match=%r\""
|
||||
"Command to use for publishing index pages.
|
||||
It must print the page to stdout.
|
||||
|
||||
%? '?' character
|
||||
%w URL of the wiki as provided by `oddmuse-wikis'
|
||||
%r Regular expression, URL encoded, of the pages to limit ourselves to.
|
||||
This uses the free variable `regexp'.")
|
||||
|
||||
(defun vc-oddmuse-print-log (files buffer &optional shortlog
|
||||
start-revision limit)
|
||||
"Load complete recent changes for the files."
|
||||
(let* ((wiki (or oddmuse-wiki
|
||||
(completing-read "Wiki: " oddmuse-wikis nil t)))
|
||||
(wiki-data (assoc wiki oddmuse-wikis))
|
||||
(url (nth 1 wiki-data))
|
||||
(regexp (concat
|
||||
"^(" ;; Perl regular expression!
|
||||
(mapconcat 'file-name-nondirectory files "|")
|
||||
")$"))
|
||||
(command (oddmuse-format-command vc-oddmuse-log-command))
|
||||
(coding (nth 2 wiki-data))
|
||||
(coding-system-for-read coding)
|
||||
(coding-system-for-write coding)
|
||||
(max-mini-window-height 1))
|
||||
(oddmuse-run "Getting recent changes" command buffer nil))
|
||||
;; Parse current buffer as RSS 3.0 and display it correctly.
|
||||
(save-excursion
|
||||
(with-current-buffer buffer
|
||||
(let (result)
|
||||
(dolist (item (cdr (split-string (buffer-string) "\n\n")));; skip first item
|
||||
(let ((data (mapcar (lambda (line)
|
||||
(when (string-match "^\\(.*?\\): \\(.*\\)" line)
|
||||
(cons (match-string 1 line)
|
||||
(match-string 2 line))))
|
||||
(split-string item "\n"))))
|
||||
(setq result (cons data result))))
|
||||
(dolist (item (nreverse result))
|
||||
(insert "title: " (cdr (assoc "title" item)) "\n"
|
||||
"version: " (cdr (assoc "revision" item)) "\n"
|
||||
"generator: " (cdr (assoc "generator" item)) "\n"
|
||||
"timestamp: " (cdr (assoc "last-modified" item)) "\n\n"
|
||||
" " (or (cdr (assoc "description" item)) ""))
|
||||
(fill-paragraph)
|
||||
(insert "\n\n"))
|
||||
(goto-char (point-min))))))
|
||||
|
||||
(defun vc-oddmuse-log-outgoing ()
|
||||
(error "This is not supported."))
|
||||
|
||||
(defun vc-oddmuse-log-incoming ()
|
||||
(error "This is not supported."))
|
||||
|
||||
(defvar vc-oddmuse-get-revision-command
|
||||
"curl --silent %w\"?action=browse;id=%t;revision=%o;raw=1\""
|
||||
"Command to use to get older revisions of a page.
|
||||
It must print the page to stdout.
|
||||
|
||||
%? '?' character
|
||||
%w URL of the wiki as provided by `oddmuse-wikis'
|
||||
%t Page title as provided by `oddmuse-page-name'
|
||||
%o Revision to retrieve as provided by `oddmuse-revision'")
|
||||
|
||||
(defvar vc-oddmuse-get-history-command
|
||||
"curl --silent %w\"?action=history;id=%t;raw=1\""
|
||||
"Command to use to get the history of a page.
|
||||
It must print the page to stdout.
|
||||
|
||||
%? '?' character
|
||||
%w URL of the wiki as provided by `oddmuse-wikis'
|
||||
%t Page title as provided by `oddmuse-page-name'")
|
||||
|
||||
(defun vc-oddmuse-diff (files &optional rev1 rev2 buffer)
|
||||
"Report the differences for FILES."
|
||||
(setq buffer (or buffer (get-buffer-create "*vc-diff*")))
|
||||
(dolist (file files)
|
||||
(setq oddmuse-page-name (file-name-nondirectory file)
|
||||
oddmuse-wiki (or oddmuse-wiki
|
||||
(file-name-nondirectory
|
||||
(directory-file-name
|
||||
(file-name-directory file)))))
|
||||
(let* ((wiki-data (or (assoc oddmuse-wiki oddmuse-wikis)
|
||||
(error "Cannot find data for wiki %s" oddmuse-wiki)))
|
||||
(url (nth 1 wiki-data)))
|
||||
(unless rev1
|
||||
;; Since we don't know the most recent revision we have to fetch
|
||||
;; it from the server every time.
|
||||
(with-temp-buffer
|
||||
(let ((max-mini-window-height 1))
|
||||
(oddmuse-run "Determining latest revision"
|
||||
(oddmuse-format-command vc-oddmuse-get-history-command)
|
||||
(current-buffer) nil))
|
||||
(if (re-search-forward "^revision: \\([0-9]+\\)$" nil t)
|
||||
(setq rev1 (match-string 1))
|
||||
(error "Cannot determine the latest revision from the page history"))))
|
||||
(dolist (rev (list rev1 rev2))
|
||||
(when (and rev
|
||||
(not (file-readable-p (concat oddmuse-directory
|
||||
"/" oddmuse-wiki "/"
|
||||
oddmuse-page-name
|
||||
".~" rev "~"))))
|
||||
(let* ((oddmuse-revision rev)
|
||||
(command (oddmuse-format-command vc-oddmuse-get-revision-command))
|
||||
(coding (nth 2 wiki-data))
|
||||
(filename (concat oddmuse-directory "/" oddmuse-wiki "/"
|
||||
oddmuse-page-name ".~" rev "~"))
|
||||
(coding-system-for-read coding)
|
||||
(coding-system-for-write coding))
|
||||
(with-temp-buffer
|
||||
(let ((max-mini-window-height 1))
|
||||
(oddmuse-run (concat "Downloading revision " rev)
|
||||
command (current-buffer) nil))
|
||||
(write-file filename)))))
|
||||
(diff-no-select
|
||||
(if rev1
|
||||
(concat oddmuse-directory "/" oddmuse-wiki "/" oddmuse-page-name ".~" rev1 "~")
|
||||
file)
|
||||
(if rev2
|
||||
(concat oddmuse-directory "/" oddmuse-wiki "/" oddmuse-page-name ".~" rev2 "~")
|
||||
file)
|
||||
nil
|
||||
(vc-switches 'oddmuse 'diff)
|
||||
buffer))))
|
||||
|
||||
(provide 'vc-oddmuse)
|
||||
@@ -237,9 +237,6 @@ a.near:link {
|
||||
a.near:visited {
|
||||
color:#550;
|
||||
}
|
||||
a.tag:before {
|
||||
content:"\2601\ ";
|
||||
}
|
||||
ol, ul, dl {
|
||||
padding-top:0.5em;
|
||||
}
|
||||
|
||||
169
modules/balanced-page-directories.pl
Normal file
169
modules/balanced-page-directories.pl
Normal file
@@ -0,0 +1,169 @@
|
||||
# Copyright (C) 2014 Alex Schroeder <alex@gnu.org>
|
||||
# Copyright (C) 2014 Aki Goto <tyatsumi@gmail.com>
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
=head1 Balanced Page Directories
|
||||
|
||||
By default, Oddmuse disperses page data files into 27 directories
|
||||
based on the first character of the page name. The directories are "A"
|
||||
to "Z", and "other". If you use your wiki as a blog, all the pages
|
||||
starting with a date end up in "other". If your page names start with
|
||||
letters other than "A" to "Z", all the pages end up in "other". If you
|
||||
are using comment pages, all your comment pages end in "C". This can
|
||||
turn into a problem if you reach ten thousand pages and more in a
|
||||
single directory.
|
||||
|
||||
=over
|
||||
|
||||
The ext2 inode specification allows for over 100 trillion files to
|
||||
reside in a single directory, however because of the current
|
||||
linked-list directory implementation, only about 10-15 thousand files
|
||||
can realistically be stored in a single directory. – L<haversian-ga on
|
||||
09 Dec 2002 22:56
|
||||
PST|http://answers.google.com/answers/threadview?id=122241>
|
||||
|
||||
=back
|
||||
|
||||
CAUTION: When this extension is installed, your data structure I<must>
|
||||
change. Make sure you have a backup of your data directory somewhere.
|
||||
|
||||
=head2 Finding the right directory
|
||||
|
||||
On the command line, finding the right subdirectory can be a problem.
|
||||
Here's how to use md5sum. Note that the -n option to echo prevents the
|
||||
trailing newline. Its inclusion would change the checksum.
|
||||
|
||||
echo -n HomePage | md5sum | cut -c 1-2
|
||||
c1
|
||||
echo -n ホームページ | md5sum | cut -c 1-2
|
||||
10
|
||||
|
||||
=head2 $BalancedPageDirectoriesSize
|
||||
|
||||
If you have more than 2560000 pages (w00t!) you might want to set
|
||||
$BalancedPageDirectoriesSize to 3. This will give you 16× more
|
||||
directories, which should let you have 40960000 pages. Also, please
|
||||
let us know about your wiki. :)
|
||||
|
||||
=head2 Migration
|
||||
|
||||
Once you install the code, reload any page. This should trigger
|
||||
migration. No output is produced during migration. Migration is
|
||||
triggered whenever a page file isn't found but a page is found at the
|
||||
default old location. If, for example, $PageDir/c1/HomePage.pg doesn't
|
||||
exist but $PageDir/h/HomePage.pg does, and the wiki can be locked, the
|
||||
wiki is locked and migration is started.
|
||||
|
||||
=cut
|
||||
|
||||
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/balanced-page-directories.pl">balanced-page-directories.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Balanced_Page_Directories_Extension">Balanced Page Directories Extension</a>';
|
||||
|
||||
use Digest::MD5 qw(md5_hex);
|
||||
use File::Find qw(finddepth);
|
||||
use vars qw($BalancedPageDirectoriesSize);
|
||||
|
||||
$BalancedPageDirectoriesSize = 2;
|
||||
|
||||
*OldBalancedPageDirectoriesGetPageDirectory = *GetPageDirectory;
|
||||
*GetPageDirectory = *NewBalancedPageDirectoriesGetPageDirectory;
|
||||
|
||||
sub NewBalancedPageDirectoriesGetPageDirectory {
|
||||
my $id = shift;
|
||||
utf8::encode($id);
|
||||
return substr(md5_hex($id), 0, $BalancedPageDirectoriesSize);
|
||||
}
|
||||
|
||||
*OldBalancedPageDirectoriesOpenPage = *OpenPage;
|
||||
*OpenPage = *NewBalancedPageDirectoriesOpenPage;
|
||||
|
||||
sub NewBalancedPageDirectoriesOpenPage {
|
||||
my $id = shift;
|
||||
if (! -f GetPageFile($id)) {
|
||||
BalancedPageDirectoriesMigrate($id);
|
||||
}
|
||||
return OldBalancedPageDirectoriesOpenPage($id, @_);
|
||||
}
|
||||
|
||||
sub BalancedPageDirectoriesMigrate {
|
||||
my $id = shift;
|
||||
|
||||
# This code is called if the page file does not exist. Perhaps we
|
||||
# need to migrate? Check if the old page file exists. If it does
|
||||
# not, there is no point in migration.
|
||||
*GetPageDirectory = *OldBalancedPageDirectoriesGetPageDirectory;
|
||||
if (not -f GetPageFile($id)) {
|
||||
*GetPageDirectory = *NewBalancedPageDirectoriesGetPageDirectory;
|
||||
return;
|
||||
}
|
||||
|
||||
# Make sure we can change the data structure now.
|
||||
RequestLockOrError();
|
||||
|
||||
# Now we know that we need to migrate. The list of pages is scanned
|
||||
# using globbing.
|
||||
SetParam('refresh', 1);
|
||||
|
||||
for $id (AllPagesList()) {
|
||||
|
||||
*GetPageDirectory = *OldBalancedPageDirectoriesGetPageDirectory;
|
||||
my $page_from = GetPageFile($id);
|
||||
my $keep_from = GetKeepDir($id);
|
||||
my $lock_from = GetLockedPageFile($id);
|
||||
my $joiner_from = $JoinerDir . '/' . GetPageDirectory($username) if $JoinerDir;
|
||||
my $joiner_email_from = $JoinerEmailDir . '/' . GetPageDirectory($username) if $JoinerEmailDir;
|
||||
my $referrer_from = $RefererDir . '/' . GetPageDirectory($id) if $RefererDir;
|
||||
*GetPageDirectory = *NewBalancedPageDirectoriesGetPageDirectory;
|
||||
my $page_to = GetPageFile($id);
|
||||
my $keep_to = GetKeepDir($id);
|
||||
my $lock_to = GetLockedPageFile($id);
|
||||
my $joiner_to = $JoinerDir . '/' . GetPageDirectory($username) if $JoinerDir;
|
||||
my $joiner_email_to = $JoinerEmailDir . '/' . GetPageDirectory($username) if $JoinerEmailDir;
|
||||
my $referrer_to = $RefererDir . '/' . GetPageDirectory($id) if $RefererDir;
|
||||
|
||||
# no clobbering
|
||||
if (! -f $page_to) {
|
||||
CreatePageDir($PageDir, $id);
|
||||
rename $page_from, $page_to || ReportError("Cannot rename $page_from");
|
||||
}
|
||||
if (-f $lock_from and ! -f $lock_to) {
|
||||
rename $lock_from, $lock_to || ReportError("Cannot rename $lock_from");
|
||||
}
|
||||
if (-d $keep_from and ! -d $keep_to) {
|
||||
CreateKeepDir($KeepDir, $id);
|
||||
rename $keep_from, $keep_to || ReportError("Cannot rename $keep_from");
|
||||
}
|
||||
if ($joiner_from and -d $joiner_from and ! -d $joiner_to) {
|
||||
CreatePageDir($JoinerDir, $id);
|
||||
rename $joiner_from, $joiner_to || ReportError("Cannot rename $joiner_from");
|
||||
}
|
||||
if ($joiner_email_from and -d $joiner_email_from and ! -d $joiner_email_to) {
|
||||
CreatePageDir($JoinerEmailDir, $id);
|
||||
rename $joiner_email_from, $joiner_email_to || ReportError("Cannot rename $joiner_email_from");
|
||||
}
|
||||
if ($referrer_from and -d $referrer_from and ! -d $referrer_to) {
|
||||
CreateRefererDir($RefererDir, $id);
|
||||
rename $referrer_from, $referrer_to || ReportError("Cannot rename $referrer_from");
|
||||
}
|
||||
}
|
||||
|
||||
# Delete empty subdirectories. Actually, attempt to delete all the
|
||||
# directories, depth first. It will simply fail for the non-empty
|
||||
# directories. http://www.perlmonks.org/?node_id=520791
|
||||
for my $parent ($PageDir, $KeepDir, $JoinerDir, $JoinerEmailDir, $RefererDir) {
|
||||
next unless $parent;
|
||||
finddepth(sub { rmdir $_ if -d }, $parent);
|
||||
}
|
||||
|
||||
ReleaseLock();
|
||||
}
|
||||
@@ -91,14 +91,14 @@ sub DespamBannedContent {
|
||||
foreach my $url (@urls) {
|
||||
if ($url =~ /($regexp)/i) {
|
||||
return Tss('Rule "%1" matched "%2" on this page.',
|
||||
QuoteHtml($regexp), $url);
|
||||
QuoteHtml($regexp), QuoteHtml($url));
|
||||
}
|
||||
}
|
||||
}
|
||||
# depends on strange-spam.pl!
|
||||
foreach (@DespamStrangeRules) {
|
||||
my $regexp = $_;
|
||||
if ($str =~ /($regexp)/) {
|
||||
if ($str =~ /($regexp)/i) {
|
||||
my $match = $1;
|
||||
$match =~ s/\n/ /g;
|
||||
return Tss('Rule "%1" matched "%2" on this page.',
|
||||
|
||||
@@ -44,6 +44,6 @@ sub DuckDuckGoSearchInit {
|
||||
}
|
||||
|
||||
sub DoDuckDuckGoSearch {
|
||||
my $search = GetParam('search', undef);
|
||||
my $search = UrlEncode(GetParam('search', undef));
|
||||
print $q->redirect({-uri=>"https://www.duckduckgo.com/?q=$search+site%3A$DuckDuckGoSearchDomain"});
|
||||
}
|
||||
|
||||
1131
modules/joiner.pl
Normal file
1131
modules/joiner.pl
Normal file
File diff suppressed because it is too large
Load Diff
@@ -78,7 +78,8 @@ sub NewQuestionaskerDoPost {
|
||||
print GetHeader('', T('Edit Denied'), undef, undef, '403 FORBIDDEN');
|
||||
print $q->p(T('You did not answer correctly.'));
|
||||
print GetFormStart(), QuestionaskerGetQuestion(1),
|
||||
(map { $q->hidden($_, '') }
|
||||
(map { $q->input({-type=>'hidden', -name=>$_,
|
||||
-value=>UnquoteHtml(GetParam($_))}) }
|
||||
qw(title text oldtime summary recent_edit aftertext)), $q->end_form;
|
||||
PrintFooter();
|
||||
# logging to the error log file of the server
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (C) 2004-2013 Alex Schroeder <alex@gnu.org>
|
||||
# Copyright (C) 2004-2014 Alex Schroeder <alex@gnu.org>
|
||||
#
|
||||
# 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
|
||||
@@ -35,6 +35,7 @@ sub DoStatic {
|
||||
}
|
||||
CreateDir($StaticDir);
|
||||
%StaticFiles = ();
|
||||
print '<p>' unless $raw;
|
||||
StaticWriteFiles();
|
||||
print '</p>' unless $raw;
|
||||
PrintFooter() unless $raw;
|
||||
@@ -56,15 +57,21 @@ sub StaticMimeTypes {
|
||||
|
||||
sub StaticWriteFiles {
|
||||
my $raw = GetParam('raw', 0);
|
||||
my $html = GetParam('html', 0);
|
||||
local *ScriptLink = *StaticScriptLink;
|
||||
local *GetDownloadLink = *StaticGetDownloadLink;
|
||||
# get rid of subscribe link in the footer by mail.pl
|
||||
local *GetCommentForm = *MailOldGetCommentForm if defined &MailNewGetCommentForm;
|
||||
foreach my $id (AllPagesList()) {
|
||||
if ($StaticAlways > 1
|
||||
or GetParam('html', 0)
|
||||
or $html
|
||||
or PageIsUploadedFile($id)) {
|
||||
StaticWriteFile($id);
|
||||
StaticWriteFile($id, $html);
|
||||
}
|
||||
}
|
||||
if ($StaticAlways > 1 or $html) {
|
||||
StaticWriteCss();
|
||||
}
|
||||
}
|
||||
|
||||
sub StaticScriptLink {
|
||||
@@ -120,15 +127,19 @@ sub StaticFileName {
|
||||
}
|
||||
|
||||
sub StaticWriteFile {
|
||||
my $id = shift;
|
||||
my ($id, $html) = @_;
|
||||
my $raw = GetParam('raw', 0);
|
||||
my $filename = StaticFileName($id);
|
||||
OpenPage($id);
|
||||
my ($mimetype, $encoding, $data) = $Page{text} =~ /^\#FILE ([^ \n]+) ?([^ \n]*)\n(.*)/s;
|
||||
open(F,"> $StaticDir/$filename") or ReportError(Ts('Cannot write %s', $filename));
|
||||
my ($mimetype, $encoding, $data) =
|
||||
$Page{text} =~ /^\#FILE ([^ \n]+) ?([^ \n]*)\n(.*)/s;
|
||||
open(F,"> $StaticDir/$filename")
|
||||
or ReportError(Ts('Cannot write %s', $filename));
|
||||
if ($data) {
|
||||
binmode(F);
|
||||
StaticFile($id, $mimetype, $data);
|
||||
} elsif ($html) {
|
||||
binmode(F, ':utf8');
|
||||
StaticHtml($id);
|
||||
} else {
|
||||
print "no data for ";
|
||||
@@ -141,7 +152,6 @@ sub StaticWriteFile {
|
||||
sub StaticFile {
|
||||
my ($id, $type, $data) = @_;
|
||||
require MIME::Base64;
|
||||
binmode(F);
|
||||
print F MIME::Base64::decode($data);
|
||||
}
|
||||
|
||||
@@ -200,7 +210,8 @@ EOT
|
||||
print F $q->div({-class=>'content'}, PageHtml($id)); # this reopens the page currently open
|
||||
# footer
|
||||
my $links = '';
|
||||
if ($OpenPageName !~ /^$CommentsPrefix/) { # fails if $CommentsPrefix is empty!
|
||||
if ($OpenPageName !~ /^$CommentsPrefix/ # fails if $CommentsPrefix is empty!
|
||||
and $IndexHash{$CommentsPrefix . $OpenPageName}) {
|
||||
$links .= ScriptLink(UrlEncode($CommentsPrefix . $OpenPageName),
|
||||
T('Comments on this page'));
|
||||
}
|
||||
@@ -216,6 +227,21 @@ EOT
|
||||
print F '</body></html>';
|
||||
}
|
||||
|
||||
sub StaticWriteCss {
|
||||
my $css;
|
||||
if ($StyleSheet) {
|
||||
$css = GetRaw($StyleSheet);
|
||||
}
|
||||
if (not $css and $IndexHash{$StyleSheetPage}) {
|
||||
$css = GetPageContent($StyleSheetPage);
|
||||
}
|
||||
if (not $css) {
|
||||
$css = GetRaw('http://www.oddmuse.org/default.css');
|
||||
}
|
||||
WriteStringToFile("$StaticDir/static.css", $css) if $css;
|
||||
chmod 0644,"$StaticDir/static.css";
|
||||
}
|
||||
|
||||
*StaticFilesOldSave = *Save;
|
||||
*Save = *StaticFilesNewSave;
|
||||
|
||||
|
||||
@@ -142,7 +142,7 @@ Go!
|
||||
(minor)
|
||||
(次要的)
|
||||
rollback
|
||||
回復
|
||||
回滾
|
||||
new
|
||||
新增
|
||||
All changes for %s
|
||||
@@ -168,13 +168,13 @@ Revision %s
|
||||
Contributors to %s
|
||||
編寫 %s 的作者
|
||||
Missing target for rollback.
|
||||
找不到要回復的目標
|
||||
找不到要回滾的目標
|
||||
Target for rollback is too far back.
|
||||
要回復的目標已太久以前了。
|
||||
要回滾的目標已太久以前了。
|
||||
A username is required for ordinary users.
|
||||
需使用普通用戶名稱
|
||||
Rolling back changes
|
||||
回復修改
|
||||
回滾修改
|
||||
The two revisions are the same.
|
||||
二個版本相同
|
||||
Editing not allowed for %s.
|
||||
@@ -182,9 +182,9 @@ Editing not allowed for %s.
|
||||
Rollback of %s would restore banned content.
|
||||
|
||||
Rollback to %s
|
||||
回復至 %s
|
||||
回滾至 %s
|
||||
%s rolled back
|
||||
%s 已回復
|
||||
%s 已回滾
|
||||
to %s
|
||||
到 %s
|
||||
Index of all pages
|
||||
@@ -644,7 +644,7 @@ SPAM 廣告頁面
|
||||
Cannot find revision %s.
|
||||
無法取得版本 %s 。
|
||||
Revert to revision %1: %2
|
||||
回復至版本 %1: %2
|
||||
回滾至版本 %1: %2
|
||||
Marked as %s.
|
||||
標記為 %s 。
|
||||
Cannot find unspammed revision.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
44
t/balanced-page-directories.t
Normal file
44
t/balanced-page-directories.t
Normal file
@@ -0,0 +1,44 @@
|
||||
# Copyright (C) 2014 Alex Schroeder <alex@gnu.org>
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
require 't/test.pl';
|
||||
package OddMuse;
|
||||
use Test::More tests => 10;
|
||||
use utf8; # tests contain UTF-8 characters and it matters
|
||||
|
||||
clear_pages();
|
||||
|
||||
update_page('HomePage', 'Das ist ein Ei.');
|
||||
ok(-f GetPageFile('HomePage'), 'page file');
|
||||
|
||||
update_page('HomePage', 'This is an egg.');
|
||||
ok(-f GetKeepFile('HomePage', 1), 'keep file');
|
||||
|
||||
update_page('ホームページ', 'これが卵です。');
|
||||
ok(-f GetPageFile('ホームページ'), 'Japanese page file');
|
||||
|
||||
update_page($StyleSheetPage, '/* nothing to see */', '', 0, 1);
|
||||
ok(-f GetPageFile($StyleSheetPage), 'locked page file');
|
||||
ok(-f GetLockedPageFile($StyleSheetPage), 'page lock');
|
||||
|
||||
add_module('balanced-page-directories.pl');
|
||||
|
||||
test_page(get_page('HomePage'), 'This is an egg.');
|
||||
ok(-f GetKeepFile('HomePage', 1), 'keep file');
|
||||
test_page(get_page('ホームページ'), 'これが卵です。');
|
||||
ok(-f GetLockedPageFile($StyleSheetPage), 'page lock');
|
||||
|
||||
# create a new page
|
||||
test_page(update_page('サイトマップ', '日本語ユーザーに向けて'),
|
||||
'日本語ユーザーに向けて');
|
||||
32
t/comments.t
32
t/comments.t
@@ -1,24 +1,20 @@
|
||||
# Copyright (C) 2006 Alex Schroeder <alex@emacswiki.org>
|
||||
# Copyright (C) 2006–2014 Alex Schroeder <alex@gnu.org>
|
||||
#
|
||||
# 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 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
# 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.
|
||||
# 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, write to the
|
||||
# Free Software Foundation, Inc.
|
||||
# 59 Temple Place, Suite 330
|
||||
# Boston, MA 02111-1307 USA
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
require 't/test.pl';
|
||||
package OddMuse;
|
||||
use Test::More tests => 35;
|
||||
use Test::More tests => 36;
|
||||
clear_pages();
|
||||
|
||||
AppendStringToFile($ConfigFile, "\$CommentsPrefix = 'Comments on ';\n");
|
||||
@@ -89,11 +85,17 @@ test_page(get_page('Comments_on_Yadda'), 'This is my comment\.', '-- Alex');
|
||||
test_page(get_page('action=rc raw=1'), 'title: Comments on Yadda',
|
||||
'description: This is my comment.', 'generator: Alex');
|
||||
|
||||
# homepage
|
||||
get_page('title=Comments_on_Yadda', 'aftertext=This%20is%20another%20comment.',
|
||||
'username=Alex', 'homepage=http%3a%2f%2fwww%2eoddmuse%2eorg%2f');
|
||||
xpath_test(get_page('Comments_on_Yadda'),
|
||||
'//p[contains(text(),"This is my comment.")]',
|
||||
'//a[@class="url http outside"][@href="http://www.oddmuse.org/"][text()="Alex"]');
|
||||
# variant without protocol
|
||||
get_page('title=Comments_on_Yadda', 'aftertext=This%20is%20another%20comment.',
|
||||
'username=Berta', 'homepage=alexschroeder%2ech');
|
||||
xpath_test(get_page('Comments_on_Yadda'),
|
||||
'//a[@class="url http outside"][@href="http://alexschroeder.ch"][text()="Berta"]');
|
||||
|
||||
my $textarea = '//textarea[@name="aftertext"][@id="aftertext"]';
|
||||
xpath_test(get_page('Comments_on_Yadda'), $textarea);
|
||||
|
||||
13
t/journal3.t
13
t/journal3.t
@@ -1,4 +1,4 @@
|
||||
# Copyright (C) 2011 Alex Schroeder <alex@gnu.org>
|
||||
# Copyright (C) 2011–2014 Alex Schroeder <alex@gnu.org>
|
||||
#
|
||||
# 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
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
require 't/test.pl';
|
||||
package OddMuse;
|
||||
use Test::More tests => 34;
|
||||
use Test::More tests => 35;
|
||||
|
||||
clear_pages();
|
||||
|
||||
@@ -38,7 +38,7 @@ test_page($page, '2011-12-17', '2011-12-16', '2011-12-15',
|
||||
test_page_negative($page, '2011-12-12', '2011-12-11', '2011-12-10',
|
||||
'2011-12-09', '2011-12-08');
|
||||
|
||||
xpath_test($page, '//a[@href="http://localhost/wiki.pl?action=more;num=5;regexp=^\d\d\d\d-\d\d-\d\d;search=;mode=;offset=5"][text()="More..."]');
|
||||
xpath_test($page, '//a[@href="http://localhost/wiki.pl?action=more;num=5;regexp=%5e%5cd%5cd%5cd%5cd-%5cd%5cd-%5cd%5cd;search=;mode=;offset=5"][text()="More..."]');
|
||||
|
||||
# check that the link for more actually works
|
||||
|
||||
@@ -60,7 +60,12 @@ test_page($page, '2011-12-13', '2011-12-12', '2011-12-11',
|
||||
'2011-12-10', '2011-12-09');
|
||||
xpath_test($page, '//a[text()="More..."]');
|
||||
|
||||
# one las check
|
||||
# one last check
|
||||
|
||||
xpath_test_negative(get_page("action=more num=5 offset=6 "),
|
||||
'//a[text()="More..."]');
|
||||
|
||||
# check for unescaped URL
|
||||
|
||||
$page = update_page('Plus', "Using a plus:\n\n<journal 5 \"^.+\">");
|
||||
xpath_test($page, '//a[text()="More..."][@href="http://localhost/wiki.pl?action=more;num=5;regexp=%5e.%2b;search=;mode=;offset=5"]');
|
||||
|
||||
@@ -55,3 +55,7 @@ test_page(update_page('test', 'answer new question', undef, undef, undef,
|
||||
test_page(get_page('Comments_on_test'),
|
||||
'label for="username"',
|
||||
'say hi');
|
||||
|
||||
# test for corruption of Unicode text
|
||||
update_page('Umlaute', '<Schröder>');
|
||||
test_page($redirect, '<Schröder>')
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
# Copyright (C) 2007, 2008, 2009 Alex Schroeder <alex@gnu.org>
|
||||
# Copyright (C) 2007–2014 Alex Schroeder <alex@gnu.org>
|
||||
#
|
||||
# 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 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.
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
require 't/test.pl';
|
||||
package OddMuse;
|
||||
use Test::More tests => 29;
|
||||
use utf8;
|
||||
use Test::More tests => 36;
|
||||
clear_pages();
|
||||
|
||||
add_module('static-copy.pl');
|
||||
@@ -114,16 +115,37 @@ xpath_test(update_page('HomePage', "Static: [[image:Trogs]]"),
|
||||
# delete the static pages and regenerate it
|
||||
ok(unlink("$DataDir/static/Trogs.svgz"), "Deleted $DataDir/static/Trogs.svgz");
|
||||
ok(unlink("$DataDir/static/Logo.png"), "Deleted $DataDir/static/Logo.png");
|
||||
test_page(get_page('action=static raw=1 pwd=foo'), "Trogs", "Logo");
|
||||
ok(-f "$DataDir/static/Trogs.svgz", "$DataDir/static/Trogs.svgz exists");
|
||||
ok(-f "$DataDir/static/Logo.png", "$DataDir/static/Logo.png exists");
|
||||
ok(! -f "$DataDir/static/HomePage.html", "$DataDir/static/HomePage.html does not exist");
|
||||
test_page(get_page('action=static raw=1 pwd=foo html=1'), "Trogs", "Logo", "HomePage");
|
||||
ok(-f "$DataDir/static/Trogs.svgz", "$DataDir/static/Trogs.svgz exists");
|
||||
ok(-f "$DataDir/static/Logo.png", "$DataDir/static/Logo.png exists");
|
||||
ok(-f "$DataDir/static/HomePage.html", "$DataDir/static/HomePage.html exists");
|
||||
|
||||
# Make sure spaces are translated to underscores (fixed in image.pl)
|
||||
# StaticWriteFiles must write uploaded files only (since $StaticAlways = 1)
|
||||
$page = get_page('action=static raw=1 pwd=foo');
|
||||
test_page($page, "Trogs", "Logo"); # Remember, a rollback has restored Logo.png
|
||||
test_page_negative($page, "HomePage"); # since it an ordinary page
|
||||
|
||||
ok(-s "$DataDir/static/Trogs.svgz", "$DataDir/static/Trogs.svgz has nonzero size");
|
||||
ok(-s "$DataDir/static/Logo.png", "$DataDir/static/Logo.png has nonzero size");
|
||||
ok(! -e "$DataDir/static/HomePage.html", "$DataDir/static/HomePage.html does not exist");
|
||||
|
||||
# force generation of HomePage using html=1
|
||||
$page = get_page('action=static raw=1 pwd=foo html=1');
|
||||
test_page($page, "Trogs", "Logo", "HomePage");
|
||||
test_page_negative($page, "no data"); # must not skip HomePage!
|
||||
|
||||
ok(-s "$DataDir/static/Trogs.svgz", "$DataDir/static/Trogs.svgz has nonzero size");
|
||||
ok(-s "$DataDir/static/Logo.png", "$DataDir/static/Logo.png has nonzero size");
|
||||
ok(-s "$DataDir/static/HomePage.html", "$DataDir/static/HomePage.html has nonzero size");
|
||||
|
||||
# check that links between pages work as expected
|
||||
xpath_test(update_page("Test", "Link to HomePage. Testing Ümlaute."),
|
||||
'//a[text()="HomePage"][@href="http://localhost/wiki.pl/HomePage"]');
|
||||
test_page(get_page('action=static raw=1 pwd=foo html=1'), 'Test');
|
||||
xpath_test_file("$DataDir/static/Test.html",
|
||||
'//a[text()="HomePage"][@href="HomePage.html"]');
|
||||
test_file("$DataDir/static/Test.html",
|
||||
"Ümlaute");
|
||||
test_file("$DataDir/static/static.css",
|
||||
"body { background-color:#FFF; color:#000; margin:1em 2em; }");
|
||||
|
||||
# make sure spaces are translated to underscores (fixed in image.pl)
|
||||
add_module('image.pl');
|
||||
|
||||
# Now, create real pages. First, we'll use the ordinary image link to
|
||||
|
||||
23
t/test.pl
23
t/test.pl
@@ -158,6 +158,18 @@ sub test_page {
|
||||
}
|
||||
}
|
||||
|
||||
# one file, many tests
|
||||
sub test_file {
|
||||
my ($file, @tests) = @_;
|
||||
if (open(F, '< :utf8', $file)) {
|
||||
local $/ = undef;
|
||||
test_page(<F>, @tests);
|
||||
close(F);
|
||||
} else {
|
||||
warn "cannot open $file\n";
|
||||
}
|
||||
}
|
||||
|
||||
# one string, many negative tests
|
||||
sub test_page_negative {
|
||||
my $page = shift;
|
||||
@@ -208,6 +220,17 @@ sub xpath_test {
|
||||
xpath_do(sub { shift > 0; }, "No Matches\n", @_);
|
||||
}
|
||||
|
||||
sub xpath_test_file {
|
||||
my ($file, @tests) = @_;
|
||||
if (open(F, '< :utf8', $file)) {
|
||||
local $/ = undef;
|
||||
xpath_test(<F>, @tests);
|
||||
close(F);
|
||||
} else {
|
||||
warn "cannot open $file\n";
|
||||
}
|
||||
}
|
||||
|
||||
sub negative_xpath_test {
|
||||
xpath_do(sub { shift == 0; }, "Unexpected Matches\n", @_);
|
||||
}
|
||||
|
||||
89
wiki.pl
89
wiki.pl
@@ -39,7 +39,8 @@ use vars qw($RssLicense $RssCacheHours @RcDays $TempDir $LockDir $DataDir
|
||||
$KeepDir $PageDir $RcOldFile $IndexFile $BannedContent $NoEditFile $BannedHosts
|
||||
$ConfigFile $FullUrl $SiteName $HomePage $LogoUrl $RcDefault $RssDir
|
||||
$IndentLimit $RecentTop $RecentLink $EditAllowed $UseDiff $KeepDays $KeepMajor
|
||||
$EmbedWiki $BracketText $UseConfig $UseLookup $AdminPass $EditPass $NetworkFile
|
||||
$EmbedWiki $BracketText $UseConfig $UseLookup $AdminPass $EditPass
|
||||
$PassHashFunction $PassSalt $NetworkFile
|
||||
$BracketWiki $FreeLinks $WikiLinks $SummaryHours $FreeLinkPattern $RCName
|
||||
$RunCGI $ShowEdits $LinkPattern $RssExclude $InterLinkPattern $MaxPost $UseGrep
|
||||
$UrlPattern $UrlProtocols $ImageExtensions $InterSitePattern $FS $CookieName
|
||||
@@ -49,7 +50,7 @@ $RssImageUrl $ReadMe $RssRights $BannedCanRead $SurgeProtection $TopLinkBar
|
||||
$LanguageLimit $SurgeProtectionTime $SurgeProtectionViews $DeletedPage
|
||||
%Languages $InterMap $ValidatorLink %LockOnCreation $RssStyleSheet
|
||||
%CookieParameters @UserGotoBarPages $NewComment $HtmlHeaders $StyleSheetPage
|
||||
$ConfigPage $ScriptName $CommentsPrefix @UploadTypes $AllNetworkFiles
|
||||
$ConfigPage $ScriptName $CommentsPrefix $CommentsPattern @UploadTypes $AllNetworkFiles
|
||||
$UsePathInfo $UploadAllowed $LastUpdate $PageCluster %PlainTextPages
|
||||
$RssInterwikiTranslate $UseCache $Counter $ModuleDir $FullUrlPattern
|
||||
$SummaryDefaultLength $FreeInterLinkPattern %InvisibleCookieParameters
|
||||
@@ -95,12 +96,14 @@ $StyleSheetPage = 'css'; # Page for CSS sheet
|
||||
$LogoUrl = ''; # URL for site logo ('' for no logo)
|
||||
$NotFoundPg = ''; # Page for not-found links ('' for blank pg)
|
||||
|
||||
$NewText = "This page is empty.\n"; # New page text
|
||||
$NewComment = "Add your comment here.\n"; # New comment text
|
||||
$NewText = T('This page is empty.') . "\n"; # New page text
|
||||
$NewComment = T('Add your comment here.') . "\n"; # New comment text
|
||||
|
||||
$EditAllowed = 1; # 0 = no, 1 = yes, 2 = comments pages only, 3 = comments only
|
||||
$AdminPass = '' unless defined $AdminPass; # Whitespace separated passwords.
|
||||
$EditPass = '' unless defined $EditPass; # Whitespace separated passwords.
|
||||
$PassHashFunction = '' unless defined $PassHashFunction; # Name of the function to create hashes
|
||||
$PassSalt = '' unless defined $PassSalt; # Salt will be added to any password before hashing
|
||||
|
||||
$BannedHosts = 'BannedHosts'; # Page for banned hosts
|
||||
$BannedCanRead = 1; # 1 = banned cannot edit, 0 = banned cannot read
|
||||
@@ -151,6 +154,7 @@ $TopLinkBar = 1; # 1 = add a goto bar at the top of the page
|
||||
$UserGotoBar = ''; # HTML added to end of goto bar
|
||||
$ValidatorLink = 0; # 1 = Link to the W3C HTML validator service
|
||||
$CommentsPrefix = ''; # prefix for comment pages, eg. 'Comments_on_' to enable
|
||||
$CommentsPattern = undef; # regex used to match comment pages
|
||||
$HtmlHeaders = ''; # Additional stuff to put in the HTML <head> section
|
||||
$IndentLimit = 20; # Maximum depth of nested lists
|
||||
$LanguageLimit = 3; # Number of matches req. for each language
|
||||
@@ -289,6 +293,8 @@ sub InitVariables { # Init global session variables for mod_perl!
|
||||
(\$HomePage, \$RCName, \$BannedHosts, \$InterMap, \$StyleSheetPage, \$CommentsPrefix,
|
||||
\$ConfigPage, \$NotFoundPg, \$RssInterwikiTranslate, \$BannedContent, \$RssExclude, );
|
||||
$CommentsPrefix .= '_' if $add_space;
|
||||
$CommentsPattern = "^$CommentsPrefix(.*)"
|
||||
unless defined $CommentsPattern or not $CommentsPrefix;
|
||||
@UserGotoBarPages = ($HomePage, $RCName) unless @UserGotoBarPages;
|
||||
my @pages = sort($BannedHosts, $StyleSheetPage, $ConfigPage, $InterMap,
|
||||
$RssInterwikiTranslate, $BannedContent);
|
||||
@@ -465,12 +471,12 @@ sub ApplyRules {
|
||||
}
|
||||
Clean(AddHtmlEnvironment('p')); # if dirty block is looked at later, this will disappear
|
||||
($_, pos) = ($old_, $oldpos); # restore \G (assignment order matters!)
|
||||
} elsif ($bol && m/\G(\<journal(\s+(\d*))?(\s+"(.*?)")?(\s+(reverse|past|future))?(\s+search\s+(.*))?\>[ \t]*\n?)/cgi) {
|
||||
} elsif ($bol && m/\G(\<journal(\s+(\d*)(,(\d*))?)?(\s+"(.*?)")?(\s+(reverse|past|future))?(\s+search\s+(.*))?\>[ \t]*\n?)/cgi) {
|
||||
# <journal 10 "regexp"> includes 10 pages matching regexp
|
||||
Clean(CloseHtmlEnvironments());
|
||||
Dirty($1);
|
||||
my ($oldpos, $old_) = (pos, $_); # remember these because of the call to PrintJournal()
|
||||
PrintJournal($3, $5, $7, 0, $9); # no offset
|
||||
PrintJournal($3, $5, $7, $9, 0, $11); # no offset
|
||||
Clean(AddHtmlEnvironment('p')); # if dirty block is looked at later, this will disappear
|
||||
($_, pos) = ($old_, $oldpos); # restore \G (assignment order matters!)
|
||||
} elsif ($bol && m/\G(\<rss(\s+(\d*))?\s+(.*?)\>[ \t]*\n?)/cgis) {
|
||||
@@ -819,7 +825,7 @@ sub GetRaw {
|
||||
sub DoJournal {
|
||||
print GetHeader(undef, T('Journal'));
|
||||
print $q->start_div({-class=>'content'});
|
||||
PrintJournal(map { GetParam($_, ''); } qw(num regexp mode offset search));
|
||||
PrintJournal(map { GetParam($_, ''); } qw(num num regexp mode offset search));
|
||||
print $q->end_div();
|
||||
PrintFooter();
|
||||
}
|
||||
@@ -829,9 +835,10 @@ sub JournalSort { $b cmp $a }
|
||||
sub PrintJournal {
|
||||
return if $CollectingJournal; # avoid infinite loops
|
||||
local $CollectingJournal = 1;
|
||||
my ($num, $regexp, $mode, $offset, $search) = @_;
|
||||
my ($num, $numMore, $regexp, $mode, $offset, $search) = @_;
|
||||
$regexp = '^\d\d\d\d-\d\d-\d\d' unless $regexp;
|
||||
$num = 10 unless $num;
|
||||
$numMore = $num unless $numMore;
|
||||
$offset = 0 unless $offset;
|
||||
# FIXME: Should pass filtered list of pages to SearchTitleAndBody to save time?
|
||||
my @pages = sort JournalSort (grep(/$regexp/, $search ? SearchTitleAndBody($search) : AllPagesList()));
|
||||
@@ -860,7 +867,9 @@ sub PrintJournal {
|
||||
print $q->start_div({-class=>'journal'});
|
||||
my $next = $offset + PrintAllPages(1, 1, $num, @pages[$offset .. $#pages]);
|
||||
print $q->end_div();
|
||||
print $q->p({-class=>'more'}, ScriptLink("action=more;num=$num;regexp=$regexp;search=$search;mode=$mode;offset=$next", T('More...'), 'more')) if $pages[$next];
|
||||
$regexp = UrlEncode($regexp);
|
||||
$search = UrlEncode($search);
|
||||
print $q->p({-class=>'more'}, ScriptLink("action=more;num=$numMore;regexp=$regexp;search=$search;mode=$mode;offset=$next", T('More...'), 'more')) if $pages[$next];
|
||||
}
|
||||
|
||||
sub PrintAllPages {
|
||||
@@ -880,17 +889,21 @@ sub PrintAllPages {
|
||||
$q->h1($links ? GetPageLink($id)
|
||||
: $q->a({-name=>$id}, UrlEncode(FreeToNormal($id))));
|
||||
PrintPageHtml();
|
||||
if ($comments and $id !~ /^$CommentsPrefix/o) {
|
||||
print $q->p({-class=>'comment'},
|
||||
GetPageLink($CommentsPrefix . $id,
|
||||
T('Comments on this page')));
|
||||
}
|
||||
PrintPageCommentsLink($id, $comments);
|
||||
print $q->end_div();
|
||||
$n++; # pages actually printed
|
||||
}
|
||||
return $i;
|
||||
}
|
||||
|
||||
sub PrintPageCommentsLink {
|
||||
my ($id, $comments) = @_;
|
||||
if ($comments and $CommentsPattern and $id !~ /$CommentsPattern/o) {
|
||||
print $q->p({-class=>'comment'},
|
||||
GetPageLink($CommentsPrefix . $id, T('Comments on this page')));
|
||||
}
|
||||
}
|
||||
|
||||
sub RSS {
|
||||
return if $CollectingJournal; # avoid infinite loops when using full=1
|
||||
local $CollectingJournal = 1;
|
||||
@@ -1380,7 +1393,7 @@ sub BrowseResolvedPage {
|
||||
print $q->redirect({-uri=>$resolved});
|
||||
} elsif ($class && $class eq 'alias') { # an anchor was found instead of a page
|
||||
ReBrowsePage($resolved);
|
||||
} elsif (not $resolved and $NotFoundPg and $id !~ /^$CommentsPrefix/o) { # custom page-not-found message
|
||||
} elsif (not $resolved and $NotFoundPg and $id !~ /$CommentsPattern/o) { # custom page-not-found message
|
||||
BrowsePage($NotFoundPg);
|
||||
} elsif ($resolved) { # an existing page was found
|
||||
BrowsePage($resolved, GetParam('raw', 0));
|
||||
@@ -1942,7 +1955,7 @@ sub RssItem {
|
||||
$rss .= "<description>" . QuoteHtml($summary) . "</description>\n" if $summary;
|
||||
$rss .= "<pubDate>" . $date . "</pubDate>\n";
|
||||
$rss .= "<comments>" . ScriptUrl($CommentsPrefix . UrlEncode($id))
|
||||
. "</comments>\n" if $CommentsPrefix and $id !~ /^$CommentsPrefix/o;
|
||||
. "</comments>\n" if $CommentsPattern and $id !~ /$CommentsPattern/o;
|
||||
$rss .= "<dc:contributor>" . $username . "</dc:contributor>\n" if $username;
|
||||
$rss .= "<wiki:status>" . (1 == $revision ? 'new' : 'updated')
|
||||
. "</wiki:status>\n";
|
||||
@@ -2428,8 +2441,8 @@ sub GetFooterLinks {
|
||||
my ($id, $rev) = @_;
|
||||
my @elements;
|
||||
if ($id and $rev ne 'history' and $rev ne 'edit') {
|
||||
if ($CommentsPrefix) {
|
||||
if ($id =~ /^$CommentsPrefix(.*)/o) {
|
||||
if ($CommentsPattern) {
|
||||
if ($id =~ /$CommentsPattern/o) {
|
||||
push(@elements, GetPageLink($1, undef, 'original', T('a')));
|
||||
} else {
|
||||
push(@elements, GetPageLink($CommentsPrefix . $id, undef, 'comment', T('c')));
|
||||
@@ -2460,8 +2473,8 @@ sub GetFooterLinks {
|
||||
|
||||
sub GetCommentForm {
|
||||
my ($id, $rev, $comment) = @_;
|
||||
if ($CommentsPrefix ne '' and $id and $rev ne 'history' and $rev ne 'edit'
|
||||
and $id =~ /^$CommentsPrefix/o and UserCanEdit($id, 0, 1)) {
|
||||
if ($CommentsPattern ne '' and $id and $rev ne 'history' and $rev ne 'edit'
|
||||
and $id =~ /$CommentsPattern/o and UserCanEdit($id, 0, 1)) {
|
||||
return $q->div({-class=>'comment'}, GetFormStart(undef, undef, 'comment'), # protected by questionasker
|
||||
$q->p(GetHiddenValue('title', $id),
|
||||
GetTextArea('aftertext', $comment ? $comment : $NewComment, 10)), $EditNote,
|
||||
@@ -2706,7 +2719,6 @@ sub OpenPage { # Sets global variables
|
||||
local $/ = undef;
|
||||
$Page{text} = <F>;
|
||||
close F;
|
||||
} elsif ($CommentsPrefix and $id =~ /^$CommentsPrefix(.*)/o) { # do nothing
|
||||
}
|
||||
}
|
||||
$OpenPageName = $id;
|
||||
@@ -3032,11 +3044,9 @@ sub FreeToNormal { # trim all spaces and convert them to underlines
|
||||
my $id = shift;
|
||||
return '' unless $id;
|
||||
$id =~ s/ /_/g;
|
||||
if (index($id, '_') > -1) { # Quick check for any space/underscores
|
||||
$id =~ s/__+/_/g;
|
||||
$id =~ s/^_//;
|
||||
$id =~ s/_$//;
|
||||
}
|
||||
$id =~ s/__+/_/g;
|
||||
$id =~ s/^_//;
|
||||
$id =~ s/_$//;
|
||||
return UnquoteHtml($id);
|
||||
}
|
||||
|
||||
@@ -3221,7 +3231,7 @@ sub UserCanEdit {
|
||||
return 1 if UserIsEditor();
|
||||
return 0 if !$EditAllowed or -f $NoEditFile;
|
||||
return 0 if $editing and UserIsBanned(); # this call is more expensive
|
||||
return 0 if $EditAllowed >= 2 and (not $CommentsPrefix or $id !~ /^$CommentsPrefix/o);
|
||||
return 0 if $EditAllowed >= 2 and (not $CommentsPattern or $id !~ /$CommentsPattern/o);
|
||||
return 1 if $EditAllowed >= 3 and ($comment or (GetParam('aftertext', '') and not GetParam('text', '')));
|
||||
return 0 if $EditAllowed >= 3;
|
||||
return 1;
|
||||
@@ -3243,19 +3253,22 @@ sub UserIsBanned {
|
||||
}
|
||||
|
||||
sub UserIsAdmin {
|
||||
return 0 if $AdminPass eq '';
|
||||
my $pwd = GetParam('pwd', '');
|
||||
foreach (split(/\s+/, $AdminPass)) {
|
||||
return 1 if $pwd eq $_;
|
||||
}
|
||||
return 0;
|
||||
return UserHasPassword(GetParam('pwd', ''), $AdminPass);
|
||||
}
|
||||
|
||||
sub UserIsEditor {
|
||||
return 1 if UserIsAdmin(); # Admin includes editor
|
||||
return 0 if $EditPass eq '';
|
||||
my $pwd = GetParam('pwd', ''); # Used for both passwords
|
||||
foreach (split(/\s+/, $EditPass)) {
|
||||
return UserHasPassword(GetParam('pwd', ''), $EditPass);
|
||||
}
|
||||
|
||||
sub UserHasPassword {
|
||||
my ($pwd, $pass) = @_;
|
||||
return 0 if not $pass;
|
||||
if ($PassHashFunction ne '') {
|
||||
no strict 'refs';
|
||||
$pwd = &$PassHashFunction($pwd . $PassSalt);
|
||||
}
|
||||
foreach (split(/\s+/, $pass)) {
|
||||
return 1 if $pwd eq $_;
|
||||
}
|
||||
return 0;
|
||||
@@ -3338,7 +3351,7 @@ sub AllPagesList {
|
||||
if (not $refresh and -f $IndexFile) {
|
||||
my ($status, $rawIndex) = ReadFile($IndexFile); # not fatal
|
||||
if ($status) {
|
||||
%IndexHash = split(/\s+/, $rawIndex);
|
||||
%IndexHash = split(/ /, $rawIndex);
|
||||
@IndexList = sort(keys %IndexHash);
|
||||
return @IndexList;
|
||||
}
|
||||
@@ -3711,7 +3724,7 @@ sub AddComment {
|
||||
my $author = GetParam('username', T('Anonymous'));
|
||||
my $homepage = GetParam('homepage', '');
|
||||
$homepage = 'http://' . $homepage
|
||||
if $homepage and not substr($homepage,0,7) eq 'http://';
|
||||
if $homepage and $homepage !~ /^($UrlProtocols):/;
|
||||
$author = "[$homepage $author]" if $homepage;
|
||||
$string .= "\n----\n\n" if $string and $string ne "\n";
|
||||
$string .= $comment . "\n\n"
|
||||
|
||||
Reference in New Issue
Block a user