Merge branch 'branch_2.3' of ssh://shish@marigold.shishnet.org/home/shish/git/shimmie2 into branch_2.3

This commit is contained in:
Shish 2009-07-22 22:09:28 +01:00
commit 88c7233ced
39 changed files with 340 additions and 280 deletions

@ -1,5 +1,5 @@
<?php
class DowntimeTest extends ShimmieWebTestCase {
class DowntimeTest extends SCoreWebTestCase {
function testDowntime() {
$this->log_in_as_admin();
$this->get_page("setup");

@ -1,7 +1,7 @@
<?php
class DowntimeTheme Extends Themelet {
/*
/**
* Show the admin that downtime mode is enabled
*/
public function display_notification(Page $page) {
@ -9,7 +9,7 @@ class DowntimeTheme Extends Themelet {
"<span style='font-size: 1.5em'><b>DOWNTIME MODE IS ON!</b></span>", "left", 0));
}
/*
/**
* Display $message and exit
*/
public function display_message($message) {

@ -1,5 +1,5 @@
<?php
class IPBanTest extends ShimmieWebTestCase {
class IPBanTest extends SCoreWebTestCase {
function testIPBan() {
$this->get_page('ip_ban/list');
$this->assertResponse(403);

@ -1,5 +1,5 @@
<?php
class NewsTest extends ShimmieWebTestCase {
class NewsTest extends SCoreWebTestCase {
function testNews() {
$this->log_in_as_admin();

@ -1,5 +1,5 @@
<?php
class PMTest extends ShimmieWebTestCase {
class PMTest extends SCoreWebTestCase {
function testPM() {
$this->log_in_as_admin();
$this->get_page("user/test");

@ -19,14 +19,10 @@
* <code>/random_image/download/size:1024x768+cute</code>
*/
class RandomImage implements Extension {
var $theme;
public function receive_event(Event $event) {
class RandomImage extends SimpleExtension {
public function onPageRequest($event) {
global $config, $database, $page, $user;
if(is_null($this->theme)) $this->theme = get_theme_object($this);
if(($event instanceof PageRequestEvent) && $event->page_matches("random_image")) {
if($event->page_matches("random_image")) {
if($event->count_args() == 1) {
$action = $event->get_arg(0);
$search_terms = array();
@ -50,22 +46,22 @@ class RandomImage implements Extension {
}
}
}
}
if(($event instanceof SetupBuildingEvent)) {
$sb = new SetupBlock("Random Image");
$sb->add_bool_option("show_random_block", "Show Random Block: ");
$event->panel->add_block($sb);
}
public function onSetupBuilding($event) {
$sb = new SetupBlock("Random Image");
$sb->add_bool_option("show_random_block", "Show Random Block: ");
$event->panel->add_block($sb);
}
if($event instanceof PostListBuildingEvent) {
if($config->get_bool("show_random_block")) {
$image = Image::by_random($event->search_terms);
if(!is_null($image)) {
$this->theme->display_random($page, $image);
}
public function onPostListBuilding($event) {
global $config, $page;
if($config->get_bool("show_random_block")) {
$image = Image::by_random($event->search_terms);
if(!is_null($image)) {
$this->theme->display_random($page, $image);
}
}
}
}
add_event_listener(new RandomImage());
?>

@ -6,6 +6,19 @@
* Description: adds unit testing to SCore
*/
/**
* \page unittests Unit Tests
*
* Each extension should (although doesn't technically have to) come with a
* test.php file, for example ext/index/test.php. The SimpleSCoreTest
* extension will look for these files and load any SCoreWebTestCase classes
* it finds inside them, then run them and report whether or not the test
* passes.
*
* For Shimmie2 specific extensions, there is a ShimmieWebTestCase class which
* includes functions to upload and delete images.
*/
require_once('simpletest/web_tester.php');
require_once('simpletest/unit_tester.php');
require_once('simpletest/reporter.php');
@ -15,6 +28,9 @@ define('USER_PASS', "test");
define('ADMIN_NAME', "demo");
define('ADMIN_PASS', "demo");
/**
* A set of common SCore activities to test
*/
class SCoreWebTestCase extends WebTestCase {
protected function get_page($page) {
$url = "http://".$_SERVER["HTTP_HOST"].get_base_href().'/'.make_link($page);
@ -49,6 +65,9 @@ class SCoreWebTestCase extends WebTestCase {
}
}
/**
* A set of common Shimmie activities to test
*/
class ShimmieWebTestCase extends SCoreWebTestCase {
protected function post_image($filename, $tags) {
$image_id = -1;
@ -81,6 +100,7 @@ class ShimmieWebTestCase extends SCoreWebTestCase {
}
}
/** @private */
class TestFinder extends TestSuite {
function TestFinder($hint) {
if(strpos($hint, "..") !== FALSE) return;

@ -2,6 +2,7 @@
class SimpleSCoreTestTheme extends Themelet {
}
/** @private */
class SCoreReporter extends HtmlReporter {
var $current_html = "";
var $clear_modules = array();

@ -8,22 +8,19 @@
* This extension sets the "description" meta tag in the header
* of pages so that search engines can pick it up
*/
class SiteDescription implements Extension {
public function receive_event(Event $event) {
global $config, $database, $page, $user;
if($event instanceof PageRequestEvent) {
if(strlen($config->get_string("site_description")) > 0) {
$description = $config->get_string("site_description");
$page->add_header("<meta name=\"description\" content=\"$description\">");
}
}
if($event instanceof SetupBuildingEvent) {
$sb = new SetupBlock("Site Description");
$sb->add_longtext_option("site_description");
$event->panel->add_block($sb);
class SiteDescription extends SimpleExtension {
public function onPageRequest(PageRequestEvent $event) {
global $config, $page;
if(strlen($config->get_string("site_description")) > 0) {
$description = $config->get_string("site_description");
$page->add_header("<meta name=\"description\" content=\"$description\">");
}
}
public function onSetupBuilding(SetupBuildingEvent $event) {
$sb = new SetupBlock("Site Description");
$sb->add_longtext_option("site_description");
$event->panel->add_block($sb);
}
}
add_event_listener(new SiteDescription());
?>

@ -1,5 +1,5 @@
<?php
class SiteDescriptionTest extends ShimmieWebTestCase {
class SiteDescriptionTest extends SCoreWebTestCase {
function testSiteDescription() {
$this->log_in_as_admin();
$this->get_page('setup');

@ -1,5 +1,5 @@
<?php
class WikiTest extends ShimmieWebTestCase {
class WikiTest extends SCoreWebTestCase {
function testWiki() {
$this->log_in_as_admin();
$this->get_page("wiki");

@ -1,6 +1,6 @@
<?php
class WikiTheme {
class WikiTheme extends Themelet {
/*
* Show a page
*

@ -1,43 +0,0 @@
The Highest Level
~~~~~~~~~~~~~~~~~
index.php takes care of loading the globals:
$config -- some variety of Config class
$database -- a class used to get raw SQL access
$page -- a GenericPage object, a data structure which holds all the page parts
$user -- the currently logged in User
then it sends an InitExtEvent and PageRequestEvent, these can each trigger
more events of their own.
Once the chain of events comes to an end, the $page object is passed
to the theme's layout.class.php to be turned into HTML
Events and Extensions
~~~~~~~~~~~~~~~~~~~~~
An event is a little blob of data saying "something happened", possibly
"something happened, here's the specific data". Events are sent with the
send_event() function.
An extension is something which is capable of reacting to events. They
register themselves using the add_event_listener() command. (Although for
subclasses of SimpleExtension, registration is handled automatically).
Themes
~~~~~~
Each extension has a theme with a specific name -- the extension Cake which
is stored in ext/cake/main.php will have a theme called CakeTheme stored in
ext/cake/theme.php. If you want to customise it, create a class in the file
themes/mytheme/cake.theme.php called CustomCakeTheme which extends CakeTheme
and overrides some of its methods.
Generally an extension should only deal with processing data; whenever it
wants to display something, it should pass the $page data structure along
with the data to be displayed to the theme object, and the theme will add
the data into the page.

@ -1,8 +1,4 @@
<?php
/**
* @package SCore
*/
/**
* A basic chunk of a page
*/
@ -10,20 +6,20 @@ class Block {
/**
* The block's title
*
* @var string
* @retval string
*/
var $header;
/**
* The content
*
* @var string
* @retval string
*/
var $body;
/**
* Where the block should be placed. The default theme supports
* "main" and "left", other themes can add their own areas
*
* @var string
* @retval string
*/
var $section;
/**
@ -31,7 +27,7 @@ class Block {
* numbers appear lower. The scale is 0-100 by convention,
* though any number or string will work.
*
* @var int
* @retval int
*/
var $position;

@ -3,17 +3,13 @@
* Functions which are only in some versions of PHP,
* or only implemented on some platforms
*
* @ignore
* @package SCore
* \privatesection
*/
# (PHP 5 >= 5.2.1)
# Based on http://www.phpit.net/
# article/creating-zip-tar-archives-dynamically-php/2/
if(!function_exists('sys_get_temp_dir')) {
/**
* @ignore
*/
function sys_get_temp_dir() {
// Try to get from environment variable
if(!empty($_ENV['TMP'])) {
@ -46,9 +42,6 @@ function sys_get_temp_dir() {
# (PHP >= 5.1)
# from http://www.php.net/inet_pton
if(!function_exists('inet_pton')) {
/**
* @ignore
*/
function inet_pton($ip) {
# ipv4
if(strpos($ip, '.') !== FALSE) {
@ -70,9 +63,6 @@ function inet_pton($ip) {
# (PHP >= 5.1)
# from http://www.php.net/inet_ntop
if(!function_exists('inet_ntop')) {
/**
* @ignore
*/
function inet_ntop($ip) {
if (strlen($ip)==4) {
// ipv4

@ -1,8 +1,4 @@
<?php
/**
* @package SCore
*/
/**
* an abstract interface for altering a name:value pair list
*/
@ -29,8 +25,6 @@ interface Config {
/**
* Common methods for manipulating the list, loading and saving is
* left to the concrete implementation
*
* @ignore
*/
abstract class BaseConfig implements Config {
var $values = array();
@ -106,8 +100,6 @@ abstract class BaseConfig implements Config {
* $config['foo'] = "bar";
* $config['baz'] = "qux";
* ?>
*
* @ignore
*/
class StaticConfig extends BaseConfig {
public function __construct($filename) {
@ -135,12 +127,12 @@ class StaticConfig extends BaseConfig {
* Loads the config list from a table in a given database, the table should
* be called config and have the schema:
*
* \code
* CREATE TABLE config(
* name VARCHAR(255) NOT NULL,
* value TEXT
* );
*
* @ignore
* \endcode
*/
class DatabaseConfig extends BaseConfig {
var $database = null;

@ -1,16 +1,10 @@
<?php
/**
* @package SCore
*/
require_once "compat.inc.php";
$ADODB_CACHE_DIR=sys_get_temp_dir();
require_once "lib/adodb/adodb.inc.php";
require_once "lib/adodb/adodb-exceptions.inc.php";
/**#@+
* @ignore
*/
/** @privatesection */
// Querylet {{{
class Querylet {
var $sql;
@ -202,7 +196,7 @@ class MemCache implements CacheEngine {
public function get_misses() {return $this->misses;}
}
// }}}
/**#@-*/
/** @publicsection */
/**
* A class for controlled database access

@ -1,8 +1,4 @@
<?php
/**
* @package SCore
*/
/**
* Generic parent class for all events.
*
@ -14,7 +10,9 @@ abstract class Event {
/**
* A wake-up call for extensions
* A wake-up call for extensions. Upon recieving an InitExtEvent an extension
* should check that it's database tables are there and install them if not,
* and set any defaults with Config::set_default_int() and such.
*/
class InitExtEvent extends Event {}
@ -111,28 +109,28 @@ class LogEvent extends Event {
/**
* a category, normally the extension name
*
* @var string
* @retval string
*/
var $section;
/**
* See python...
*
* @var int
* @retval int
*/
var $priority = 0;
/**
* Free text to be logged
*
* @var text
* @retval text
*/
var $message;
/**
* The time that the event was created
*
* @var int
* @retval int
*/
var $time;

@ -1,8 +1,4 @@
<?php
/**
* @package SCore
*/
/**
* A base exception to be caught by the upper levels
*/

@ -1,6 +1,65 @@
<?php
/**
* @package SCore
* \page eande Events and Extensions
*
* An event is a little blob of data saying "something happened", possibly
* "something happened, here's the specific data". Events are sent with the
* send_event() function. Since events can store data, they can be used to
* return data to the extension which sent them, for example:
*
* \code
* $tfe = new TextFormattingEvent($original_text);
* send_event($tfe);
* $formatted_text = $tfe->formatted;
* \endcode
*
* An extension is something which is capable of reacting to events. They
* register themselves using the add_event_listener() function, after which
* events will be sent to the object's recieve_event() function.
*
* SimpleExtension subclasses are slightly different -- they are registered
* automatically, and events are sent to a named method, eg PageRequestEvent
* will be sent to onPageRequest()
*
*
* \page hello The Hello World Extension
*
* \code
* // ext/hello/main.php
* public class Hello extends SimpleExtension {
* public void onPageRequest(PageRequestEvent $event) {
* global $page, $user;
* $this->theme->display_hello($page, $user);
* }
* }
*
* // ext/hello/theme.php
* public class HelloTheme extends Themelet {
* public void display_hello(Page $page, User $user) {
* $page->add_block(new Block("Hello!", "Hello there ".html_escape($user->name));
* }
* }
*
* // ext/hello/test.php
* public class HelloTest extends ShimmieWebTestCase {
* public void testHello() {
* $this->get_page("post/list");
* $this->assertText("Hello there");
* }
* }
*
* // themes/mytheme/hello.theme.php
* public class CustomHelloTheme extends HelloTheme {
* public function display_hello(Page $page, User $user) {
* $h_user = html_escape($user->name);
* $page->add_block(new Block(
* "Hello!",
* "Hello there $h_user, look at my snazzy custom theme!"
* );
* }
* }
* \endcode
*
*/
/**
@ -19,7 +78,7 @@ interface Extension {
* priority, so no need for register_extension(new Foo())
*
* Hopefully this removes as much copy & paste code from the extension
* files as possible \o/
* files as possible~
*
* The original concept came from Artanis's SimpleExtension extension
* --> http://github.com/Artanis/simple-extension/tree/master

@ -2,8 +2,21 @@
/**
* All the imageboard-specific bits of code should be in this file, everything
* else in /core should be standard SCore bits.
*
* @package SCore
*/
/**
* \page search Shimmie2: Searching
*
* The current search system is built of several search item -> image ID list
* translators, eg:
*
* \li the item "fred" will search the image_tags table to find image IDs with the fred tag
* \li the item "size=640x480" will search the images table to find image IDs of 640x480 images
*
* So the search "fred size=640x480" will calculate two lists and take the
* intersection. (There are some optimisations in there making it more
* complicated behind the scenes, but as long as you can turn a single word
* into a list of image IDs, making a search plugin should be simple)
*/
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
@ -42,7 +55,7 @@ class Image {
/**
* Find an image by ID
*
* @var Image
* @retval Image
*/
public static function by_id($id) {
assert(is_numeric($id));
@ -55,7 +68,7 @@ class Image {
/**
* Find an image by hash
*
* @var Image
* @retval Image
*/
public static function by_hash($hash) {
assert(is_string($hash));
@ -68,7 +81,7 @@ class Image {
/**
* Pick a random image out of a set
*
* @var Image
* @retval Image
*/
public static function by_random($tags=array()) {
assert(is_array($tags));
@ -145,7 +158,7 @@ class Image {
* Rather than simply $this_id + 1, one must take into account
* deleted images and search queries
*
* @var Image
* @retval Image
*/
public function get_next($tags=array(), $next=true) {
assert(is_array($tags));
@ -177,7 +190,7 @@ class Image {
/**
* The reverse of get_next
*
* @var Image
* @retval Image
*/
public function get_prev($tags=array()) {
return $this->get_next($tags, false);
@ -186,7 +199,7 @@ class Image {
/**
* Find the User who owns this Image
*
* @var User
* @retval User
*/
public function get_owner() {
return User::by_id($this->owner_id);
@ -223,7 +236,7 @@ class Image {
/**
* Get the URL for the full size image
*
* @var string
* @retval string
*/
public function get_image_link() {
global $config;
@ -242,7 +255,7 @@ class Image {
* Get a short link to the full size image
*
* @deprecated
* @var string
* @retval string
*/
public function get_short_link() {
global $config;
@ -252,7 +265,7 @@ class Image {
/**
* Get the URL for the thumbnail
*
* @var string
* @retval string
*/
public function get_thumb_link() {
global $config;
@ -271,7 +284,7 @@ class Image {
* Get the tooltip for this image, formatted according to the
* configured template
*
* @var string
* @retval string
*/
public function get_tooltip() {
global $config;
@ -281,7 +294,7 @@ class Image {
/**
* Figure out where the full size image is on disk
*
* @var string
* @retval string
*/
public function get_image_filename() {
$hash = $this->hash;
@ -293,7 +306,7 @@ class Image {
/**
* Figure out where the thumbnail is on disk
*
* @var string
* @retval string
*/
public function get_thumb_filename() {
$hash = $this->hash;
@ -304,7 +317,7 @@ class Image {
/**
* Get the original filename
*
* @var string
* @retval string
*/
public function get_filename() {
return $this->filename;
@ -315,7 +328,7 @@ class Image {
*
* FIXME: now we handle more than just images
*
* @var string
* @retval string
*/
public function get_mime_type() {
return "image/".($this->ext);
@ -324,7 +337,7 @@ class Image {
/**
* Get the image's filename extension
*
* @var string
* @retval string
*/
public function get_ext() {
return $this->ext;
@ -333,7 +346,7 @@ class Image {
/**
* Get the image's source URL
*
* @var string
* @retval string
*/
public function get_source() {
return $this->source;
@ -418,9 +431,9 @@ class Image {
}
/**
* ...?
* Someone please explain this
*
* @var string
* @retval string
*/
public function parse_link_template($tmpl, $_escape="url_escape") {
global $config;

@ -1,15 +1,39 @@
<?php
/**
* @package SCore
* \page themes Themes
*
* Each extension has a theme with a specific name -- eg. the extension Setup
* which is stored in ext/setup/main.php will have a theme called SetupTheme
* stored in ext/setup/theme.php. If you want to customise it, create a class
* in the file themes/mytheme/setup.theme.php called CustomSetupTheme which
* extends SetupTheme and overrides some of its methods.
*
* Generally an extension should only deal with processing data; whenever it
* wants to display something, it should pass the $page data structure along
* with the data to be displayed to the theme object, and the theme will add
* the data into the page.
*
* A page should make sure that all the data it outputs is free from dangerous
* data by using html_escape(), url_escape(), or int_escape() as appropriate.
*
* Because some HTML can be placed anywhere according to the theme, coming up
* with the correct way to link to a page can be hard -- thus we have the
* make_link() function, which will take a path like "post/list" and turn it
* into a full and correct link, eg /myboard/post/list, /foo/index.php?q=post/list,
* etc depending on how things are set up. This should always be used to link
* to pages rather than hardcoding a path.
*
* Various other common functions are available as part of the Themelet class.
*/
/**
* A data structure for holding all the bits of data that make up a page.
*
* The various extensions all add whatever they want to this structure,
* then layout.class.php turns it into HTML
* then Layout turns it into HTML
*/
class GenericPage {
class Page {
var $mode = "page";
var $type = "text/html";

@ -1,11 +1,5 @@
<?php
/**
* @package SCore
*/
/**
* @ignore
*/
/** @private */
function _new_user($row) {
return new User($row);
}
@ -94,7 +88,7 @@ class User {
/**
* Test if this user is anonymous (not logged in)
*
* @var bool
* @retval bool
*/
public function is_anonymous() {
global $config;
@ -104,7 +98,7 @@ class User {
/**
* Test if this user is an administrator
*
* @var bool
* @retval bool
*/
public function is_admin() {
return $this->admin;

@ -1,9 +1,4 @@
<?php
/**
* @package SCore
*/
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
* Input / Output Sanitising *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
@ -11,7 +6,7 @@
/**
* Make some data safe for printing into HTML
*
* @var string
* @retval string
*/
function html_escape($input) {
return htmlentities($input, ENT_QUOTES, "UTF-8");
@ -20,7 +15,7 @@ function html_escape($input) {
/**
* Make sure some data is safe to be used in integer context
*
* @var int
* @retval int
*/
function int_escape($input) {
return (int)$input;
@ -29,7 +24,7 @@ function int_escape($input) {
/**
* Make sure some data is safe to be used in URL context
*
* @var string
* @retval string
*/
function url_escape($input) {
$input = str_replace('^', '^^', $input);
@ -41,7 +36,7 @@ function url_escape($input) {
/**
* Make sure some data is safe to be used in SQL context
*
* @var string
* @retval string
*/
function sql_escape($input) {
global $database;
@ -51,7 +46,7 @@ function sql_escape($input) {
/**
* Turn a human readable filesize into an integer, eg 1KB -> 1024
*
* @var int
* @retval int
*/
function parse_shorthand_int($limit) {
if(is_numeric($limit)) {
@ -77,7 +72,7 @@ function parse_shorthand_int($limit) {
/**
* Turn an integer into a human readable filesize, eg 1024 -> 1KB
*
* @var string
* @retval string
*/
function to_shorthand_int($int) {
if($int >= pow(1024, 3)) {
@ -103,7 +98,7 @@ function to_shorthand_int($int) {
* Figure out the correct way to link to a page, taking into account
* things like the nice URLs setting
*
* @var string
* @retval string
*/
function make_link($page=null, $query=null) {
global $config;
@ -132,6 +127,10 @@ function make_link($page=null, $query=null) {
}
}
/**
* Make a link to a static file in the current theme's
* directory
*/
function theme_file($filepath) {
global $config;
$theme = $config->get_string("theme","default");
@ -144,21 +143,21 @@ function theme_file($filepath) {
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
* @ignore
* @private
*/
function version_check() {
function _version_check() {
if(version_compare(PHP_VERSION, "5.0.0") == -1) {
print <<<EOD
print "
Currently SCore Engine doesn't support versions of PHP lower than 5.0.0 --
PHP4 and earlier are officially dead according to their creators,
please tell your host to upgrade.
EOD;
";
exit;
}
}
/**
* @ignore
* @private
*/
function check_cli() {
if(isset($_SERVER['REMOTE_ADDR'])) {
@ -171,7 +170,7 @@ function check_cli() {
/**
* $db is the connection object
*
* @ignore
* @private
*/
function _count_execs($db, $sql, $inputarray) {
global $_execs;
@ -213,9 +212,9 @@ function get_theme_object(Extension $class, $fatal=true) {
/**
* Compare two Block objects, used to sort them before being displayed
*
* @var int
* @retval int
*/
function blockcmp($a, $b) {
function blockcmp(Block $a, Block $b) {
if($a->position == $b->position) {
return 0;
}
@ -227,7 +226,7 @@ function blockcmp($a, $b) {
/**
* Figure out PHP's internal memory limit
*
* @var int
* @retval int
*/
function get_memory_limit() {
global $config;
@ -257,7 +256,7 @@ function get_memory_limit() {
* Get the currently active IP, masked to make it not change when the last
* octet or two change, for use in session cookies and such
*
* @var string
* @retval string
*/
function get_session_ip($config) {
$mask = $config->get_string("session_hash_mask", "255.255.0.0");
@ -271,7 +270,7 @@ function get_session_ip($config) {
*
* PHP really, really sucks.
*
* @var string
* @retval string
*/
function get_base_href() {
$possible_vars = array('SCRIPT_NAME', 'PHP_SELF', 'PATH_INFO', 'ORIG_PATH_INFO');
@ -292,7 +291,7 @@ function get_base_href() {
* A shorthand way to send a TextFormattingEvent and get the
* results
*
* @var string
* @retval string
*/
function format_text($string) {
$tfe = new TextFormattingEvent($string);
@ -312,10 +311,16 @@ if(!defined("LOG_INFO")) define("LOG_INFO", 20);
if(!defined("LOG_DEBUG")) define("LOG_DEBUG", 10);
if(!defined("LOG_NOTSET")) define("LOG_NOTSET", 0);
/**
* A shorthand way to send a LogEvent
*/
function log_msg($section, $priority, $message) {
send_event(new LogEvent($section, $priority, $message));
}
/**
* A shorthand way to send a LogEvent
*/
function log_info($section, $message) {
log_msg($section, LOG_INFO, $message);
}
@ -328,7 +333,7 @@ function log_info($section, $message) {
/**
* Remove an item from an array
*
* @var array
* @retval array
*/
function array_remove($array, $to_remove) {
$array = array_unique($array);
@ -344,7 +349,7 @@ function array_remove($array, $to_remove) {
/**
* Add an item to an array
*
* @var array
* @retval array
*/
function array_add($array, $element) {
$array[] = $element;
@ -355,7 +360,7 @@ function array_add($array, $element) {
/**
* Return the unique elements of an array, case insensitively
*
* @var array
* @retval array
*/
function array_iunique($array) {
$ok = array();
@ -378,7 +383,7 @@ function array_iunique($array) {
*
* from http://uk.php.net/network
*
* @var bool
* @retval bool
*/
function ip_in_range($IP, $CIDR) {
list ($net, $mask) = split ("/", $CIDR);
@ -446,33 +451,7 @@ function full_copy($source, $target) {
}
/**
* @ignore
*/
function stripslashes_r($arr) {
return is_array($arr) ? array_map('stripslashes_r', $arr) : stripslashes($arr);
}
/**
* @ignore
*/
function sanitise_environment() {
if(DEBUG) {
error_reporting(E_ALL);
assert_options(ASSERT_ACTIVE, 1);
assert_options(ASSERT_BAIL, 1);
}
ob_start();
if(get_magic_quotes_gpc()) {
$_GET = stripslashes_r($_GET);
$_POST = stripslashes_r($_POST);
$_COOKIE = stripslashes_r($_COOKIE);
}
}
/**
* @ignore
* @private
*/
function weighted_random($weights) {
$total = 0;
@ -493,9 +472,7 @@ function weighted_random($weights) {
* Event API *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
* @ignore
*/
/** @private */
$_event_listeners = array();
/**
@ -509,9 +486,7 @@ function add_event_listener(Extension $extension, $pos=50) {
$_event_listeners[$pos] = $extension;
}
/**
* @ignore
*/
/** @private */
$_event_count = 0;
/**
@ -605,13 +580,33 @@ function print_GET() {
* Request initialisation stuff *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/** @privatesection */
function _stripslashes_r($arr) {
return is_array($arr) ? array_map('stripslashes_r', $arr) : stripslashes($arr);
}
function _sanitise_environment() {
if(DEBUG) {
error_reporting(E_ALL);
assert_options(ASSERT_ACTIVE, 1);
assert_options(ASSERT_BAIL, 1);
}
ob_start();
if(get_magic_quotes_gpc()) {
$_GET = _stripslashes_r($_GET);
$_POST = _stripslashes_r($_POST);
$_COOKIE = _stripslashes_r($_COOKIE);
}
}
/**
* Turn ^^ into ^ and ^s into /
*
* Necessary because various servers and various clients
* think that / is special...
*
* @ignore
*/
function _decaret($str) {
$out = "";
@ -628,9 +623,6 @@ function _decaret($str) {
return $out;
}
/**
* @ignore
*/
function _get_query_parts() {
if(isset($_GET["q"])) {
$path = $_GET["q"];
@ -660,9 +652,6 @@ function _get_query_parts() {
}
}
/**
* @ignore
*/
function _get_page_request() {
global $config;
$args = _get_query_parts();
@ -674,9 +663,6 @@ function _get_page_request() {
return new PageRequestEvent($args);
}
/**
* @ignore
*/
function _get_user() {
global $config, $database;
$user = null;

@ -1,6 +1,5 @@
<?php
/* AdminBuildingEvent {{{
*
/**
* Sent when the admin page is ready to be added to
*/
class AdminBuildingEvent extends Event {
@ -9,7 +8,6 @@ class AdminBuildingEvent extends Event {
$this->page = $page;
}
}
// }}}
class AdminPage implements Extension {
var $theme;

@ -7,7 +7,8 @@
* Description: A thing for point & click extension management
*/
class ExtensionInfo { // {{{
/** @private */
class ExtensionInfo {
var $ext_name, $name, $link, $author, $email, $description, $documentation, $version;
function ExtensionInfo($main) {
@ -66,7 +67,7 @@ class ExtensionInfo { // {{{
private function is_enabled($fname) {
return file_exists("ext/$fname");
}
} // }}}
}
class ExtManager extends SimpleExtension {
public function onPageRequest($event) {

@ -1,5 +1,5 @@
<?php
class ExtManagerTest extends ShimmieWebTestCase {
class ExtManagerTest extends SCoreWebTestCase {
function testAuth() {
$this->get_page('ext_manager');
$this->assertResponse(403);

@ -1,5 +1,5 @@
<?php
class Handle404Test extends ShimmieWebTestCase {
class Handle404Test extends SCoreWebTestCase {
function test404Handler() {
$this->get_page('not/a/page');
$this->assertResponse(404);

@ -1,5 +1,5 @@
<?php
class SetupTest extends ShimmieWebTestCase {
class SetupTest extends SCoreWebTestCase {
function testAuth() {
$this->get_page('setup');
$this->assertResponse(403);

@ -1,5 +1,5 @@
<?php
class UserPageTest extends ShimmieWebTestCase {
class UserPageTest extends SCoreWebTestCase {
function testUserPage() {
$this->get_page('user');
$this->assertTitle("Not Logged In");

@ -1,4 +1,55 @@
<?php
/**
* \mainpage Shimmie2 / SCore Documentation
*
* SCore is a framework designed for writing flexible, extendable applications.
* Whereas most PHP apps are built monolithicly, score's event-based nature
* allows parts to be mixed and matched. For instance, the most famous
* collection of score extensions is the Shimmie image board, which includes
* user management, a wiki, a private messaging system, etc. But one could
* easily remove the image board bits and simply have a wiki with users and
* PMs; or one could replace it with a blog module; or one could have a blog
* which links to images on an image board, with no wiki or messaging, and so
* on and so on...
*
* To learn about the innards of SCore, start with the \ref overview.
*
*
* \page overview High Level Overview
*
* Dijkstra will kill me for personifying my architecture, but I can't think
* of a better way without going into all the little details.
*
* There are a bunch of Extension subclasses, they talk to eachother by sending
* and recieving Event subclasses. The topic of conversation is decided by the
* initial PageRequestEvent, and each extension puts its notes into the shared
* Page data store. Once the conversation is over, the Page is passed to the
* current theme's Layout class which will tidy up the data and present it to
* the user.
*
* To learn more about the architecture:
*
* \li \ref eande
* \li \ref themes
*
* To learn more about practical development:
*
* \li \ref scglobals
* \li \ref unittests
* \li \ref hello
*
* \page scglobals SCore Globals
*
* There are four global variables which are pretty essential to most extensions:
*
* \li $config -- some variety of Config subclass
* \li $database -- a Database object used to get raw SQL access
* \li $page -- a Page to holds all the loose bits of extension output
* \li $user -- the currently logged in User
*
* Each of these can be imported at the start of a function with eg "global $page, $user;"
*/
// set up and purify the environment
define("DEBUG", true);
define("SCORE_VERSION", 's2hack');
@ -10,8 +61,8 @@ if(!file_exists("config.php")) {
}
require_once "core/util.inc.php";
version_check();
sanitise_environment();
_version_check();
_sanitise_environment();
try {
@ -31,7 +82,7 @@ try {
// load the theme parts
$_theme = $config->get_string("theme", "default");
if(!file_exists("themes/$_theme")) $_theme = "default";
require_once "themes/$_theme/page.class.php";
if(file_exists("themes/$_theme/custompage.class.php")) require_once "themes/$_theme/custompage.class.php";
require_once "themes/$_theme/layout.class.php";
require_once "themes/$_theme/themelet.class.php";
@ -63,7 +114,7 @@ try {
// start the page generation waterfall
$page = new Page();
$page = class_exists("CustomPage") ? new CustomPage() : new Page();
$user = _get_user($config, $database);
send_event(new InitExtEvent());
send_event(_get_page_request());

@ -1,6 +1,6 @@
<?php
class Page extends GenericPage {
class CustomPage extends Page {
var $left_enabled = true;
public function disable_left() {
$this->left_enabled = false;

@ -1,7 +1,12 @@
<?php
/**
* A class to turn a Page data structure into a blob of HTML
*/
class Layout {
function display_page($page) {
/**
* turns the Page into HTML
*/
public function display_page(Page $page) {
global $config;
$theme_name = $config->get_string('theme', 'default');
@ -71,7 +76,10 @@ $header_html
EOD;
}
function block_to_html($block, $hidable=false, $salt="") {
/**
* A handy function which does exactly what it says in the method name
*/
private function block_to_html($block, $hidable=false, $salt="") {
$h = $block->header;
$b = $block->body;
$html = "";

@ -1,6 +0,0 @@
<?php
class Page extends GenericPage {
// no changes from default
}
?>

@ -1,6 +1,11 @@
<?php
/**
* A customised version of the Setup theme
*/
class CustomSetupTheme extends SetupTheme {
/**
* Turn a SetupBlock into HTML... with rounded corners.
*/
protected function sb_to_html(SetupBlock $block) {
return "
<div class='rr setupblock'>

@ -1,5 +1,7 @@
<?php
/**
* A collection of common functions for theme parts
*/
class Themelet {
/**
* Generic error message display

@ -1,6 +1,6 @@
<?php
class Page extends GenericPage {
class CustomPage extends Page {
var $left_enabled = true;
public function disable_left() {
$this->left_enabled = false;

@ -1,6 +0,0 @@
<?php
class Page extends GenericPage {
// no changes from default
}
?>

@ -1,6 +0,0 @@
<?php
class Page extends GenericPage {
// no changes from default
}
?>