From: arno Date: Sat, 15 Aug 2009 22:23:42 +0000 (+0200) Subject: web interface to add co-administrators X-Git-Tag: v0.3b_thomas~21 X-Git-Url: https://dev.renevier.net/gitweb.cgi?p=syp.git;a=commitdiff_plain;h=3c74920cb66b4e6c47c7e8a0eaeed40ffb7e8544 web interface to add co-administrators --- diff --git a/COPYING.txt b/COPYING.txt index 42134a9..b25feb3 100644 --- a/COPYING.txt +++ b/COPYING.txt @@ -11,8 +11,8 @@ - Jquery is available under both MIT and GPL licences. More informations can be found at http://docs.jquery.com/Licensing -- editor-throbber.gif and pwd-throbber.gif files have been generated with - http://ajaxload.info/ generator and are free for use. +- editor-throbber.gif, newuser-throbber.gif and pwd-throbber.gif files have + been generated with http://ajaxload.info/ generator and are free for use. diff --git a/README.txt b/README.txt index 33f29a3..ce452dd 100644 --- a/README.txt +++ b/README.txt @@ -45,6 +45,22 @@ Upgrade - copy upload/ back. - open http://yoururl.com/upgrade.php with your web browser +co-administrators +----------------- +It is possible to allow other people to upload and manage +pictures/descriptions. In admin interface, select "Add an co-administrator" +and fill informations (user name and password). Then, you need to communicate +to your user its username and password. Only admin can add new users. + +Other co-administrators will be able to add markers, and delete/modifiy them. +They cannot modify markers they have not created. admin is the only user +allowed to manage markers of other users. If you plan to have several +co-administrators, you may want to create a normal user for yourself, and use +it to manage your markers. You will then only use admin account when really +needed. + +Currently, SYP does not allow + server API ---------- The way server side communicates with client side is described at diff --git a/api.php b/api.php index 0d6e727..af8af1a 100644 --- a/api.php +++ b/api.php @@ -6,6 +6,17 @@ function exit_document ($body) { exit ("$body"); } +function success ($reason) { + exit_document (""); +} + +function success_newuser ($username) { + $res = "" . + htmlspecialchars ($user) . + ""; + exit_document ($res); +} + function success_auth ($user) { $res = "" . htmlspecialchars ($user) . @@ -46,14 +57,14 @@ function success_delete_feature ($feature) { exit_document ($res); } -function success ($reason) { - exit_document (""); -} - function error ($reason) { exit_document (""); } +function error_newuser_exists () { + error ("newuser_exists"); +} + function error_feature ($id, $reason) { $res = ""; $res .= "" . $id . ""; @@ -61,30 +72,30 @@ function error_feature ($id, $reason) { exit_document ($res); } -function nochange_error ($id) { +function error_nochange ($id) { error_feature ($id, "nochange"); } -function unreferenced_error ($id) { +function error_unreferenced ($id) { error_feature ($id, "unreferenced"); } -function server_error () { +function error_server () { error ("server"); } -function unauthorized_error () { +function error_unauthorized () { error ("unauthorized"); } -function request_error () { +function error_request () { error ("request"); } -function file_too_big_error () { +function error_file_too_big () { error ("toobig"); } -function notanimage_error () { +function error_notanimage () { error ("notimage"); } @@ -95,12 +106,12 @@ function save_uploaded_file ($file, $con) { $dest = unique_file (UPLOADDIR, $file ["name"], $con); if (!isset ($dest) || (!move_uploaded_file ($file ["tmp_name"], $dest))) { - server_error (); + error_server (); } $mini_dest = getthumbsdir () . "/mini_" . basename_safe ($dest); if (!create_thumbnail_or_copy ($dest, $mini_dest)) { - server_error (); + error_server (); } } return basename_safe ($dest); @@ -109,13 +120,13 @@ function save_uploaded_file ($file, $con) { function img_check_upload ($file) { if (!is_uploaded_file ($file ["tmp_name"])) { if ($file ["error"] == UPLOAD_ERR_INI_SIZE) { - file_too_big_error (); + error_file_too_big (); } else { - server_error (); + error_server (); } } if (!getimagesize ($file ["tmp_name"])) { - notanimage_error (); + error_notanimage (); } } @@ -181,20 +192,20 @@ function check_auth ($con, $user, $pwd, $auth_only) { success_auth ($user); } } else { - unauthorized_error (); + error_unauthorized (); } } if (!$authentificated && !($con->checkpwdmd5 ( $_COOKIE [sprintf ("%suser", DBPREFIX)], $_COOKIE [sprintf ("%sauth", DBPREFIX)]))) { - unauthorized_error (); + error_unauthorized (); } } function main ($con) { if (!isset ($_POST ["request"])) { - request_error (); + error_request (); } $pwd = unquote ($_POST ["password"]); @@ -211,10 +222,10 @@ function main ($con) { $id = $_POST ["fid"]; $feature = $con->getfeature ($id); if (!isset ($feature)) { - unreferenced_error ($id); + error_unreferenced ($id); } if ($feature->user != $user) { - unauthorized_error (); + error_unauthorized (); } // no file uploaded, but editor currently has an image: it means @@ -233,7 +244,7 @@ function main ($con) { try { $new_feature = new feature ($id, $lon, $lat, $imgpath, $title, $description, 0, $user); } catch (Exception $e) { - request_error (); + error_request (); } if (($new_feature->lon == $feature->lon) && @@ -241,7 +252,7 @@ function main ($con) { ($new_feature->title == $feature->title) && ($new_feature->imgpath == $feature->imgpath) && ($new_feature->description == $feature->description)) { - nochange_error ($feature->id); + error_nochange ($feature->id); } $old_imgpath = ""; @@ -252,7 +263,7 @@ function main ($con) { try { $con->save_feature ($new_feature); } catch (Exception $e) { - server_error (); + error_server (); } if ($old_imgpath) { try { @@ -271,12 +282,12 @@ function main ($con) { try { $feature = new feature (null, $lon, $lat, $imgpath, $title, $description, 0, $user); } catch (Exception $e) { - request_error (); + error_request (); } try { $feature = $con->save_feature ($feature); } catch (Exception $e) { - server_error (); + error_server (); } success_feature ($feature, "add"); break; @@ -284,17 +295,17 @@ function main ($con) { $id = $_POST ["fid"]; $feature = $con->getfeature ($id); if (!isset ($feature)) { - unreferenced_error ($id); + error_unreferenced ($id); } if ($feature->user != $user) { - unauthorized_error (); + error_unauthorized (); } $imgpath = $feature->imgpath; try { $con->delete_feature ($feature); } catch (Exception $e) { - server_error (); + error_server (); } try { @@ -302,16 +313,36 @@ function main ($con) { } catch (Exception $e) {} success_delete_feature ($feature); + case "newuser": + if ($user != "admin") { + error_unauthorized (); + } + $newuser_name = unquote ($_POST ["newuser_name"]); + if (!$newuser_name) { + error_request (); + } + $newuser_password = unquote ($_POST ["newuser_password"]); + try { + $con->setpwd ($newuser_name, $newuser_password, false); + } catch (Exception $e) { + if ($e->getMessage () == anydbConnection::err_query) { + error_newuser_exists (); + } else { + error_server (); + } + } + success_newuser ($newuser_name); + break; default: - request_error(); + error_request(); break; } - server_error (); + error_server (); } if (!@include_once ("./inc/settings.php")) { - server_error (); + error_server (); } require_once ("./inc/db/mysql.php"); require_once ("./inc/utils.php"); @@ -319,7 +350,7 @@ require_once ("./inc/utils.php"); try { $connection->connect (DBHOST, DBUSER, DBPWD, DBNAME, DBPREFIX); } catch (Exception $e) { - server_error (); + error_server (); } main ($connection); diff --git a/devdoc/api.txt b/devdoc/api.txt index e02b78d..8cc6fef 100644 --- a/devdoc/api.txt +++ b/devdoc/api.txt @@ -20,6 +20,14 @@ but server may be written in any language. ## auth asks for authentication +## newuser + adds a new user + * `$_POST ["newuser_name"]` must contain user name + * `$_POST ["newuser_password"]` must contain user password + + Only admin can add new users. + + ## add adds a new feature @@ -71,12 +79,16 @@ as _text/html_ * `toobig`: uploaded file was too big * `notation`: uploaded file was not an image * `nochange`: when trying to update a feature, there is nothing to update (ie: no field of the feature has changed) + * `newuser_exists`: when trying to add an user which has the same name as an already registered user ## success handling: * `?user_name?`: authentication was successfull. ?user_name? is name of authenticated user. + * `?user_name?`: + new user addition was successfull. ?user_name? is name of newly added user. + * ` ?id? diff --git a/inc/db/anydb.php b/inc/db/anydb.php index 8ccdf12..596561c 100644 --- a/inc/db/anydb.php +++ b/inc/db/anydb.php @@ -94,10 +94,12 @@ interface anydbConnection { public function create_items_table(); /* - * set password $pwd for user $usrname. If $usrname does not exist, create - * it. + * set password $pwd for user $usrname. + * If $usrname does not exist: + * - if $create_if_not_exists is true: create user. + * - if $create_if_not_exists is false: throws an err_query error. */ - public function setpwd($usrname, $pwd); + public function setpwd($usrname, $pwd, $create_if_not_exists); /* * check that $pwd_md5 is md5 for $username password. diff --git a/inc/db/mysql.php b/inc/db/mysql.php index 043e86d..8e6253f 100644 --- a/inc/db/mysql.php +++ b/inc/db/mysql.php @@ -54,14 +54,18 @@ class mysqlConnection implements anydbConnection { $this->_execute_query ($query); } - public function setpwd ($user_name, $pwd) { + public function setpwd ($user_name, $pwd, $create_if_not_exists) { $usrname_escaped = mysql_real_escape_string ($user_name); $query = sprintf ("SELECT COUNT(*) FROM %susers WHERE name LIKE '%s';", $this->dbprefix, $usrname_escaped); $res = mysql_fetch_array ($this->_execute_query ($query), MYSQL_NUM); if ($res [0] == 1) { - $query = sprintf ("UPDATE %susers SET pwd='%s' WHERE name like '%s';", + if ($create_if_not_exists) { + $query = sprintf ("UPDATE %susers SET pwd='%s' WHERE name like '%s';", $this->dbprefix, md5 ($pwd), $usrname_escaped); + } else { + throw new Exception (anydbConnection::err_query); + } } else { $query = sprintf ("INSERT INTO %susers VALUES ('%s', '%s');", $this->dbprefix, $usrname_escaped, md5 ($pwd)); diff --git a/inc/i10n/en/syp.php b/inc/i10n/en/syp.php index a16e4ce..487e4eb 100644 --- a/inc/i10n/en/syp.php +++ b/inc/i10n/en/syp.php @@ -201,24 +201,48 @@ "Server reply was inconsistent." => "", - "There was an unknown error." - => "", - "Removal took place correctly." => "", "Save took place correctly." => "", + "User name has not been set." + => "", + + "Passwords do not match." + => "", + + "User already exists in database." + => "", + + "User added correctly." + => "", + "Logout" => "", + "Add a co-administrator" + => "", + "close without saving" => "", "close" => "", + "user name:" + => "", + + "user password:" + => "", + + "confirm password:" + => "", + + "Validate user" + => "", + "title:" => "", diff --git a/inc/i10n/fr/syp.php b/inc/i10n/fr/syp.php index ff5c29b..9844ed9 100644 --- a/inc/i10n/fr/syp.php +++ b/inc/i10n/fr/syp.php @@ -326,11 +326,6 @@ "Le serveur a fait une réponse incohérente" , - "There was an unknown error." - => - "Il s'est produit une erreur inconnue." - , - "Removal took place correctly." => "La suppression s'est déroulée correctement." @@ -341,11 +336,36 @@ "La sauvegarde s'est déroulée correctement." , + "User name has not been set." + => + "Il faut un nom pour l'utilisateur." + , + + "Passwords do not match." + => + "Les mots de passe ne correspondent pas." + , + + "User already exists in database." + => + "L'utilisateur existe déjà." + , + + "User added correctly." + => + "Utilisateur ajouté correctement." + , + "Logout" => "Déconnexion" , + "Add a co-administrator" + => + "Ajouter un co-administrateur" + , + "close without saving" => "fermer sans enregistrer" @@ -356,6 +376,26 @@ "fermer" , + "user name:" + => + "nom d'utilisateur :" + , + + "user password:" + => + "mot de passe de l'utilisateur :" + , + + "confirm password:" + => + "confirmer le mot de passe :" + , + + "Validate user" + => + "Valider l'utilisateur" + , + "title:" => "titre :" diff --git a/inc/templates_admin.php b/inc/templates_admin.php index 1f28e79..90bdb52 100644 --- a/inc/templates_admin.php +++ b/inc/templates_admin.php @@ -67,9 +67,12 @@ if (!$usrtblexists || !$itemstblexists) { UnauthorizedError: "", NotimageError: "", UnconsistentError: "", - UnknownError: "", DelSucces: "", - UpdateSucces: "" + UpdateSucces: "", + newUserNonameError: "", + newUserPasswordmatchError: "", + newUserExistsError: "", + newUserSuccess: "" }; var sypSettings = { @@ -99,7 +102,35 @@ if (!$usrtblexists || !$itemstblexists) { diff --git a/inc/templates_install.php b/inc/templates_install.php index 86c8566..e9a96ff 100644 --- a/inc/templates_install.php +++ b/inc/templates_install.php @@ -200,7 +200,7 @@ } par_success (trans ('User table created.')); try { - $connection->setpwd ("admin", $_POST ["admin_pass"]); + $connection->setpwd ("admin", $_POST ["admin_pass"], true); } catch (Exception $e) { par_error_and_leave (trans ('Error when initializing password.')); } diff --git a/js/admin.js b/js/admin.js index d950aeb..8101799 100644 --- a/js/admin.js +++ b/js/admin.js @@ -176,6 +176,9 @@ var Admin = { }, closeEditor: function() { + if ($("#editor").css("display") == "none") { + return; + } if (this.currentFeature && this.currentFeature.layer) { this.selFeatureControl.unselect(this.currentFeature); } @@ -196,6 +199,8 @@ var Admin = { showEditor: function (feature) { $("#newfeature_button").hide(); + userMgr.closeAddUser(); + if (feature.fid) { $("#delete").show(); } else { @@ -263,6 +268,8 @@ var Admin = { }, addNewFeature: function () { + userMgr.closeAddUser(); + function cancel() { $(document).unbind("keydown"); Admin.reset() @@ -285,15 +292,18 @@ var Admin = { cancelCurrentFeature: function() { if (AjaxMgr.running) { - return; + return false; } var feature = this.currentFeature; - if (feature.fid) { - FeatureMgr.move (feature, this.currentFeatureLocation); - } else { - this.dataLayer.removeFeatures([feature]); + if (feature) { + if (feature.fid) { + FeatureMgr.move (feature, this.currentFeatureLocation); + } else { + this.dataLayer.removeFeatures([feature]); + } } this.closeEditor(); + return true; }, reloadLayer: function (layer) { @@ -469,13 +479,12 @@ var FeatureMgr = { case "error": switch (xml.documentElement.getAttribute("reason")) { case "unauthorized": - $("#login_area").show(); - $("#password").val(""); - $("#user").val(sypSettings.loggedUser).focus().select(); + pwdMgr.reset(); $("#cookie_warning").show(); this.reset(); Admin.cancelCurrentFeature(); Admin.reset(); + userMgr.uninit(); break; case "server": this.commError(SypStrings.ServerError); @@ -505,7 +514,7 @@ var FeatureMgr = { $("#image_file").focus(); break; default: - this.commError(SypStrings.UnknownError); + this.commError(SypStrings.UnconsistentError); $("title").focus(); break; } @@ -591,12 +600,12 @@ var FeatureMgr = { commSuccess: function (message) { $("#server_comm").text(message); - $("#server_comm").removeClass().addClass("success"); + $("#server_comm").removeClass("error success").addClass("success"); }, commError: function (message) { $("#server_comm").text(message); - $("#server_comm").removeClass().addClass("error"); + $("#server_comm").removeClass("error success").addClass("error"); } } @@ -666,6 +675,9 @@ var pwdMgr = { reset: function() { this.commError (""); + $("#login_area").show(); + $("#password").val(""); + $("#user").val(sypSettings.loggedUser).focus().select(); }, submit: function () { @@ -693,7 +705,6 @@ var pwdMgr = { }, ajaxReply: function (data) { - $("#pwd_throbber").css("visibility", "hidden"); // here, we need a timeout because onsend timeout sometimes has not been triggered yet window.setTimeout(function() { @@ -723,7 +734,7 @@ var pwdMgr = { this.commError(SypStrings.RequestError); break; default: - this.commError(SypStrings.UnknownError); + this.commError(SypStrings.UnconsistentError); break; } $("#login_error").show(); @@ -737,6 +748,10 @@ var pwdMgr = { user = $(xml).find("USER,user").text(); sypSettings.loggedUser = user; + if (sypSettings.loggedUser == "admin") { + userMgr.init(); + } + if (Admin.selFeatureControl) { Admin.selFeatureControl.destroy(); } @@ -771,6 +786,168 @@ var pwdMgr = { } } +var userMgr = { + _adduserDisplayed: false, + _deluserDisplayed: false, + + init: function() { + if (sypSettings.loggedUser != "admin") { + return; + } + + $("#add_user").show(); + + $("#add_user").click(function () { + userMgr.toggleAddUser(); + return false; + }); + $("#newuser_close").click(function () { + userMgr.closeAddUser() + }); + $("#newuser").submit(function() { + try { + userMgr.add(); + } catch(e) {} + return false; + }); + }, + + uninit: function() { + if (this._adduserDisplayed) { + this.closeAddUser(); + } + $("#add_user").unbind("click"); + $("#add_user").hide(); + $("#newuser_close").unbind("click"); + $("#newuser").unbind("submit"); + }, + + toggleAddUser: function() { + if (this._adduserDisplayed) { + this.closeAddUser(); + } else { + this.showAddUser(); + } + }, + + showAddUser: function() { + if (!Admin.cancelCurrentFeature()) { + return; + } + + $(document).unbind("keydown").keydown(function(e) { + if (e.keyCode == 27) { + userMgr.closeAddUser() + e.preventDefault(); + } + }); + + Admin.reset(); + $("#newuser_area").show(); + $("#newuser_name, #newuser_password, #newuser_password_confirm").val(""); + $("#newuser_name, #newuser_password, #newuser_password_confirm, #newuser_submit").removeAttr('disabled'); + $("#newuser_name").focus();; + this.commError(""); + + this._adduserDisplayed = true; + }, + + closeAddUser: function() { + $("#newuser_area").hide(); + $(document).unbind("keydown"); + this._adduserDisplayed = false; + }, + + add: function() { + var newuser_name = $("#newuser_name").val(); + if (!newuser_name) { + this.commError(SypStrings.newUserNonameError); + $("#newuser_name").focus(); + return; + } + + var newuser_pass = $("#newuser_password").val(); + var newuser_pass_confirm = $("#newuser_password_confirm").val(); + if (newuser_pass != newuser_pass_confirm) { + this.commError(SypStrings.newUserPasswordmatchError); + $("#newuser_password").focus().select(); + return; + } + + this.commError(""); + + AjaxMgr.add({ + form: $("#newuser"), + oncomplete: OpenLayers.Function.bind(this.ajaxReply, this), + onsend: function() { $("#newuser_throbber").css("visibility", "visible"); } + }); + }, + + ajaxReply: function (data) { + $("#newuser_throbber").css("visibility", "hidden"); + if (!data) { + this.commError(SypStrings.ServerError); + return; + } + + var xml = new OpenLayers.Format.XML().read(data); + switch (xml.documentElement.nodeName.toLowerCase()) { + case "error": + switch (xml.documentElement.getAttribute("reason")) { + case "unauthorized": + pwdMgr.reset(); + $("#cookie_warning").show(); + Admin.reset(); + this.uninit(); + break; + case "server": + this.commError(SypStrings.ServerError); + $("#newuser_name").focus().select(); + break; + case "request": + this.commError(SypStrings.RequestError); + $("#newuser_name").focus().select(); + break; + case "newuser_exists": + this.commError(SypStrings.newUserExistsError); + $("#newuser_name").focus().select(); + break; + default: + this.commError(SypStrings.UnconsistentError); + $("#newuser_name").focus().select(); + break; + } + break; + case "success": + switch (xml.documentElement.getAttribute("request")) { + case "newuser": + this.commSuccess(SypStrings.newUserSuccess); + $("#newuser_name, #newuser_password, #newuser_password_confirm, #newuser_submit").attr('disabled', 'disabled'); + break; + default: + this.commError(SypStrings.UnconsistentError); + $("newuser_name").focus().select(); + break; + } + break; + default: + this.commError(SypStrings.UnconsistentError); + $("newuser_name").focus().select(); + break; + } + }, + + commSuccess: function (message) { + $("#newuser_comm").text(message); + $("#newuser_comm").removeClass("error success").addClass("success"); + }, + + commError: function (message) { + $("#newuser_comm").text(message); + $("#newuser_comm").removeClass("error success").addClass("error"); + } +} + $(window).load(function () { // if using .ready, ie triggers an error when trying to access // document.namespaces @@ -803,5 +980,6 @@ $(window).load(function () { $("#image_file").parent().show(); }); + userMgr.init(); Admin.init(); }); diff --git a/media/admin.css b/media/admin.css index 9757300..ec9f82b 100644 --- a/media/admin.css +++ b/media/admin.css @@ -11,10 +11,20 @@ #header { height: 2em; } -#logout { +#add_user { + display: none; +} +#logout a, #add_user a { + text-decoration: none; + color: blue; +} +#user_management { float: right; margin: 0px 10px 0px 0px; } +#user_management p { + margin: 0px; +} #other-language { float: left; margin-top: 1px; @@ -32,6 +42,28 @@ border: #BBBBFF 1px solid; } +/* + * newuser + */ +#newuser_area { + border: 1px solid black; + display: none; + float: right; + clear: right; + width: 35%; +} +#newuser { + margin: 12px; + text-align: center; +} +#newuser_close { + float: right; +} +#newuser_comm { + margin-left: 4px; + margin-right: 4px; +} + /* * map */ @@ -51,7 +83,7 @@ #editor { position: absolute; width: 44%; - top: 2em; + top: 3em; left: 55%; display: none; border: 1px solid black; diff --git a/media/newuser-throbber.gif b/media/newuser-throbber.gif new file mode 100644 index 0000000..41bae58 Binary files /dev/null and b/media/newuser-throbber.gif differ