1{ config, lib, pkgs, serverInfo, php, ... }:
2
3with lib;
4
5let
6
7 httpd = serverInfo.serverConfig.package;
8
9 version24 = !versionOlder httpd.version "2.4";
10
11 allGranted = if version24 then ''
12 Require all granted
13 '' else ''
14 Order allow,deny
15 Allow from all
16 '';
17
18 mediawikiConfig = pkgs.writeText "LocalSettings.php"
19 ''
20 <?php
21 # Copied verbatim from the default (generated) LocalSettings.php.
22 if( defined( 'MW_INSTALL_PATH' ) ) {
23 $IP = MW_INSTALL_PATH;
24 } else {
25 $IP = dirname( __FILE__ );
26 }
27
28 $path = array( $IP, "$IP/includes", "$IP/languages" );
29 set_include_path( implode( PATH_SEPARATOR, $path ) . PATH_SEPARATOR . get_include_path() );
30
31 require_once( "$IP/includes/DefaultSettings.php" );
32
33 if ( $wgCommandLineMode ) {
34 if ( isset( $_SERVER ) && array_key_exists( 'REQUEST_METHOD', $_SERVER ) ) {
35 die( "This script must be run from the command line\n" );
36 }
37 }
38
39 $wgScriptPath = "${config.urlPrefix}";
40
41 # We probably need to set $wgSecretKey and $wgCacheEpoch.
42
43 # Paths to external programs.
44 $wgDiff3 = "${pkgs.diffutils}/bin/diff3";
45 $wgDiff = "${pkgs.diffutils}/bin/diff";
46 $wgImageMagickConvertCommand = "${pkgs.imagemagick.out}/bin/convert";
47
48 #$wgDebugLogFile = "/tmp/mediawiki_debug_log.txt";
49
50 # Database configuration.
51 $wgDBtype = "${config.dbType}";
52 $wgDBserver = "${config.dbServer}";
53 $wgDBuser = "${config.dbUser}";
54 $wgDBpassword = "${config.dbPassword}";
55 $wgDBname = "${config.dbName}";
56
57 # E-mail.
58 $wgEmergencyContact = "${config.emergencyContact}";
59 $wgPasswordSender = "${config.passwordSender}";
60
61 $wgSitename = "${config.siteName}";
62
63 ${optionalString (config.logo != "") ''
64 $wgLogo = "${config.logo}";
65 ''}
66
67 ${optionalString (config.articleUrlPrefix != "") ''
68 $wgArticlePath = "${config.articleUrlPrefix}/$1";
69 ''}
70
71 ${optionalString config.enableUploads ''
72 $wgEnableUploads = true;
73 $wgUploadDirectory = "${config.uploadDir}";
74 ''}
75
76 ${optionalString (config.defaultSkin != "") ''
77 $wgDefaultSkin = "${config.defaultSkin}";
78 ''}
79
80 ${config.extraConfig}
81 ?>
82 '';
83
84 # Unpack Mediawiki and put the config file in its root directory.
85 mediawikiRoot = pkgs.stdenv.mkDerivation rec {
86 name= "mediawiki-1.23.13";
87
88 src = pkgs.fetchurl {
89 url = "http://download.wikimedia.org/mediawiki/1.23/${name}.tar.gz";
90 sha256 = "168wpf53n4ksj2g5q5r0hxapx6238dvsfng5ff9ixk6axsn0j5d0";
91 };
92
93 skins = config.skins;
94
95 buildPhase =
96 ''
97 for skin in $skins; do
98 cp -prvd $skin/* skins/
99 done
100 ''; # */
101
102 installPhase =
103 ''
104 mkdir -p $out
105 cp -r * $out
106 cp ${mediawikiConfig} $out/LocalSettings.php
107 sed -i \
108 -e 's|/bin/bash|${pkgs.bash}/bin/bash|g' \
109 -e 's|/usr/bin/timeout|${pkgs.coreutils}/bin/timeout|g' \
110 $out/includes/limit.sh \
111 $out/includes/GlobalFunctions.php
112 '';
113 };
114
115 mediawikiScripts = pkgs.runCommand "mediawiki-${config.id}-scripts"
116 { buildInputs = [ pkgs.makeWrapper ]; }
117 ''
118 mkdir -p $out/bin
119 for i in changePassword.php createAndPromote.php userOptions.php edit.php nukePage.php update.php; do
120 makeWrapper ${php}/bin/php $out/bin/mediawiki-${config.id}-$(basename $i .php) \
121 --add-flags ${mediawikiRoot}/maintenance/$i
122 done
123 '';
124
125in
126
127{
128
129 extraConfig =
130 ''
131 ${optionalString config.enableUploads ''
132 Alias ${config.urlPrefix}/images ${config.uploadDir}
133
134 <Directory ${config.uploadDir}>
135 ${allGranted}
136 Options -Indexes
137 </Directory>
138 ''}
139
140 ${if config.urlPrefix != "" then "Alias ${config.urlPrefix} ${mediawikiRoot}" else ''
141 RewriteEngine On
142 RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-f
143 RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-d
144 ${concatMapStringsSep "\n" (u: "RewriteCond %{REQUEST_URI} !^${u.urlPath}") serverInfo.vhostConfig.servedDirs}
145 ${concatMapStringsSep "\n" (u: "RewriteCond %{REQUEST_URI} !^${u.urlPath}") serverInfo.vhostConfig.servedFiles}
146 RewriteRule ${if config.enableUploads
147 then "!^/images"
148 else "^.*\$"
149 } %{DOCUMENT_ROOT}/${if config.articleUrlPrefix == ""
150 then ""
151 else "${config.articleUrlPrefix}/"
152 }index.php [L]
153 ''}
154
155 <Directory ${mediawikiRoot}>
156 ${allGranted}
157 DirectoryIndex index.php
158 </Directory>
159
160 ${optionalString (config.articleUrlPrefix != "") ''
161 Alias ${config.articleUrlPrefix} ${mediawikiRoot}/index.php
162 ''}
163 '';
164
165 documentRoot = if config.urlPrefix == "" then mediawikiRoot else null;
166
167 enablePHP = true;
168
169 options = {
170
171 id = mkOption {
172 default = "main";
173 description = ''
174 A unique identifier necessary to keep multiple MediaWiki server
175 instances on the same machine apart. This is used to
176 disambiguate the administrative scripts, which get names like
177 mediawiki-$id-change-password.
178 '';
179 };
180
181 dbType = mkOption {
182 default = "postgres";
183 example = "mysql";
184 description = "Database type.";
185 };
186
187 dbName = mkOption {
188 default = "mediawiki";
189 description = "Name of the database that holds the MediaWiki data.";
190 };
191
192 dbServer = mkOption {
193 default = ""; # use a Unix domain socket
194 example = "10.0.2.2";
195 description = ''
196 The location of the database server. Leave empty to use a
197 database server running on the same machine through a Unix
198 domain socket.
199 '';
200 };
201
202 dbUser = mkOption {
203 default = "mediawiki";
204 description = "The user name for accessing the database.";
205 };
206
207 dbPassword = mkOption {
208 default = "";
209 example = "foobar";
210 description = ''
211 The password of the database user. Warning: this is stored in
212 cleartext in the Nix store!
213 '';
214 };
215
216 emergencyContact = mkOption {
217 default = serverInfo.serverConfig.adminAddr;
218 example = "admin@example.com";
219 description = ''
220 Emergency contact e-mail address. Defaults to the Apache
221 admin address.
222 '';
223 };
224
225 passwordSender = mkOption {
226 default = serverInfo.serverConfig.adminAddr;
227 example = "password@example.com";
228 description = ''
229 E-mail address from which password confirmations originate.
230 Defaults to the Apache admin address.
231 '';
232 };
233
234 siteName = mkOption {
235 default = "MediaWiki";
236 example = "Foobar Wiki";
237 description = "Name of the wiki";
238 };
239
240 logo = mkOption {
241 default = "";
242 example = "/images/logo.png";
243 description = "The URL of the site's logo (which should be a 135x135px image).";
244 };
245
246 urlPrefix = mkOption {
247 default = "/w";
248 description = ''
249 The URL prefix under which the Mediawiki service appears.
250 '';
251 };
252
253 articleUrlPrefix = mkOption {
254 default = "/wiki";
255 example = "";
256 description = ''
257 The URL prefix under which article pages appear,
258 e.g. http://server/wiki/Page. Leave empty to use the main URL
259 prefix, e.g. http://server/w/index.php?title=Page.
260 '';
261 };
262
263 enableUploads = mkOption {
264 default = false;
265 description = "Whether to enable file uploads.";
266 };
267
268 uploadDir = mkOption {
269 default = throw "You must specify `uploadDir'.";
270 example = "/data/mediawiki-upload";
271 description = "The directory that stores uploaded files.";
272 };
273
274 defaultSkin = mkOption {
275 default = "";
276 example = "nostalgia";
277 description = "Set this value to change the default skin used by MediaWiki.";
278 };
279
280 skins = mkOption {
281 default = [];
282 type = types.listOf types.path;
283 description =
284 ''
285 List of paths whose content is copied to the ‘skins’
286 subdirectory of the MediaWiki installation.
287 '';
288 };
289
290 extraConfig = mkOption {
291 default = "";
292 example =
293 ''
294 $wgEnableEmail = false;
295 '';
296 description = ''
297 Any additional text to be appended to MediaWiki's
298 configuration file. This is a PHP script. For configuration
299 settings, see <link xlink:href='http://www.mediawiki.org/wiki/Manual:Configuration_settings'/>.
300 '';
301 };
302
303 };
304
305 extraPath = [ mediawikiScripts ];
306
307 # !!! Need to specify that Apache has a dependency on PostgreSQL!
308
309 startupScript = pkgs.writeScript "mediawiki_startup.sh"
310 # Initialise the database automagically if we're using a Postgres
311 # server on localhost.
312 (optionalString (config.dbType == "postgres" && config.dbServer == "") ''
313 if ! ${pkgs.postgresql}/bin/psql -l | grep -q ' ${config.dbName} ' ; then
314 ${pkgs.postgresql}/bin/createuser --no-superuser --no-createdb --no-createrole "${config.dbUser}" || true
315 ${pkgs.postgresql}/bin/createdb "${config.dbName}" -O "${config.dbUser}"
316 ( echo 'CREATE LANGUAGE plpgsql;'
317 cat ${mediawikiRoot}/maintenance/postgres/tables.sql
318 echo 'CREATE TEXT SEARCH CONFIGURATION public.default ( COPY = pg_catalog.english );'
319 echo COMMIT
320 ) | ${pkgs.postgresql}/bin/psql -U "${config.dbUser}" "${config.dbName}"
321 fi
322 ${php}/bin/php ${mediawikiRoot}/maintenance/update.php
323 '');
324
325 robotsEntries = optionalString (config.articleUrlPrefix != "")
326 ''
327 User-agent: *
328 Disallow: ${config.urlPrefix}/
329 Disallow: ${config.articleUrlPrefix}/Special:Search
330 Disallow: ${config.articleUrlPrefix}/Special:Random
331 '';
332
333}