Kumu technical about

From Help With Kumu Wiki

Jump to: navigation, search

Information about how the Kumu wiki server works at a technical level, focusing on modifications or new code created at Brock University to support Brock University's use of Media-wiki-based wikis.

Brock University's kumu wiki server was designed to allow members of the Brock University request wikis that are based on the popular Mediawiki software that powers Wikipedia. Requests are promptly processed by members of the CPI and a wiki is created through a web-based workflow. Here are basics of how the kumu wiki server works.

As of 2013, the system needs an update to accommodate wholly new versions of Mediawiki (rather than current patched legacy version) , but here are the basics.

Contents

[edit] How Wikis Are Served

There are currently over 400 wikis. This corresponds to over 400 databases, but only one copy of the Mediawiki software.

When a request is submitted for a wiki one of the Kumu Wiki Settings that requesters are asked for is a URL/namespace (which is automatically created, but can be modified by the requester). In the Apache web server configuration an alias is entered between the URL/namespace and the Media wiki source.

Data path from user visiting a page (right) to wiki content stored in the database (left)
Data path from user visiting a page (right) to wiki content stored in the database (left)

When a visitor to the wiki accesses a wiki page/article the alias directs the Apache server to load the Mediawiki application based on the unique URL but reading the Mediawiki PHP files from a common location. The Mediawiki localsettings.php file does not contain the conventional configuration settings, instead it contains an include to a common configuration file and a common collection of function.

Two of the included functions are:

  1. get_local_wiki() - parses the URL to get the namespace for the wiki
  2. setup_wiki($namespace) - takes the namespace and looks up the settings and sets the global variables that would normally be found in localsettings.php
    • This function also uses get_wiki_config_by_namespace ($local_namespace) to get the settings for that wiki before it can apply them

The settings loaded by setup_wiki() includes those outlined in Kumu Wiki Settings and things like the database name, which matches the namespace.

[edit] How Wikis Are Created

Members of the Brock University community can request wikis at https://kumu.brocku.ca/request/ . Requesters are asked to input information (outlined in Kumu Wiki Settings).

A recent development has been the ability to request a number of wikis en mass, using the Kumu Wiki Settings submitted and then asking for a multiple of wikis created with the same settings and sequential naming. This is to allow for a number private groups to collaborate in a wiki that will likely be shared after the work is done - a use never anticipated when the system was created for more public or whole-class collaboration.

Once submitted, the request comes to the attention of the CPI.

If the request can be approved the approval processes automates the following:

  • Adding an alias to the Mediawiki source based on the namespace/URL
  • Committing the Kumu Wiki Settings to table (that can later be modified)
  • Creating the unique database and copying the basic contents from an SQL export of a source database
  • "Injecting" the requester into the wiki
  • Notifying the requester

[edit] Other Modifications

  • Creation/approval workflow
  • A custom report page on wiki activity, intended as a crude measure for those evaluating an academic wiki to start from
  • A custom IP banning system that makes use of Stop Forum Spam's database to block spambots and facilities for reporting
  • A common list of spam terms
  • Apache config/custom PHP to ensure SSL is on when passwords are sent (considering 100% SSL solution)
  • Brock University CAMPUS ID-based authentication
  • The ability to allow requesters to modify Kumu Wiki Settings and to allow a delegate to do the same
  • The ability to "inject" users by hand or from a CSV file - for creating groups
  • Logging of modifications made to settings, etc.
  • Virus scanning
  • Select Mediawiki estensions have been installed, such as YouTube integration, code highlighting and easy citing
  • PHP:APC and other caching tools
  • We have LTI-based listing of Wikis you are a member in, but single authentication is not yet implemented.

[edit] Custom PHP

[edit] $local_namespace = get_local_wiki()

<source lang="php"> <?PHP function get_local_wiki ($url = 'REQUEST_URI') { if {} //Sanitization, CLI related logic and APC caching.... else { if ($url == 'REQUEST_URI') $url = $_SERVER["REQUEST_URI"]; $a = explode('/',$url); $local_namespace = $a[1]; } } return $local_namespace; } ?> </source>

[edit] get_wiki_config_by_namespace ($local_namespace)

<source lang="php"> <?PHP

function get_wiki_config_by_namespace ($local_namespace) {

// $return Loaded from APC cache

if (empty($return)) {

global $connect; if (!isset($connect)){ global $wgDBuser, $wgDBpassword, $wgDBserver; $connect = mysql_connect($wgDBserver, $wgDBuser, $wgDBpassword); }

// $sql = ; //Omited, just incase $result = mysql_query($sql) or die(mysql_error());

if (mysql_num_rows($result) > 0) {

$info = mysql_fetch_assoc($result);

//Return info $return = array(); if ($info['uploads'] == 2) $return['uploads'] = false; else $return['uploads'] = true; if (strlen($info['skin']) > 1) $return['skin'] = $info['skin']; else $return['skin'] = 'monobook'; if (strlen($info['wgLogo']) > 1) $return['wgLogo'] = $info['wgLogo']; else $return['wgLogo'] = '/common/images/defaultBrockWiki_logo.jpg';

if (intval($info['lock']) == 1) $return['lock'] = true; else $return['lock'] = false; //needs to be updated for dates

$return['wgDBname'] = $info['wgDBname']; $return['access'] = $info['access']; $return['accounts'] = $info['accounts']; $return['license'] = $info['license']; $return['language'] = $info['language']; $return['wgSitename'] = $info['wgSitename']; $return['license'] = $info['license']; $return['contact'] = $info['contact']; $return['other'] = $info['other']; $return['takedown'] = $info['takedown']; $return['wgVersion'] = $info['wgVersion'];

} else { //No Wiki, but we didn't get a 404, so there must have been a wiki.... $title = "$local_namespace no longer active";

header('HTTP/1.1 403 Forbidden'); $html = html_head_start($title,true); $html .= html_head_stop(true); $html .= html_body_start(,$title,true);

$html .= '

[edit] The wiki you are looking for is no longer active.

';

$list = @apc_fetch('kumu:front_page_list'); //Do we have this in our APC cache? $number_of_wikis = @apc_fetch('kumu:number_of_wikis');

if (!empty($list)) $html .="

Here is a list of the $number_of_wikis other wikis on this server:

$list";

$html .= html_body_stop(true); die($html); } }

return $return; } ?> </source>

[edit] setup_wiki($local_namespace)

<source lang="php"> <?PHP


function setup_wiki ($local_namespace) { //Settigs global $wgSitename, $wgEnableUploads, $wgLanguageCode, $wgDefaultSkin, $wgLogo, $wgEmergencyContact, $special_extensions; //Rights global $wgEnableCreativeCommonsRdf, $wgRightsPage, $wgRightsUrl, $wgRightsText, $wgRightsIcon, $wgRightsCode; //Permisions global $wgGroupPermissions, $wgEnableEmail,$wgEmailConfirmToEdit,$wgAutoConfirmAge; //Authenication global $wgAuth; //Needed vars global $secureScriptPathBase, $dir; //Index control global $wgOut;

$kumu = get_wiki_config_by_namespace($local_namespace);

$wgSitename = $kumu['wgSitename']; $wgEnableUploads = $kumu['uploads']; $wgLanguageCode = $kumu['language']; $wgDefaultSkin = $kumu['skin']; $wgLogo = $kumu['wgLogo']; $wgEmergencyContact = $kumu['contact']; $wgEnableEmail = true;

if ($kumu['takedown'] == 2){ //$wgOut->setRobotPolicy('noindex,nofollow'); $GLOBALS['noindex'] = true; //Checked by the file /var/www/html/common/skins/kumu_head.php //Next to implement <meta name="robots" content="noindex, nofollow" /> and <meta name="robots" content="noarchive" /> }

switch ($kumu['license']) { case "GNU": ## For attaching licensing metadata to pages, and displaying an ## appropriate copyright notice / icon. GNU Free Documentation ## License and Creative Commons licenses are supported so far. $wgEnableCreativeCommonsRdf = true; $wgRightsPage = ""; # Set to the title of a wiki page that describes your license/copyright $wgRightsUrl = "http://www.gnu.org/copyleft/fdl.html"; $wgRightsText = "GNU Free Documentation License 1.2"; $wgRightsIcon = "/common/images/gnu-fdl.png"; $wgRightsCode = "gfdl"; # Not yet used break; case "CC": ## For attaching licensing metadata to pages, and displaying an ## appropriate copyright notice / icon. Creative Commons. $wgEnableCreativeCommonsRdf = true; $wgRightsPage = ""; # Set to the title of a wiki page that describes your license/copyright $wgRightsUrl = "http://creativecommons.org/licenses/by-sa/2.5/ca/"; $wgRightsText = "Attribution-Share Alike 2.5 Canada"; //$wgRightsIcon = "/common/images/somerights20.png"; $wgRightsIcon = '/common/images/cc-wiki.png'; $wgRightsCode = "cc"; # Not yet used break; default: ## For attaching licensing metadata to pages, and displaying an ## appropriate copyright notice / icon. Brock Guidelines for intellectual ## property as outlined in the faculty handbook and course calendar is ## the default, but GNU Free Documentation License and the Creative Commons ## are options. $wgEnableCreativeCommonsRdf = false; $wgRightsPage = ""; # Set to the title of a wiki page that describes your license/copyright $wgRightsUrl = "http://kumu.brocku.ca/rights/"; $wgRightsText = "Brock: Brock Guidelines for intellectual property as outlined in the faculty handbook and course calendar"; $wgRightsIcon = "/request/images/BrockUniversityLicense.gif"; $wgRightsCode = "bu"; }

## Disable Anonymous editing ## As per: http://www.mediawiki.org/wiki/Manual:Preventing_access#Restrict_anonymous_editing switch ($kumu['access']) { case 1: //Account-to-Edit if(!isset($wgGroupPermissions)) $wgGroupPermissions = array(); $wgGroupPermissions['*']['edit'] = false; $wgGroupPermissions['user']['edit'] = true; $wgGroupPermissions['sysop']['edit'] = true;

//Changed Wednesday November 7, 2012 $wgGroupPermissions['autoconfirmed']['createpage'] = true; $wgAutoConfirmAge = 60; $wgEmailConfirmToEdit = true;

break; case 2: //Semi-Secure if(!isset($wgGroupPermissions)) $wgGroupPermissions = array(); $wgGroupPermissions['*']['edit'] = false; $wgGroupPermissions['*']['read'] = false; $wgGroupPermissions['user']['read'] = true; $wgGroupPermissions['sysop']['read'] = true; $wgGroupPermissions['user']['edit'] = true; $wgGroupPermissions['sysop']['edit'] = true; $wgEmailConfirmToEdit = true; break; case 3: //Very secure/Magic Password if(!isset($wgGroupPermissions)) $wgGroupPermissions = array(); $wgCookieSecure = true; //If it's protected by a password then it should not be a spam target. global $wgSpamRegex,$wgBlockOpenProxies,$maxlinks; $wgSpamRegex = ; $maxlinks = 100; $wgBlockOpenProxies = false;

if ($_SERVER['SERVER_PORT'] != '443') { //What Wiki are we? $a = explode('/',$_SERVER["REQUEST_URI"]); $local_namespace = $a[1]; header('LOCATION: '.$secureScriptPathBase.$a[1]); die('This page should be viewed in HTTPS mode. Please alert the administrator.'); } break; }


## Disable Anonymous editing ## As per: http://www.mediawiki.org/wiki/Manual:Preventing_access#Restrict_anonymous_editing switch ($kumu['accounts']) { case 'email': //Account-to-Edit

break; case 'portal': //Semi-Secure require_once($dir['extensions']."AuthBrock.php"); $wgGroupPermissions['*']['createaccount'] = false; global $wgAuth; $wgAuth = new Auth_Brock(); break; case 'portal-email': //Very secure/Magic Password if (@$_GET['type'] !='signup') { //Allow for local account creation require_once($dir['extensions']."AuthBrock.php"); global $wgAuth; $wgAuth = new Auth_Brock(); }

break; }

//make sure login and logout pages are visible $wgWhitelistRead = array( "Special:Userlogout", "Special:Userlogin" );

//Lock if ($kumu['lock'] == true){ if(!isset($wgGroupPermissions)) $wgGroupPermissions = array(); # Prevent new user registrations and edits $wgGroupPermissions['*']['createaccount'] = false; $wgGroupPermissions['*']['edit'] = false; $wgGroupPermissions['user']['edit'] = false; $wgGroupPermissions['sysop']['edit'] = false; $wgGroupPermissions['user' ]['move'] = false; $wgGroupPermissions['user' ]['edit'] = false; $wgGroupPermissions['user' ]['createpage'] = false; $wgGroupPermissions['user' ]['createtalk'] = false; $wgGroupPermissions['user' ]['upload'] = false; $wgGroupPermissions['user' ]['reupload'] = false; $wgGroupPermissions['user' ]['reupload-shared'] = false; $wgGroupPermissions['user' ]['minoredit'] = false; $wgGroupPermissions['user' ]['purge'] = false; $wgGroupPermissions['user' ]['read'] = true; $wgReadOnly = ( 'This site is locked' );

$wgEnableEmail = false;

global $wgNoFollowLinks; $wgNoFollowLinks = false; //Can't be posted to, so let's share some link-love updateLocalSiteNotice('This Wiki is currently "locked". At this time no edits or non-Brock accounts can be created.',true); }

if (strlen($kumu['other']) >= 1 && $kumu['other'] != 'legacy'){ //Is the other feild set? $others = explode('|',$kumu['other']); if (in_array('errors',$others)) {error_reporting(6143);} elseif (in_array('stale',$others)) updateLocalSiteNotice('This site has been marked as stale and may be removed soon if no updates are made.',true); if (in_array('noNewAccounts',$others)) { //Block new accounts

global $wgGroupPermissions, $wgNoFollowLinks,$authBrockSettings; if(!isset($wgGroupPermissions)) $wgGroupPermissions = array(); $wgGroupPermissions['*']['createaccount'] = false; $wgNoFollowLinks = false; //Can't be posted to, so let's share some link-love

//Our Brock Auth CAMPUS ID authentication will accept anyone who comes back with a good password, unless.... if (!isset($authBrockSettings)) $authBrockSettings = array(); $authBrockSettings['createaccount'] = false; $authBrockSettings['local_namespace'] = $local_namespace; } if (in_array('linkLove',$others)) { global $wgNoFollowLinks; $wgNoFollowLinks = false; //Share some link-love } if (in_array('noSpam',$others)) { //Remove all spam checking global $wgSpamRegex,$wgBlockOpenProxies,$maxlinks; $wgBlockOpenProxies = false; $wgSpamRegex = ; $maxlinks = 100; } if (in_array('siteMessage',$others)) { foreach ($others as $value ) { if (strpos($value,'iteMessage=') > 0) updateLocalSiteNotice(substr($value,12,strlen($value)),true); } } if (in_array('maxLinks',$others)) { global $maxlinks, $wgExtensionCredits; foreach ($others as $value ) { if (strpos($value,'axLinks=') > 0) $maxlinks = substr($value,9,strlen($value)); } $wgExtensionCredits['other'][] = array( 'name' => 'LinkLogger, overridden', 'description' => 'The maximum number of links per-edit is '.$maxlinks.' which has been requested by this Wiki\'s sysop.' , 'author' => 'Matt Clare', 'url' => 'http://kumu.brocku.ca/banned.php' ); } if (in_array('externalImages',$others)) { // Whether to allow inline image pointing to other websites, security issues! global $wgAllowExternalImages; $wgAllowExternalImages = true; } if (in_array('boiler',$others)) { require_once($dir['extensions'].'Boilerplate/boilerplate.php'); global $wgBoilerPlateAry; $wgBoilerPlateAry = array('Sandbox' => 'Boilerplate'); } if (in_array('noPrefil',$others)) { global $wgHooks; unset($wgHooks['EditFormPreloadText']); } if (in_array('HideRevision',$others)) { if(!isset($wgGroupPermissions)) $wgGroupPermissions = array(); require_once($dir['extensions']."/Oversight/HideRevision.php"); $wgGroupPermissions['oversight']['hiderevision'] = true; $wgGroupPermissions['oversight']['oversight'] = true; } if (in_array('script',$others)) { local_php_sctipt($local_namespace); } }


}


?> </source>

[edit] Data Structure

We maintain a standard MediaWiki database for all wikis which are all accessed by the same MySQL user. We also maintain a table of settings for each wiki, which get_wiki_config_by_namespace() fetches.

<source lang="mysql">

CREATE TABLE IF NOT EXISTS `wiki_local_config` (

 `wid` int(100) NOT NULL default '0',
 `modified` timestamp NOT NULL default CURRENT_TIMESTAMP,
 `wgSitename` tinytext NOT NULL,
 `namespace` tinytext NOT NULL,
 `wgMetaNamespace` tinytext NOT NULL,
 `wgDBname` tinytext NOT NULL,
 `access` int(1) NOT NULL default '0',
 `accounts` tinytext NOT NULL,
 `license` tinytext NOT NULL,
 `language` tinytext NOT NULL,
 `lock` tinyint(255) NOT NULL default '0',
 `takedown` int(1) NOT NULL default '0',
 `other` text NOT NULL,
 `uploads` int(1) NOT NULL default '0',
 `skin` tinytext NOT NULL,
 `wgLogo` tinytext NOT NULL,
 `contact` tinytext NOT NULL,
 `wgVersion` varchar(32) NOT NULL,
 PRIMARY KEY  (`wid`)

) ENGINE=MyISAM DEFAULT CHARSET=latin1; </source>

Personal tools
Bookmark and Share