Page MenuHomeCode

No OneTemporary

This document is not UTF8. It was detected as ISO-8859-1 (Latin 1) and converted to UTF8 for display.
diff --git a/api.php b/api.php
--- a/api.php
+++ b/api.php
@@ -1,60 +1,131 @@
<?php
/*
* Zed
* (c) 2010, Dereckson, some rights reserved
* Released under BSD license
*
* API entry point
*
*/
//API Preferences
define('URL', 'http://' . $_SERVER['HTTP_HOST'] . '/index.php');
//Pluton library
require_once('includes/core.php');
require_once('includes/config.php');
//API libs
require_once('includes/api/api_helpers.php');
require_once('includes/api/cerbere.php');
+//Use our URL controller method if you want to mod_rewrite the API
$url = explode('/', substr($_SERVER['PATH_INFO'], 1));
switch ($module = $url[0]) {
case '':
//Nothing to do
//TODO: offer documentation instead
die();
case 'time':
//Hypership time
api_output(get_hypership_time(), "time");
break;
case 'location':
//Checks creditentials
cerbere();
//Gets location info
require_once("includes/geo/location.php");
$location = new GeoLocation($url[1], $url[2]);
api_output($location, "location");
break;
- case 'perso':
- //Checks creditentials
- cerbere();
- //Gets perso info
- require_once("includes/objects/perso.php");
- $perso = new Perso($url[1]);
- api_output($perso, "perso");
+ //case 'perso':
+ // //Checks creditentials
+ // cerbere();
+ // //Gets perso info
+ // require_once("includes/objects/perso.php");
+ // $perso = new Perso($url[1]);
+ // api_output($perso, "perso");
+ // break;
+
+ case 'ship':
+ //Ship API
+
+ //Gets ship from Ship API key (distinct of regular API keys)
+ require_once('includes/objects/ship.php');
+ $ship = Ship::from_api_key($_REQUEST['key']) or cerbere_die("Invalid ship API key");
+
+ switch ($command = $url[1]) {
+ case '':
+ //Nothing to do
+ //TODO: offer documentation instead
+ die();
+
+ case 'authenticate':
+ //TODO: web authenticate
+ break;
+
+ case 'appauthenticate':
+ //Allows desktop application to authenticate
+ $tmp_session_id = $url[2] or cerbere_die("/appauthenticate/ must be followed by any session identifier");
+ if ($_REQUEST['name']) {
+ //Perso will be offered auth invite at next login.
+ //Handy for devices like PDA, where it's not easy to auth.
+ $perso = new Perso($_REQUEST['name']);
+ if ($perso->lastError) {
+ cerbere_die($perso->lastError);
+ }
+ if (!$ship->is_perso_authenticated($perso->id)) {
+ $ship->request_perso_authenticate($perso->id);
+ }
+ $ship->request_perso_confirm_session($tmp_session_id, $perso->id);
+ } else {
+ //Delivers an URL. App have to redirects user to this URL
+ //launching a browser or printing the link.
+ $ship_code = $ship->get_code();
+ registry_set("api.ship.session.$ship_code.$tmp_session_id", -1);
+ $url = get_server_url() . get_url() . "?action=api.ship.appauthenticate&session_id=" . $tmp_session_id;
+ api_output($url, "URL");
+ }
+ break;
+
+ case 'appauthenticated':
+ //Checks the authentication
+ $tmp_session_id = $url[2] or cerbere_die("/appauthenticated/ must be followed by any session identifier you used in /appauthenticate");
+ $perso_id = $ship->get_perso_from_session($tmp_session_id);
+ if (!$isPersoAuth = $ship->is_perso_authenticated($perso_id)) {
+ //Global auth not ok/revoked.
+ $auth->status = -1;
+ } else {
+ $perso = Perso::get($perso_id);
+ $auth->status = 1;
+ $auth->perso->id = $perso->id;
+ $auth->perso->nickname = $perso->nickname;
+ $auth->perso->name = $perso->name;
+ //$auth->perso->location = $perso->location;
+ //Is the perso on board? Yes if its global location is S...
+ $auth->perso->onBoard = (
+ $perso->location_global[0] == 'S' &&
+ substr($perso->location_global, 1, 5) == $ship->id
+ );
+ if ($auth->perso->onBoard) {
+ //If so, give local location
+ $auth->perso->location_local = $perso->location_local;
+ }
+ }
+ api_output($auth, "auth");
+ break;
+ }
break;
default:
echo "Unknown module:";
dprint_r($url);
break;
}
?>
\ No newline at end of file
diff --git a/controllers/footer.php b/controllers/footer.php
--- a/controllers/footer.php
+++ b/controllers/footer.php
@@ -1,29 +1,31 @@
<?php
/*
* Zed
* (c) 2010, Dereckson, some rights reserved
* Released under BSD license
*
* Footer
*/
///
/// Tutorials div
///
if ($CurrentPerso->flags['hypership.reached'] < 1 && $controller != 'explore') {
if (!DOJO) $smarty->display('tutorial/dojo.tpl');
lang_load("tutorials.conf", "ReachHypership");
$smarty->display('tutorial/hypership_reach.tpl');
}
///
/// HTML output
///
$smarty->assign('MultiPerso', isset($_SESSION['UserWithSeveralPersos']) && $_SESSION['UserWithSeveralPersos']);
+$smarty->assign('SmartLineFormMethod', $CurrentPerso->get_flag('site.smartline.method'));
+
lang_load('footer.conf');
$smarty->display('footer.tpl');
?>
\ No newline at end of file
diff --git a/controllers/motd.php b/controllers/motd.php
--- a/controllers/motd.php
+++ b/controllers/motd.php
@@ -1,41 +1,41 @@
<?php
/*
- * Azhàr, faeries intranet
- * (c) 2009-2010, Wolfæym, some rights reserved
+ * Zed
+ * (c) 2010, Dereckson, some rights reserved
* Released under BSD license
*
* Raw text or HTML content
*/
//Loads smarty language file
lang_load('motd.conf');
//
// Handles form
//
if ($_REQUEST['text']) {
require_once('includes/objects/motd.php');
$motd = new MOTD();
$motd->text = $_REQUEST['text'];
$motd->perso_id = $CurrentPerso->id;
$motd->save_to_database();
$smarty->assign('WAP', lang_get('Published'));
}
//
// HTML output
//
//Serves header
$smarty->assign('PAGE_TITLE', lang_get('PushMessage'));
include('header.php');
//Serves content
$smarty->display('motd_add.tpl');
//Servers footer
include('footer.php');
?>
\ No newline at end of file
diff --git a/controllers/persorequest.php b/controllers/persorequest.php
new file mode 100644
--- /dev/null
+++ b/controllers/persorequest.php
@@ -0,0 +1,142 @@
+<?php
+
+/*
+ * Zed
+ * (c) 2010, Dereckson, some rights reserved
+ * Released under BSD license
+ *
+ * Perso requests
+ */
+
+///
+/// Helper class and method
+///
+
+class PersoRequest {
+ public $message;
+ public $requestFlag;
+ public $flag;
+ public $store = 'perso';
+ public $value_allow = 1;
+ public $value_deny = 0;
+
+ function __construct ($requestFlag, $message, $flag) {
+ $this->requestFlag = $requestFlag;
+ $this->message = $message;
+ $this->flag = $flag;
+ }
+}
+
+/*
+ * Gets ship from specified S00001 code
+ * @param string $ship_code the ship code (e.g. S00001)
+ * @return Ship the Ship class instance
+ */
+function get_ship ($ship_code) {
+ require_once('includes/objects/ship.php');
+ static $ships;
+ $ship_id = substr($ship_code, 1);
+ if (!$ships[$ship_id]) $ships[$ship_id] = new Ship($ship_id);
+ return $ships[$ship_id];
+}
+
+/*
+ * Gets request allow URL
+ * @param PersoRequest $request the perso request to confirm
+ */
+function get_request_allow_url ($request) {
+ return get_request_url($request->requestFlag, $request->store, $request->flag, $request->value_allow);
+}
+
+/*
+ * Gets request deny URL
+ * @param PersoRequest $request the perso request to confirm
+ */
+
+function get_request_deny_url ($request) {
+ return get_request_url($request->requestFlag, $request->store, $request->flag, $request->value_deny);
+}
+
+/*
+ * Gets request URL
+ * @param string $store 'perso' or 'registry'
+ * @param string $key the perso flag or registry key
+ * @param string $value the value to store
+ */
+function get_request_url ($requestFlag, $store, $key, $value) {
+ global $Config;
+ $hash = md5($_SESSION['ID'] . $Config['SecretKey'] . $requestFlag . $store . $key . $value);
+ return "$Config[DoURL]/perso_request/$requestFlag/$store/$key/$value/$hash";
+}
+
+///
+/// Get requests
+///
+
+//Loads perso request language file
+lang_load('persorequest.conf');
+
+//The array request will be passed to Smarty and will contain PersoRequest items.
+$requests = array();
+
+foreach ($CurrentPerso->flags as $flag => $value) {
+ if ($value && substr($flag, 0, 8) == "request.") {
+ if (string_starts_with($flag, 'request.api.ship.auth.')) {
+ //Gets ship
+
+ $ship_code = substr($flag, 22);
+ $ship = get_ship($ship_code);
+
+ //Adds request
+ $message = sprintf(lang_get('RequestShipAPIAuthenticate'), $ship->name);
+ $requests[] = new PersoRequest($flag, $message, substr($flag, 8));
+ } elseif (string_starts_with($flag, 'request.api.ship.session.')) {
+ //Gets ship
+ $ship_code = substr($flag, 25, 6);
+ $ship = get_ship($ship_code);
+
+ //Adds request
+ $message = sprintf(lang_get('RequestShipAPISessionConfirm'), $ship->name);
+ $request = new PersoRequest($flag, $message, substr($flag, 8));
+ $request->value_allow = $CurrentPerso->id;
+ $request->value_deny = -1;
+ $request->store = 'registry';
+ $requests[] = $request;
+ } else {
+ message_die(GENERAL_ERROR, "Unknown request flag: $flag. Please report this bug.");
+ }
+ }
+}
+
+///
+/// Requests handling
+///
+
+if (count($requests) == 0) {
+ //If site.requests flag is at 1 but we don't have request, ignore processing
+ $CurrentPerso->set_flag('site.requests', 0);
+
+ //We don't die, so next controller takes relay
+} else {
+ ///
+ /// HTML output
+ ///
+
+ //Serves header
+ define('DOJO', true);
+ $smarty->assign('PAGE_TITLE', lang_get('PersoRequests'));
+ include('header.php');
+
+ //Serves content
+ $smarty->assign('requests', $requests);
+ $smarty->display('persorequests.tpl');
+
+ //Serves footer
+ $smarty->assign("screen", "Perso requests");
+ include('footer.php');
+
+ //Dies
+ exit;
+}
+
+?>
\ No newline at end of file
diff --git a/controllers/profile.php b/controllers/profile.php
--- a/controllers/profile.php
+++ b/controllers/profile.php
@@ -1,307 +1,307 @@
<?php
/*
* Zed
* (c) 2010, Dereckson, some rights reserved
* Released under BSD license
*
* This code is maintained in // with Azhàr
*
* User profile
*/
//Loads language file
lang_load('profile.conf');
//Gets perso nickname from URL
$who = $url[1];
switch ($who) {
case 'edit':
$mode = 'edit';
$who = $CurrentPerso->nickname;
break;
case 'random':
$mode = 'view';
$who = $db->sql_query_express("SELECT perso_id FROM " . TABLE_PROFILES . " ORDER BY rand() LIMIT 1");
break;
default:
$mode = 'view';
}
if (!$who) {
message_die(GENERAL_ERROR, "Who?", "URL error");
}
//Libs
require_once('includes/objects/profile.php');
require_once('includes/objects/profilecomment.php');
require_once('includes/objects/profilephoto.php');
//Gets perso information
require_once('includes/objects/perso.php');
-$perso = new Perso($who);
+$perso = Perso::get($who);
if ($perso->lastError) {
message_die(GENERAL_ERROR, $perso->lastError, "Error");
}
//Gets profile
$profile = new Profile($perso->id);
//Handles form
if ($_POST['EditProfile']) {
$profile->load_from_form();
$profile->updated = time();
$profile->save_to_database();
$mode = 'view';
} elseif ($_POST['UserAccount']) {
$smarty->assign('WAP', "Your form haven't been handled. Remember Dereckson to code this, profile.php line 59.");
//$perso->load_from_form(false);
$mode = 'view';
} elseif ($_POST['message_type'] == 'private_message') {
//Sends a message
require_once('includes/objects/message.php');
$msg = new Message();
$msg->from = $CurrentPerso->id;
$msg->to = $perso->id;
$msg->text = $_POST['message'];
$msg->send();
if ($msg->from == $msg->to) {
$smarty->assign('NOTIFY', lang_get('MessageSentSelf'));
} else {
$smarty->assign('NOTIFY', lang_get('MessageSent'));
}
} elseif ($_POST['message_type'] == 'profile_comment') {
//New profile comment
$comment = new ProfileComment();
$comment->author = $CurrentPerso->id;
$comment->perso_id = $perso->id;
$comment->text = $_POST['message'];
$comment->publish();
$smarty->assign('NOTIFY', lang_get('CommentPublished'));
} elseif ($_FILES['photo']) {
#We've a file !
$hash = md5(microtime() . serialize($_FILES));
$extension = get_extension($_FILES['photo']['name']);
$filename = $CurrentPerso->id . '_' . $hash . '.' . $extension;
#We ignore $_FILES[photo][error] 4, this means no file has been uploaded
#(so user doesn't want upload a new file)
#See http:/www.php.net/features.file-upload and http://www.php.net/manual/en/features.file-upload.errors.php about common errors
#Not valid before PHP 4.2.0
switch ($_FILES['photo']['error']) {
case 0:
#There is no error, the file uploaded with success.
if (!move_uploaded_file($_FILES['photo']['tmp_name'], PHOTOS_DIR . '/' . $filename)) {
$errors[] = "Upload successful, but error saving it.";
} else {
//Attaches the picture to the profile
$photo = new ProfilePhoto();
$photo->name = $filename;
$photo->perso_id = $CurrentPerso->id;
$photo->description = $_POST['description'];
if ($photo->avatar) $photo->promote_to_avatar();
$photo->save_to_database();
//Generates thumbnail
if (!$photo->generate_thumbnail()) {
$smarty->assign('WAP', "Error generating thumbnail.");
}
$smarty->assign('NOTIFY', lang_get('PhotoUploaded'));
$mode = 'view';
}
break;
case 1:
$errors[] = "The file is too large.";
break;
#TODO : more explicit error messages
default:
$errors[] = "Unknown error (#" . $_FILES['photo']['error'] . ")";
break;
}
if (count($errors)) {
$smarty->assign('WAP', join($errors, '<br />'));
}
} elseif ($_POST['id']) {
//Edits photo properties
$photo = new ProfilePhoto($_POST['id']);
if ($photo->lastError) {
$smarty->assign('WAP', $photo->lastError);
$mode = 'view';
} elseif ($photo->perso_id != $CurrentPerso->id) {
$smarty->assign('WAP', lang_get('NotYourPic'));
$mode = 'view';
} else {
//OK
$wereAvatar = $photo->avatar;
$photo->load_from_form();
if (!$wereAvatar && $photo->avatar) {
//Promote to avatar
$photo->promote_to_avatar();
}
$photo->save_to_database();
}
}
//Prepares output
if ($profile->text) {
//Profile
$smarty->assign('PROFILE_TEXT', $profile->text);
$smarty->assign('PROFILE_FIXEDWIDTH', $profile->fixedwidth);
}
if ($mode == 'view') {
require_once('includes/objects/profilephoto.php');
//Self profile?
$self = $CurrentPerso->id == $profile->perso_id;
//Gets profiles comments, photos
$comments = ProfileComment::get_comments($profile->perso_id);
$photos = ProfilePhoto::get_photos($profile->perso_id);
//Records timestamp, to be able to track new comments
if ($self) $CurrentPerso->set_flag('profile.lastvisit', time());
//Template
$smarty->assign('PROFILE_COMMENTS', $comments);
$smarty->assign('PROFILE_SELF', $self);
$smarty->assign('USERNAME', $perso->username);
$smarty->assign('NAME', $perso->name ? $perso->name : $perso->nickname);
$template = 'profile.tpl';
} elseif ($mode == 'edit') {
switch ($url[2]) {
case 'profile':
$smarty->assign('USERNAME', $perso->name);
$smarty->assign('DIJIT', true);
$css[] = 'forms.css';
$template = 'profile_edit.tpl';
break;
case 'account':
$smarty->assign('user', $CurrentUser);
$smarty->assign('DIJIT', true);
$css[] = 'forms.css';
$template = 'user_account.tpl';
break;
case '':
$smarty->assign('NOTIFY', "What do you want to edit ? Append /profile, /account or /photos to the URL");
break;
case 'photo':
case 'photos':
$smarty->assign('USERNAME', $perso->name);
switch ($action = $url[3]) {
case '':
//Nothing to do
break;
case 'delete':
//Deletes a picture
if (!$id = $url[4]) {
$smarty->assign('WAP', "URL error. Parameter missing: picture id.");
} else {
$photo = new ProfilePhoto($id);
if ($photo->lastError) {
//Probably an non existent id (e.g. double F5, photo already deleted)
$smarty->assign('WAP', $photo->lastError);
} elseif ($photo->perso_id != $CurrentPerso->id) {
$smarty->assign('WAP', lang_get('NotYourPic'));
} else {
//OK we can delete it
$photo->delete();
$smarty->assign('NOTIFY', lang_get('PictureDeleted'));
}
}
break;
case 'edit':
if (!$id = $url[4]) {
$smarty->assign('WAP', "URL error. Parameter missing: picture id.");
} else {
$photo = new ProfilePhoto($id);
if ($photo->lastError) {
//Probably an non existent id (e.g. double F5, photo already deleted)
$smarty->assign('WAP', $photo->lastError);
} elseif ($photo->perso_id != $CurrentPerso->id) {
$smarty->assign('WAP', lang_get('NotYourPic'));
} else {
//Photo information edit form
$smarty->assign('photo', $photo);
$template = 'profile_photo_edit.tpl';
}
}
break;
case 'avatar':
//Promotes a picture to avatar
if (!$id = $url[4]) {
$smarty->assign('WAP', "URL error. Parameter missing: picture id.");
} else {
$photo = new ProfilePhoto($id);
if ($photo->lastError) {
$smarty->assign('WAP', $photo->lastError);
} elseif ($photo->perso_id != $CurrentPerso->id) {
$smarty->assign('WAP', lang_get('NotYourPic'));
} else {
//OK, promote it to avatar
$photo->promote_to_avatar();
$photo->save_to_database();
$smarty->assign('NOTIFY', lang_get('PromotedToAvatar'));
}
}
break;
default:
$smarty->assign('WAP', "Unknown URL. To delete a picture it's /delete/<picture id>. To edit it /edit/<picture id>");
break;
}
if (!$template) {
$photos = ProfilePhoto::get_photos($profile->perso_id);
if (!$smarty->_tpl_vars['NOTIFY'])
$smarty->assign('NOTIFY', "Your feedback is valued. Report any bug or suggestion on the graffiti wall.");
$template = 'profile_photo.tpl';
}
break;
default:
$smarty->assign('WAP', "URL error. You can use /edit with profile, account or photos.");
break;
}
}
//
// HTML output
//
//Photos
if (count($photos) || $photo) {
$smarty->assign('URL_PICS', PHOTOS_URL);
$css[] = 'lightbox.css';
$smarty->assign('PAGE_JS', array('prototype.js', 'scriptaculous.js?load=effects', 'lightbox.js'));
$smarty->assign('PICS', $photos);
}
//Serves header
$css[] = "profile.css";
$smarty->assign('PAGE_CSS', $css);
$smarty->assign('PAGE_TITLE', $perso->name);
include('header.php');
//Serves content
if ($template) $smarty->display($template);
//Serves footer
include('footer.php');
?>
\ No newline at end of file
diff --git a/controllers/usersearch.php b/controllers/usersearch.php
--- a/controllers/usersearch.php
+++ b/controllers/usersearch.php
@@ -1,100 +1,100 @@
<?php
/*
- * Azhàr, faeries intranet
- * (c) 2009-2010, Wolfæym, some rights reserved
+ * Zed
+ * (c) 2010, Dereckson, some rights reserved
* Released under BSD license
*
* User search
*/
//Libs
require_once('includes/objects/ProfilePhoto.php');
//
// Does the search
//
//Search type
switch ($resource = $url[1]) {
case '':
break;
case 'online':
$sql = "SELECT u.username, u.user_id, u.user_longname FROM " .
TABLE_USERS . " u, " . TABLE_SESSIONS .
" s WHERE s.online = 1 AND u.user_id = s.user_id
ORDER BY HeureLimite DESC";
if (!$result = $db->sql_query($sql)) {
message_die(SQL_ERROR, "Unable to query the table", '', __LINE__, __FILE__, $sql);
}
$i = 0;
while ($row = $db->sql_fetchrow($result)) {
$users[$i]->id = $row['user_id'];
$users[$i]->username = $row['username'];
$users[$i]->longname = $row['user_longname'];
$i++;
}
$title = sprintf(lang_get('UsersOnline'), $i, s($i));
break;
case 'directory':
$sql = 'SELECT username, user_longname FROM ' . TABLE_USERS .
' WHERE user_active < 2 ORDER by user_longname ASC';
if (!$result = $db->sql_query($sql)) {
message_die(SQL_ERROR, "Unable to query the table", '', __LINE__, __FILE__, $sql);
}
$i = 0;
while ($row = $db->sql_fetchrow($result)) {
$users[$i]->username = $row['username'];
$users[$i]->longname = $row['user_longname'];
$i++;
}
$title = lang_get('Directory');
$mode = 'directory';
break;
default:
$smarty->assign('WAP', lang_get('Nay'));
break;
}
switch ($mode) {
case 'directory':
$template = 'directory.tpl';
$smarty->assign('USERS', $users);
break;
default:
//Prepares avatars
if (count($users)) {
foreach ($users as $user) {
$name = $user->longname ? $user->longname : $user->username;
$user->avatar = ProfilePhoto::get_avatar($user->id, $name);
}
}
$template = 'usersearch.tpl';
$smarty->assign('TITLE', $title);
$smarty->assign('USERS', $users);
break;
}
//
// HTML output
//
//Serves header
$smarty->assign('PAGE_CSS', 'usersearch.css');
$smarty->assign('PAGE_TITLE', $title);
include('header.php');
//Serves content
if ($template)
$smarty->display($template);
//Serves footer
include('footer.php');
?>
\ No newline at end of file
diff --git a/css/zed/theme.css b/css/zed/theme.css
--- a/css/zed/theme.css
+++ b/css/zed/theme.css
@@ -1,400 +1,401 @@
@charset "utf-8";
/* -------------------------------------------------------------
Zed
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Author: Dereckson
Tags: space retro futurist
Filename: forms.css
Version: 1.0
Created: 2010-01-27
Updated: 2010-01-27
Licence: Creative Commons BY 3.0
------------------------------------------------------------- */
/* -------------------------------------------------------------
Page settings
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
body {
margin: 0 0 0 0;
background-attachment: fixed;
background-color: #343434;
background-image: url("../../img/zed/bg.jpg");
background-position: top left;
background-repeat: no-repeat;
font-family: "Calibri", "Lucida Sans Unicode", "Trebuchet MS", "Helvetica", "Arial", sans-serif;
min-height: 1200px;
color: white;
}
#content {
width: 980px;
background-image: url("../../img/zed/bg_content.jpg");
background-position: top left;
background-repeat: no-repeat;
}
h1, h2, h3, h4, h5, h6 {
color: #04acf8;
font-weight: normal;
}
h1 {
color: #19B5E7;
font-size: 21px;
font-weight: normal;
}
h2 {
font-size: 19px;
}
pre {
font-family: FixedSys, monospace;
}
/* -------------------------------------------------------------
Links
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
a {
color: #1AC8E8;
text-decoration: none;
}
a:visited {
color: gray;
}
a:hover {
color: red;
text-decoration: none;
}
/* -------------------------------------------------------------
Notify messages
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
.notify {
padding-top: 25px;
padding-bottom: 25px;
margin-bottom: 10px;
text-align: center;
background: #eeeeee;
font-size: 1.5em;
color: black;
border: 5px solid #1AC8E8;
width: 950px;
}
.wap {
padding-top: 50px;
padding-bottom: 50px;
margin-bottom: 10px;
text-align: center;
background: #eeeeee;
font-size: 2em;
color: black;
border: 5px solid indianred;
width: 950px;
}
/* -------------------------------------------------------------
Header
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#header {
background-color: #1fbeba;
background-image: url("../../img/zed/bg_header.jpg");
background-repeat: repeat-x;
background-position: top left;
height: 81px;
margin-bottom: 3.14em;
}
#header_content {
background-image: url("../../img/zed/bg_header_content.jpg");
height: 74px;
}
/* -------------------------------------------------------------
Header - wall
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
.wall {
text-align: left;
float: right;
}
.wall_info {
display: block;
text-align: right;
font-size: 80%;
}
.wall a {
color: white;
}
.wall a:hover {
color: #cae2fd;
}
/* -------------------------------------------------------------
Info
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
.info {
width: 584px;
height: 25px;
background-image: url(/img/zed/bg_meta.png);
margin-bottom: 1em;
padding-top: 7px;
font-size: 90%;
}
.info strong {
display: inline-block;
display: -moz-inline-box;
width: 9em;
min-width: 9em;
font-weight: 600;
color: #fd9800;
}
.info_left {
float: left;
width: 415px;
margin-left: 20px;
margin-right: 18px;
}
#HypershipTime {
color: red;
}
.info_right {
float: left;
width: 130px;
}
/* -------------------------------------------------------------
Avatars wall
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
.avatar {
float: left;
margin-bottom: 2em;
margin-right: 2em;
text-align: center;
}
.avatar_name {
display: block;
}
/* -------------------------------------------------------------
Messages
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
.message {
margin-bottom: 17px;
padding: 8px 9px 8px 9px;
width: 940px;
font-size: 80%;
}
.message.light {
background-color: #fafafa;
border: 3px solid #dedede;
width: 938px;
color: black;
}
.message.light a {color: #343434;}
.message.dark {
background-color: #acc0c3;
border: solid 3px #4e5758;
width: 938px;
+ color: #000033;
}
.message.dark a {color: #154c4c;}
.message a:hover {
font-weight: 900;
}
.message_info {
text-align: right;
margin-bottom: 1em;
}
.message_text {
font-size: 1.25em;
}
.message_info {
color: #343434;
}
/* -------------------------------------------------------------
Color boxes
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
.plum {
background-color: plum;
border: 1px solid #800080;
color: black;
}
.plum a { color: #800080; }
.green {
background-color: beige;
border: 1px solid darkgreen;
color: black;
}
.green a { color: darkgreen; }
.skyblue {
background-color: lightskyblue;
border: 1px solid #6e47fe;
}
.skyblue a { color:navy }
.indigo {
background-color: #AE97E1;
border: 1px solid #C97FFF;
}
.indigo a {color: #800080;}
.yellow {
background-color: #FFFFCC;
border: 1px solid #C4B963;
}
.yellow a {color: navy;}
.orange {
background-color: #FDD9AC;
border: 1px solid #eaaf67;
}
.orange a {color: #43392e;}
.red {
background-color: #FFE4E1;
border: solid 1px #DC7777;
}
.red a {color: #993333;}
.black {
background-color: black;
color: #ccc;
border: solid 2px #555;
}
.plum a:hover,
.green a:hover,
.skyblue a:hover,
.indigo a:hover,
.yellow a:hover,
.orange a:hover,
.red a:hover{
font-weight: bold;
}
/* -------------------------------------------------------------
SmartLine
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#SmartLine {
width: 100%;
}
#SmartLine .left {
}
#SmartLine .right {
float: right;
text-align: right;
}
/* TODO: ajouter un sélecteur de SmarLine pour chat/commandes (60px) */
/* grid_1 alpha -> sélecteur, grid_3 -> history, grid_12 > bar */
#SmartLineHistory {
width: 115%; /* dépasse de sa bordure */
}
#SmartLineBar{
/* 99.6% for alignment with .message.light */
width: 99.6%;
}
#SmartLineResults {
font-family: "Fixedsys Excelsior 3.01", FixedSys, Terminal;
font-size: 12pt;
}
#SmartLineResults .highlight {
color: #16c3cc;
}
#SmartLineResults .error {
color: red;
}
#SmartLineResults p {
padding-left: 1em;
}
/* -------------------------------------------------------------
Floating panes
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
.floatingPaneTutorial {
width: 957.5px;
margin-bottom: 1em;
color: black;
}
.floatingPaneTutorial a {
color: navy;
}
.floatingPaneTutorial a:hover {
color: #5f0505;
}
.floatingPaneTutorial p {
color: black;
margin: 0;
padding: 5px 10px 0px 10px;
}
.dojoxDockList {
color: black;
}
/* -------------------------------------------------------------
Footer
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#footer {
font-size: 80%;
}
\ No newline at end of file
diff --git a/dev/quux.php b/dev/quux.php
new file mode 100644
--- /dev/null
+++ b/dev/quux.php
@@ -0,0 +1,9 @@
+<?php
+ require_once('includes/objects/ship.php');
+ $ship = new Ship(1);
+ Ship::clean_ship_sessions();
+
+ include('controllers/header.php');
+ echo "<p>Sessions cleaned</p>";
+ include('controllers/footer.php');
+?>
\ No newline at end of file
diff --git a/dev/restore_persos_flags.sql b/dev/restore_persos_flags.sql
new file mode 100644
--- /dev/null
+++ b/dev/restore_persos_flags.sql
@@ -0,0 +1,14 @@
+---
+--- Empties the table and inserts again my flags
+--- Dereckson
+---
+
+TRUNCATE `persos_flags`;
+
+INSERT INTO `persos_flags` (`perso_id`, `flag_key`, `flag_value`)
+VALUES
+(5555, 'hypership.reached', '3'),
+(5555, 'admin.pages.editor', '1'),
+(5555, 'admin.api.keyprovider', '1'),
+(1148, 'site.smartline.method', 'get'),
+(5555, 'site.smartline.method', 'get');
diff --git a/do.php b/do.php
new file mode 100644
--- /dev/null
+++ b/do.php
@@ -0,0 +1,186 @@
+<?php
+
+/*
+ * Zed
+ * (c) 2010, Dereckson, some rights reserved
+ * Released under BSD license
+ *
+ * AJAX callbacks
+ *
+ * As main controller could potentially be interrupted (e.g. if site.requests
+ * flag is at 1, user is redirected to controllers/userrequest.php), all AJAX
+ * queries should be handled by this script and not directly by the controllers.
+ *
+ * Standard return values:
+ * -7 user is logged but perso isn't selected
+ * -9 user is not logged
+ *
+ */
+
+////////////////////////////////////////////////////////////////////////////////
+///
+/// Initialization
+///
+
+//Standard return values
+define('USER_NOT_LOGGED', -9);
+define('PERSO_NOT_SELECTED', -7);
+
+//Pluton library
+include('includes/core.php');
+
+//Session
+$IP = encode_ip($_SERVER["REMOTE_ADDR"]);
+require_once('includes/story/story.php'); //this class can be stored in session
+session_start();
+$_SESSION[ID] = session_id();
+session_update(); //updates or creates the session
+
+include("includes/login.php"); //login/logout
+$CurrentUser = get_logged_user(); //Gets current user infos
+
+//Gets current perso
+require_once('includes/objects/perso.php');
+if ($perso_id = $CurrentUser->session['perso_id']) {
+ $CurrentPerso = new Perso($perso_id);
+}
+
+//Requires user and perso
+if ($CurrentUser->id < 1000) {
+ echo USER_NOT_LOGGED;
+ exit;
+}
+if (!$CurrentPerso) {
+ echo PERSO_NOT_SELECTED;
+ exit;
+}
+
+//Loads Smarty (as it handles l10n, it will be used by lang_get)
+require('includes/Smarty/Smarty.class.php');
+$smarty = new Smarty();
+$current_dir = dirname(__FILE__);
+$smarty->compile_dir = $current_dir . '/cache/compiled';
+$smarty->cache_dir = $current_dir . '/cache';
+$smarty->config_dir = $current_dir;
+
+//Loads language files
+initialize_lang();
+lang_load('core.conf');
+
+
+////////////////////////////////////////////////////////////////////////////////
+///
+/// Actions definitions
+///
+
+/*
+ * Actions class
+ * Each method is called by first part of your URL, other parts are arguments
+ * e.g. /do.php/validate_quux_request/52 = Actions::validate_quux_request(52);
+ *
+ * You can also use $_GET, $_POST or better $_REQUEST.
+ *
+ * Don't echo the value but return it, so we can in the future implement custom
+ * formats like api_output();
+ */
+
+class Actions {
+ /*
+ * Checks the arguments hash
+ * @param Array $args the arguments, the last being the hash
+ */
+ static private function is_hash_valid ($args) {
+ global $Config;
+ return array_pop($args) == md5($_SESSION['ID'] . $Config['SecretKey'] . implode('', $args));
+ }
+
+ /*
+ * Handles a allow/deny perso request
+ * @param string $request_flag the request flag to clear
+ * @param string $store 'perso' or 'registry'
+ * @param string $key the perso flag or registry key
+ * @param string $value the value to store
+ * @param string $hash the security hash
+ * @return boolean true if the request is valid and have been processed ; otherwise, false.
+ */
+ static function perso_request ($request_flag, $store, $key, $value, $hash) {
+ //Ensures we've the correct amount of arguments
+ if (func_num_args() < 4) return false;
+
+ //Checks hash
+ $args = func_get_args();
+ if (!self::is_hash_valid($args)) {
+ return false;
+ }
+
+ //Sets flag
+ switch ($store) {
+ case 'perso':
+ global $CurrentPerso;
+ $CurrentPerso->set_flag($key, $value);
+ break;
+
+ case 'registry':
+ registry_set($key, $value);
+ break;
+
+ default:
+ //Unknown storage location
+ return false;
+ }
+
+ //Clears request flag
+ if ($request_flag != 0)
+ $CurrentPerso->delete_flag($request_flag);
+
+ return true;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+///
+/// Handles request
+///
+
+//You really should use $_SERVER['PATH_INFO']
+//i.e. calling /do.php/your request without any mod rewrite intervention
+//
+//If you choose otherwise, uncomment and tweak one of the following lines:
+//$Config['SiteURL'] = 'http://yourserver/zed/do.php';
+//$Config['SiteURL'] = get_server_url() . '/do.php';
+$args = get_current_url_fragments();
+
+$method = array_shift($args);
+
+if ($_REQUEST['debug']) {
+ //Debug version
+ //Most of E_STRICT errors are evaluated at the compile time thus such errors
+ //are not reported
+ ini_set('display_errors', 'stderr');
+ error_reporting(-1);
+ if (method_exists('Actions', $method)) {
+ $result = call_user_func_array(array('Actions', $method), $args);
+ echo json_encode($result);
+ } else {
+ echo "<p>Method doesn't exist: $method</p>";
+ }
+
+ if (array_key_exists('redirectTo', $_REQUEST)) {
+ //If user JS disabled, you can add ?redirectTo= followed by an URL
+ echo "<p>Instead to print a callback value, redirects to <a href=\"$_REQUEST[redirectTo]\">$_REQUEST[redirectTo]</a></p>";
+ }
+} else {
+ //Prod version doesn't prints warning <== silence operator
+ if (method_exists('Actions', $method)) {
+ $result = @call_user_func_array(array('Actions', $method), $args);
+
+ if (array_key_exists('redirectTo', $_REQUEST)) {
+ //If user JS disabled, you can add ?redirectTo= followed by an URL
+ header("location: " . $_REQUEST['redirectTo']);
+ } else {
+ echo json_encode($result);
+ }
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/includes/SmartLine/ZedCommands.php b/includes/SmartLine/ZedCommands.php
--- a/includes/SmartLine/ZedCommands.php
+++ b/includes/SmartLine/ZedCommands.php
@@ -1,190 +1,208 @@
<?php
/*
* Zed
* (c) 2010, Dereckson, some rights reserved
* Released under BSD license
*
* SmartLine
*
*/
///
/// Register commands
///
$smartLine->register_object('goto', 'GotoSmartLineCommand');
$smartLine->register_object('guid', 'GUIDSmartLineCommand');
$smartLine->register_object('list', 'ListSmartLineCommand');
$smartLine->register_object('unixtime', 'UnixTimeSmartLineCommand');
+$smartLine->register_object('requests', 'RequestsSmartLineCommand');
$smartLine->register_object('whereami', 'WhereAmISmartLineCommand');
+
+///
+/// Help (todo: move $lang array in lang folder)
+///
+
+$lang['Help']['goto'] = "Go to a location";
+$lang['Help']['guid'] = "Generate a GUID";
+$lang['Help']['list'] = "Lists specified objects (bodies, locations or places)";
+$lang['Help']['requests'] = "Checks if there are waiting requests";
+$lang['Help']['unixtime'] = "Prints current unixtime (seconds elapsed since 1970-01-01 00:00, UTC) or the specified unixtime date.";
+$lang['Help']['whereami'] = "Where am I?";
+
///
/// whereami
///
-$lang['Help']['whereami'] = "Where am I?";
-
class WhereAmISmartLineCommand extends SmartLineCommand {
public function run ($argv, $argc) {
global $CurrentPerso;
require_once("includes/geo/location.php");
$place = new GeoLocation($CurrentPerso->location_global);
$this->SmartLine->puts($CurrentPerso->location_global . ' - ' . $place);
}
}
///
/// GUID
///
-$lang['Help']['GUID'] = "Generate a GUID";
-
class GUIDSmartLineCommand extends SmartLineCommand {
public function run ($argv, $argc) {
if ($argc > 1 && is_numeric($argv[1])) {
for ($i = 0 ; $i < $argv[1] ; $i++) {
$this->SmartLine->puts(new_guid());
}
return;
}
$this->SmartLine->puts(new_guid());
-
+ }
+}
+
+///
+/// Requests
+///
+
+class RequestsSmartLineCommand extends SmartLineCommand {
+ public function run ($argv, $argc) {
+ global $CurrentPerso;
+ if (array_key_exists('site.requests', $CurrentPerso->flags) && $CurrentPerso->flags['site.requests']) {
+ global $controller;
+ $controller = 'controllers/persorequest.php';
+ } else {
+ $this->SmartLine->puts("No request waiting.");
+ }
}
}
///
/// goto
///
-$lang['Help']['goto'] = "Go to a location";
-
class GotoSmartLineCommand extends SmartLineCommand {
public function run ($argv, $argc) {
global $CurrentPerso;
if ($argc == 1) {
$this->SmartLine->puts("Where do you want to go?", STDERR);
return;
}
require_once("includes/geo/location.php");
try {
$place = new GeoLocation($argv[1]);
} catch (Exception $ex) {
$this->SmartLine->puts($ex->getMessage(), STDERR);
return;
}
if ($place->equals($CurrentPerso->location_global)) {
$this->SmartLine->puts("You're already there.");
return;
}
if (!$place->exists()) {
$this->SmartLine->puts("This place doesn't seem to exist.");
return;
}
$this->SmartLine->puts("TODO: code travel assistant");
}
}
///
/// list
///
-$lang['Help']['list'] = "Lists specified objects (bodies, locations or places)";
-
class ListSmartLineCommand extends SmartLineCommand {
public function run ($argv, $argc) {
if ($argc == 1) {
$this->SmartLine->puts("Available lists: bodies, locations, places");
return;
}
switch ($objects = $argv[1]) {
case 'bodies':
$list = $this->get_list(TABLE_BODIES, "CONCAT('B', body_code)", "body_name");
$this->SmartLine->puts($list);
break;
case 'locations':
$list = $this->get_list(TABLE_LOCATIONS, "location_code", "location_name");
$this->SmartLine->puts($list);
break;
case 'places':
if ($argv[2] == "-a" || $argv[2] == "--all") {
//Global bodies places list
$list = $this->get_list(TABLE_PLACES, "CONCAT('B', body_code, place_code)", "place_name");
} else {
//Local places (or equivalent) list
global $CurrentPerso;
switch ($CurrentPerso->location_global[0]) {
case 'B':
$body_code = substr($CurrentPerso->location_global, 1, 5);
$list = $this->get_list(TABLE_PLACES, "CONCAT('B', body_code, place_code)", "place_name", "body_code = $body_code");
break;
case 'S':
$this->SmartLine->puts("I don't have a map of the spaceship.", STDERR);
return;
default:
$this->SmartLine->puts("Unknown location type. Can only handle B or S.", STDERR);
return;
}
}
$this->SmartLine->puts($list);
break;
default:
$this->SmartLine->puts("Unknown objects to list: $objects", STDERR);
}
}
public function get_list ($table, $key, $value, $where = null) {
global $db;
$sql = "SELECT $key as `key`, $value as value FROM $table ";
if ($where) $sql .= "WHERE $where ";
$sql .= "ORDER BY `key` ASC";
if (!$result = $db->sql_query($sql)) {
message_die(SQL_ERROR, "Unable to fetch list", '', __LINE__, __FILE__, $sql);
}
while ($row = $db->sql_fetchrow($result)) {
$rows .= "<tr><td>$row[key]</td><td>$row[value]</td></tr>";
}
$this->SmartLine->truncate(STDERR);
return "<table cellspacing=\"8\"><thead style=\"color: white\" scope=\"row\"><tr><th>Key</th><th>Value</th></thead><tbody>$rows</tbody></table>";
}
}
///
/// unixtime
///
-$lang['Help']['unixtime'] = "Prints current unixtime (seconds elapsed since 1970-01-01 00:00, UTC) or the specified unixtime date.";
-
class UnixTimeSmartLineCommand extends SmartLineCommand {
public function run ($argv, $argc) {
date_default_timezone_set('UTC');
if ($argc == 1) {
$this->SmartLine->puts(time());
} elseif ($argc == 2 && is_numeric($argv[1])) {
$this->SmartLine->puts(strftime("%Y-%m-%d %X", $argv[1]));
} else {
array_shift($argv);
$date = implode(' ', $argv);
if ($time = strtotime($date) !== false) {
$this->SmartLine->puts("Unixtime from $date: <span class=\"highlight\">$time</span>");
} else {
$this->SmartLine->puts("$date isn't a unixtime nor a valid date strtotime is able to parse.", STDERR);
}
}
}
}
?>
\ No newline at end of file
diff --git a/includes/SmartLine/ZedSmartLine.php b/includes/SmartLine/ZedSmartLine.php
--- a/includes/SmartLine/ZedSmartLine.php
+++ b/includes/SmartLine/ZedSmartLine.php
@@ -1,73 +1,78 @@
<?php
/*
* Zed
* (c) 2010, Dereckson, some rights reserved
* Released under BSD license
*
* SmartLine
*
*/
///
/// Helpers
///
/*
* Logs a Smartline command
* @param string $command the command to log
* @param boolean $isError indicates if the command is an error
*/
function log_C ($command, $isError = false) {
global $db, $CurrentPerso;
$isError = $isError ? 1 : 0;
$command = $db->sql_escape($command);
$sql = "INSERT INTO " . TABLE_LOG_SMARTLINE . " (perso_id, command_time, command_text, isError)
VALUES ($CurrentPerso->id, UNIX_TIMESTAMP(), '$command', $isError)";
if (!$db->sql_query($sql))
message_die(SQL_ERROR, "Historique C", '', __LINE__, __FILE__, $sql);
}
///
/// Executes command
///
-if ($C = $_POST['C']) {
+if ($C = $_REQUEST['C']) {
//Initializes SmartLine object
require_once("SmartLine.php");
$smartLine = new SmartLine();
require_once("ZedCommands.php");
//Executes SmartLine
+ $controller = '';
$smartLine->execute($C);
$error = $smartLine->count(STDERR) > 0;
if ($smartLine->count(STDOUT) > 0)
$smarty->assign("SmartLine_STDOUT", $smartLine->gets_all(STDOUT, '', '<br />'));
if ($error)
$smarty->assign("SmartLine_STDERR", $smartLine->gets_all(STDERR, '', '<br />'));
-
+
+ if ($controller != '') {
+ include($controller);
+ }
+
log_C($C, $error);
}
///
/// Gets SmartLine history
///
$sql = "SELECT command_time, command_text FROM log_smartline
WHERE isError = 0 AND perso_id = $CurrentPerso->id
ORDER BY command_time DESC LIMIT 100";
if (!$result = $db->sql_query($sql)) {
message_die(SQL_ERROR, "Wiki fetching", '', __LINE__, __FILE__, $sql);
}
$i = 0;
while ($row = $db->sql_fetchrow($result)) {
$commands[$i]->time = get_hypership_time($row['command_time']);
$commands[$i]->text = $row['command_text'];
$i++;
}
$smarty->assign("SmartLineHistory", $commands);
?>
\ No newline at end of file
diff --git a/includes/api/cerbere.php b/includes/api/cerbere.php
--- a/includes/api/cerbere.php
+++ b/includes/api/cerbere.php
@@ -1,67 +1,70 @@
<?php
/*
* Zed
* (c) 2010, Dereckson, some rights reserved
* Released under BSD license
*
* API security
*
*/
define('ALLOW_LOCALHOST', false);
define('OUTPUT_ERROR', true);
define('FORMAT_ERROR', false);
if (!defined('TABLE_API_KEYS')) define('TABLE_API_KEYS', 'api_keys');
/*
* Checks if creditentials are okay and exits after a message error if not
*/
function cerbere () {
//If ALLOW_LOCALHOST is true, we allow 127.0.0.1 queries
//If you use one of your local IP in your webserver vhost like 10.0.0.3
//it could be easier to create yourself a test key
if (ALLOW_LOCALHOST && $_SERVER['REMOTE_ADDR'] == '127.0.0.1') {
return;
}
//No key, no authentication
if (!$guid = $_REQUEST['key']) {
cerbere_die('You must add creditentials to your request.');
}
//Authenticates user
global $db;
$guid = $db->sql_escape($guid);
$sql = "SELECT key_active FROM " . TABLE_API_KEYS .
" WHERE key_guid like '$guid'";
if (!$result = $db->sql_query($sql)) {
message_die(SQL_ERROR, "Can't get key", '', __LINE__, __FILE__, $sql);
}
if ($row = $db->sql_fetchrow($result)) {
if ($row['key_active']) {
//key_hits++
$sql = "UPDATE " . TABLE_API_KEYS . " SET key_hits = key_hits + 1" .
" WHERE key_guid like '$guid'";
if (!$db->sql_query($sql))
message_die(SQL_ERROR, "Can't record api call", '', __LINE__, __FILE__, $sql);
} else {
cerbere_die("Key disabled.");
}
} else {
cerbere_die("Key doesn't exist.");
}
}
+/*
+ * Prints a message in raw or API format, then exits.
+ */
function cerbere_die ($message) {
if (OUTPUT_ERROR) {
if (FORMAT_ERROR) {
api_output($message, 'error');
} else {
echo $message;
}
}
exit;
}
?>
\ No newline at end of file
diff --git a/includes/config.php b/includes/config.php
--- a/includes/config.php
+++ b/includes/config.php
@@ -1,168 +1,174 @@
<?php
/*
* Zed
* (c) 2010, Dereckson, some rights reserved
* Released under BSD license
*
* Autogenerable configuration file
*/
////////////////////////////////////////////////////////////////////////////////
/// ///
/// I. SQL configuration ///
/// ///
////////////////////////////////////////////////////////////////////////////////
//SQL configuration
$Config['sql']['product'] = 'MySQL'; //Only MySQL is currently implemented
$Config['sql']['host'] = 'localhost';
$Config['sql']['username'] = 'zed';
$Config['sql']['password'] = 'zed';
$Config['sql']['database'] = 'zed';
//SQL tables
$prefix = '';
define('TABLE_API_KEYS', $prefix . 'api_keys');
define('TABLE_COMMENTS', $prefix . 'comments');
define('TABLE_LOG_SMARTLINE', $prefix . 'log_smartline');
define('TABLE_MESSAGES', $prefix . 'messages');
define('TABLE_MOTD', $prefix . 'motd');
define('TABLE_PAGES', $prefix . 'pages');
define('TABLE_PAGES_EDITS', $prefix . 'pages_edits');
define('TABLE_PERSOS', $prefix . 'persos');
define('TABLE_PERSOS_FLAGS', $prefix . 'persos_flags');
define('TABLE_PROFILES', $prefix . 'profiles');
define('TABLE_PROFILES_COMMENTS', $prefix . 'profiles_comments');
define('TABLE_PROFILES_PHOTOS', $prefix . 'profiles_photos');
define('TABLE_REGISTRY', $prefix . 'registry');
define('TABLE_SESSIONS', $prefix . 'sessions');
define('TABLE_USERS', $prefix . 'users');
define('TABLE_USERS_OPENID', $prefix . 'users_openid');
//Geo tables
define('TABLE_BODIES', $prefix . 'geo_bodies');
define('TABLE_LOCATIONS', $prefix . 'geo_locations'); //Well... it's view
define('TABLE_PLACES', $prefix . 'geo_places');
////////////////////////////////////////////////////////////////////////////////
/// ///
/// II. Site configuration ///
/// ///
////////////////////////////////////////////////////////////////////////////////
//Default theme
$Config['DefaultTheme'] = "Zed";
//Dates
date_default_timezone_set("UTC");
+//Secret key, used for some verification hashes in URLs or forms.
+$Config['SecretKey'] = 'Je balaye les petits ewoks comme le vent balaye les feuilles mortes';
+
////////////////////////////////////////////////////////////////////////////////
/// ///
/// III. Script URLs ///
/// ///
////////////////////////////////////////////////////////////////////////////////
/*
* Without mod_rewrite:
*
* Subdirectory:
* - $Config['SiteURL'] = 'http://zed.dereckson.be/hypership/index.php';
* - $Config['BaseURL'] = '/hypership/index.php';
*
* Root directory:
* - $Config['SiteURL'] = 'http://zed.dereckson.be/index.php';
* - $Config['BaseURL'] = '/index.php';
*
* With mod_rewrite:
*
* Subdirectory:
* - $Config['SiteURL'] = 'http://zed.dereckson.be/hypership';
* - $Config['BaseURL'] = '/hypership';
*
* In .htaccess or your vhost definition:
* RewriteEngine On
* RewriteBase /hypership/
* RewriteCond %{REQUEST_FILENAME} !-f
* RewriteCond %{REQUEST_FILENAME} !-d
* RewriteRule . /hypership/index.php [L]
*
* Root directory:
* - $Config['SiteURL'] = 'http://zed.dereckson.be';
* - $Config['BaseURL'] = '';
*
* In .htaccess or your vhost definition:
* RewriteEngine On
* RewriteBase /
* RewriteCond %{REQUEST_FILENAME} !-f
* RewriteCond %{REQUEST_FILENAME} !-d
* RewriteRule . /index.php [L]
*
*
* If you don't want to specify the server domain, you can use get_server_url:
* $Config['SiteURL'] = get_server_url() . '/hypership';
* $Config['SiteURL'] = get_server_url();
*
* !!! No trailing slash !!!
*
*/
$Config['SiteURL'] = get_server_url();
$Config['BaseURL'] = '';
+//AJAX callbacks URL
+$Config['DoURL'] = $Config['SiteURL'] . "/do.php";
+
////////////////////////////////////////////////////////////////////////////////
/// ///
/// IV. Static content ///
/// ///
////////////////////////////////////////////////////////////////////////////////
//Where the static content is located?
//Static content = 4 directories: js, css, img and content
//On default installation, those directories are at site root.
//To improve site performance, you can use a CDN for that.
//To use
//
//Recommanded setting: $Config['StaticContentURL'] = $Config['SiteURL'];
//Or if Zed is the site root: $Config['StaticContentURL'] = '';
//With CoralCDN: $Config['StaticContentURL'] = . '.nyud.net';
//
$Config['StaticContentURL'] = '';
//$Config['StaticContentURL'] = get_server_url() . '.nyud.net';
//Scenes
define('SCENE_DIR', 'content/scenes');
define('SCENE_URL', $Config['StaticContentURL'] . '/' . SCENE_DIR);
//Stories
define('STORIES_DIR', "content/stories");
//Profile's photos
define('PHOTOS_DIR', 'content/users/_photos');
define('PHOTOS_URL', $Config['StaticContentURL'] . '/' . PHOTOS_DIR);
//ImageMagick paths
//Be careful on Windows platform convert could match the NTFS convert command.
$Config['ImageMagick']['convert'] = 'convert';
$Config['ImageMagick']['mogrify'] = 'mogrify';
$Config['ImageMagick']['composite'] = 'composite';
$Config['ImageMagick']['identify'] = 'identify';
////////////////////////////////////////////////////////////////////////////////
/// ///
/// V. Sessions ///
/// ///
////////////////////////////////////////////////////////////////////////////////
//Sessions
//If you want to use a common table of sessions / user handling
//with several websites, specify a different resource id for each site.
$Config['ResourceID'] = 21;
//PHP variables
ini_set('session.serialize_handler', 'wddx');
ini_set('session.save_path', 'cache/sessions');
ini_set('session.gc_maxlifetime', 345600); //4 days, for week-end story pause and continue url
?>
\ No newline at end of file
diff --git a/includes/core.php b/includes/core.php
--- a/includes/core.php
+++ b/includes/core.php
@@ -1,469 +1,488 @@
<?php
/*
* Zed
* (c) 2010, Dereckson, some rights reserved
* Released under BSD license
*
* Core
*/
////////////////////////////////////////////////////////////////////////////////
/// ///
/// Configures PHP and loads site-wide used libraries ///
/// ///
////////////////////////////////////////////////////////////////////////////////
//No register globals
ini_set('register_globals', 'off');
error_reporting(E_ALL & ~E_NOTICE);
//Load libraries
include_once("config.php"); //Site config
include_once("error.php"); //Error management
include_once("mysql.php"); //MySQL layer
include_once("sessions.php"); //Sessions handler
////////////////////////////////////////////////////////////////////////////////
/// ///
/// Information helper methods ///
/// ///
////////////////////////////////////////////////////////////////////////////////
//Gets username from specified user_id
function get_name ($id) {
global $db;
$id = $db->sql_escape($id);
$sql = 'SELECT perso_nickname FROM '. TABLE_PERSOS . " WHERE perso_id = '$id'";
if (!$result = $db->sql_query($sql)) message_die(SQL_ERROR, "Can't query persos table.", '', __LINE__, __FILE__, $sql);
$row = $db->sql_fetchrow($result);
return $row['perso_nickname'];
}
//Gets user_id from specified username
function get_userid ($username) {
global $db;
$username = $db->sql_escape($username);
$sql = 'SELECT user_id FROM '. TABLE_USERS . " WHERE username LIKE '$username'";
if (!$result = $db->sql_query($sql)) message_die(SQL_ERROR, "Can't query users table.", '', __LINE__, __FILE__, $sql);
$row = $db->sql_fetchrow($result);
return $row['user_id'];
}
function registry_get ($key) {
global $db;
$key = $db->sql_escape($key);
$sql = "SELECT registry_value FROM " . TABLE_REGISTRY . " WHERE registry_key = '$key'";
if (!$result = $db->sql_query($sql)) message_die(SQL_ERROR, "Can't read registry.", '', __LINE__, __FILE__, $sql);
$row = $db->sql_fetchrow($result);
return $row['registry_value'];
}
function registry_set ($key, $value) {
global $db;
$key = $db->sql_escape($key);
$value = $db->sql_escape($value);
$sql = "REPLACE INTO " . TABLE_REGISTRY . " (registry_key, registry_value) VALUES ('$key', '$value')";
if (!$db->sql_query($sql))
message_die(SQL_ERROR, "Can't update registry", '', __LINE__, __FILE__, $sql);
}
////////////////////////////////////////////////////////////////////////////////
/// ///
/// Misc helper methods ///
/// ///
////////////////////////////////////////////////////////////////////////////////
/*
* Generates a random string
* @author Pierre Habart <p.habart@ifrance.com>
*
* @param string $format The format e.g. AAA111
* @return string a random string
*/
function genereString ($format) {
mt_srand((double)microtime()*1000000);
$str_to_return="";
$t_alphabet=explode(",","A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z");
$t_number=explode(",","1,2,3,4,5,6,7,8,9,0");
for ($i=0;$i<strlen($format);$i++)
{
if (ereg("^[a-zA-Z]",$format[$i]))
{
$add=$t_alphabet[mt_rand() % sizeof($t_alphabet)];
if (ereg("^[a-z]",$format[$i]))
$add=strtolower($add);
}
elseif(ereg("^[0-9]",$format[$i]))
$add=$t_number[mt_rand() % sizeof($t_number)];
else $add="?";
$str_to_return.=$add;
}
return $str_to_return;
}
function generer_hexa($longueur) {
mt_srand((double)microtime()*1000000);
$str_to_return="";
$t_number=explode(",","1,2,3,4,5,6,7,8,9,0,A,B,C,D,E,F");
for ($i = 0 ; $i < $longueur ; $i++) {
$str_to_return .= $t_number[mt_rand() % sizeof($t_number)];
}
return $str_to_return;
}
//Plural management
function s ($amount) {
if ($amount > 1) return "s";
}
function x ($amount) {
if ($amount > 1) return "x";
}
//Debug
function dprint_r ($mixed) {
echo "<pre>", print_r($mixed, true), "</pre>";
}
//GUID
function new_guid() {
$characters = explode(",","a,b,c,d,e,f,0,1,2,3,4,5,6,7,8,9");
$guid = "";
for ($i = 0 ; $i < 36 ; $i++) {
if ($i == 8 || $i == 13 || $i == 18 || $i == 23) {
$guid .= "-";
} else {
$guid .= $characters[mt_rand() % sizeof($characters)];
}
}
return $guid;
}
function is_guid ($expression) {
//We avoid regexp to speed up the check
//A guid is a 36 characters string
if (strlen($expression) != 36) return false;
$expression = strtolower($expression);
for ($i = 0 ; $i < 36 ; $i++) {
if ($i == 8 || $i == 13 || $i == 18 || $i == 23) {
//with dashes
if ($expression[$i] != "-") return false;
} else {
//and numbers
if (!is_numeric($expression[$i]) && $expression[$i] != 'a' && $expression[$i] != 'b' && $expression[$i] != 'c' && $expression[$i] != 'd' && $expression[$i] != 'e' && $expression[$i] != 'f' ) return false;
}
}
return true;
}
-//Gets file extension
+/*
+ * Gets file extension
+ * @param string $file the file to get the extension
+ */
function get_extension ($file) {
$dotPosition = strrpos($file, ".");
return substr($file, $dotPosition + 1);
}
+/*
+ * Determines if a string starts with specified substring
+ * @param string $haystack the string to check
+ * @param string $needle the substring to determines if it's the start
+ * @param boolean $case_sensitive determines if the search must be case sensitive
+ * @return boolean true if $haystack starts with $needle ; otherwise, false.
+ */
+function string_starts_with ($haystack, $needle, $case_sensitive = true) {
+ if (!$case_sensitive) {
+ $haystack = strtoupper($haystack);
+ $needle = strtoupper($needle);
+ }
+ if ($haystack == $needle) return true;
+ return strpos($haystack, $needle) === 0;
+}
+
////////////////////////////////////////////////////////////////////////////////
/// ///
/// Localization (l10n) ///
/// ///
////////////////////////////////////////////////////////////////////////////////
/*
* Defines LANG constant to lang to print
*/
function initialize_lang () {
//If $_SESSION['lang'] doesn't exist yet, find a common language
if (!array_key_exists('lang', $_SESSION)) {
$lang = find_lang();
$_SESSION['lang'] = $lang ? $lang : '-';
}
if ($_SESSION['lang'] != '-')
define('LANG', $_SESSION['lang']);
}
/*
* Gets a common lang spoken by the site and the user
* @return string the language
*/
function find_lang () {
if (file_exists('lang') && is_dir('lang')) {
//Gets lang/ subdirectories: this is the list of available languages
$handle = opendir('lang');
while ($file = readdir($handle)) {
if ($file != '.' && $file != '..' && is_dir("lang/$file")) {
$langs[] = $file;
}
}
//The array $langs contains now the language available.
//Gets the langs the user should want:
if (!$userlangs = get_http_accept_languages())
return;
//Gets the intersection between the both languages arrays
//If it matches, returns first result
$intersect = array_intersect($userlangs, $langs);
if (count($intersect)) {
return $intersect[0];
}
//Now it's okay with Opera and Firefox but Internet Explorer
//will return en-US and not en or fr-BE and not fr, so second pass
foreach ($userlangs as $userlang) {
$lang = explode('-', $userlang);
if (count($lang) > 1)
$userlangs2[] = $lang[0];
}
$intersect = array_intersect($userlangs2, $langs);
if (count($intersect)) {
return $intersect[0];
}
}
}
/*
* Returns the languages accepted by the browser, by order of priority
* @return Array a array of languages string
*/
function get_http_accept_languages () {
//What language to print is sent by browser in HTTP_ACCEPT_LANGUAGE var.
//This will be something like en,fr;q=0.8,fr-fr;q=0.5,en-us;q=0.3
if (!array_key_exists('HTTP_ACCEPT_LANGUAGE', $_SERVER)) {
return null;
}
$http_accept_language = explode(',', $_SERVER["HTTP_ACCEPT_LANGUAGE"]);
foreach ($http_accept_language as $language) {
$userlang = explode(';q=', $language);
if (count($userlang) == 1) {
$userlangs[] = array(1, $language);
} else {
$userlangs[] = array($userlang[1], $userlang[0]);
}
}
rsort($userlangs);
foreach ($userlangs as $userlang) {
$result[] = $userlang[1];
}
return $result;
}
/*
* Loads specified language Smarty configuration file
*
* @param string $file the file to load
* @param mixed $sections array of section names, single section or null
*/
function lang_load ($file, $sections = null) {
global $smarty;
//Loads English file as fallback if some parameters are missing
if (file_exists("lang/en/$file"))
$smarty->config_load("lang/en/$file", $sections);
//Loads wanted file (if it exists and a language have been defined)
if (defined('LANG') && LANG != 'en' && file_exists('lang/' . LANG . '/' . $file))
$smarty->config_load('lang/' . LANG . '/' . $file, $sections);
}
/*
* Gets a specified language expression defined in configuration file
*
* @param string $key the configuration key matching the value to get
* @return string The value in the configuration file
*/
function lang_get ($key) {
global $smarty;
$smartyConfValue = $smarty->config_vars[$key];
return $smartyConfValue ? $smartyConfValue : "#$key#";
}
////////////////////////////////////////////////////////////////////////////////
/// ///
/// Zed date and time helper methods ///
/// ///
////////////////////////////////////////////////////////////////////////////////
/*
* Converts a YYYYMMDD or YYYY-MM-DD timestamp to unixtime
*/
function to_unixtime ($timestamp) {
switch (strlen($timestamp)) {
case 8:
//YYYYMMDD
return mktime(0, 0, 0, substr($timestamp, 4, 2), substr($timestamp, 6, 2), substr($timestamp, 0, 4));
case 10:
//YYYY-MM-DD
return mktime(0, 0, 0, substr($timestamp, 5, 2), substr($timestamp, 8, 2), substr($timestamp, 0, 4));
default:
throw new Exception("timestamp is not a valid YYYYMMDD or YYYY-MM-DD timestamp: $timestamp");
}
}
/*
* Converts a unixtime to the YYYYMMDD or YYYY-MM-DD timestamp format
*
* @param int $unixtime the time to convert
* @param int $format 8 or 10. If 8 (default), will output YYYYMMDD. If 10, YYYY-MM-DD.
*/
function to_timestamp ($unixtime = null, $format = 8) {
//If no parameter is specified (or null, or false), current time is used
//==== allows to_timestamp(0) to return correct 1970-1-1 value.
if ($unixtime === null || $unixtime === false) $unixtime = time();
switch ($format) {
case 8:
//YYYYMMDD
return date('Ymd', $unixtime);
case 10:
//YYYY-MM-DD
return date('Y-m-d', $unixtime);
default:
throw new Exception("format must be 8 (YYYYMMDD) or 10 (YYYY-MM-DD) and not $format.");
}
}
/*
* Converts a unixtime to the Hypership time format.
*/
function get_hypership_time ($unixtime = null) {
//If unixtime is not specified, it's now
if ($unixtime === null) $unixtime = time();
//Hypership time is a count of days since launch @ 2010-01-25 00:00:00
//Followed by a fraction of the current day /1000, like the internet time
//but in UTC timezone and not Switzerland CET/CEST.
//We don't need to use floor(), as we output the result at int, truncating
//automatically decimal values instead of round it (like in C).
$seconds = $unixtime - 1264377600;
$days = $seconds / 86400;
$fraction = ($seconds % 86400) / 86.4;
return sprintf("%d.%03d", $days, $fraction);
}
////////////////////////////////////////////////////////////////////////////////
/// ///
/// URL helpers functions ///
/// ///
////////////////////////////////////////////////////////////////////////////////
/*
* Gets URL
* @return string URL
*/
function get_url () {
global $Config;
if (func_num_args() > 0) {
$pieces = func_get_args();
return $Config['BaseURL'] . '/' . implode('/', $pieces);
} elseif ($Config['BaseURL'] == "" || $Config['BaseURL'] == "/index.php") {
return "/";
} else {
return $Config['BaseURL'];
}
}
/*
* Gets page URL
* @return string URL
*/
function get_page_url () {
$url = $_SERVER['SCRIPT_NAME'] . $_SERVER['PATH_INFO'];
if (substr($url, -10) == "/index.php") {
return substr($url, 0, -9);
}
return $url;
}
/*
* Gets server URL
* @todo find a way to detect https:// on non standard port
* @return string the server URL
*/
function get_server_url () {
switch ($port = $_SERVER['SERVER_PORT']) {
case '80':
return "http://$_SERVER[SERVER_NAME]";
case '443':
return "https://$_SERVER[SERVER_NAME]";
default:
return "http://$_SERVER[SERVER_NAME]:$_SERVER[SERVER_PORT]";
}
}
/*
* Gets $_SERVER['PATH_INFO'] or computes the equivalent if not defined.
* @return string the relevant URL part
*/
function get_current_url () {
global $Config;
//Gets relevant URL part from relevant $_SERVER variables
if (array_key_exists('PATH_INFO', $_SERVER)) {
//Without mod_rewrite, and url like /index.php/controller
//we use PATH_INFO. It's the easiest case.
return $_SERVER["PATH_INFO"];
}
//In other cases, we'll need to get the relevant part of the URL
$current_url = get_server_url() . $_SERVER['REQUEST_URI'];
//Relevant URL part starts after the site URL
$len = strlen($Config['SiteURL']);
//We need to assert it's the correct site
if (substr($current_url, 0, $len) != $Config['SiteURL']) {
dieprint_r(GENERAL_ERROR, "Edit includes/config.php and specify the correct site URL<br /><strong>Current value:</strong> $Config[SiteURL]<br /><strong>Expected value:</strong> a string starting by " . get_server_url(), "Setup");
}
if (array_key_exists('REDIRECT_URL', $_SERVER)) {
//With mod_rewrite, we can use REDIRECT_URL
//We takes the end of the URL, ie *FROM* $len position
return substr(get_server_url() . $_SERVER["REDIRECT_URL"], $len);
}
//Last possibility: use REQUEST_URI, but remove QUERY_STRING
//If you need to edit here, use $_SERVER['REQUEST_URI']
//but you need to discard $_SERVER['QUERY_STRING']
//We takes the end of the URL, ie *FROM* $len position
$url = substr(get_server_url() . $_SERVER["REQUEST_URI"], $len);
//But if there are a query string (?action=... we need to discard it)
if ($_SERVER['QUERY_STRING']) {
return substr($url, 0, strlen($url) - strlen($_SERVER['QUERY_STRING']) - 1);
}
return $url;
}
/*
* Gets an array of url fragments to be processed by controller
*/
function get_current_url_fragments () {
$url_source = get_current_url();
if ($url_source == '/index.php') return array();
return explode('/', substr($url_source, 1));
}
?>
\ No newline at end of file
diff --git a/includes/objects/perso.php b/includes/objects/perso.php
--- a/includes/objects/perso.php
+++ b/includes/objects/perso.php
@@ -1,304 +1,396 @@
<?php
/*
* Perso class
*
* 0.1 2010-01-27 00:39 Autogenerated by Pluton Scaffolding
* 0.2 2010-01-29 14:39 Adding flags support
+ * 0.3 2010-02-06 17:50 Adding static perso hashtable
*
* @package Zed
* @copyright Copyright (c) 2010, Dereckson
* @license Released under BSD license
- * @version 0.1
+ * @version 0.3
*
*/
require_once("includes/geo/location.php");
class Perso {
public $id;
public $user_id;
public $name;
public $nickname;
public $race;
public $sex;
public $avatar;
public $location_global;
public $location_local;
public $flags;
+ public static $hashtable_id = array();
+ public static $hashtable_name = array();
+
/*
* Initializes a new instance
* @param mixed $data perso ID or nickname
*/
function __construct ($data = null) {
if ($data) {
if (is_numeric($data)) {
$this->id = $data;
} else {
$this->nickname = $data;
}
$this->load_from_database();
} else {
$this->generate_id();
}
}
/*
+ * Initializes a new Perso instance if needed or get already available one.
+ * @param mixed $data perso ID or nickname
+ * @eturn Perso the perso instance
+ */
+ static function get ($data = null) {
+ if ($data) {
+ //Checks in the hashtables if we already have loaded this instance
+ if (is_numeric($data)) {
+ if (array_key_exists($data, Perso::$hashtable_id)) {
+ return Perso::$hashtable_id[$data];
+ }
+ } else {
+ if (array_key_exists($data, Perso::$hashtable_name)) {
+ return Perso::$hashtable_name[$data];
+ }
+ }
+ }
+
+ $perso = new Perso($data);
+ return $perso;
+ }
+
+ /*
* Loads the object Perso (ie fill the properties) from the $_POST array
*/
function load_from_form () {
if (array_key_exists('user_id', $_POST)) $this->user_id = $_POST['user_id'];
if (array_key_exists('name', $_POST)) $this->name = $_POST['name'];
if (array_key_exists('nickname', $_POST)) $this->nickname = $_POST['nickname'];
if (array_key_exists('race', $_POST)) $this->race = $_POST['race'];
if (array_key_exists('sex', $_POST)) $this->sex = $_POST['sex'];
if (array_key_exists('avatar', $_POST)) $this->avatar = $_POST['avatar'];
if (array_key_exists('location_global', $_POST)) $this->location_global = $_POST['location_global'];
if (array_key_exists('location_local', $_POST)) $this->location_local = $_POST['location_local'];
}
/*
* Loads the object Perso (ie fill the properties) from the database
*/
function load_from_database () {
global $db;
//Gets perso
$sql = "SELECT * FROM " . TABLE_PERSOS;
if ($this->id) {
$id = $db->sql_escape($this->id);
$sql .= " WHERE perso_id = '" . $id . "'";
} else {
$nickname = $db->sql_escape($this->nickname);
$sql .= " WHERE perso_nickname = '" . $nickname . "'";
}
if ( !($result = $db->sql_query($sql)) ) message_die(SQL_ERROR, "Unable to query persos", '', __LINE__, __FILE__, $sql);
if (!$row = $db->sql_fetchrow($result)) {
$this->lastError = "Perso unkwown: " . $this->id;
return false;
}
$this->id = $row['perso_id'];
$this->user_id = $row['user_id'];
$this->name = $row['perso_name'];
$this->nickname = $row['perso_nickname'];
$this->race = $row['perso_race'];
$this->sex = $row['perso_sex'];
$this->avatar = $row['perso_avatar'];
$this->location_global = $row['location_global'];
$this->location_local = $row['location_local'];
//Gets flags
$sql = "SELECT flag_key, flag_value FROM " . TABLE_PERSOS_FLAGS .
" WHERE perso_id = $this->id";
if (!$result = $db->sql_query($sql)) {
message_die(SQL_ERROR, "Can't get flags", '', __LINE__, __FILE__, $sql);
}
while ($row = $db->sql_fetchrow($result)) {
$this->flags[$row["flag_key"]] = $row["flag_value"];
}
//Gets location
$this->location = new GeoLocation(
$this->location_global,
$this->location_local
);
+ //Puts object in hashtables
+ Perso::$hashtable_id[$this->id] = $this;
+ Perso::$hashtable_name[$this->nickname] = $this;
+
return true;
}
/*
* Saves to database
*/
function save_to_database () {
global $db;
$id = $this->id ? "'" . $db->sql_escape($this->id) . "'" : 'NULL';
$user_id = $db->sql_escape($this->user_id);
$name = $db->sql_escape($this->name);
$nickname = $db->sql_escape($this->nickname);
$race = $db->sql_escape($this->race);
$sex = $db->sql_escape($this->sex);
$avatar = $db->sql_escape($this->avatar);
$location_global = $this->location_global ? "'" . $db->sql_escape($this->location_global) . "'" : 'NULL';
$location_local = $this->location_local ? "'" . $db->sql_escape($this->location_local) . "'" : 'NULL';
//Updates or inserts
$sql = "REPLACE INTO " . TABLE_PERSOS . " (`perso_id`, `user_id`, `perso_name`, `perso_nickname`, `perso_race`, `perso_sex`, `perso_avatar`, `location_global`, `location_local`) VALUES ($id, '$user_id', '$name', '$nickname', '$race', '$sex', '$avatar', $location_global, $location_local)";
if (!$db->sql_query($sql)) {
message_die(SQL_ERROR, "Unable to save", '', __LINE__, __FILE__, $sql);
}
if (!$id) {
//Gets new record id value
$this->id = $db->sql_nextid();
}
}
/*
* Updates the specified field in the database record
*/
function save_field ($field) {
global $db;
if (!$this->id) {
message_die(GENERAL_ERROR, "You're trying to update a perso record not yet saved in the database: $field");
}
$id = $db->sql_escape($this->id);
$value = $db->sql_escape($this->$field);
$sql = "UPDATE " . TABLE_PERSOS . " SET `$field` = '$value' WHERE perso_id = '$id'";
if (!$db->sql_query($sql)) {
message_die(SQL_ERROR, "Unable to save $field field", '', __LINE__, __FILE__, $sql);
}
}
/*
* Gets perso location
* @return string The location names
*/
public function where () {
return $this->location->__toString();
}
/*
* Moves the perso to a new location
*/
public function move_to ($global = null, $local = null) {
//Sets global location
if ($global != null) {
$this->location_global = $global;
}
//Sets local location
if ($local != null) {
$this->location_local = $local;
}
//Updates database record
if ($global != null && $local != null) {
global $db;
$perso_id = $db->sql_escape($this->id);
$g = $db->sql_escape($this->location_global);
$l = $db->sql_escape($this->location_local);
$sql = "UPDATE " . TABLE_PERSOS .
" SET location_global = '$g', location_local = '$l'" .
" WHERE perso_id = '$perso_id'";
if (!$db->sql_query($sql))
message_die(SQL_ERROR, "Can't save new $global $local location.", '', __LINE__, __FILE__, $sql);
} elseif ($global != null) {
$this->save_field('location_global');
} elseif ($local != null) {
$this->save_field('location_local');
}
//Updates location member
$this->location = new GeoLocation(
$this->location_global,
$this->location_local
);
}
+
+ /*
+ * Gets the specified flag value
+ * @param string $key flag key
+ * @return mixed the flag value (string) or null if not existing
+ */
+ public function get_flag ($key) {
+ if (array_key_exists($key, $this->flags)) {
+ return $this->flags[$key];
+ }
+ return null;
+ }
+ /*
+ * Sets the specified flag
+ * @param string $key flag key
+ * @param string $value flag value (optional, default value: 1)
+ */
public function set_flag ($key, $value = 1) {
//Checks if flag isn't already set at this value
- if ($this->flags[$key] === $value)
+ if (array_key_exists($key, $this->flags) && $this->flags[$key] === $value)
return;
//Saves flag to database
global $db;
$id = $db->sql_escape($this->id);
$key = $db->sql_escape($key);
$value = $db->sql_escape($value);
$sql = "REPLACE " . TABLE_PERSOS_FLAGS . " SET perso_id = '$id', flag_key = '$key', flag_value = '$value'";
if (!$db->sql_query($sql))
message_die(SQL_ERROR, "Can't save flag", '', __LINE__, __FILE__, $sql);
//Sets flag in this perso instance
$this->flags[$key] = $value;
}
+ /*
+ * Deletes the specified flag
+ * @param string $key flag key
+ */
+ public function delete_flag ($key) {
+ global $db;
+ if (!array_key_exists($key, $this->flags)) return;
+
+ $id = $db->sql_escape($this->id);
+ $key = $db->sql_escape($key);
+ $sql = "DELETE FROM " . TABLE_PERSOS_FLAGS .
+ " WHERE flag_key = '$key' AND perso_id = '$id' LIMIT 1";
+ if (!$db->sql_query($sql))
+ message_die(SQL_ERROR, "Can't delete flag", '', __LINE__, __FILE__, $sql);
+ }
+
+ /*
+ * Ensures the current perso have the flag or dies.
+ * @param string $flag XXXX
+ * @param string $$threshold YYYY
+ */
public function request_flag ($flag, $threshold = 0) {
if (!array_key_exists($flag, $this->flags) || $this->flags[$flag] <= $threshold) {
message_die(HACK_ERROR, "You don't have $flag permission.", "Permissions");
- }
+ }
}
+ /*
+ * Determines if the specified ID is available
+ * @param integer $id The perso ID to check
+ * @return boolean true if the specified ID is available ; otherwise, false
+ */
public static function is_available_id ($id) {
global $db;
$sql = "SELECT COUNT(*) FROM " . TABLE_PERSOS . " WHERE perso_id = $id LOCK IN SHARE MODE";
if (!$result = $db->sql_query($sql)) {
message_die(SQL_ERROR, "Can't access users table", '', __LINE__, __FILE__, $sql);
}
$row = $db->sql_fetchrow($result);
return ($row[0] == 0);
}
/*
* Generates a unique ID for the current object
*/
private function generate_id () {
do {
$this->id = rand(2001, 5999);
} while (!Perso::is_available_id($this->id));
}
/*
* Checks if the nickname is available
* @param string $nickname the nickname to check
*/
public static function is_available_nickname ($nickname) {
global $db;
$nickname = $db->sql_escape($nickname);
$sql = "SELECT COUNT(*) FROM " . TABLE_PERSOS . " WHERE perso_nickname LIKE '$nickname' LOCK IN SHARE MODE;";
if (!$result = $db->sql_query($sql)) {
message_die(SQL_ERROR, "Utilisateurs non parsable", '', __LINE__, __FILE__, $sql);
}
$row = $db->sql_fetchrow($result);
return ($row[0] == 0);
}
/*
* Counts the perso a user have
*
* @param int user_id the user ID
+ * @return the user's perso count
*/
public static function get_persos_count ($user_id) {
global $db;
$sql = "SELECT COUNT(*) FROM " . TABLE_PERSOS . " WHERE user_id = $user_id";
return $db->sql_query_express($sql);
+
}
+ /*
+ * Gets an array with all the perso of the specified user
+ */
public static function get_persos ($user_id) {
global $db;
$user_id = $db->sql_escape($user_id);
$sql = "SELECT perso_id FROM " . TABLE_PERSOS . " WHERE user_id = $user_id";
if (!$result = $db->sql_query($sql)) {
message_die(SQL_ERROR, "Can't get persos", '', __LINE__, __FILE__, $sql);
}
while ($row = $db->sql_fetchrow($result)) {
- $persos[] = new Perso($row['perso_id']);
+ $persos[] = Perso::get($user_id);
}
return $persos;
}
/*
* Gets the first perso a user have
* (typically to be used when get_persos_count returns 1 to autoselect)
*
* @param int user_id the user ID
*/
public static function get_first_perso ($user_id) {
global $db;
$sql = "SELECT perso_id FROM " . TABLE_PERSOS . " WHERE user_id = $user_id LIMIT 1";
if ($perso_id = $db->sql_query_express($sql)) {
return new Perso($perso_id);
}
}
+
+ public function on_select () {
+ //Session
+ set_info('perso_id', $this->id);
+ $this->set_flag("site.lastlogin", $_SERVER['REQUEST_TIME']);
+ define("PersoSelected", true);
+ }
+
+ public function on_logout () {
+ //Clears perso information in $_SESSION and session table
+ set_info('perso_id', null);
+ clean_session();
+ }
}
?>
\ No newline at end of file
diff --git a/includes/objects/ship.php b/includes/objects/ship.php
new file mode 100644
--- /dev/null
+++ b/includes/objects/ship.php
@@ -0,0 +1,202 @@
+<?php
+
+/*
+ * Ship class
+ *
+ * 0.1 2010-02-05 18:51 Autogenerated by Pluton Scaffolding
+ * 0.2 2010-02-06 17:30 Ship API
+ *
+ * @package Zed
+ * @copyright Copyright (c) 2010, Dereckson
+ * @license Released under BSD license
+ * @version 0.1
+ *
+ */
+
+require_once("perso.php");
+
+class Ship {
+
+ /*
+ * ----------------------------------------------------------------------- *
+ * Ship class definition
+ * ----------------------------------------------------------------------- *
+ */
+
+ public $id;
+ public $name;
+ public $location;
+ public $api_key;
+ public $description;
+
+ /*
+ * Initializes a new instance
+ * @param int $id the primary key
+ */
+ function __construct ($id = null) {
+ if ($id) {
+ $this->id = $id;
+ $this->load_from_database();
+ }
+ }
+
+ /*
+ * Loads the object Ship (ie fill the properties) from the $_POST array
+ */
+ function load_from_form () {
+ if (array_key_exists('name', $_POST)) $this->name = $_POST['name'];
+ if (array_key_exists('location', $_POST)) $this->location = $_POST['location'];
+ if (array_key_exists('api_key', $_POST)) $this->api_key = $_POST['api_key'];
+ if (array_key_exists('description', $_POST)) $this->description = $_POST['description'];
+ }
+
+ /*
+ * Loads the object Ship (ie fill the properties) from the database
+ */
+ function load_from_database () {
+ global $db;
+ $id = $db->sql_escape($this->id);
+ $sql = "SELECT * FROM ships WHERE ship_id = '" . $id . "'";
+ if ( !($result = $db->sql_query($sql)) ) message_die(SQL_ERROR, "Unable to query Ships", '', __LINE__, __FILE__, $sql);
+ if (!$row = $db->sql_fetchrow($result)) {
+ $this->lastError = "Ship unkwown: " . $this->id;
+ return false;
+ }
+ $this->name = $row['ship_name'];
+ $this->location = $row['ship_location'];
+ $this->api_key = $row['api_key'];
+ $this->description = $row['ship_description'];
+ return true;
+ }
+
+ /*
+ * Saves to database
+ */
+ function save_to_database () {
+ global $db;
+
+ $id = $this->id ? "'" . $db->sql_escape($this->id) . "'" : 'NULL';
+ $name = $db->sql_escape($this->name);
+ $location = $db->sql_escape($this->location);
+ $api_key = $db->sql_escape($this->api_key);
+ $description = $db->sql_escape($this->description);
+
+ //Updates or inserts
+ $sql = "REPLACE INTO ships (`ship_id`, `ship_name`, `ship_location`, `api_key`, `ship_description`) VALUES ($id, '$name', '$location', '$api_key', '$description')";
+ if (!$db->sql_query($sql)) {
+ message_die(SQL_ERROR, "Unable to save", '', __LINE__, __FILE__, $sql);
+ }
+
+ if (!$id) {
+ //Gets new record id value
+ $this->id = $db->sql_nextid();
+ }
+ }
+
+ function __toString () {
+ return $this->get_code();
+ }
+
+ /*
+ * ----------------------------------------------------------------------- *
+ * Helper methods
+ * ----------------------------------------------------------------------- *
+ */
+
+ /*
+ * Gets ship code, e.g. S00001
+ */
+ function get_code () {
+ return sprintf("S%05d", $this->id);
+ }
+
+ /*
+ * ----------------------------------------------------------------------- *
+ * Ship API methods
+ * ----------------------------------------------------------------------- *
+ */
+
+ /*
+ * Requests the specified perso to authenticate to this ship
+ * @param mixed $perso_data the perso id or name
+ */
+ function request_perso_authenticate ($perso_data) {
+ $perso = Perso::get($perso_data);
+ $flag = sprintf("request.api.ship.auth.%s", $this->get_code());
+ $perso->set_flag($flag);
+ $perso->set_flag("site.requests");
+ }
+
+ /*
+ * Determines if a perso is authenticated to this ship
+ * @param mixed $perso_data the perso id or name
+ * @return boolean true if the specified perso name is authenticated to this ship ; otherwise, false.
+ */
+ function is_perso_authenticated ($perso_data) {
+ $flag = sprintf("api.ship.auth.%s", $this->get_code());
+ return Perso::get($perso_data)->flags[$flag] == 1;
+ }
+
+ /*
+ * Requests the specified perso to confirm the ship API session
+ * @param string $session_id a session ID provided by calling application
+ * @param mixed $perso_data the perso id or name
+ */
+ function request_perso_confirm_session ($session_id, $perso_data) {
+ $perso = Perso::get($perso_data);
+ $flag = sprintf("request.api.ship.session.%s.%s", $this->get_code(), $session_id);
+ $perso->set_flag($flag);
+ $perso->set_flag("site.requests");
+ }
+
+ /*
+ * Cleans ship API temporary sessions
+ */
+ static function clean_ship_sessions () {
+ //Cleans old sessions
+ global $db;
+ $sql = "DELETE FROM " . TABLE_REGISTRY . " WHERE registry_key LIKE 'api.ship.session.%' AND registry_updated < NOW() - 7200";
+ if (!$db->sql_query($sql))
+ message_die(SQL_ERROR, "Can't delete old ship API sessions", '', __LINE__, __FILE__, $sql);
+ }
+
+ /*
+ * Gets perso id from specified session
+ * @param string $session_id a session ID provided by calling application
+ * @return mixed the session
+ */
+ function get_perso_from_session ($session_id) {
+ //Cleands old session
+ self::clean_ship_sessions();
+
+ //Reads api.ship.session.S00001.$session_id
+ //This registry key contains perso_id if it exists and valid
+ $key = sprintf("api.ship.session.%s.%s", $this->get_code(), $session_id);
+ return registry_get($key);
+ }
+
+ /*
+ * Loads a Ship object from its API key
+ * @param string $key API key GUID
+ * @return Ship the ship matching the API key
+ */
+ static function from_api_key ($key) {
+ global $db;
+ $key = $db->sql_escape($key);
+ $sql = "SELECT * FROM ships WHERE api_key = '" . $key . "'";
+ if ( !($result = $db->sql_query($sql)) ) message_die(SQL_ERROR, "Unable to query ships", '', __LINE__, __FILE__, $sql);
+ if (!$row = $db->sql_fetchrow($result))
+ return null;
+
+ //Fills ship information
+ $ship = new Ship();
+ $ship->id = $row['ship_id'];
+ $ship->name = $row['ship_name'];
+ $ship->location = $row['ship_location'];
+ $ship->api_key = $row['api_key'];
+ $ship->description = $row['ship_description'];
+ return $ship;
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/index.php b/index.php
--- a/index.php
+++ b/index.php
@@ -1,202 +1,205 @@
<?php
/*
* Zed
* (c) 2010, Dereckson, some rights reserved
* Released under BSD license
*
* Application entry point
*/
////////////////////////////////////////////////////////////////////////////////
///
/// Initialization
///
//Pluton library
include('includes/core.php');
//Session
$IP = encode_ip($_SERVER["REMOTE_ADDR"]);
require_once('includes/story/story.php'); //this class can be stored in session
session_start();
$_SESSION[ID] = session_id();
session_update(); //updates or creates the session
include("includes/login.php"); //login/logout
$CurrentUser = get_logged_user(); //Gets current user infos
//Gets current perso
require_once('includes/objects/perso.php');
if ($perso_id = $CurrentUser->session['perso_id']) {
$CurrentPerso = new Perso($perso_id);
}
//Skin and accent to load
define('THEME', $CurrentUser->session['Skin']);
define('ACCENT', $CurrentUser->session['Skin_accent']);
//Loads Smarty
require('includes/Smarty/Smarty.class.php');
$smarty = new Smarty();
$current_dir = dirname(__FILE__);
$smarty->template_dir = $current_dir . '/skins/' . THEME;
$smarty->compile_dir = $current_dir . '/cache/compiled';
$smarty->cache_dir = $current_dir . '/cache';
$smarty->config_dir = $current_dir;
$smarty->config_vars['StaticContentURL'] = $Config['StaticContentURL'];
//Loads language files
initialize_lang();
lang_load('core.conf');
if ($CurrentUser->id < 1000) {
//Anonymous user, proceed to login
if (array_key_exists('LastUsername', $_COOKIE))
$smarty->assign('username', $_COOKIE['LastUsername']);
if (array_key_exists('LastOpenID', $_COOKIE))
$smarty->assign('OpenID', $_COOKIE['LastOpenID']);
$smarty->assign('LoginError', $LoginError);
$smarty->display('login.tpl');
exit;
}
////////////////////////////////////////////////////////////////////////////////
///
/// Perso selector
///
//Handles form
if ($_POST['form'] == 'perso.create') {
$perso = new Perso();
$perso->load_from_form();
$perso->user_id = $CurrentUser->id;
//Validates forms
if (!$perso->name) $errors[] = lang_get("NoFullnameSpecified");
if (!$perso->race) {
$errors[] = lang_get("NoRaceSpecified");
$perso->race = "being";
}
if (!$perso->sex) $errors[] = lang_get("NoSexSpecified");
if (!$perso->nickname) {
$errors[] = lang_get("NoNicknameSpecified");
} else if (!Perso::is_available_nickname($perso->nickname)) {
$errors[] = lang_get("UnavailableNickname");
}
//Save or prints again forms
if (!$errors) {
$perso->save_to_database();
$smarty->assign('NOTIFY', lang_get('NewCharacterCreated'));
$CurrentPerso = $perso;
set_info('perso_id', $perso->id);
$CurrentPerso->set_flag("site.lastlogin", $_SERVER['REQUEST_TIME']);
} else {
$smarty->assign('WAP', join("<br />", $errors));
$smarty->assign('perso', $perso);
}
}
if ($_GET['action'] == 'perso.logout') {
//User wants to change perso
+ $CurrentPerso->on_logout();
$CurrentPerso = null;
- set_info('perso_id', null);
- clean_session();
} elseif ($_GET['action'] == 'perso.select') {
//User have selected a perso
$CurrentPerso = new Perso($_GET['perso_id']);
if ($CurrentPerso->user_id != $CurrentUser->id) {
//Hack
message_die(HACK_ERROR, "This isn't your perso.");
}
- set_info('perso_id', $CurrentPerso->id);
- $CurrentPerso->set_flag("site.lastlogin", $_SERVER['REQUEST_TIME']);
+ $CurrentPerso->on_select();
}
-if (!$CurrentPerso) {
+if (!$CurrentPerso) {
switch ($count = Perso::get_persos_count($CurrentUser->id)) {
case 0:
- //Create a perso
+ //User have to create a perso
$smarty->display("perso_create.tpl");
exit;
case 1:
- //Autoselect
+ //Autoselects only perso
$CurrentPerso = Perso::get_first_perso($CurrentUser->id);
- set_info('perso_id', $CurrentPerso->id);
- $CurrentPerso->set_flag("site.lastlogin", $_SERVER['REQUEST_TIME']);
+ $CurrentPerso->on_select();
break;
default:
- //Pick a perso
+ //User have to pick a perso
$persos = Perso::get_persos($CurrentUser->id);
$smarty->assign("PERSOS", $persos);
$smarty->display("perso_select.tpl");
$_SESSION['UserWithSeveralPersos'] = true;
exit;
}
}
//Assigns current perso object as Smarty variable
$smarty->assign('CurrentPerso', $CurrentPerso);
////////////////////////////////////////////////////////////////////////////////
///
/// Tasks to execute before calling the URL controller:
/// - assert the perso is somewhere
/// - executes the smartline
///
//If the perso location is unknown, ejects it to an asteroid
if (!$CurrentPerso->location_global) {
require_once('includes/geo/place.php');
$smarty->assign('NOTIFY', lang_get('NewLocationNotify'));
$CurrentPerso->move_to(GeoPlace::get_start_location());
}
//SmartLine
include("includes/SmartLine/ZedSmartLine.php");
+//Redirects user to user request controller if site.requests flag on
+if (defined('PersoSelected') && array_key_exists('site.requests', $CurrentPerso->flags) && $CurrentPerso->flags['site.requests']) {
+ include('controllers/persorequest.php');
+}
+
////////////////////////////////////////////////////////////////////////////////
///
/// Calls the specific controller to serve the requested page
///
$url = get_current_url_fragments();
switch ($controller = $url[0]) {
case '':
include('controllers/home.php');
break;
case 'request':
case 'page':
case 'explore':
include("controllers/$controller.php");
break;
-
-
- case 'api':
- //Should be directly called
- array_shift($url);
- $_SERVER['PATH_INFO'] = '/' . implode('/', $url);
- include('api.php');
- exit;
case 'who':
include('controllers/profile.php'); //Azhàr controller
break;
case 'push':
include('controllers/motd.php'); //Azhàr controller
break;
+
+ case 'quux':
+ //It's like a test/debug console/sandbox, you put what you want into
+ if (file_exists('dev/quux.php')) {
+ include('dev/quux.php');
+ } else {
+ message_die(GENERAL_ERROR, "Quux lost in Hollywood.", "Nay");
+ }
+ break;
default:
//TODO: returns a 404 error
dieprint_r($url, 'Unknown URL');
}
?>
\ No newline at end of file
diff --git a/lang/en/core.conf b/lang/en/core.conf
--- a/lang/en/core.conf
+++ b/lang/en/core.conf
@@ -1,134 +1,136 @@
#Zed language config file
#Language: English
#Code: en
#Author: Dereckson
###
### Site configuration
###
SiteTitle = Zed
Product = "<strong>Zed 0.1</strong>, alpha technical preview"
###
### General stuff
###
_t = ":"
###
### Login
###
Login = Login
Password = Password
OK = OK
LoginNotFound = Login not found.
IncorrectPassword = Incorrect password.
JaMata = Ja mata!
WelcomeBack = Welcome back.
OpenID = OpenID
Logout = Logout
###
### Errors
###
UnauthorizedAccess = "Unauthorized access"
SQLError = "SQL Error"
line = line
Error = Error
BackToHome = "Back to homepage"
FatalErrorScreen = Fatal error screen
FatalErrorInterrupt = Fatal error breaking screen
GeneralError = General error
PageNotFound = "Page not found"
###
### Homepage
###
Welcome = Welcome
WelcomeText = "<p>Welcome to the Zed alpha technical preview. Zed, it's a mix between a gallery, a place to meet new and existing friends, with some RPG inspiration.<br />
The concept is to have each information stored at physical places in a virtual world, like the 80s cyberspace vision. Another goal is to build a community sharing values like cooperation, freedom, ethic.</p>"
###
### Homepage - messages
###
#messages.tpl, Reply
Reply = Reply
#messages.tpl, the X link title
DeleteThisMessage = Delete this message
#home.php, messages error
MessageDeleted = Message deleted.
NotYourMessage = This message is not one of yours.
MessageAlreadyDeleted = Message already deleted.
###
### Perso create/select
###
NewCharacterCreated = New character created
CreateCharacter = Create a character
EditCharacter = Edit %s information
NoSexSpecified = "Pick a sex, or '<em>Neutral</em>' if you don't want to tell it."
NoNicknameSpecified = "You must pick a nickname, it's like your login to identify your character."
NoFullnameSpecified = "All beings must have a name."
NoRaceSpecified = "You've to specify a race: '<em>humanoid</em>' for human and co.<br />If you don't want to specify a race, use the generic '<em>being</em>'."
NicknameUnavailable = "This nickname is already used.<br />Choose a more original one."
PickPerso = Pick your perso
SwapPerso = "Swap perso (%s's logout)"
NewLocationNotify = "You're slowly awaking in a place you don't recognize."
###
### Places
###
+CurrentLocation = "Current location"
+
UnknownBody = "Unknown asteroid"
UnknownPlace = "Unknown place"
WherePlace = "%s @ %s"
SpaceAround = "Space around %s"
hypership = hypership
asteroid = asteroid
moon = moon
planet = planet
star = star
orbital = orbital
###
### Stories
###
InvalidStoryGUID = "In story mode, you can't use previous/back URL."
ExpiredStorySession = "Story choices URL are temporary.<br />You can't bookmark them or use in another session."
###
### Requests
###
Title = Title
###
### MOTD
###
PushMessage = Push a message to the header
TextToAdd = Text to add
TextToAddWarning = Warning: once published, it can't be (easily) removed.
Rendering = How it will be printed?
RenderingWhere = "At the top right header corner:"
DummyPlaceholder = Here your message.
Push = Push
Published = Published :)
\ No newline at end of file
diff --git a/lang/en/footer.conf b/lang/en/footer.conf
--- a/lang/en/footer.conf
+++ b/lang/en/footer.conf
@@ -1,1 +1,11 @@
+#Zed language config file - Footer
+#Language: English
+#Code: en
+#Author: Dereckson
+
+###
+### SmartLine
+###
+
+[SmartLine]
SmartLineHistory = SmartLine History
\ No newline at end of file
diff --git a/lang/en/persorequest.conf b/lang/en/persorequest.conf
new file mode 100644
--- /dev/null
+++ b/lang/en/persorequest.conf
@@ -0,0 +1,40 @@
+#Zed language config file - Perso requests
+#Language: English
+#Code: en
+#Author: Dereckson
+
+###
+### Generalities
+###
+
+#Page title
+PersoRequests = Requests
+
+#Page H1
+Requests = Requests
+
+#Button allow, to allow a request
+Allow = allow
+
+#Button deny, to deny a request
+Deny = deny
+
+#Link ignore all, user can click here to continue normal site operations
+IgnoreAll = "Ignore all requests"
+
+###
+### Callbacks messages
+###
+
+CallbackError = "An error have occured processing your request reply."
+CallbackDone = "All requests have been processed."
+
+###
+### Ship API
+###
+
+#When a ship initiates a auth request, the perso is prompted the following message:
+RequestShipAPIAuthenticate = "The ship %s asks you to authenticate your identity."
+
+#When a ship initiates a session, the perso is prompted the following message:
+RequestShipAPISessionConfirm = "The ship %s asks you to confirm the link initialization. Thus, you'll be able to communicate with it."
\ No newline at end of file
diff --git a/lang/fr/core.conf b/lang/fr/core.conf
--- a/lang/fr/core.conf
+++ b/lang/fr/core.conf
@@ -1,136 +1,137 @@
#Zed language config file
#Language: English
#Code: fr
#Author: Dereckson
###
### Site configuration
###
SiteTitle = Zed
Product = "<strong>Zed 0.1</strong>, alpha technical preview"
###
### General stuff
###
_t = " :"
###
### Login
###
Login = Login
Password = Password
OK = OK
LoginNotFound = Login introuvable.
IncorrectPassword = Mot de passe incorrect.
JaMata = Ja mata!
WelcomeBack = Welcome back.
OpenID = OpenID
Logout = Déconnexion
###
### Homepage
###
Welcome = Bienvenue
WelcomeText = "<p>Bienvenue sur la version alpha de Zed, un hybride un peu étrange entre une galerie, un endroit où rencontrer ses amis ou s'en faire de nouveaux, avec une légère inspiration RPG, dans un environnement galactique inspiré des romans de la Culture de Iain M. Banks.</p>
<p>Le concept est d'expérimenter ce qui se passe lorsque chaque information est dans un espace précis, un peu comme la vision cyberpunk des années 80 du cyberespace. Un autre but est de créer une communauté partagant des valeurs de respect, de coopération, de liberté et d'éthique.</p>"
-
###
### Homepage - Messages
###
#messages.tpl, Reply
Reply = Répondre
#messages.tpl, the X link title
DeleteThisMessage = Effacer ce message
#home.php, messages error
MessageDeleted = Message effacé.
NotYourMessage = Hey, ce message appartient à autrui !
MessageAlreadyDeleted = Message déjà effacé
###
### Errors
###
UnauthorizedAccess = "Accès non autorisé"
SQLError = "Erreur dans la requête SQL"
line = ligne
Error = Erreur
BackToHome = "Retour à la page d'accueil"
FatalErrorScreen = Fatal error screen
FatalErrorInterrupt = Fatal error screen (interruption)
GeneralError = "Erreur"
PageNotFound = "Cette page n'existe pas."
###
### Perso create/select
###
NewCharacterCreated = Nouveau perso créé.
CreateCharacter = Nouveau perso
EditCharacter = Éditer les infos de %s
NoSexSpecified = "Pick a sex, or '<em>Neutral</em>' if you don't want to tell it."
NoNicknameSpecified = "You must pick a nickname, it's like your login to identify your character."
NoFullnameSpecified = "All beings must have a name."
NoRaceSpecified = "You've to specify a race: '<em>humanoid</em>' for human and co.<br />If you don't want to specify a race, use the generic '<em>being</em>'."
NicknameUnavailable = "This nickname is already used.<br />Choose a more original one."
PickPerso = "Sélectionnez votre perso"
SwapPerso = "Changer de perso (déco %s)"
NewLocationNotify = "Vous vous réveillez lentement dans un endroit inconnu"
###
### Places
###
+CurrentLocation = "Localisateur"
+
UnknownBody = "Astéroïde inconnu"
UnknownPlace = "Endroit inconnu"
WherePlace = "%2$s, %1$s."
SpaceAround = "%s et l'espace autour"
hypership = hypership
asteroid = astéroïde
moon = lune
planet = planète
star = étoile
orbital = orbitale
###
### Stories
###
InvalidStoryGUID = "En mode récit, il n'est pas possible <br />d'utiliser les boutons précédents et suivants."
ExpiredStorySession = "Les URL de choix sont temporaires.<br />Il n'est pas possible de les bookmark pour y revenir."
###
### Requests
###
Title = Titre
###
### MOTD
###
PushMessage = Publier un message tout en haut
TextToAdd = Texte à ajouter
TextToAddWarning = "Une fois publié, ne peut être facilement enlevé."
Rendering = Aperçu
RenderingWhere = "Coin supérieur droit de la page :"
DummyPlaceholder = Lorem ipsum dolor.
Push = Publier
Published = Publié :)
\ No newline at end of file
diff --git a/lang/fr/persorequest.conf b/lang/fr/persorequest.conf
new file mode 100644
--- /dev/null
+++ b/lang/fr/persorequest.conf
@@ -0,0 +1,40 @@
+#Zed language config file - Perso requests
+#Language: French
+#Code: fr
+#Author: Dereckson
+
+###
+### Generalities
+###
+
+#Page title
+PersoRequests = Requêtes
+
+#Page H1
+Requests = Requêtes
+
+#Button allow, to allow a request
+Allow = confirmer
+
+#Button deny, to deny a request
+Deny = refuser
+
+#Link ignore all, user can click here to continue normal site operations
+IgnoreAll = "Tout ignorer pour l'instant"
+
+###
+### Callbacks messages
+###
+
+CallbackError = "Une erreur est survenue lors du traitement de la requête."
+CallbackDone = "Une réponse à chaque requête. Terminé la bureaucratie :)"
+
+###
+### Ship API
+###
+
+#When a ship initiates a auth request, the perso is prompted the following message:
+RequestShipAPIAuthenticate = "Le vaisseau %s vous demande de confirmer votre identité."
+
+#When a ship initiates a session, the perso is prompted the following message:
+RequestShipAPISessionConfirm = "Le vaisseau %s vous demande de confirmer le lancement d'un lien vous permettant de communiquer avec lui."
\ No newline at end of file
diff --git a/skins/zed/header.tpl b/skins/zed/header.tpl
--- a/skins/zed/header.tpl
+++ b/skins/zed/header.tpl
@@ -1,77 +1,77 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>{$PAGE_TITLE} - {#SiteTitle#}</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="stylesheet" type="text/css" href="{#StaticContentURL#}/css/960.css" media="screen" />
<link rel="stylesheet" href="{#StaticContentURL#}/css/zed/theme.css" />
<script type="text/javascript" src="{#StaticContentURL#}/js/misc.js"></script>
{foreach from=$PAGE_CSS item=css}
<link rel="stylesheet" href="{#StaticContentURL#}/css/{$css}" />
{/foreach}
{foreach from=$PAGE_JS item=js}
<script src="{#StaticContentURL#}/js/{$js}"></script>
{/foreach}
{if $DOJO}
<!-- DOJO -->
<script type="text/javascript" src="{#StaticContentURL#}/js/dojo/dojo/dojo.js" djConfig="isDebug:false, parseOnLoad: true" ></script>
{if $DIJIT}
<link rel="stylesheet" type="text/css" href="{#StaticContentURL#}/css/zed/forms.css">
{/if}
{/if}
</head>
<body{if $DIJIT} class="tundra"{/if}>
<!-- Header -->
<div id="header">
<div id="header_content">
<div class="container_16">
<div class="grid_4 alpha">
<a href="{get_url()}"><img src="{#StaticContentURL#}/img/zed/logo.png" src="Zed logo" border=0 /></a>
</div>
<div class="grid_12 omega">
<div class="wall">
<p>
{$WALL_TEXT}
<br /><span class="wall_info">-- <a href="{$WALL_USER_URL}">{$WALL_USER}</a></span>
</p>
</div>
</div>
<div class="clear"></div>
</div>
</div>
</div>
<div class="clear"></div>
<!-- Content -->
<div class="container_16">
{if $WAP}
<!-- WAP -->
<div class="grid_16 alpha omega">
<div class="wap">{$WAP}</div>
</div>
<div class="clear"></div>
{/if}
{if $NOTIFY}
<!-- Notify -->
<div class="grid_16 alpha omega">
<div class="notify">{$NOTIFY}</div>
</div>
<div class="clear"></div>
{/if}
<!-- Where? When? -->
<div class="info">
<div class="info_left">
- <strong>Current location</strong> {$CurrentPerso->where()}
+ <strong>{#CurrentLocation#}</strong> {$CurrentPerso->where()}
</div>
<div class="info_right">
<span id="HypershipTime">{get_hypership_time()}</span>
</div>
</div>
{if $SmartLine_STDOUT || $SmartLine_STDERR}
{include file="smartline_results.tpl"}
{/if}
diff --git a/skins/zed/persorequests.tpl b/skins/zed/persorequests.tpl
new file mode 100644
--- /dev/null
+++ b/skins/zed/persorequests.tpl
@@ -0,0 +1,89 @@
+ <!-- Javascript bits for request handling -->
+ <script type="text/javascript">
+
+ //The amount of requests printed on the page.
+ //When it falls to 0, request_reply_callback will print a temporary exit
+ //message and then redirects to the homepage.
+ var requestsQuantity = {count($requests)};
+
+ //Performs an AJAX call
+ // id the request DOM element id
+ // url the URL to query
+ //
+ //The reply will be handled by request_reply_callback function.
+ function request_reply (id, url) {
+ dojo.xhrGet({
+ handleAs: "json",
+ url: url,
+ preventCache: true,
+ handle: function (response, ioArgs) {
+ request_reply_callback(response, id);
+ }
+ });
+ }
+
+ //Prints a wap message
+ // message the error message to print
+ function wap (message) {
+ var html = '<div class="wap">' + message + '</div><div class="clear"></div>';
+ document.getElementById('RequestsWap').innerHTML = html;
+ }
+
+ //Prints a notify message
+ // message the warning message to print
+ function notify (message) {
+ var html = '<div class="notify">' + message + '</div><div class="clear"></div>';
+ document.getElementById('RequestsNotify').innerHTML = html;
+ }
+
+ //This function is called when there isn't requests anymore.
+ //It prints a close message, clears the site.requests flag and redirects to
+ //Zed homepage.
+ function no_more_site_requests () {
+ document.getElementById('RequestsBody').style.display = 'none';
+ notify("{#CallbackDone#}");
+ setTimeout('document.location = "{get_url()}";', 3000);
+ dojo.xhrGet({
+ url: '{get_request_url(0, 'perso' , 'site.requests', 0)}',
+ preventCache: true
+ });
+ }
+
+ //Handles the reply
+ // reply ajax reply ; a boolean is expected, so true or false.
+ // id the request DOM element id
+ //
+ //If the reply is true hides request id.
+ //If the reply is false outputs a WAP error.
+ function request_reply_callback (reply, id) {
+ if (reply == true) {
+ document.getElementById(id).style.display = 'none';
+ requestsQuantity--;
+ if (requestsQuantity == 0) {
+ no_more_site_requests();
+ }
+ } else {
+ wap("{#CallbackError#}");
+ }
+ }
+ </script>
+
+ <!-- Perso requests -->
+ <div id="RequestsWap"></div>
+ <div id="RequestsNotify"></div>
+ <div id="RequestsBody">
+ <h1>{#Requests#}</h1>
+ <div class="grid_16 alpha omega">
+{foreach from=$requests item=request}
+{$i = {counter}}
+ <div id="request{$i}" class="request message {cycle values="dark,light"}">
+ <p>{$request->message}</p>
+ <ul>
+ <li><a onclick="request_reply('request{$i}', '{get_request_allow_url($request)}'); return false;" href="{get_request_allow_url($request)}?redirectTo={get_url()}">{#Allow#}</li>
+ <li><a onclick="request_reply('request{$i}', '{get_request_deny_url($request)}'); return false;" href="{get_request_deny_url($request)}?redirectTo={get_url()}">{#Deny#}</a></li>
+ </ul>
+ </div>
+{/foreach}
+ </div>
+ <p><a href="{get_request_url(0, 'perso', 'site.requests', 0)}?redirectTo={get_url()}">{#IgnoreAll#}</a></p>
+ </div>
\ No newline at end of file
diff --git a/skins/zed/smartline.tpl b/skins/zed/smartline.tpl
--- a/skins/zed/smartline.tpl
+++ b/skins/zed/smartline.tpl
@@ -1,26 +1,26 @@
<!-- SmartLine -->
<div class="grid_16 alpha omega" id="SmartLine">
- <form method="post" name="SmartLine" action="{get_current_url()}">
+ <form name="SmartLine" method="{if $SmartLineFormMethod}{$SmartLineFormMethod}{else}post{/if}" action="{get_current_url()}">
{if $SmartLineHistory}
<!-- SmartLine history -->
<div class="grid_4 left alpha">
- <select name="SmartLineHistory" id="SmartLineHistory" class="black" onChange=UpdateSmartLine()>
+ <select id="SmartLineHistory" class="black" onChange=UpdateSmartLine()>
<option value="">[ {#SmartLineHistory#} ]</option>
{foreach from=$SmartLineHistory item=command}
<option value="{$command->text|escape}">{$command->time} | {$command->text|escape}</option>
{/foreach}
</select>
</div>
<!-- SmartLine line -->
<div class="grid_12 right omega">
{else}
<!-- SmartLine line -->
<div class="grid_16 alpha omega left" style="width: 100.2%">
{/if}
<input name="C" type="text" id="SmartLineBar" maxlength=255 class="black" style="text-align: left;">
</div>
</form>
</div>
<div class="clear"></div>

File Metadata

Mime Type
text/x-diff
Expires
Sat, Nov 23, 10:35 (1 d, 6 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
21025
Default Alt Text
(122 KB)

Event Timeline