Converted homepage to use SihnonFramework and updated content
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
# Eclipse project
|
||||
.buildpath
|
||||
.project
|
||||
.settings
|
||||
@@ -1,38 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* MySQL Authentication Module
|
||||
*
|
||||
*/
|
||||
|
||||
class Authenticator_mysql implements IAuthenticator {
|
||||
|
||||
public function __construct() {
|
||||
}
|
||||
|
||||
public function initialise() {
|
||||
// Nothing required
|
||||
}
|
||||
|
||||
public function uninitialise() {
|
||||
// Nothing required
|
||||
}
|
||||
|
||||
public function user_exists( $username ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function authenticate( $username, $password ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function username2fullname( $username ) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public function fullname2username( $fullname ) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
};
|
||||
|
||||
?>
|
||||
@@ -1,103 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Configuration
|
||||
* This file contains all global configuration variables
|
||||
*/
|
||||
|
||||
$_config = array();
|
||||
|
||||
// DEBUG MODE
|
||||
// This config variable triggers verbose error output, which is useful for developers, but
|
||||
// would be ugly or bad practice to show to users. Enable this variable on development systems
|
||||
// and disable it for a production system.
|
||||
$_config['DEBUG'] = true;
|
||||
error_reporting( E_ALL | E_NOTICE | E_STRICT );
|
||||
|
||||
// Current timezone settings
|
||||
date_default_timezone_set('Europe/London');
|
||||
|
||||
require_once('request_handler.php');
|
||||
require_once("functions.php");
|
||||
require_once("exceptions.php");
|
||||
require_once("session_handler.php");
|
||||
|
||||
|
||||
// Variable used for passing information around the script,
|
||||
// Should not be used by the user
|
||||
$_meta = array( 'base-dir' => get_web_base_dir(),
|
||||
'script-dir' => get_fs_base_dir(),
|
||||
'error-code' => 403,
|
||||
'error-message' => 'Unknown Error');
|
||||
// Placeholder for template fragments
|
||||
$_template = array( 'messages' => array(),
|
||||
'redirect-to' => false,
|
||||
'head' => '',
|
||||
'title' => 'Default',
|
||||
'page' => '');
|
||||
// Forward declarations
|
||||
$_session = null;
|
||||
|
||||
// Templating
|
||||
$_config['template-file'] = "{$_meta['script-dir']}/templates/default.php";
|
||||
|
||||
// Homepage
|
||||
$_config['homepage'] = "{$_meta['script-dir']}/page-sources/home.php";
|
||||
|
||||
// Sessions
|
||||
// How long a logged in session will last without activity from the user
|
||||
$_config['session-login-timeout'] = 60*60*1; // One hour
|
||||
// How long the username will be stoed in the users cookie
|
||||
$_config['session-username-timeout'] = 60*60*24*7; // Seven days
|
||||
|
||||
// See session-handler.php for reasons behind the session-network-* config variables
|
||||
// session-network-mask is used to determine how much of the users IP is hashed into the salt
|
||||
$_config['session-network-mask'] = 24;
|
||||
// session-network-mode defines whether the above parameter was passed as a CIDR form, or dotted decimal form
|
||||
$_config['session-network-mode'] = MASK_CIDR;
|
||||
|
||||
// Maximum number of items to keep in the users session history
|
||||
$_config['max-history'] = 5;
|
||||
|
||||
// Account Lockout
|
||||
// How many incorrect authentication attempts before the user is locked out
|
||||
$_config['lockout-attempts'] = 3;
|
||||
// How long the account lockout period lasts. During this time, the user will not
|
||||
// be able to authenticate, even witha valid passwords
|
||||
$_config['lockout-duration'] = 60*10; // Ten minutes
|
||||
|
||||
|
||||
// Authantication
|
||||
require_once( "{$_meta['script-dir']}/code/iauthenticator.php" );
|
||||
$_config['authentication-module'] = 'mysql';
|
||||
|
||||
// Database
|
||||
// Mysql connections parameters
|
||||
$_config['db'] = null;
|
||||
$_config['mysql'] = array();
|
||||
$_config['mysql']['host'] = 'localhost';
|
||||
$_config['mysql']['port'] = 3306;
|
||||
$_config['mysql']['username'] = '';
|
||||
$_config['mysql']['password'] = '';
|
||||
$_config['mysql']['database'] = '';
|
||||
|
||||
// Database tables
|
||||
$_config['mysql']['prefix'] = '';
|
||||
|
||||
// Connecting to the database
|
||||
$_db = null;
|
||||
require_once( "{$_meta['script-dir']}/code/db_mysql.php" );
|
||||
|
||||
// Only show php error messages if the application is in debug mode
|
||||
if( isset($_GET['nodebug']) ) $_config['DEBUG'] = false;
|
||||
if( !$_config['DEBUG'] ) {
|
||||
set_error_handler( "null_error_handler" );
|
||||
set_exception_handler( "null_exception_handler" );
|
||||
}
|
||||
|
||||
// Set the default template for all individual pages
|
||||
$_template['template-file'] = $_config['template-file'];
|
||||
|
||||
|
||||
|
||||
?>
|
||||
@@ -1,21 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* MySQL Database wrappper
|
||||
*
|
||||
*/
|
||||
|
||||
if( $_config['db'] == 'mysql' ) {
|
||||
|
||||
// Egress checking, make sure everyting we need is available
|
||||
if( !class_exists( 'mysqli' ) ) throw new ConfigException('Missing required PHP Extension "mysqli".');
|
||||
if( !is_array( $_config['mysql'] ) ) throw new ConfigException('Missing configuration data: mysql');
|
||||
|
||||
// Connect to the database using the config variables provided in _config
|
||||
$_db = new mysqli( $_config['mysql']['host'], $_config['mysql']['username'], $_config['mysql']['password'], $_config['mysql']['database'], $_config['mysql']['port'] );
|
||||
if( mysqli_connect_errno() ){
|
||||
throw new ConfigException('Cannot connect to the mysql database');
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,41 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Exceptions
|
||||
*
|
||||
*/
|
||||
|
||||
class BaseException extends Exception {
|
||||
|
||||
// Overridden constuctor with message and code parameters, which will optionally display error output
|
||||
public function __construct( $message = '', $code = 0) {
|
||||
global $_config;
|
||||
|
||||
parent::__construct( $message, $code );
|
||||
// If debug mode is on, print out the raw data
|
||||
if( $_config['DEBUG'] ) {
|
||||
echo get_class($this) . ": Code='{$code}', Message='{$message}'<br />\n";
|
||||
echo '<pre>';print_r($this->getTrace());echo '</pre>';
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
class FatalException extends BaseException {
|
||||
// Overridden constructor prints an error message, then terminates the application
|
||||
public function __construct( $message = '', $code = 0 ) {
|
||||
parent::__construct( $message, $code );
|
||||
die( 'FATAL EXCEPTION: ' . $message );
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class ConfigException extends BaseException {};
|
||||
class SessionException extends BaseException {};
|
||||
class AccountLockoutException extends BaseException {};
|
||||
class AuthenticationException extends BaseException {};
|
||||
class ParameterException extends BaseException {};
|
||||
class NotImplementedException extends BaseException {};
|
||||
|
||||
?>
|
||||
@@ -1,78 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Utility Functions
|
||||
*
|
||||
*/
|
||||
|
||||
define("MASK_DOTTED_DECIMAL", 1);
|
||||
define("MASK_CIDR", 2);
|
||||
|
||||
// Override the default error handler to prevent error messages being shown to the user
|
||||
function null_error_handler( $errno, $errstr, $errfile, $errline, $errcontext ) {
|
||||
switch( $errono ) {
|
||||
case E_ERROR:
|
||||
case E_CORE_ERROR:
|
||||
case E_COMPILE_ERROR:
|
||||
case E_USER_ERROR:
|
||||
case E_RECOVERABLE_ERROR: {
|
||||
// Fatal error, cause the page to fail here
|
||||
header("HTTP/1.1 500 Internal Server Error");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
default: {
|
||||
// non fatal error, let it pass
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Override the default exception handler to prevent error messages being shown to the user
|
||||
function null_exception_handler( $exception ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
function get_web_base_dir() {
|
||||
static $Dir;
|
||||
if (!isset($Dir))
|
||||
$Dir = dirname($_SERVER['SCRIPT_NAME']);
|
||||
// Doesnt cope well with being at the site root
|
||||
if ($Dir == "/") $Dir = "";
|
||||
return $Dir;
|
||||
}
|
||||
function get_fs_base_dir() {
|
||||
static $Dir;
|
||||
if (!isset($Dir))
|
||||
$Dir = dirname($_SERVER['SCRIPT_FILENAME']);
|
||||
return $Dir;
|
||||
}
|
||||
|
||||
function get_network_mask( $ip, $subnet, $mode = MASK_DOTTED_DECIMAL ) {
|
||||
$ip_l = ip2long( $ip );
|
||||
if( $mode == MASK_DOTTED_DECIMAL )
|
||||
// 255.255.255.0 type subnet
|
||||
$subnet_l = ip2long( $subnet );
|
||||
else
|
||||
// CIDR type subnet
|
||||
$subnet_l = (~0) << (32 - $subnet);
|
||||
|
||||
// Mask the two together
|
||||
$network_l = $ip_l & $subnet_l;
|
||||
|
||||
return long2ip($network_l);
|
||||
}
|
||||
|
||||
function array_clone( &$source, &$dest ) {
|
||||
foreach( $source as $key => $value ) {
|
||||
$dest[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
function print_rating_graph( $star_rating ) {
|
||||
global $_meta;
|
||||
?>
|
||||
<img class="foreground" src="<?php echo $_meta['base-dir']; ?>/resources/ratings/<?php echo $star_rating; ?>" alt="Rated: <?php echo $star_rating; ?>" />
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
@@ -1,60 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* IAuthenticator
|
||||
* Interface for authentication classes
|
||||
*/
|
||||
|
||||
interface IAuthenticator {
|
||||
|
||||
// Do any module-specific initialisation
|
||||
public function initialise();
|
||||
// Shutdown the module cleanly when finished
|
||||
public function uninitialise();
|
||||
|
||||
// Identifies whether a user with a given name exists
|
||||
public function user_exists( $username );
|
||||
// Checks a given username and password
|
||||
public function authenticate( $username, $password );
|
||||
|
||||
// Does translation between a username and full name
|
||||
public function username2fullname( $username );
|
||||
// And vice versa
|
||||
public function fullname2username( $fullname );
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
* IAuthenticatorFactory
|
||||
* Creates an instance of an Authenticator module, given its name
|
||||
*/
|
||||
class IAuthenticatorFactory {
|
||||
|
||||
// Prevent any instances of this class being constructed
|
||||
private function __construct() {
|
||||
|
||||
}
|
||||
|
||||
public static function get( $module ) {
|
||||
global $_meta;
|
||||
|
||||
// Get the filename and classnames for this module
|
||||
$filename = "{$_meta['script-dir']}/code/auth_{$module}.php";
|
||||
$classname = "Authenticator_{$module}";
|
||||
|
||||
// Check to make sure this module exists
|
||||
if( !file_exists($filename) ) throw new ConfigException("Authentication module could not be found: '{$filename}.'", 500);
|
||||
|
||||
// Import the auth modules code
|
||||
require_once( $filename );
|
||||
|
||||
// Ensure the class has been defined
|
||||
if( !class_exists( $classname ) ) throw new ConfigException("Authentication module is invalid: '{$classname}'.", 500);
|
||||
|
||||
// Create an instance of the module, and return it
|
||||
return new $classname();
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
?>
|
||||
@@ -1,58 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* IAuthorisor
|
||||
* Interfakce for authorisation classes
|
||||
*/
|
||||
|
||||
interface IAuthorisor {
|
||||
|
||||
// Do any module-specific initialisation
|
||||
public function initialise();
|
||||
// Shutdown the module cleanly when finished
|
||||
public function uninitialise();
|
||||
|
||||
// Find out which usergroup a given member belongs
|
||||
public function is_student( $username, $module, $year = null );
|
||||
public function is_lecturer( $username, $module, $year = null );
|
||||
public function is_sysadmin( $username );
|
||||
// A sysadmin should not be able to administrate a course for which they are a student
|
||||
public function may_sysadmin( $username, $module, $year = null );
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* IAuthorisor
|
||||
* Interface for authorisation classes
|
||||
*/
|
||||
|
||||
class IAuthorisorFactory {
|
||||
|
||||
public function __construct() {
|
||||
|
||||
}
|
||||
|
||||
public static function get( $module ) {
|
||||
global $_meta;
|
||||
|
||||
// Get the filename and classnames for this module
|
||||
$filename = "{$_meta['script-dir']}/code/auth_{$module}.php";
|
||||
$classname = "Authorisor_{$module}";
|
||||
|
||||
// Check to make sure this module exists
|
||||
if( !file_exists($filename) ) throw new ConfigException("Authorisation module could not be found: '{$filename}.'", 500);
|
||||
|
||||
// Import the auth modules code
|
||||
require_once( $filename );
|
||||
|
||||
// Ensure the class has been defined
|
||||
if( !class_exists( $classname ) ) throw new ConfigException("Authorisation module is invalid: '{$classname}'.", 500);
|
||||
|
||||
// Create an instance of the module, and return it
|
||||
return new $classname();
|
||||
}
|
||||
};
|
||||
|
||||
?>
|
||||
@@ -1,71 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* RequestHandler
|
||||
* This class decodes the Request URI in order to store multiple variables in the request URI itself
|
||||
*/
|
||||
|
||||
class RequestHandler {
|
||||
|
||||
// The request uri
|
||||
private $request_string;
|
||||
// Stores a list of all the variables we've already found to avoid needing to
|
||||
// find them using regular expressions many times.
|
||||
private $cache;
|
||||
|
||||
public function __construct( $request_string ) {
|
||||
$this->request_string = $request_string;
|
||||
$this->cache = array();
|
||||
}
|
||||
|
||||
public function current_page() {
|
||||
return $this->request_string;
|
||||
}
|
||||
|
||||
public function get( $key, $value_pattern = '[^/]*' ) {
|
||||
// Look in the cache to see if weve already decoded this variable
|
||||
if( in_array( $key, $this->cache ) ) return $this->cache[ $key ];
|
||||
|
||||
// Construct the regex to search for /$key/$value/ pairs, and return the $value part
|
||||
$key = str_replace('£', '\£', $key);
|
||||
$value_pattern = str_replace('£', '\£', $value_pattern);
|
||||
$pattern = "£/{$key}/({$value_pattern})(/|\$)£";
|
||||
|
||||
// Look to see if this variable is in the request string
|
||||
$count = preg_match( $pattern, $this->request_string, $matches );
|
||||
|
||||
// See if the variable was set
|
||||
if( $count == 0 ) return null;
|
||||
|
||||
// Store the result for next time
|
||||
$this->cache[ $key ] = $matches[1];
|
||||
|
||||
// And return it to the user
|
||||
return $matches[1];
|
||||
}
|
||||
|
||||
public function construct() {
|
||||
global $_meta;
|
||||
|
||||
// Varargsy
|
||||
$args = func_get_args();
|
||||
|
||||
// Construct the proper request string for these arguments
|
||||
$request_string = "{$_meta['base-dir']}/";
|
||||
$count = count( $args );
|
||||
for( $i = 0 ; $i < $count; $i++ ) {
|
||||
$arg = $args[ $i ];
|
||||
// If this item is null, try to find the value of the previous key from the current
|
||||
// request object as a convenience to the user. It assumes the default value pattern.
|
||||
if( $arg === null && $i > 0) {
|
||||
$arg = $this->get( $args[ $i -1 ] );
|
||||
}
|
||||
$request_string .= urlencode($arg) . '/';
|
||||
}
|
||||
|
||||
return $request_string;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
?>
|
||||
@@ -1,229 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* SessionHandler
|
||||
* This class handles using php sessions to maintain user state across
|
||||
* multiple sessions
|
||||
*/
|
||||
|
||||
class SessionHandler {
|
||||
|
||||
private $authentication;
|
||||
|
||||
public function __construct() {
|
||||
global $_config;
|
||||
|
||||
// Initialise PHP's Session subsystem
|
||||
session_start();
|
||||
|
||||
// Check to see if this is a new session
|
||||
if( !isset( $_SESSION['initialised'] ) || !$_SESSION['initialised'] ) {
|
||||
$this->start_new_session();
|
||||
} else {
|
||||
// The session already exists, check its validity
|
||||
if( $this->is_session_valid() ) {
|
||||
|
||||
} else {
|
||||
// BAD USER SESSION, start a new one
|
||||
$this->start_new_session();
|
||||
// And inform the user
|
||||
$_template['messages'][] = "Bad session, starting a new one";
|
||||
}
|
||||
}
|
||||
|
||||
// Load the Authentication modules
|
||||
$this->authentication = IAuthenticatorFactory::get( $_config['authentication-module'] );
|
||||
$this->authentication->initialise();
|
||||
|
||||
}
|
||||
|
||||
public function __destruct() {
|
||||
// Shut down the authentication modules
|
||||
$this->authentication->uninitialise();
|
||||
}
|
||||
|
||||
/*
|
||||
* Accessors
|
||||
*/
|
||||
public function authenticator() { return $this->authentication; }
|
||||
|
||||
/*
|
||||
* The following methods deal with the user session
|
||||
*/
|
||||
|
||||
// Initialises all the variables we require in each user session
|
||||
public function start_new_session() {
|
||||
global $_config;
|
||||
|
||||
// Set up all the session variables
|
||||
$_SESSION['initialised'] = true;
|
||||
$_SESSION['logged_in'] = false;
|
||||
$_SESSION['username'] = '';
|
||||
$_SESSION['hash'] = $this->generate_hash();
|
||||
$_SESSION['previous_page'] = $_config['homepage'];
|
||||
$_SESSION['requested_page'] = '';
|
||||
$_SESSION['history'] = array('home');
|
||||
$_SESSION['lockout'] = false;
|
||||
$_SESSION['lockout-attempts'] = 0;
|
||||
|
||||
// Be paranoid, change session id
|
||||
$this->auth_state_changed();
|
||||
}
|
||||
|
||||
public function is_session_valid() {
|
||||
// Check that the identifying information given by the user matches that which was
|
||||
// saved in the session when it was created
|
||||
return ($_SESSION['hash'] == $this->generate_hash());
|
||||
}
|
||||
|
||||
/*
|
||||
* This function should be called whenever the authorisation level
|
||||
* changes in order to keep the session secure.
|
||||
* It prevents against Session Fixation (http://www.acros.si/papers/session_fixation.pdf)
|
||||
*/
|
||||
public function auth_state_changed() {
|
||||
session_regenerate_id();
|
||||
}
|
||||
|
||||
/*
|
||||
* This function marks a user as having been logged into the system
|
||||
*/
|
||||
private function mark_logged_in_as( $username ) {
|
||||
$_SESSION['username'] = $username;
|
||||
$_SESSION['logged_in'] = true;
|
||||
|
||||
// The login state has changed
|
||||
$this->auth_state_changed();
|
||||
}
|
||||
|
||||
/*
|
||||
* This function marks a user as having been logged out of the system
|
||||
*/
|
||||
private function mark_logged_out() {
|
||||
$_SESSION['logged_in'] = false;
|
||||
|
||||
// The login state has changedd
|
||||
$this->auth_state_changed();
|
||||
}
|
||||
|
||||
/*
|
||||
* This function returns whether or not the user is logged in
|
||||
*/
|
||||
public function is_logged_in() {
|
||||
return $_SESSION['logged_in'];
|
||||
}
|
||||
|
||||
/*
|
||||
* This function returns the username of the currently logged in user
|
||||
*/
|
||||
public function username() {
|
||||
return $_SESSION['username'];
|
||||
}
|
||||
|
||||
/*
|
||||
* This function requires a user to be logged in, else an exception is thrown
|
||||
*/
|
||||
public function require_logged_in() {
|
||||
if( !$_SESSION['logged_in'] ) throw new AuthenticationException('You must be logged on to view this resource');
|
||||
}
|
||||
|
||||
/*
|
||||
* This function generates a hash from user identifiable information
|
||||
* to try and prevent session theft.
|
||||
* If the session id is stolen by an attacker, chances are some of the
|
||||
* information used to generate the hash will change, and the session
|
||||
* will be immediately marked as invalid. This hash is checked for
|
||||
* consistency on every request.
|
||||
*/
|
||||
public function generate_hash() {
|
||||
global $_config;
|
||||
// Hash together the following pieces of identifying information which remain constant throughout the session:
|
||||
// User Agent string - This will be constant for the user, but might not be for the attacker
|
||||
// Netork Mask - ensures each request is coming from the same network. We may not be able to use the
|
||||
// while ip, because some ISPs use load-balanced proxies, so subsequent requests may come from a
|
||||
// different machine ip, but we can still use at least part of the address to filter out would be attackers.
|
||||
$key = $_SERVER['HTTP_USER_AGENT'] . get_network_mask( $_SERVER['REMOTE_ADDR'], $_config['session-network-mask'], $_config['session-network-mode']);
|
||||
return md5( $key );
|
||||
}
|
||||
|
||||
/*
|
||||
* The following methods deal with the users history
|
||||
* These will be used to set up redirection after special pages, such as login
|
||||
*/
|
||||
|
||||
// Add a new item to the user history
|
||||
public function history_add_request( $page ) {
|
||||
global $_config;
|
||||
// Add this item to the beginning of the history array
|
||||
array_unshift( $_SESSION['history'], $page );
|
||||
// Keep the size below a fixed limit
|
||||
if( count($_SESSION['history']) > $_config['max-history'] ) {
|
||||
array_pop( $_SESSION['history'] );
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the current item from the user history
|
||||
public function history_drop_request() {
|
||||
// remove the item from the beginning of the array
|
||||
array_shift( $_SESSION['history'] );
|
||||
}
|
||||
|
||||
// Return an item from the user history
|
||||
public function history_get( $index ) {
|
||||
if( is_numeric($index) ) {
|
||||
if( $index < count($_SESSION['history']) ) {
|
||||
return $_SESSION['history'][$index];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The following methods deal with user authentication and authorisation
|
||||
*/
|
||||
|
||||
// Log the user in
|
||||
public function login( $username, $password ) {
|
||||
global $_config;
|
||||
|
||||
// Check the user hasnt been locked out before trying to login
|
||||
if( $_SESSION['lockout'] == true ) {
|
||||
// See if the lockout has expired
|
||||
if($_SESSION['lockout-expiry'] > time() ) throw new AccountLockoutException('Your session is currently locked as a result of enterring too many incorrect passwords. You will not be able to attempt a login for another ' . date('i \m\i\n(\s), s \s\e\c(\s)', $_SESSION['lockout-expiry']-time()));
|
||||
else {
|
||||
// Unset the lockout
|
||||
$_SESSION['lockout'] = false;
|
||||
$_SESSION['lockout-expiry'] = 0;
|
||||
$_SESSION['lockout-attempts'] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
// Attempt to authenticate with these credentials
|
||||
$this->authentication->authenticate( $username, $password );
|
||||
} catch( Exception $e ) {
|
||||
// Increment the number of failed authentication attempts
|
||||
$_SESSION['lockout-attempts']++;
|
||||
// Check the lockout attempts
|
||||
if( $_SESSION['lockout-attempts'] >= $_config['lockout-attempts'] ) {
|
||||
$_SESSION['lockout'] = true;
|
||||
$_SESSION['lockout-expiry'] = time() + $_config['lockout-duration'];
|
||||
throw new AccountLockoutException('You have enterred an incorrect password too many times, and your session has been locked. You will not be able to attempt another login for the next 10 minutes.');
|
||||
}
|
||||
|
||||
// The login failed, rethrow the original exception
|
||||
throw $e;
|
||||
}
|
||||
|
||||
// Successful login, update the session state
|
||||
$this->mark_logged_in_as( $username );
|
||||
}
|
||||
|
||||
// Log the current user out
|
||||
public function logout() {
|
||||
$this->mark_logged_out();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
?>
|
||||
@@ -1,115 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* IValidator
|
||||
*
|
||||
*/
|
||||
|
||||
interface IValidator {
|
||||
|
||||
/* Overhead to be called internally by the validator */
|
||||
|
||||
// Called when the class is first loaded
|
||||
public static function initialise();
|
||||
// Called whent the validation engine shuts down
|
||||
public static function shutdown();
|
||||
// Called when a validator object is associated with a variable to be validated
|
||||
public function associate();
|
||||
// Called when a validator obhject is disassociated from a variable having been validated
|
||||
public function disassociate();
|
||||
|
||||
// Validate some input against the constructor parameters
|
||||
public function validate($input);
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
* IValidatorFactory
|
||||
* Creates an instance of an Validator module, given its name
|
||||
*/
|
||||
class IValidatorFactory {
|
||||
|
||||
// Prevent any instances of this class being constructed
|
||||
private function __construct() {
|
||||
|
||||
}
|
||||
|
||||
public static function get( $module ) {
|
||||
global $_meta;
|
||||
|
||||
// Get the filename and classnames for this module
|
||||
$filename = "{$_meta['script-dir']}/code/validation/{$module}_validator.php";
|
||||
$classname = "{$module}Validator";
|
||||
|
||||
// Check to make sure this module exists
|
||||
if( !file_exists($filename) ) throw new ConfigException("Validation module could not be found: '{$filename}.'", 500);
|
||||
|
||||
// Import the auth modules code
|
||||
require_once( $filename );
|
||||
|
||||
// Ensure the class has been defined
|
||||
if( !class_exists( $classname ) ) throw new ConfigException("Validation module is invalid: '{$classname}'.", 500);
|
||||
|
||||
// Create an instance of the module, and return it
|
||||
return new $classname();
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Validator
|
||||
* This class provides validation for a variable using a variety of algorithms
|
||||
*/
|
||||
|
||||
abstract class Validator {
|
||||
|
||||
public static function check($name, &$value) {
|
||||
// Retrieve the varargs for this function
|
||||
$args = func_get_args();
|
||||
// Remove the first two arguments, since we already have those by name
|
||||
array_shift($args); array_shift($args);
|
||||
|
||||
try {
|
||||
// Each of the remaining arguments should be implementations of IValidator
|
||||
foreach ($args as $validator) {
|
||||
// Ensure this object is a validator
|
||||
if (!( $validator instanceof IValidator)) {
|
||||
throw new ValidationException("Invalid Validator object");
|
||||
}
|
||||
|
||||
// Attempt to validate the input through each validator in turn
|
||||
$validator->validate( $value );
|
||||
}
|
||||
|
||||
// All successful
|
||||
|
||||
} catch (ValidationException $e) {
|
||||
// Add the friendly name of the variable that failed validation, and rethrow the exception
|
||||
// for the calling code to catch
|
||||
$e->append_name($name);
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
* Validation Exceptions
|
||||
*/
|
||||
|
||||
class ValidationException extends BaseException {
|
||||
|
||||
public function __construct($message) {
|
||||
parent::__construct($message);
|
||||
}
|
||||
|
||||
public function append_name($name) {
|
||||
$this->e .= ", while validating '{$name}'.";
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
?>
|
||||
@@ -1,40 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
class RangeValidator implements IValidator {
|
||||
|
||||
private $min;
|
||||
private $max;
|
||||
|
||||
public function __construct($min, $max) {
|
||||
|
||||
}
|
||||
|
||||
public static function initialise() {
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
public static function shutdown() {
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
public function associate() {
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
public function disassociate() {
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
public function validate($input) {
|
||||
if( $input < $min || $input > $max )
|
||||
throw new ValidationException("Input is no in the range {$this->min}-{$this->max}");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
?>
|
||||
82
index.php
@@ -1,82 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Index
|
||||
* This page handles all requests, authentication, authorisation, etc.
|
||||
* It loads the page requested by the user, embeds it in the template, and sends it to the browser
|
||||
*/
|
||||
|
||||
// Begin output buffering on the entire document, so we can set cookies
|
||||
// after some output has been printed.
|
||||
ob_start();
|
||||
|
||||
// Include our global configuration.
|
||||
// It will pull all other includes we need, as well as define all global configuration and state variables.
|
||||
require_once('code/config.php');
|
||||
|
||||
// Process the request uri for this page
|
||||
$_req = new RequestHandler( $_SERVER['REQUEST_URI'] );
|
||||
|
||||
try {
|
||||
// We will use PHP sessions to track users of the system.
|
||||
// On their own, php sessions are not secure by default, so we will
|
||||
// do some additional work to ensure they are used correctly.
|
||||
$_session = new SessionHandler();
|
||||
|
||||
// See if the requested page exists
|
||||
$_chroot = realpath("{$_meta['script-dir']}/page-sources/");
|
||||
$_pagename = (!is_null($_req->get('page')) ? strtolower($_req->get('page')) : 'home');
|
||||
$_page = $_chroot . '/' . $_pagename . '.php';
|
||||
|
||||
// Capture this request so we know where the user wanted to go
|
||||
$_session->history_add_request( $_SERVER['REQUEST_URI'] );
|
||||
|
||||
// Check that this path exists
|
||||
$_realpath = realpath($_page);
|
||||
if( $_realpath === false ) throw new Exception('Requested page doesnt exist', 404);
|
||||
|
||||
// Check that the real file exists under the pages directory
|
||||
if( substr($_realpath, 0, strlen($_chroot)) != $_chroot ) throw new Exception('Forbidden', 403);
|
||||
|
||||
|
||||
} catch( Exception $e ) {
|
||||
$_meta['error-code'] = $e->getCode();
|
||||
$_meta['error-message'] = $e->getMessage();
|
||||
$_page = "{$_meta['script-dir']}/page-sources/error.php";
|
||||
}
|
||||
|
||||
// Capture the output and store it in the template
|
||||
ob_start();
|
||||
|
||||
try {
|
||||
include( $_page );
|
||||
} catch( AuthenticationException $e ) {
|
||||
// Redirect to the login page
|
||||
$_template['messages'][] = $e->getMessage();
|
||||
$_page = "{$_meta['script-dir']}/page-sources/login.php";
|
||||
// Get the new page
|
||||
ob_clean();
|
||||
include( $_page );
|
||||
} catch( ParameterException $e ) {
|
||||
// Redirect to the error page
|
||||
$_meta['error-code'] = $e->getCode();
|
||||
$_meta['error-message'] = "Required parameter is either missing, or contains an illegal value: '{$e->getMessage()}'";
|
||||
$_page = "{$_meta['script-dir']}/page-sources/error.php";
|
||||
// Get the new page
|
||||
ob_clean();
|
||||
include( $_page );
|
||||
}
|
||||
|
||||
$_template['page'] = ob_get_contents();
|
||||
|
||||
// Since we've already caught them, prevent the contents from being
|
||||
// passed to the browser
|
||||
ob_end_clean();
|
||||
|
||||
// Get the template
|
||||
include( $_template['template-file'] );
|
||||
|
||||
// Send any remaining output to the browser
|
||||
ob_end_flush();
|
||||
|
||||
?>
|
||||
@@ -1,26 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Third Year Project
|
||||
*
|
||||
*/
|
||||
|
||||
$_template['title'] = "Third Year Project";
|
||||
|
||||
?>
|
||||
<p>
|
||||
I am still working on my project, but in the mean time I have some binaries available for user testing.
|
||||
Please report any bugs you might find to <a href="https://dev.sihnon.net/bugs" title="Sihnon Bug Tracker">my bug tracker</a>.
|
||||
(Note: The <a href="http://www.startcom.org" title="StartCom Certification Authority">provider</a> of my SSL certificates does not yet have their root CA certificate distributed with Internet Explorer or Opera, so if you need to, please add them as a Trusted CA.)
|
||||
</p>
|
||||
<p>
|
||||
These binaries are solely for testing purposes, and may not be redistributed from anywhere other than this site.
|
||||
I am in the process of packaging a source distribution.
|
||||
|
||||
<ul>
|
||||
<li><a href="<?php echo $_meta['base-dir']; ?>/files/rsdss_1.01_i386.deb" title="Ubuntu x86 deb package">rsdss-1.01-i386.deb</a></li>
|
||||
<li><a href="<?php echo $_meta['base-dir']; ?>/files/rsdss-1.0.1-i386.tar.bz2" title="Linux x86 binary archive">rsdss-1.0.1-i386.tar.bz2</a></li>
|
||||
<li><a href="<?php echo $_meta['base-dir']; ?>/files/rsdss-1.0.2-win32.zip" title="Windows 32-bit zip archive">rsdss-1.0.2-win32.zip</a></li>
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
// Hide this page from the users history in the session
|
||||
$_session->history_drop_request();
|
||||
// Display the error message, and redirect
|
||||
$_template['title'] = "Errawr";
|
||||
$_template['messages'][] = $_meta['error-message'];
|
||||
$_template['redirect-to'] = $_session->history_get(0); // Top of the list now
|
||||
|
||||
?>
|
||||
@@ -1,31 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
$_template['title'] = 'Home';
|
||||
|
||||
?>
|
||||
<div>
|
||||
<img class="avatar" style="width: 10em;" src="<?php echo $_meta['base-dir']; ?>/files/portrait.jpg" alt="Photo of Ben Roberts" />
|
||||
<p>
|
||||
I have almost finished the final year of a Master's degree in Computer Science at ECS, University of Southampton, UK and am due to graduate in June 2010.
|
||||
</p>
|
||||
<p>
|
||||
Starting this summer, I will be working for <a href="http://www.uk.atosorigin.com/en-uk/" title="Atos Origin UK homepage">Atos Origin</a> as a <em>Graduate Technical Specialist</em> in the <em>Managed Operations</em> division.
|
||||
</p>
|
||||
<p>
|
||||
I previously worked for <a href="http://www.netcraft.com/" title="Netcraft homepage">Netcraft</a> in Bath, while taking a year out from my degree studies. My roles included developing and running the <a href="http://news.netcraft.com/SSL-survey" title="Netcraft's SSL Server Survey">SSL Server Survey</a>, reviewing <a href="http://audited.netcraft.com/audited" title="Netcraft's Automated Vulnerability Scanning">Automated Vulnerability Scan</a> results, and performing occasional <a href="http://audited.netcraft.com/web-application" title="Netcraft's Application Penetration & Security Testing">penetration tests</a> against web applications for financial institutions.
|
||||
</p>
|
||||
<p>
|
||||
On this site you can find a full copy of my <a href="<?php echo $_meta['base-dir']; ?>/files/BenRobertsCv.pdf" title="Curriculum Vitae">CV</a>,
|
||||
or see what <a href="<?php echo $_req->construct('page','projects'); ?>" title="Projects">projects</a> I have been working on in my spare time.
|
||||
</p>
|
||||
<p>
|
||||
You can contact me via me<img class="at" src="<?php echo $_meta['base-dir']; ?>/resources/at.png" alt="@" />benroberts.net.
|
||||
</p>
|
||||
|
||||
|
||||
</div>
|
||||
@@ -1,59 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Login
|
||||
* This page allows and processes a user login
|
||||
*
|
||||
*/
|
||||
|
||||
$_template['title'] = 'Login';
|
||||
|
||||
// Has the login form been submitted?
|
||||
if( count( $_POST ) > 0 ) {
|
||||
// Hide this request from the user's history
|
||||
$_session->history_drop_request();
|
||||
// Now it wont matter how many times a user fails authentication, they will always be redirected to the
|
||||
// page they requested in the first place
|
||||
|
||||
// Check for the presence of the required form fields
|
||||
if( !isset($_POST['username']) ) throw new ParameterException(); $username = $_POST['username'];
|
||||
|
||||
$password = '';
|
||||
if( isset($_POST['password']) ) $password = $_POST['password'];
|
||||
|
||||
// Attempt the login
|
||||
try {
|
||||
$_session->login( $username, $password );
|
||||
|
||||
// Present a message to the user
|
||||
$_template['messages'][] = 'You have successfully logged in.';
|
||||
|
||||
// Set a redirection to the page the user was originally on (now the top of the list, because we dropped this page)
|
||||
$_template['redirect-to'] = $_session->history_get(0);
|
||||
|
||||
} catch (AuthenticationException $e) {
|
||||
// Authentication failed
|
||||
$_template['messages'][] = 'Authentication failed';
|
||||
_show_login_form();
|
||||
}
|
||||
|
||||
} else {
|
||||
_show_login_form();
|
||||
}
|
||||
|
||||
function _show_login_form() {
|
||||
global $_meta, $_req;
|
||||
|
||||
// Present the login form to the user
|
||||
?>
|
||||
<form method="post" action="<?php echo $_req->construct('page','login'); ?>">
|
||||
<p class="loginform">
|
||||
<input class="username" name="username" type="text" /><label for="username">Username</label><br />
|
||||
<input name="submit" type="submit" value="Login" />
|
||||
</p>
|
||||
</form>
|
||||
<?php
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
@@ -1,17 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
// Log the user our of their current session
|
||||
$_session->logout();
|
||||
|
||||
// Leave the user a notice, and redirect them back to the home page
|
||||
$_template['title'] = 'Logout';
|
||||
$_template['messages'][] = 'You have successfully been logged out.';
|
||||
$_template['redirect-to'] = $_req->construct('page','home');
|
||||
|
||||
|
||||
?>
|
||||
@@ -1,25 +0,0 @@
|
||||
<?php
|
||||
|
||||
$_template['title'] = "Gentoo Portage Overlay";
|
||||
?>
|
||||
<p>
|
||||
The ebuilds in this overlay have mostly been taken from the Gentoo
|
||||
bugzilla, where the packages haven't yet made it into the portage tree. There
|
||||
are also a couple of version-bumped packages, and packages to install my own
|
||||
software on my own machines. Feel free to use these packages, but do so at your
|
||||
own risk.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
You can install this overlay using layman. Add the the
|
||||
<a href="https://dev.sihnon.net/projects/gentoo-overlay/layman.xml" title="Sihnon overlay url">Sihnon overlay url</a>
|
||||
to your overlays variable in <code class="file">/etc/layman/layman.cfg</code>. Then update
|
||||
the list of overlays with <code class="root">layman -L</code> and add the Sihnon overlay
|
||||
with <code class="root">layman -a sihnon</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The contents of the overlay can be browsed in the
|
||||
<a href="https://dev.sihnon.net/websvn/listing.php?repname=gentoo-overlay" title="Sihnon overlay browser">Sihnon overlay browser</a>.
|
||||
</p>
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
$_template['title'] = "Projects";
|
||||
|
||||
?>
|
||||
<h2>Development projects:</h2>
|
||||
<dl>
|
||||
<dt><a href="<?php echo $_req->construct("page", "overlay"); ?>" title="Gentoo Overlay">Gentoo Portage Overlay</a></dt>
|
||||
<dd>Personally developed software, or miscellaneous ebuilds that can't be found in any other overlay.</dd>
|
||||
|
||||
<dt><a href="https://wiki.sihnon.net/" title="Sihnon Wiki">Sihnon Wiki</a></dt>
|
||||
<dd>Documentation for various systems I've configured; mostly for personal reference, but may be useful to others.</dd>
|
||||
|
||||
<dt><a href="https://git.sihnon.net/cgit.cgi/handbrake-cluster.git" title="HandBrakeCluster">HandBrakeCluster</a></dt>
|
||||
<dd>A collection of perl scripts to use HandBrakeCLI to batch rip DVD images using multiple machines.</dd>
|
||||
|
||||
<dt><a href="https://git.sihnon.net/cgit.cgi/handbrake-cluster-webui.git/" title="HandBrakeCluster WebUI">HandBrakeCluster WebUI</a></dt>
|
||||
<dd>An alternative web-based UI for the HandBrakeCluster scripts, written in PHP.</dd>
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
<h2>University projects:</h2>
|
||||
<dl>
|
||||
<dt><a href="<?php echo $_req->construct("page", "3yp"); ?>" title="Third Year Project">Third Year Project</a></dt>
|
||||
<dd>A cross-platform, zero-config file sharing client using public keys and a web of trust for password-less authentication and access control.</dd>
|
||||
</dl>
|
||||
|
||||
4
private/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
# configuration files
|
||||
config.php
|
||||
dbconfig.conf
|
||||
settings.txt
|
||||
92
private/config.php.dist
Normal file
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Sihnon Framework Library path
|
||||
*
|
||||
* Specifies the absolute or relative path to the Sihnon Framework library directory, relative to the webui root directory.
|
||||
* Path must end with a trailing slash.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
define('SihnonFramework_Lib', '/usr/lib/sihnon-php-lib/source/lib/');
|
||||
|
||||
/**
|
||||
* Sihnon Library path
|
||||
*
|
||||
* Specifies the absolute or relative path to the Sihnon library directory, relative to the webui root directory.
|
||||
* Path must end with a trailing slash.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
define('Sihnon_Lib', '/usr/lib/homepage/source/lib/');
|
||||
|
||||
/**
|
||||
* Homepage Library path
|
||||
*
|
||||
* Specifies the absolute or relative path to the Homepage library directory, relative to the webui root directory.
|
||||
* Path must end with a trailing slash.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
define('Homepage_Lib', '/usr/lib/homepage/source/lib/');
|
||||
|
||||
/**
|
||||
* Sihnon Database Support
|
||||
*
|
||||
* Specifies whether or not to include database support in the Framework
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
define('Sihnon_DatabaseSupport', true);
|
||||
|
||||
/**
|
||||
* Sihnon Database Configuration
|
||||
*
|
||||
* Specifies the absolute or relative path to the Sihnon database configuration file, required when Database support is enabled.
|
||||
* This is a standard ini type file, containing the config required to connect to the database.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
define('Sihnon_DBConfig', '/etc/homepage/dbconfig.conf');
|
||||
|
||||
/**
|
||||
* Sihnon Config Plugin
|
||||
*
|
||||
* Specifies the plugin to use for configuration value storage.
|
||||
* Options include:
|
||||
* - Database (Requires Database Support to be enabled, and the Sihnon_ConfigTable option set)
|
||||
* - FlatFile (Requires the Sihnon_ConfigFile option set)
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
define('Sihnon_ConfigPlugin', 'FlatFile');
|
||||
|
||||
/**
|
||||
* Sihnon Config Table
|
||||
*
|
||||
* Specifies the name of the database table thats used for storing configuration values
|
||||
* when the Database Config Plugin is used.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
define('Sihnon_ConfigTable', 'settings');
|
||||
|
||||
/**
|
||||
* Sihnon Config File
|
||||
*
|
||||
* Specifies the name of the file used to store configuration values when the FlatFile Config Plugin is used
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
define('Sihnon_ConfigFile', '/etc/homepage/settings.txt');
|
||||
|
||||
/**
|
||||
* Sihnon Development Mode
|
||||
*
|
||||
* Specifies whether or not the Framework should operate in debug mode
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
define('Sihnon_Dev', false);
|
||||
|
||||
?>
|
||||
5
private/dbconfig.conf.dist
Normal file
@@ -0,0 +1,5 @@
|
||||
hostname = localhost
|
||||
username = homepage
|
||||
password = changeme
|
||||
dbname = homepage
|
||||
|
||||
16
private/htaccess.dist
Normal file
@@ -0,0 +1,16 @@
|
||||
SetEnv STATUSBOARD_CONFIG /etc/homepage/config.php
|
||||
|
||||
<IfModule mod_rewrite.c>
|
||||
|
||||
RewriteEngine on
|
||||
RewriteBase /
|
||||
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteRule ^(ajax/.*)$ a.php?l=$1 [L]
|
||||
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteRule ^(.*)$ index.php?l=$1
|
||||
|
||||
</IfModule>
|
||||
35
private/settings.txt.dist
Normal file
@@ -0,0 +1,35 @@
|
||||
[logging.plugins]
|
||||
type="array(string)"
|
||||
value=FlatFile
|
||||
|
||||
[logging.FlatFile]
|
||||
type="array(string)"
|
||||
value=logfile
|
||||
|
||||
[logging.FlatFile.logfile.filename]
|
||||
type=string
|
||||
value=/var/log/homepage/homepage.log
|
||||
|
||||
[logging.FlatFile.logfile.format]
|
||||
type=string
|
||||
value="%timestamp% %hostname%:%pid% %progname%:%shortfile%[%line%] %message%"
|
||||
|
||||
[logging.FlatFile.logfile.severity]
|
||||
type="array(string)"
|
||||
value="debug
|
||||
info
|
||||
warning
|
||||
error"
|
||||
|
||||
[logging.FlatFile.logfile.category]
|
||||
type="array(string)"
|
||||
value="default"
|
||||
|
||||
[cache.base_dir]
|
||||
type=string
|
||||
value=/dev/shm/homepage
|
||||
|
||||
[debug.display_exceptions]
|
||||
type=bool
|
||||
value=1
|
||||
|
||||
16
public/.htaccess
Normal file
@@ -0,0 +1,16 @@
|
||||
SetEnv HOMEPAGE_CONFIG /home/ben/projects/homepage/private/config.php
|
||||
|
||||
<IfModule mod_rewrite.c>
|
||||
|
||||
RewriteEngine on
|
||||
RewriteBase /~ben/homepage/
|
||||
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteRule ^(ajax/.*)$ a.php?l=$1 [L]
|
||||
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteRule ^(.*)$ index.php?l=$1
|
||||
|
||||
</IfModule>
|
||||
16
public/_inc.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
if (isset($_SERVER['HOMEPAGE_CONFIG']) &&
|
||||
file_exists($_SERVER['HOMEPAGE_CONFIG']) &&
|
||||
is_readable($_SERVER['HOMEPAGE_CONFIG'])) {
|
||||
require_once($_SERVER['HOMEPAGE_CONFIG']);
|
||||
} else {
|
||||
require_once '/etc/homepage/config.php';
|
||||
}
|
||||
|
||||
require_once SihnonFramework_Lib . 'SihnonFramework/Main.class.php';
|
||||
|
||||
SihnonFramework_Main::registerAutoloadClasses('SihnonFramework', SihnonFramework_Lib,
|
||||
'Homepage', Homepage_Lib);
|
||||
|
||||
?>
|
||||
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 86 KiB |
BIN
public/images/ripping-cluster/overview.png
Normal file
|
After Width: | Height: | Size: 63 KiB |
BIN
public/images/status-board/overview.png
Normal file
|
After Width: | Height: | Size: 65 KiB |
21
public/index.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
define('Homepage_File', 'index');
|
||||
|
||||
require '_inc.php';
|
||||
|
||||
try {
|
||||
$main = Homepage_Main::instance();
|
||||
Homepage_LogEntry::setLocalProgname('webui');
|
||||
$smarty = $main->smarty();
|
||||
|
||||
$page = new Homepage_Page($smarty, $main->request());
|
||||
if ($page->evaluate()) {
|
||||
$smarty->display('index.tpl');
|
||||
}
|
||||
|
||||
} catch (Homepage_Exception $e) {
|
||||
die("Uncaught Exception: " . $e->getMessage());
|
||||
}
|
||||
|
||||
?>
|
||||
113
public/scripts/3rdparty/bootstrap-alerts.js
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
/* ==========================================================
|
||||
* bootstrap-alerts.js v1.4.0
|
||||
* http://twitter.github.com/bootstrap/javascript.html#alerts
|
||||
* ==========================================================
|
||||
* Copyright 2011 Twitter, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* ========================================================== */
|
||||
|
||||
|
||||
!function( $ ){
|
||||
|
||||
"use strict"
|
||||
|
||||
/* CSS TRANSITION SUPPORT (https://gist.github.com/373874)
|
||||
* ======================================================= */
|
||||
|
||||
var transitionEnd
|
||||
|
||||
$(document).ready(function () {
|
||||
|
||||
$.support.transition = (function () {
|
||||
var thisBody = document.body || document.documentElement
|
||||
, thisStyle = thisBody.style
|
||||
, support = thisStyle.transition !== undefined || thisStyle.WebkitTransition !== undefined || thisStyle.MozTransition !== undefined || thisStyle.MsTransition !== undefined || thisStyle.OTransition !== undefined
|
||||
return support
|
||||
})()
|
||||
|
||||
// set CSS transition event type
|
||||
if ( $.support.transition ) {
|
||||
transitionEnd = "TransitionEnd"
|
||||
if ( $.browser.webkit ) {
|
||||
transitionEnd = "webkitTransitionEnd"
|
||||
} else if ( $.browser.mozilla ) {
|
||||
transitionEnd = "transitionend"
|
||||
} else if ( $.browser.opera ) {
|
||||
transitionEnd = "oTransitionEnd"
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
/* ALERT CLASS DEFINITION
|
||||
* ====================== */
|
||||
|
||||
var Alert = function ( content, options ) {
|
||||
this.settings = $.extend({}, $.fn.alert.defaults, options)
|
||||
this.$element = $(content)
|
||||
.delegate(this.settings.selector, 'click', this.close)
|
||||
}
|
||||
|
||||
Alert.prototype = {
|
||||
|
||||
close: function (e) {
|
||||
var $element = $(this).parent('.alert-message')
|
||||
|
||||
e && e.preventDefault()
|
||||
$element.removeClass('in')
|
||||
|
||||
function removeElement () {
|
||||
$element.remove()
|
||||
}
|
||||
|
||||
$.support.transition && $element.hasClass('fade') ?
|
||||
$element.bind(transitionEnd, removeElement) :
|
||||
removeElement()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* ALERT PLUGIN DEFINITION
|
||||
* ======================= */
|
||||
|
||||
$.fn.alert = function ( options ) {
|
||||
|
||||
if ( options === true ) {
|
||||
return this.data('alert')
|
||||
}
|
||||
|
||||
return this.each(function () {
|
||||
var $this = $(this)
|
||||
|
||||
if ( typeof options == 'string' ) {
|
||||
return $this.data('alert')[options]()
|
||||
}
|
||||
|
||||
$(this).data('alert', new Alert( this, options ))
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
$.fn.alert.defaults = {
|
||||
selector: '.close'
|
||||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
new Alert($('body'), {
|
||||
selector: '.alert-message[data-alert] .close'
|
||||
})
|
||||
})
|
||||
|
||||
}( window.jQuery || window.ender );
|
||||
55
public/scripts/3rdparty/bootstrap-dropdown.js
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
/* ============================================================
|
||||
* bootstrap-dropdown.js v1.4.0
|
||||
* http://twitter.github.com/bootstrap/javascript.html#dropdown
|
||||
* ============================================================
|
||||
* Copyright 2011 Twitter, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* ============================================================ */
|
||||
|
||||
|
||||
!function( $ ){
|
||||
|
||||
"use strict"
|
||||
|
||||
/* DROPDOWN PLUGIN DEFINITION
|
||||
* ========================== */
|
||||
|
||||
$.fn.dropdown = function ( selector ) {
|
||||
return this.each(function () {
|
||||
$(this).delegate(selector || d, 'click', function (e) {
|
||||
var li = $(this).parent('li')
|
||||
, isActive = li.hasClass('open')
|
||||
|
||||
clearMenus()
|
||||
!isActive && li.toggleClass('open')
|
||||
return false
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/* APPLY TO STANDARD DROPDOWN ELEMENTS
|
||||
* =================================== */
|
||||
|
||||
var d = 'a.menu, .dropdown-toggle'
|
||||
|
||||
function clearMenus() {
|
||||
$(d).parent('li').removeClass('open')
|
||||
}
|
||||
|
||||
$(function () {
|
||||
$('html').bind("click", clearMenus)
|
||||
$('body').dropdown( '[data-dropdown] a.menu, [data-dropdown] .dropdown-toggle' )
|
||||
})
|
||||
|
||||
}( window.jQuery || window.ender );
|
||||
260
public/scripts/3rdparty/bootstrap-modal.js
vendored
Normal file
@@ -0,0 +1,260 @@
|
||||
/* =========================================================
|
||||
* bootstrap-modal.js v1.4.0
|
||||
* http://twitter.github.com/bootstrap/javascript.html#modal
|
||||
* =========================================================
|
||||
* Copyright 2011 Twitter, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* ========================================================= */
|
||||
|
||||
|
||||
!function( $ ){
|
||||
|
||||
"use strict"
|
||||
|
||||
/* CSS TRANSITION SUPPORT (https://gist.github.com/373874)
|
||||
* ======================================================= */
|
||||
|
||||
var transitionEnd
|
||||
|
||||
$(document).ready(function () {
|
||||
|
||||
$.support.transition = (function () {
|
||||
var thisBody = document.body || document.documentElement
|
||||
, thisStyle = thisBody.style
|
||||
, support = thisStyle.transition !== undefined || thisStyle.WebkitTransition !== undefined || thisStyle.MozTransition !== undefined || thisStyle.MsTransition !== undefined || thisStyle.OTransition !== undefined
|
||||
return support
|
||||
})()
|
||||
|
||||
// set CSS transition event type
|
||||
if ( $.support.transition ) {
|
||||
transitionEnd = "TransitionEnd"
|
||||
if ( $.browser.webkit ) {
|
||||
transitionEnd = "webkitTransitionEnd"
|
||||
} else if ( $.browser.mozilla ) {
|
||||
transitionEnd = "transitionend"
|
||||
} else if ( $.browser.opera ) {
|
||||
transitionEnd = "oTransitionEnd"
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
|
||||
/* MODAL PUBLIC CLASS DEFINITION
|
||||
* ============================= */
|
||||
|
||||
var Modal = function ( content, options ) {
|
||||
this.settings = $.extend({}, $.fn.modal.defaults, options)
|
||||
this.$element = $(content)
|
||||
.delegate('.close', 'click.modal', $.proxy(this.hide, this))
|
||||
|
||||
if ( this.settings.show ) {
|
||||
this.show()
|
||||
}
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
Modal.prototype = {
|
||||
|
||||
toggle: function () {
|
||||
return this[!this.isShown ? 'show' : 'hide']()
|
||||
}
|
||||
|
||||
, show: function () {
|
||||
var that = this
|
||||
this.isShown = true
|
||||
this.$element.trigger('show')
|
||||
|
||||
escape.call(this)
|
||||
backdrop.call(this, function () {
|
||||
var transition = $.support.transition && that.$element.hasClass('fade')
|
||||
|
||||
that.$element
|
||||
.appendTo(document.body)
|
||||
.show()
|
||||
|
||||
if (transition) {
|
||||
that.$element[0].offsetWidth // force reflow
|
||||
}
|
||||
|
||||
that.$element.addClass('in')
|
||||
|
||||
transition ?
|
||||
that.$element.one(transitionEnd, function () { that.$element.trigger('shown') }) :
|
||||
that.$element.trigger('shown')
|
||||
|
||||
})
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
, hide: function (e) {
|
||||
e && e.preventDefault()
|
||||
|
||||
if ( !this.isShown ) {
|
||||
return this
|
||||
}
|
||||
|
||||
var that = this
|
||||
this.isShown = false
|
||||
|
||||
escape.call(this)
|
||||
|
||||
this.$element
|
||||
.trigger('hide')
|
||||
.removeClass('in')
|
||||
|
||||
$.support.transition && this.$element.hasClass('fade') ?
|
||||
hideWithTransition.call(this) :
|
||||
hideModal.call(this)
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* MODAL PRIVATE METHODS
|
||||
* ===================== */
|
||||
|
||||
function hideWithTransition() {
|
||||
// firefox drops transitionEnd events :{o
|
||||
var that = this
|
||||
, timeout = setTimeout(function () {
|
||||
that.$element.unbind(transitionEnd)
|
||||
hideModal.call(that)
|
||||
}, 500)
|
||||
|
||||
this.$element.one(transitionEnd, function () {
|
||||
clearTimeout(timeout)
|
||||
hideModal.call(that)
|
||||
})
|
||||
}
|
||||
|
||||
function hideModal (that) {
|
||||
this.$element
|
||||
.hide()
|
||||
.trigger('hidden')
|
||||
|
||||
backdrop.call(this)
|
||||
}
|
||||
|
||||
function backdrop ( callback ) {
|
||||
var that = this
|
||||
, animate = this.$element.hasClass('fade') ? 'fade' : ''
|
||||
if ( this.isShown && this.settings.backdrop ) {
|
||||
var doAnimate = $.support.transition && animate
|
||||
|
||||
this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />')
|
||||
.appendTo(document.body)
|
||||
|
||||
if ( this.settings.backdrop != 'static' ) {
|
||||
this.$backdrop.click($.proxy(this.hide, this))
|
||||
}
|
||||
|
||||
if ( doAnimate ) {
|
||||
this.$backdrop[0].offsetWidth // force reflow
|
||||
}
|
||||
|
||||
this.$backdrop.addClass('in')
|
||||
|
||||
doAnimate ?
|
||||
this.$backdrop.one(transitionEnd, callback) :
|
||||
callback()
|
||||
|
||||
} else if ( !this.isShown && this.$backdrop ) {
|
||||
this.$backdrop.removeClass('in')
|
||||
|
||||
$.support.transition && this.$element.hasClass('fade')?
|
||||
this.$backdrop.one(transitionEnd, $.proxy(removeBackdrop, this)) :
|
||||
removeBackdrop.call(this)
|
||||
|
||||
} else if ( callback ) {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
|
||||
function removeBackdrop() {
|
||||
this.$backdrop.remove()
|
||||
this.$backdrop = null
|
||||
}
|
||||
|
||||
function escape() {
|
||||
var that = this
|
||||
if ( this.isShown && this.settings.keyboard ) {
|
||||
$(document).bind('keyup.modal', function ( e ) {
|
||||
if ( e.which == 27 ) {
|
||||
that.hide()
|
||||
}
|
||||
})
|
||||
} else if ( !this.isShown ) {
|
||||
$(document).unbind('keyup.modal')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* MODAL PLUGIN DEFINITION
|
||||
* ======================= */
|
||||
|
||||
$.fn.modal = function ( options ) {
|
||||
var modal = this.data('modal')
|
||||
|
||||
if (!modal) {
|
||||
|
||||
if (typeof options == 'string') {
|
||||
options = {
|
||||
show: /show|toggle/.test(options)
|
||||
}
|
||||
}
|
||||
|
||||
return this.each(function () {
|
||||
$(this).data('modal', new Modal(this, options))
|
||||
})
|
||||
}
|
||||
|
||||
if ( options === true ) {
|
||||
return modal
|
||||
}
|
||||
|
||||
if ( typeof options == 'string' ) {
|
||||
modal[options]()
|
||||
} else if ( modal ) {
|
||||
modal.toggle()
|
||||
}
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
$.fn.modal.Modal = Modal
|
||||
|
||||
$.fn.modal.defaults = {
|
||||
backdrop: false
|
||||
, keyboard: false
|
||||
, show: false
|
||||
}
|
||||
|
||||
|
||||
/* MODAL DATA- IMPLEMENTATION
|
||||
* ========================== */
|
||||
|
||||
$(document).ready(function () {
|
||||
$('body').delegate('[data-controls-modal]', 'click', function (e) {
|
||||
e.preventDefault()
|
||||
var $this = $(this).data('show', true)
|
||||
$('#' + $this.attr('data-controls-modal')).modal( $this.data() )
|
||||
})
|
||||
})
|
||||
|
||||
}( window.jQuery || window.ender );
|
||||
90
public/scripts/3rdparty/bootstrap-popover.js
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
/* ===========================================================
|
||||
* bootstrap-popover.js v1.4.0
|
||||
* http://twitter.github.com/bootstrap/javascript.html#popover
|
||||
* ===========================================================
|
||||
* Copyright 2011 Twitter, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* =========================================================== */
|
||||
|
||||
|
||||
!function( $ ) {
|
||||
|
||||
"use strict"
|
||||
|
||||
var Popover = function ( element, options ) {
|
||||
this.$element = $(element)
|
||||
this.options = options
|
||||
this.enabled = true
|
||||
this.fixTitle()
|
||||
}
|
||||
|
||||
/* NOTE: POPOVER EXTENDS BOOTSTRAP-TWIPSY.js
|
||||
========================================= */
|
||||
|
||||
Popover.prototype = $.extend({}, $.fn.twipsy.Twipsy.prototype, {
|
||||
|
||||
setContent: function () {
|
||||
var $tip = this.tip()
|
||||
$tip.find('.title')[this.options.html ? 'html' : 'text'](this.getTitle())
|
||||
$tip.find('.content p')[this.options.html ? 'html' : 'text'](this.getContent())
|
||||
$tip[0].className = 'popover'
|
||||
}
|
||||
|
||||
, hasContent: function () {
|
||||
return this.getTitle() || this.getContent()
|
||||
}
|
||||
|
||||
, getContent: function () {
|
||||
var content
|
||||
, $e = this.$element
|
||||
, o = this.options
|
||||
|
||||
if (typeof this.options.content == 'string') {
|
||||
content = $e.attr(this.options.content)
|
||||
} else if (typeof this.options.content == 'function') {
|
||||
content = this.options.content.call(this.$element[0])
|
||||
}
|
||||
|
||||
return content
|
||||
}
|
||||
|
||||
, tip: function() {
|
||||
if (!this.$tip) {
|
||||
this.$tip = $('<div class="popover" />')
|
||||
.html(this.options.template)
|
||||
}
|
||||
return this.$tip
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
|
||||
/* POPOVER PLUGIN DEFINITION
|
||||
* ======================= */
|
||||
|
||||
$.fn.popover = function (options) {
|
||||
if (typeof options == 'object') options = $.extend({}, $.fn.popover.defaults, options)
|
||||
$.fn.twipsy.initWith.call(this, options, Popover, 'popover')
|
||||
return this
|
||||
}
|
||||
|
||||
$.fn.popover.defaults = $.extend({} , $.fn.twipsy.defaults, {
|
||||
placement: 'right'
|
||||
, content: 'data-content'
|
||||
, template: '<div class="arrow"></div><div class="inner"><h3 class="title"></h3><div class="content"><p></p></div></div>'
|
||||
})
|
||||
|
||||
$.fn.twipsy.rejectAttrOptions.push( 'content' )
|
||||
|
||||
}( window.jQuery || window.ender );
|
||||
80
public/scripts/3rdparty/bootstrap-tabs.js
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
/* ========================================================
|
||||
* bootstrap-tabs.js v1.4.0
|
||||
* http://twitter.github.com/bootstrap/javascript.html#tabs
|
||||
* ========================================================
|
||||
* Copyright 2011 Twitter, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* ======================================================== */
|
||||
|
||||
|
||||
!function( $ ){
|
||||
|
||||
"use strict"
|
||||
|
||||
function activate ( element, container ) {
|
||||
container
|
||||
.find('> .active')
|
||||
.removeClass('active')
|
||||
.find('> .dropdown-menu > .active')
|
||||
.removeClass('active')
|
||||
|
||||
element.addClass('active')
|
||||
|
||||
if ( element.parent('.dropdown-menu') ) {
|
||||
element.closest('li.dropdown').addClass('active')
|
||||
}
|
||||
}
|
||||
|
||||
function tab( e ) {
|
||||
var $this = $(this)
|
||||
, $ul = $this.closest('ul:not(.dropdown-menu)')
|
||||
, href = $this.attr('href')
|
||||
, previous
|
||||
, $href
|
||||
|
||||
if ( /^#\w+/.test(href) ) {
|
||||
e.preventDefault()
|
||||
|
||||
if ( $this.parent('li').hasClass('active') ) {
|
||||
return
|
||||
}
|
||||
|
||||
previous = $ul.find('.active a').last()[0]
|
||||
$href = $(href)
|
||||
|
||||
activate($this.parent('li'), $ul)
|
||||
activate($href, $href.parent())
|
||||
|
||||
$this.trigger({
|
||||
type: 'change'
|
||||
, relatedTarget: previous
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* TABS/PILLS PLUGIN DEFINITION
|
||||
* ============================ */
|
||||
|
||||
$.fn.tabs = $.fn.pills = function ( selector ) {
|
||||
return this.each(function () {
|
||||
$(this).delegate(selector || '.tabs li > a, .pills > li > a', 'click', tab)
|
||||
})
|
||||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
$('body').tabs('ul[data-tabs] li > a, ul[data-pills] > li > a')
|
||||
})
|
||||
|
||||
}( window.jQuery || window.ender );
|
||||
321
public/scripts/3rdparty/bootstrap-twipsy.js
vendored
Normal file
@@ -0,0 +1,321 @@
|
||||
/* ==========================================================
|
||||
* bootstrap-twipsy.js v1.4.0
|
||||
* http://twitter.github.com/bootstrap/javascript.html#twipsy
|
||||
* Adapted from the original jQuery.tipsy by Jason Frame
|
||||
* ==========================================================
|
||||
* Copyright 2011 Twitter, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* ========================================================== */
|
||||
|
||||
|
||||
!function( $ ) {
|
||||
|
||||
"use strict"
|
||||
|
||||
/* CSS TRANSITION SUPPORT (https://gist.github.com/373874)
|
||||
* ======================================================= */
|
||||
|
||||
var transitionEnd
|
||||
|
||||
$(document).ready(function () {
|
||||
|
||||
$.support.transition = (function () {
|
||||
var thisBody = document.body || document.documentElement
|
||||
, thisStyle = thisBody.style
|
||||
, support = thisStyle.transition !== undefined || thisStyle.WebkitTransition !== undefined || thisStyle.MozTransition !== undefined || thisStyle.MsTransition !== undefined || thisStyle.OTransition !== undefined
|
||||
return support
|
||||
})()
|
||||
|
||||
// set CSS transition event type
|
||||
if ( $.support.transition ) {
|
||||
transitionEnd = "TransitionEnd"
|
||||
if ( $.browser.webkit ) {
|
||||
transitionEnd = "webkitTransitionEnd"
|
||||
} else if ( $.browser.mozilla ) {
|
||||
transitionEnd = "transitionend"
|
||||
} else if ( $.browser.opera ) {
|
||||
transitionEnd = "oTransitionEnd"
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
|
||||
/* TWIPSY PUBLIC CLASS DEFINITION
|
||||
* ============================== */
|
||||
|
||||
var Twipsy = function ( element, options ) {
|
||||
this.$element = $(element)
|
||||
this.options = options
|
||||
this.enabled = true
|
||||
this.fixTitle()
|
||||
}
|
||||
|
||||
Twipsy.prototype = {
|
||||
|
||||
show: function() {
|
||||
var pos
|
||||
, actualWidth
|
||||
, actualHeight
|
||||
, placement
|
||||
, $tip
|
||||
, tp
|
||||
|
||||
if (this.hasContent() && this.enabled) {
|
||||
$tip = this.tip()
|
||||
this.setContent()
|
||||
|
||||
if (this.options.animate) {
|
||||
$tip.addClass('fade')
|
||||
}
|
||||
|
||||
$tip
|
||||
.remove()
|
||||
.css({ top: 0, left: 0, display: 'block' })
|
||||
.prependTo(document.body)
|
||||
|
||||
pos = $.extend({}, this.$element.offset(), {
|
||||
width: this.$element[0].offsetWidth
|
||||
, height: this.$element[0].offsetHeight
|
||||
})
|
||||
|
||||
actualWidth = $tip[0].offsetWidth
|
||||
actualHeight = $tip[0].offsetHeight
|
||||
|
||||
placement = maybeCall(this.options.placement, this, [ $tip[0], this.$element[0] ])
|
||||
|
||||
switch (placement) {
|
||||
case 'below':
|
||||
tp = {top: pos.top + pos.height + this.options.offset, left: pos.left + pos.width / 2 - actualWidth / 2}
|
||||
break
|
||||
case 'above':
|
||||
tp = {top: pos.top - actualHeight - this.options.offset, left: pos.left + pos.width / 2 - actualWidth / 2}
|
||||
break
|
||||
case 'left':
|
||||
tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth - this.options.offset}
|
||||
break
|
||||
case 'right':
|
||||
tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width + this.options.offset}
|
||||
break
|
||||
}
|
||||
|
||||
$tip
|
||||
.css(tp)
|
||||
.addClass(placement)
|
||||
.addClass('in')
|
||||
}
|
||||
}
|
||||
|
||||
, setContent: function () {
|
||||
var $tip = this.tip()
|
||||
$tip.find('.twipsy-inner')[this.options.html ? 'html' : 'text'](this.getTitle())
|
||||
$tip[0].className = 'twipsy'
|
||||
}
|
||||
|
||||
, hide: function() {
|
||||
var that = this
|
||||
, $tip = this.tip()
|
||||
|
||||
$tip.removeClass('in')
|
||||
|
||||
function removeElement () {
|
||||
$tip.remove()
|
||||
}
|
||||
|
||||
$.support.transition && this.$tip.hasClass('fade') ?
|
||||
$tip.bind(transitionEnd, removeElement) :
|
||||
removeElement()
|
||||
}
|
||||
|
||||
, fixTitle: function() {
|
||||
var $e = this.$element
|
||||
if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
|
||||
$e.attr('data-original-title', $e.attr('title') || '').removeAttr('title')
|
||||
}
|
||||
}
|
||||
|
||||
, hasContent: function () {
|
||||
return this.getTitle()
|
||||
}
|
||||
|
||||
, getTitle: function() {
|
||||
var title
|
||||
, $e = this.$element
|
||||
, o = this.options
|
||||
|
||||
this.fixTitle()
|
||||
|
||||
if (typeof o.title == 'string') {
|
||||
title = $e.attr(o.title == 'title' ? 'data-original-title' : o.title)
|
||||
} else if (typeof o.title == 'function') {
|
||||
title = o.title.call($e[0])
|
||||
}
|
||||
|
||||
title = ('' + title).replace(/(^\s*|\s*$)/, "")
|
||||
|
||||
return title || o.fallback
|
||||
}
|
||||
|
||||
, tip: function() {
|
||||
return this.$tip = this.$tip || $('<div class="twipsy" />').html(this.options.template)
|
||||
}
|
||||
|
||||
, validate: function() {
|
||||
if (!this.$element[0].parentNode) {
|
||||
this.hide()
|
||||
this.$element = null
|
||||
this.options = null
|
||||
}
|
||||
}
|
||||
|
||||
, enable: function() {
|
||||
this.enabled = true
|
||||
}
|
||||
|
||||
, disable: function() {
|
||||
this.enabled = false
|
||||
}
|
||||
|
||||
, toggleEnabled: function() {
|
||||
this.enabled = !this.enabled
|
||||
}
|
||||
|
||||
, toggle: function () {
|
||||
this[this.tip().hasClass('in') ? 'hide' : 'show']()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* TWIPSY PRIVATE METHODS
|
||||
* ====================== */
|
||||
|
||||
function maybeCall ( thing, ctx, args ) {
|
||||
return typeof thing == 'function' ? thing.apply(ctx, args) : thing
|
||||
}
|
||||
|
||||
/* TWIPSY PLUGIN DEFINITION
|
||||
* ======================== */
|
||||
|
||||
$.fn.twipsy = function (options) {
|
||||
$.fn.twipsy.initWith.call(this, options, Twipsy, 'twipsy')
|
||||
return this
|
||||
}
|
||||
|
||||
$.fn.twipsy.initWith = function (options, Constructor, name) {
|
||||
var twipsy
|
||||
, binder
|
||||
, eventIn
|
||||
, eventOut
|
||||
|
||||
if (options === true) {
|
||||
return this.data(name)
|
||||
} else if (typeof options == 'string') {
|
||||
twipsy = this.data(name)
|
||||
if (twipsy) {
|
||||
twipsy[options]()
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
options = $.extend({}, $.fn[name].defaults, options)
|
||||
|
||||
function get(ele) {
|
||||
var twipsy = $.data(ele, name)
|
||||
|
||||
if (!twipsy) {
|
||||
twipsy = new Constructor(ele, $.fn.twipsy.elementOptions(ele, options))
|
||||
$.data(ele, name, twipsy)
|
||||
}
|
||||
|
||||
return twipsy
|
||||
}
|
||||
|
||||
function enter() {
|
||||
var twipsy = get(this)
|
||||
twipsy.hoverState = 'in'
|
||||
|
||||
if (options.delayIn == 0) {
|
||||
twipsy.show()
|
||||
} else {
|
||||
twipsy.fixTitle()
|
||||
setTimeout(function() {
|
||||
if (twipsy.hoverState == 'in') {
|
||||
twipsy.show()
|
||||
}
|
||||
}, options.delayIn)
|
||||
}
|
||||
}
|
||||
|
||||
function leave() {
|
||||
var twipsy = get(this)
|
||||
twipsy.hoverState = 'out'
|
||||
if (options.delayOut == 0) {
|
||||
twipsy.hide()
|
||||
} else {
|
||||
setTimeout(function() {
|
||||
if (twipsy.hoverState == 'out') {
|
||||
twipsy.hide()
|
||||
}
|
||||
}, options.delayOut)
|
||||
}
|
||||
}
|
||||
|
||||
if (!options.live) {
|
||||
this.each(function() {
|
||||
get(this)
|
||||
})
|
||||
}
|
||||
|
||||
if (options.trigger != 'manual') {
|
||||
binder = options.live ? 'live' : 'bind'
|
||||
eventIn = options.trigger == 'hover' ? 'mouseenter' : 'focus'
|
||||
eventOut = options.trigger == 'hover' ? 'mouseleave' : 'blur'
|
||||
this[binder](eventIn, enter)[binder](eventOut, leave)
|
||||
}
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
$.fn.twipsy.Twipsy = Twipsy
|
||||
|
||||
$.fn.twipsy.defaults = {
|
||||
animate: true
|
||||
, delayIn: 0
|
||||
, delayOut: 0
|
||||
, fallback: ''
|
||||
, placement: 'above'
|
||||
, html: false
|
||||
, live: false
|
||||
, offset: 0
|
||||
, title: 'title'
|
||||
, trigger: 'hover'
|
||||
, template: '<div class="twipsy-arrow"></div><div class="twipsy-inner"></div>'
|
||||
}
|
||||
|
||||
$.fn.twipsy.rejectAttrOptions = [ 'title' ]
|
||||
|
||||
$.fn.twipsy.elementOptions = function(ele, options) {
|
||||
var data = $(ele).data()
|
||||
, rejects = $.fn.twipsy.rejectAttrOptions
|
||||
, i = rejects.length
|
||||
|
||||
while (i--) {
|
||||
delete data[rejects[i]]
|
||||
}
|
||||
|
||||
return $.extend({}, options, data)
|
||||
}
|
||||
|
||||
}( window.jQuery || window.ender );
|
||||
73
public/scripts/3rdparty/jquery.chained.js
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Chained - jQuery non AJAX(J) chained selects plugin
|
||||
*
|
||||
* Copyright (c) 2010-2011 Mika Tuupola
|
||||
*
|
||||
* Licensed under the MIT license:
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
*
|
||||
*/
|
||||
|
||||
(function($) {
|
||||
|
||||
$.fn.chained = function(parent_selector, options) {
|
||||
|
||||
return this.each(function() {
|
||||
|
||||
/* Save this to self because this changes when scope changes. */
|
||||
var self = this;
|
||||
var backup = $(self).clone();
|
||||
|
||||
/* Handles maximum two parents now. */
|
||||
$(parent_selector).each(function() {
|
||||
|
||||
$(this).bind("change", function() {
|
||||
$(self).html(backup.html());
|
||||
|
||||
/* If multiple parents build classname like foo\bar. */
|
||||
var selected = "";
|
||||
$(parent_selector).each(function() {
|
||||
selected += "\\" + $(":selected", this).val();
|
||||
});
|
||||
selected = selected.substr(1);
|
||||
|
||||
/* Also check for first parent without subclassing. */
|
||||
/* TODO: This should be dynamic and check for each parent */
|
||||
/* without subclassing. */
|
||||
var first = $(parent_selector).first();
|
||||
var selected_first = $(":selected", first).val();
|
||||
|
||||
$("option", self).each(function() {
|
||||
/* Remove unneeded items but save the default value. */
|
||||
if (!$(this).hasClass(selected) &&
|
||||
!$(this).hasClass(selected_first) && $(this).val() !== "") {
|
||||
$(this).remove();
|
||||
}
|
||||
});
|
||||
|
||||
/* If we have only the default value disable select. */
|
||||
if (1 == $("option", self).size() && $(self).val() === "") {
|
||||
$(self).attr("disabled", "disabled");
|
||||
} else {
|
||||
$(self).removeAttr("disabled");
|
||||
}
|
||||
$(self).trigger("change");
|
||||
});
|
||||
|
||||
/* Force IE to see something selected on first page load, */
|
||||
/* unless something is already selected */
|
||||
if ( !$("option:selected", this).length ) {
|
||||
$("option", this).first().attr("selected", "selected");
|
||||
}
|
||||
|
||||
/* Force updating the children. */
|
||||
$(this).trigger("change");
|
||||
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/* Alias for those who like to use more English like syntax. */
|
||||
$.fn.chainedTo = $.fn.chained;
|
||||
|
||||
})(jQuery);
|
||||
16
public/scripts/3rdparty/less-1.1.5.min.js
vendored
Normal file
88
public/scripts/main.js
Normal file
@@ -0,0 +1,88 @@
|
||||
/**
|
||||
* StatusBoard main script file
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
var sb = {
|
||||
|
||||
init: function() {
|
||||
// Properly format any alert boxes
|
||||
$('.alert-data').alert();
|
||||
|
||||
// Properly format any tab widgets
|
||||
$('.tabs').tabs();
|
||||
|
||||
// Display popovers on all configured items
|
||||
$("a[rel=popover]").popover({
|
||||
offset: 10,
|
||||
html: true,
|
||||
});
|
||||
},
|
||||
|
||||
admin: {
|
||||
|
||||
init: function() {
|
||||
$('#confirm_delete').modal({
|
||||
backdrop: true,
|
||||
keyboard: true
|
||||
});
|
||||
$('#confirm_delete_cancel').click(function() {
|
||||
$('#confirm_delete').modal('hide');
|
||||
});
|
||||
},
|
||||
|
||||
deleteItem: function(url) {
|
||||
$('#confirm_delete_do').click(function() {
|
||||
sb.request.post(url);
|
||||
});
|
||||
|
||||
$('#confirm_delete').modal('show');
|
||||
},
|
||||
|
||||
},
|
||||
|
||||
usercp: {
|
||||
|
||||
init: function() {
|
||||
$('#usercp_newpassword,#usercp_confirmpassword').bind('keyup', sb.usercp.checkPassword);
|
||||
|
||||
},
|
||||
|
||||
checkPassword: function() {
|
||||
password = $('#usercp_newpassword');
|
||||
confirm = $('#usercp_confirmpassword');
|
||||
|
||||
confirm_container = confirm.parent().parent();
|
||||
|
||||
if (password.val() == confirm.val()) {
|
||||
console.log("passwords match");
|
||||
confirm_container.removeClass('error').addClass('success');
|
||||
$('#usercp_confirmpassword_help').hide();
|
||||
} else {
|
||||
console.log("passwords do not match");
|
||||
confirm_container.addClass('error').removeClass('success');
|
||||
$('#usercp_confirmpassword_help').show();
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
request: {
|
||||
|
||||
post: function(url, data) {
|
||||
console.log('Posting');
|
||||
var form = $('<form />').attr('method', 'post').attr('action', url);
|
||||
for (var key in data) {
|
||||
form.appendChild($('<input type="hidden">').attr('name', key).val(data[key]));
|
||||
}
|
||||
|
||||
form.submit();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
$('document').ready(sb.init);
|
||||
47
public/styles/normal.css
Normal file
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* StatusBoard normal stylesheet
|
||||
*
|
||||
*/
|
||||
@import url('http://twitter.github.com/bootstrap/1.4.0/bootstrap.min.css');
|
||||
@CHARSET "UTF-8";
|
||||
|
||||
body {
|
||||
margin: 0em;
|
||||
margin-top: 60px;
|
||||
padding-top: 40px;
|
||||
padding: 0em;
|
||||
font-family: verdana, helvetica, sans-serif;
|
||||
background: #F7F7F7;
|
||||
}
|
||||
|
||||
a {
|
||||
color: gray;
|
||||
}
|
||||
|
||||
label {
|
||||
margin-left: 1em;
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
footer {
|
||||
padding: 2em;
|
||||
font-size: smaller;
|
||||
font-style: italic;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
/*
|
||||
Images
|
||||
*/
|
||||
img.avatar {
|
||||
float: right;
|
||||
vertical-align: top;
|
||||
border: 1px solid grey;
|
||||
padding: 0.2em;
|
||||
margin: 0.75em;
|
||||
}
|
||||
|
||||
img.at {
|
||||
height: 1em;
|
||||
width: 1em;
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
|
||||
window.onload = function() {
|
||||
for (var imgs = document.getElementsByTagName('img'),i=0,l=imgs.length; i<l; i++) {
|
||||
if (/at\.png$/.exec(imgs[i].src) ) {
|
||||
imgs[i].parentNode.insertBefore(document.createTextNode('@'),imgs[i]);
|
||||
imgs[i].parentNode.removeChild(imgs[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,183 +0,0 @@
|
||||
/*
|
||||
Layout
|
||||
*/
|
||||
|
||||
body {
|
||||
margin: 0em;
|
||||
padding: 0em;
|
||||
font-family: verdana, helvetica, tahoma, sans-serif;
|
||||
}
|
||||
|
||||
div.header {
|
||||
/*border-bottom: 1px solid grey;*/
|
||||
padding-bottom: 0.5em;
|
||||
margin: 0.5em 1em 1em 1em;
|
||||
}
|
||||
|
||||
div.sidebar {
|
||||
border-right: 1px solid grey;
|
||||
margin: 0em;
|
||||
padding: 1em;
|
||||
float: left;
|
||||
line-height: 1.8em;
|
||||
}
|
||||
|
||||
div.page {
|
||||
margin: 1em;
|
||||
margin-left: 15em;
|
||||
max-width: 60em;
|
||||
}
|
||||
|
||||
div.footer {
|
||||
border-top: 1px solid grey;
|
||||
margin: 1em;
|
||||
margin-top: 2em;
|
||||
padding-top: 0.5em;
|
||||
height: 3em;
|
||||
clear: both;
|
||||
|
||||
font-size: smaller;
|
||||
color: grey;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
div.sidebar ul {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
/*
|
||||
Page styles
|
||||
*/
|
||||
|
||||
div.header h1 {
|
||||
font-size: 3.0em;
|
||||
margin: 0.2em;
|
||||
margin-left: 0em;
|
||||
color: dimgrey;
|
||||
}
|
||||
|
||||
p.subtitle {
|
||||
font-weight: bold;
|
||||
font-style: italic;
|
||||
color: dimgrey;
|
||||
}
|
||||
|
||||
h2 {
|
||||
color: steelblue;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: underline;
|
||||
color: steelblue;
|
||||
}
|
||||
|
||||
a:visited {
|
||||
color: dimgrey;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Utilities
|
||||
*/
|
||||
br.spacer {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
div.quote {
|
||||
margin-left: 1em;
|
||||
padding-left: 2em;
|
||||
border: 1px solid moccasin;
|
||||
background-color: moccasin;
|
||||
background-image: url('../resources/quote-32.png');
|
||||
background-repeat: no-repeat;
|
||||
background-position: top left;
|
||||
}
|
||||
|
||||
div.quote blockquote {
|
||||
margin: 0em;
|
||||
padding: 0.3em 0.6em 0em 0.3em;
|
||||
font-style: italic;
|
||||
background-color: lightyellow;
|
||||
}
|
||||
|
||||
img.at {
|
||||
height: 1em;
|
||||
width: 1em;
|
||||
}
|
||||
|
||||
/*
|
||||
Dialog boxes
|
||||
*/
|
||||
|
||||
p.message {
|
||||
border: 1px solid red;
|
||||
background-color: lightsalmon;
|
||||
color: darkred;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
p.information {
|
||||
border: 1px solid blue;
|
||||
background-color: powderblue;
|
||||
color: darkslateblue;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Boxed item
|
||||
*/
|
||||
|
||||
div.box {
|
||||
margin-bottom: 2em;
|
||||
padding: 1.5em;
|
||||
border: 1px solid grey;
|
||||
}
|
||||
|
||||
div.box ul {
|
||||
width: 20em;
|
||||
line-height: 1.5em;
|
||||
}
|
||||
|
||||
div.box span.result {
|
||||
float: right;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Forms
|
||||
*/
|
||||
p.loginform {
|
||||
width: 30em;
|
||||
}
|
||||
p.loginform label {
|
||||
line-height: 200%;
|
||||
}
|
||||
p.loginform input {
|
||||
float: right;
|
||||
}
|
||||
|
||||
/*
|
||||
Images
|
||||
*/
|
||||
img.avatar {
|
||||
float: right;
|
||||
vertical-align: top;
|
||||
border: 1px solid grey;
|
||||
padding: 0.1em;
|
||||
margin: 0.77777775em;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
code.root {
|
||||
color: crimson;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
code.file {
|
||||
color: steelblue;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
Before Width: | Height: | Size: 4.4 KiB |
@@ -1,36 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
if( !isset($_GET['r']) || (float)$_GET['r'] < 0.0 || 10.0 < (float)$_GET['r'] ) {
|
||||
header("HTTP/1.0 500 Illegal Parameter", true, 500);
|
||||
die();
|
||||
}
|
||||
|
||||
$rating = (float)$_GET['r'] / 10;
|
||||
|
||||
// Load in the two images
|
||||
$bg = imagecreatefrompng( "rating_bg.png" );
|
||||
$fg = imagecreatefrompng( "rating_fg.png" );
|
||||
|
||||
// Find the size of the source images
|
||||
$width = imagesx( $bg );
|
||||
$height = imagesy( $bg );
|
||||
|
||||
// Modify the width to crop to the required percentage
|
||||
$fgwidth = $rating * $width;
|
||||
|
||||
// Crop the foreground to the desired width, copying it over the background
|
||||
imagecopyresampled( $bg, $fg, 0, 0, 0, 0, $fgwidth, $height, $fgwidth, $height );
|
||||
|
||||
// Send the correct image content type header
|
||||
header("Content-Type: image/png");
|
||||
|
||||
// Send the new combined image
|
||||
imagepng( $bg );
|
||||
|
||||
|
||||
?>
|
||||
|
Before Width: | Height: | Size: 990 B |
|
Before Width: | Height: | Size: 1.1 KiB |
68
source/lib/Homepage/Main.class.php
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
require 'smarty/Smarty.class.php';
|
||||
|
||||
class Homepage_Main extends SihnonFramework_Main {
|
||||
|
||||
const TEMPLATE_DIR = '../source/webui/templates/';
|
||||
const CODE_DIR = '../source/webui/pages/';
|
||||
|
||||
protected static $instance;
|
||||
|
||||
protected $smarty;
|
||||
protected $request;
|
||||
|
||||
protected function __construct() {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function init() {
|
||||
parent::init();
|
||||
|
||||
$request_string = isset($_GET['l']) ? $_GET['l'] : '';
|
||||
|
||||
$this->request = new Homepage_RequestParser($request_string, self::TEMPLATE_DIR, self::CODE_DIR);
|
||||
|
||||
switch (Homepage_File) {
|
||||
case 'ajax':
|
||||
case 'index': {
|
||||
$smarty_tmp = $this->config->get('templates.tmp_path');
|
||||
$this->smarty = new Smarty();
|
||||
$this->smarty->template_dir = static::makeAbsolutePath(self::TEMPLATE_DIR);
|
||||
$this->smarty->compile_dir = static::makeAbsolutePath($smarty_tmp . '/templates');
|
||||
$this->smarty->cache_dir = static::makeAbsolutePath($smarty_tmp . '/cache');
|
||||
$this->smarty->config_dir = static::makeAbsolutePath($smarty_tmp . '/config');
|
||||
$this->smarty->plugins_dir[]= static::makeAbsolutePath('../source/smarty/plugins');
|
||||
|
||||
$this->smarty->registerPlugin('modifier', 'formatDuration', array('Homepage_Main', 'formatDuration'));
|
||||
$this->smarty->registerPlugin('modifier', 'formatFilesize', array('Homepage_Main', 'formatFilesize'));
|
||||
$this->smarty->registerPlugin('modifier', 'fuzzyTime', array('Homepage_DateTime', 'fuzzyTime'));
|
||||
|
||||
$this->smarty->assign('version', '0.1.0');
|
||||
$this->smarty->assign('messages', array());
|
||||
|
||||
$this->smarty->assign('base_uri', $this->base_uri);
|
||||
$this->smarty->assign('base_url', static::absoluteUrl(''));
|
||||
$this->smarty->assign('title', 'Homepage');
|
||||
|
||||
} break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public function smarty() {
|
||||
return $this->smarty;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return StatusBoard_RequestParser
|
||||
*/
|
||||
public function request() {
|
||||
return $this->request;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
9
source/webui/pages/errors/401.php
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
$main = Homepage_Main::instance();
|
||||
$req = $main->request();
|
||||
|
||||
$this->smarty->assign('requested_page', $req->request_string());
|
||||
|
||||
|
||||
?>
|
||||
9
source/webui/pages/errors/404.php
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
$main = Homepage_Main::instance();
|
||||
$req = $main->request();
|
||||
|
||||
$this->smarty->assign('requested_page', $req->request_string());
|
||||
|
||||
|
||||
?>
|
||||
10
source/webui/pages/errors/unhandled-exception.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
$main = Homepage_Main::instance();
|
||||
$config = $main->config();
|
||||
|
||||
$this->smarty->assign('display_exceptions', $config->get('debug.display_exceptions'));
|
||||
$this->smarty->assign('exception', $exception);
|
||||
$this->smarty->assign('exception_type', get_class($exception));
|
||||
|
||||
?>
|
||||
6
source/webui/templates/cv.tpl
Normal file
@@ -0,0 +1,6 @@
|
||||
<h2>Curriculum Vitae</h2>
|
||||
|
||||
<p>
|
||||
I will update this page with an overview of my CV, but in the meatime, please feel free to download a
|
||||
<a href="{$base_uri}files/BenRobertsCv.pdf" title="Ben Roberts CV">PDF of my full CV</a>.
|
||||
</p>
|
||||
5
source/webui/templates/errors/401.tpl
Normal file
@@ -0,0 +1,5 @@
|
||||
<h2>This page is not accessible.</h2>
|
||||
<p>
|
||||
The page you requested ({$requested_page|escape:html}) could not be opened.
|
||||
Please ensure you are logged in and have permission to access this page.
|
||||
</p>
|
||||
6
source/webui/templates/errors/404.tpl
Normal file
@@ -0,0 +1,6 @@
|
||||
<h2>The requested page could not be found</h2>
|
||||
<p>
|
||||
The file you requested ({$requested_page|escape:html}) could not be found.
|
||||
If you typed in the address manually, check that you have spelled it correctly,
|
||||
or if you followed a link, let us know and we'll look into it.
|
||||
</p>
|
||||
62
source/webui/templates/errors/unhandled-exception.tpl
Normal file
@@ -0,0 +1,62 @@
|
||||
<h2>An unhandled error has occurred</h2>
|
||||
<p>
|
||||
There was a problem trying to complete the requested action. Please try again and if the problem persists, let us know.
|
||||
</p>
|
||||
|
||||
{if $display_exceptions}
|
||||
<p>
|
||||
An unhandled exception was caught during the page template processing. The full details are shown below:
|
||||
</p>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="span4 column">
|
||||
<h2>Exception</h2>
|
||||
</div>
|
||||
<div class="span11 column">
|
||||
{$exception_type|escape:html}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="span4 column">
|
||||
<h2>File</h2>
|
||||
</div>
|
||||
<div class="span11 column">
|
||||
{$exception->getFile()|escape:html}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="span4 column">
|
||||
<h2>Line</h2>
|
||||
</div>
|
||||
<div class="span11 column">
|
||||
{$exception->getLine()}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="span4 column">
|
||||
<h2>Message</h2>
|
||||
</div>
|
||||
<div class="span11 column">
|
||||
{$exception->getMessage()}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="span4 column">
|
||||
<h2>Stack Trace</h2>
|
||||
</div>
|
||||
<div class="span11 column">
|
||||
{$exception->getTrace()|var_dump}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
<em>Note:</em> Exception details should not be displayed on production systems.
|
||||
Disable the <a href="{$base_uri}admin/tab/settings/"><code>Display Exceptions</code></a>
|
||||
setting to omit the exception details from this page.
|
||||
</p>
|
||||
{/if}
|
||||
29
source/webui/templates/home.tpl
Normal file
@@ -0,0 +1,29 @@
|
||||
<div>
|
||||
<img class="avatar" style="width: 10em;" src="{$base_uri}images/portrait.jpg" alt="Ben Roberts" />
|
||||
|
||||
<p>
|
||||
I currently work as a Network Projects engineer for <a href="http://uk.atos.net/en-uk/" title="Atos - United Kingdom">Atos</a>
|
||||
in the Major Projects division. My role here includes design and implementation of LAN and WAN systems in Data Centre environments.
|
||||
</p>
|
||||
<p>
|
||||
I previously worked for <a href="http://www.netcraft.com/" title="Netcraft homepage">Netcraft</a> in Bath,
|
||||
while taking a year out from my degree studies.
|
||||
My roles included developing and running the <a href="http://news.netcraft.com/SSL-survey" title="Netcraft's SSL Server Survey">SSL Server Survey</a>,
|
||||
reviewing <a href="http://audited.netcraft.com/audited" title="Netcraft's Automated Vulnerability Scanning">Automated Vulnerability Scan</a> results,
|
||||
and performing occasional <a href="http://audited.netcraft.com/web-application" title="Netcraft's Application Penetration & Security Testing">penetration tests</a> against web applications for financial institutions.
|
||||
</p>
|
||||
<p>
|
||||
I am a former graudate of Computer Science from ECS (University of Southampton) which I studied to the Masters level.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
On this site you can find a copy of my <a href="{$base_uri}cv/" title="Curriculum Vitae">CV</a>,
|
||||
or see what <a href="{$base_uri}projects/" title="Projects">projects</a> I have been working on in my spare time.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
You can contact me via {mailto address="me@benroberts.net" encode="hex"}.
|
||||
</p>
|
||||
|
||||
|
||||
</div>
|
||||
97
source/webui/templates/index.tpl
Normal file
@@ -0,0 +1,97 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>{$title}</title>
|
||||
|
||||
<!-- JQuery //-->
|
||||
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.min.js"></script>
|
||||
<!-- JQuery Plugins //-->
|
||||
<script type="text/javascript" src="{$base_uri}scripts/3rdparty/jquery.chained.js"></script>
|
||||
|
||||
<!-- Less //-->
|
||||
<script type="text/javascript" src="{$base_uri}scripts/3rdparty/less-1.1.5.min.js"></script>
|
||||
|
||||
<!-- Bootstrap //-->
|
||||
<script type="text/javascript" src="{$base_uri}scripts/3rdparty/bootstrap-alerts.js"></script>
|
||||
<script type="text/javascript" src="{$base_uri}scripts/3rdparty/bootstrap-twipsy.js"></script>
|
||||
<script type="text/javascript" src="{$base_uri}scripts/3rdparty/bootstrap-popover.js"></script>
|
||||
<script type="text/javascript" src="{$base_uri}scripts/3rdparty/bootstrap-dropdown.js"></script>
|
||||
<script type="text/javascript" src="{$base_uri}scripts/3rdparty/bootstrap-tabs.js"></script>
|
||||
<script type="text/javascript" src="{$base_uri}scripts/3rdparty/bootstrap-modal.js"></script>
|
||||
|
||||
<!-- Local //-->
|
||||
<script type="text/javascript" src="{$base_uri}scripts/main.js"></script>
|
||||
|
||||
<link type="text/css" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/themes/smoothness/jquery-ui.css" rel="Stylesheet" />
|
||||
<link rel="stylesheet/less" href="{$base_uri}less/bootstrap.less" media="all" />
|
||||
<link rel="stylesheet" type="text/css" href="{$base_uri}styles/normal.css" />
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div class="topbar">
|
||||
<div class="topbar-inner">
|
||||
<div class="container-fluid">
|
||||
{$page->include_template('navigation')}
|
||||
</div><!-- /tobar-inner -->
|
||||
</div><!-- /container-fliud -->
|
||||
</div><!-- /topbar -->
|
||||
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="span16">
|
||||
<h1>
|
||||
Ben Roberts
|
||||
<small>MEng Computer Science @ ecs.soton.ac.uk</small>
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
{if ! $messages}
|
||||
{$session = Homepage_Main::instance()->session()}
|
||||
{$messages = $session->get('messages')}
|
||||
{$session->delete('messages')}
|
||||
{/if}
|
||||
{if $messages}
|
||||
<div id="messages">
|
||||
{foreach from=$messages item=message}
|
||||
{if is_array($message)}
|
||||
{$severity=$message['severity']}
|
||||
<div class="alert-message {$severity}">
|
||||
{$message['content']|escape:html}
|
||||
</div>
|
||||
{else}
|
||||
<div class="alert-message info">
|
||||
{$message|escape:html}
|
||||
</div>
|
||||
{/if}
|
||||
{/foreach}
|
||||
</div><!-- /messages -->
|
||||
{/if}
|
||||
|
||||
{$page_content}
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<p>
|
||||
Copyright © 2012 by Ben Roberts. All rights reserved unless otherwise specified.
|
||||
</p>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Piwik -->
|
||||
<script type="text/javascript">
|
||||
var pkBaseURL = (("https:" == document.location.protocol) ? "https://miranda.sihnon.net/logs/" : "http://miranda.sihnon.net/logs/");
|
||||
document.write(unescape("%3Cscript src='" + pkBaseURL + "piwik.js' type='text/javascript'%3E%3C/script%3E"));
|
||||
</script><script type="text/javascript">
|
||||
try {
|
||||
var piwikTracker = Piwik.getTracker(pkBaseURL + "piwik.php", 3);
|
||||
piwikTracker.trackPageView();
|
||||
piwikTracker.enableLinkTracking();
|
||||
} catch( err ) {}
|
||||
</script><noscript><p><img src="http://miranda.sihnon.net/logs/piwik.php?idsite=3" style="border:0" alt=""/></p></noscript>
|
||||
<!-- End Piwik Tag -->
|
||||
</body>
|
||||
</html>
|
||||
24
source/webui/templates/navigation.tpl
Normal file
@@ -0,0 +1,24 @@
|
||||
<a class="brand" href="{$base_uri}home/">Ben Roberts</a>
|
||||
|
||||
<ul class="nav">
|
||||
<li {if $requested_page == "home"}class="active"{/if}>
|
||||
<a href="{$base_uri}home/" title="Home">Home</a>
|
||||
</li>
|
||||
|
||||
<li {if $requested_page == "cv"}class="active"{/if}>
|
||||
<a href="{$base_uri}cv/" title="CV">CV</a>
|
||||
</li>
|
||||
|
||||
<li class="dropdown {if $requested_page == "projects"}active{/if}" data-dropdown="dropdown">
|
||||
<a href="#" class="dropdown-toggle" title="Projects">Projects</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="{$base_uri}projects/" title="Projects Home">Home</a></li>
|
||||
<li><a href="https://wiki.sihnon.net/" title="Sihnon Wiki">Sihnon Wiki</a></li>
|
||||
<li><a href="{$base_uri}projects/gentoo-overlay/" title="Gentoo Portage Overlay">Gentoo Overlay</a></li>
|
||||
<li><a href="{$base_uri}projects/sabayon-crepo/" title="Sabayon Entropy Community Repositories">Sabayon Community Repos</a></li>
|
||||
<li><a href="{$base_uri}projects/ripping-cluster/" title="RippingCluster">RippingCluster</a></li>
|
||||
<li><a href="{$base_uri}projects/status-board/" title="StatusBoard">StatusBoard</a></li>
|
||||
<li><a href="{$base_uri}projects/3yp/" title="Third Year Project">Third Year Project</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
23
source/webui/templates/projects.tpl
Normal file
@@ -0,0 +1,23 @@
|
||||
<h2>Opensource Projects</h2>
|
||||
<dl>
|
||||
<dt><a href="https://wiki.sihnon.net/" title="Sihnon Wiki">Sihnon Wiki</a></dt>
|
||||
<dd>Documentation for various systems I've configured; mostly for personal reference, but may be useful to others.</dd>
|
||||
|
||||
<dt><a href="{$base_uri}projects/gentoo-overlay/" title="Gentoo Overlay">Gentoo Portage Overlay</a></dt>
|
||||
<dd>Personally developed software, or miscellaneous ebuilds that can't be found in any other overlay.</dd>
|
||||
|
||||
<dt><a href="{$base_uri}projects/sabayon-crepo/" title="Sabayon Community Repositories">Sabayon Entropy Community Repositories</a></dt>
|
||||
<dd>Personally developed software, or miscellaneous packages for Sabayon Linux that can't be found in the main repositories.</dd>
|
||||
|
||||
<dt><a href="{$base_uri}projects/ripping-cluster/" title="RippingCluster WebUI">RippingCluster WebUI</a></dt>
|
||||
<dd>Web-based UI for transcoding DVDs on a cluster of multiple nodes.</dd>
|
||||
|
||||
<dt><a href="{$base_uri}projects/status-board/" title="StatusBoard">StatusBoard</a></dt>
|
||||
<dd>PHP/Web tool for displaying service status and incident details.</dd>
|
||||
</dl>
|
||||
|
||||
<h2>University Projects</h2>
|
||||
<dl>
|
||||
<dt><a href="{$base_uri}projects/3yp/" title="Third Year Project">Third Year Project</a></dt>
|
||||
<dd>A cross-platform, zero-config file sharing client using public keys and a web of trust for password-less authentication and access control.</dd>
|
||||
</dl>
|
||||
16
source/webui/templates/projects/3yp.tpl
Normal file
@@ -0,0 +1,16 @@
|
||||
<h2>Third Year Project</h2>
|
||||
|
||||
<p>
|
||||
I am still working on my project, but in the mean time I have some binaries available for user testing.
|
||||
Please report any bugs you might find on the <a href="https://bugs.sihnon.net/" title="Sihnon Bug Tracker">bug tracker</a>.
|
||||
</p>
|
||||
<p>
|
||||
These binaries are solely for testing purposes, and may not be redistributed from anywhere other than this site.
|
||||
I may find time to produce a source package in the future.
|
||||
|
||||
<ul>
|
||||
<li><a href="{$base_uri}files/rsdss_1.01_i386.deb" title="Ubuntu x86 deb package">rsdss-1.01-i386.deb</a></li>
|
||||
<li><a href="{$base_uri}files/rsdss-1.0.1-i386.tar.bz2" title="Linux x86 binary archive">rsdss-1.0.1-i386.tar.bz2</a></li>
|
||||
<li><a href="{$base_uri}files/rsdss-1.0.2-win32.zip" title="Windows 32-bit zip archive">rsdss-1.0.2-win32.zip</a></li>
|
||||
</ul>
|
||||
</p>
|
||||
22
source/webui/templates/projects/gentoo-overlay.tpl
Normal file
@@ -0,0 +1,22 @@
|
||||
<h2>Gentoo Portage Overlay</h2>
|
||||
|
||||
<p>
|
||||
The ebuilds in this overlay have mostly been taken from the Gentoo
|
||||
bugzilla, where the packages haven't yet made it into the portage tree. There
|
||||
are also a couple of version-bumped packages, and packages to install homegrown
|
||||
software on local machines. Feel free to use these packages, but do so at your
|
||||
own risk.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
You can install this overlay using layman. Add the the
|
||||
<a href="https://dev.sihnon.net/projects/gentoo-overlay/layman.xml" title="Sihnon overlay url">Sihnon overlay url</a>
|
||||
to your overlays variable in <code class="file">/etc/layman/layman.cfg</code>. Then update
|
||||
the list of overlays with <code class="root">layman -L</code> and add the Sihnon overlay
|
||||
with <code class="root">layman -a sihnon</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The contents of the overlay can be browsed in the
|
||||
<a href="https://git.sihnon.net/cgit.cgi/gentoo-overlay.git/" title="Sihnon Git repository browser">Sihnon Git repository browser</a>.
|
||||
</p>
|
||||
36
source/webui/templates/projects/ripping-cluster.tpl
Normal file
@@ -0,0 +1,36 @@
|
||||
<h2>RippingCluster</h2>
|
||||
|
||||
<p>
|
||||
RippingCluster provides a web interface for managing a cluster of nodes for transcoding DVDs. The application provides the means
|
||||
to list available sources and prepare a list of titles to rip over a collection of nodes using HandBrake and Gearman.
|
||||
</p>
|
||||
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="span8 column">
|
||||
<img class="span8" src="{$base_uri}images/ripping-cluster/overview.png" alt="RippingCluster Overview" />
|
||||
</div>
|
||||
<div class="span8 column">
|
||||
<h3>Features</h3>
|
||||
<ul>
|
||||
<li>Multiple machines can participate in transcoding jobs using a worker daemon.</li>
|
||||
<li>Single WebUI to prepare and manage jobs.</li>
|
||||
<li>Batch multiple titles from a single DVD source (perfect for TV boxsets).</li>
|
||||
<li>Select audio and subtitle streams to include with the rip.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="span16">
|
||||
<h3>Source</h3>
|
||||
<p>
|
||||
View or clone a copy of the Git repositories from one of the mirrors listed below:
|
||||
</p>
|
||||
<ul>
|
||||
<li><a href="https://git.sihnon.net/cgit.cgi/handbrake-cluster-webui.git/" title="Sihnon Mirror">Sihnon Mirror</a></li>
|
||||
<li><a href="https://github.com/optiz0r/handbrake-cluster-webui/" title="GitHub Mirror">GitHub Mirror</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
18
source/webui/templates/projects/sabayon-crepo.tpl
Normal file
@@ -0,0 +1,18 @@
|
||||
<h2>Sabayon Entropy Community Repositories</h2>
|
||||
|
||||
<p>
|
||||
I have a collection of community repositories for both amd64 and i686 architectures. These contain version-bumped or modified packages already
|
||||
present in the upstream repositories, packages available in Gentoo but not Sabayon, and locally-developed software. Feel free to add these if any
|
||||
of the packages inside might be of use, but please be aware they are provided as-is with no guarantees.
|
||||
</p>
|
||||
|
||||
<dl>
|
||||
<dt><a href="http://packages.sihnon.net/standard/packages.sihnon.net/" title="Common Repository">packages.sihnon.net</a></dt>
|
||||
<dd>Packages suitable for machines of any designation.</dd>
|
||||
|
||||
<dt><a href="http://packages.sihnon.net/standard/server.packages.sihnon.net/" title="Server Repository">server.packages.sihnon.net</a></dt>
|
||||
<dd>Packages suitable for server machines (without X).</dd>
|
||||
|
||||
<dt><a href="http://packages.sihnon.net/standard/desktop.packages.sihnon.net/" title="Desktop Repository">desktop.packages.sihnon.net</a></dt>
|
||||
<dd>Packages suitable for desktop machines (with X).</dd>
|
||||
</dl>
|
||||
37
source/webui/templates/projects/status-board.tpl
Normal file
@@ -0,0 +1,37 @@
|
||||
<h2>StatusBoard</h2>
|
||||
|
||||
<p>
|
||||
StatusBoard is a simple PHP web-based tool for displaying the status of services. Administrators can manually record incidents and provide
|
||||
estimated end times and simple descriptions. This tool is suitable for exposing status information to customers or other third parties and
|
||||
does not need to be connected to internal systems.
|
||||
</p>
|
||||
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="span8 column">
|
||||
<h3>Features</h3>
|
||||
<ul>
|
||||
<li>Customisable list of Services and Sites.</li>
|
||||
<li>Manual reporting and status changes for Incidents.</li>
|
||||
<li>Multiple severity levels.</li>
|
||||
<li>Full admin UI.</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="span8 column">
|
||||
<img class="span8" src="{$base_uri}images/status-board/overview.png" alt="StatusBoard Overview" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="span16">
|
||||
<h3>Source</h3>
|
||||
<p>
|
||||
View or clone a copy of the Git repositories from one of the mirrors listed below:
|
||||
</p>
|
||||
<ul>
|
||||
<li><a href="https://git.sihnon.net/cgit.cgi/status-board.git/" title="Sihnon Mirror">Sihnon Mirror</a></li>
|
||||
<li><a href="https://github.com/optiz0r/status-board/" title="GitHub Mirror">GitHub Mirror</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,98 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Template
|
||||
* This file contains the common html elements for all pages in the site.
|
||||
* _template variables contain the information from the acutal page to be displayed
|
||||
*/
|
||||
|
||||
|
||||
|
||||
?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title><?php echo $_template['title']; ?></title>
|
||||
<link rel="stylesheet" type="text/css" href="<?php echo $_meta['base-dir']; ?>/resources/normal.css" />
|
||||
<script language="javascript" type="text/javascript" src="<?php echo $_meta['base-dir']; ?>/resources/email.js"></script>
|
||||
<?php
|
||||
// If we have a redirection, implement a meta refresh here
|
||||
if( $_template['redirect-to'] ) {
|
||||
?>
|
||||
<meta http-equiv="refresh" content="5;url=<?php echo $_template['redirect-to']; ?>" />
|
||||
<?php
|
||||
}
|
||||
|
||||
// Add any header info from the page
|
||||
echo $_template['head'];
|
||||
?>
|
||||
</head>
|
||||
<body>
|
||||
<div class="header">
|
||||
<h1>Ben Roberts</h1>
|
||||
<p class="subtitle">MEng Computer Science @ ecs.soton.ac.uk</p>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="sidebar">
|
||||
<ul>
|
||||
<li><a href="<?php echo $_req->construct('page','home'); ?>" title="Homepage">Home</a></li>
|
||||
<li><a href="<?php echo $_meta['base-dir']; ?>/files/BenRobertsCv.pdf" title="Curriculum Vitae">Curriculum Vitae</a></li>
|
||||
<li><a href="<?php echo $_req->construct('page','projects'); ?>" title="Projects">Projects</a></li>
|
||||
<?php if( $_session->is_logged_in() ) { ?>
|
||||
<li><a href="<?php echo $_req->construct('page','logout'); ?>" title="Logout">Logout</a></li>
|
||||
<?php } ?>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="page">
|
||||
<?php
|
||||
// Display any page annoucements
|
||||
if( count($_template['messages']) > 0 ) {
|
||||
foreach( $_template['messages'] as $_message ) {
|
||||
?>
|
||||
<p class="message">
|
||||
<?php echo $_message; ?>
|
||||
</p>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
?>
|
||||
<h2><?php echo $_template['title']; ?></h2>
|
||||
<?php
|
||||
// Include the main page content
|
||||
echo $_template['page'];
|
||||
|
||||
// Display any redirections
|
||||
if( $_template['redirect-to'] ) {
|
||||
?>
|
||||
<p class="information">
|
||||
About to be redirected... If nothing happens after 10 seconds, please click <a href="<?php echo $_template['redirect-to']; ?>" title="Redirecting">here</a>.
|
||||
</p>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
<p>
|
||||
Copyright © 2008-2010 by Ben Roberts. All rights reserved unless otherwise specified.
|
||||
</p>
|
||||
<p>
|
||||
This file was last modified <?php echo date("j F Y", filemtime($_page)); ?>.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Piwik -->
|
||||
<script type="text/javascript">
|
||||
var pkBaseURL = (("https:" == document.location.protocol) ? "https://miranda.sihnon.net/logs/" : "http://miranda.sihnon.net/logs/");
|
||||
document.write(unescape("%3Cscript src='" + pkBaseURL + "piwik.js' type='text/javascript'%3E%3C/script%3E"));
|
||||
</script><script type="text/javascript">
|
||||
try {
|
||||
var piwikTracker = Piwik.getTracker(pkBaseURL + "piwik.php", 3);
|
||||
piwikTracker.trackPageView();
|
||||
piwikTracker.enableLinkTracking();
|
||||
} catch( err ) {}
|
||||
</script><noscript><p><img src="http://miranda.sihnon.net/logs/piwik.php?idsite=3" style="border:0" alt=""/></p></noscript>
|
||||
<!-- End Piwik Tag -->
|
||||
</body>
|
||||
</html>
|
||||