diff --git a/db/update.sql b/db/update.sql
index 7da5f3e6..c8079f3a 100644
--- a/db/update.sql
+++ b/db/update.sql
@@ -1,3 +1,7 @@
+/* password recovery */
+ALTER TABLE `User` ADD `password_recovery_token` VARCHAR( 32 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL AFTER `Passwort` ,
+ADD INDEX ( `password_recovery_token` );
+
/* Update für #27, iCal-Export */
ALTER TABLE `User` ADD `ical_key` VARCHAR( 32 ) NOT NULL;
ALTER TABLE `User` ADD INDEX ( `ical_key` );
diff --git a/includes/controller/users_controller.php b/includes/controller/users_controller.php
new file mode 100644
index 00000000..8e0aace7
--- /dev/null
+++ b/includes/controller/users_controller.php
@@ -0,0 +1,84 @@
+= MIN_PASSWORD_LENGTH) {
+ if ($_REQUEST['password'] != $_REQUEST['password2']) {
+ $ok = false;
+ error(_("Your passwords don't match."));
+ }
+ } else {
+ $ok = false;
+ error(_("Your password is to short (please use at least 6 characters)."));
+ }
+
+ if ($ok) {
+ $result = set_password($user_source['UID'], $_REQUEST['password']);
+ if ($result === false)
+ engelsystem_error(_("Password could not be updated."));
+
+ success(_("Password saved."));
+ redirect(page_link_to('login'));
+ }
+ }
+
+ return User_password_set_view();
+ } else {
+ if (isset($_REQUEST['submit'])) {
+ $ok = true;
+
+ if (isset($_REQUEST['email']) && strlen(strip_request_item('email')) > 0) {
+ $email = strip_request_item('email');
+ if (check_email($email)) {
+ $user_source = User_by_email($email);
+ if ($user_source === false)
+ engelsystem_error("Unable to load user.");
+ if ($user_source == null) {
+ $ok = false;
+ $msg .= error(_("E-mail address is not correct."), true);
+ }
+ } else {
+ $ok = false;
+ $msg .= error(_("E-mail address is not correct."), true);
+ }
+ } else {
+ $ok = false;
+ $msg .= error(_("Please enter your e-mail."), true);
+ }
+
+ if ($ok) {
+ $token = User_generate_password_recovery_token($user_source);
+ if ($token === false)
+ engelsystem_error("Unable to generate password recovery token.");
+ $result = engelsystem_email_to_user($user_source, _("Password recovery"), sprintf(_("Please visit %s to recover your password."), page_link_to_absolute('user_password_recovery') . '&token=' . $token));
+ if ($result === false)
+ engelsystem_error("Unable to send password recovery email.");
+
+ success(_("We sent an email containing your password recovery link."));
+ redirect(page_link_to('login'));
+ }
+ }
+
+ return User_password_recovery_view();
+ }
+}
+
+function user_password_recovery_title() {
+ return _("Password recovery");
+}
+
+?>
\ No newline at end of file
diff --git a/includes/helper/email_helper.php b/includes/helper/email_helper.php
new file mode 100644
index 00000000..98cfd0f3
--- /dev/null
+++ b/includes/helper/email_helper.php
@@ -0,0 +1,16 @@
+");
+}
+
+?>
\ No newline at end of file
diff --git a/includes/helper/internationalization_helper.php b/includes/helper/internationalization_helper.php
index ae88eb21..db150fec 100644
--- a/includes/helper/internationalization_helper.php
+++ b/includes/helper/internationalization_helper.php
@@ -17,13 +17,25 @@ function gettext_init() {
elseif (! isset($_SESSION['locale']))
$_SESSION['locale'] = $default_locale;
- putenv('LC_ALL=' . $_SESSION['locale']);
- setlocale(LC_ALL, $_SESSION['locale']);
+ gettext_locale();
bindtextdomain('default', '../locale');
bind_textdomain_codeset('default', 'UTF-8');
textdomain('default');
}
+/**
+ * Swich gettext locale.
+ *
+ * @param string $locale
+ */
+function gettext_locale($locale = null) {
+ if ($locale == null)
+ $locale = $_SESSION['locale'];
+
+ putenv('LC_ALL=' . $locale);
+ setlocale(LC_ALL, $locale);
+}
+
/**
* Renders language selection.
*
diff --git a/includes/model/User_model.php b/includes/model/User_model.php
index 884aeae8..523685df 100644
--- a/includes/model/User_model.php
+++ b/includes/model/User_model.php
@@ -30,10 +30,40 @@ function User_by_api_key($api_key) {
return $user[0];
}
+/**
+ * Returns User by email.
+ *
+ * @param string $email
+ * @return Matching user, null or false on error
+ */
+function User_by_email($email) {
+ $user = sql_select("SELECT * FROM `User` WHERE `email`='" . sql_escape($email) . "' LIMIT 1");
+ if ($user === false)
+ return false;
+ if (count($user) == 0)
+ return null;
+ return $user[0];
+}
+
+/**
+ * Returns User by password token.
+ *
+ * @param string $token
+ * @return Matching user, null or false on error
+ */
+function User_by_password_recovery_token($token) {
+ $user = sql_select("SELECT * FROM `User` WHERE `password_recovery_token`='" . sql_escape($token) . "' LIMIT 1");
+ if ($user === false)
+ return false;
+ if (count($user) == 0)
+ return null;
+ return $user[0];
+}
+
/**
* Generates a new api key for given user.
*
- * @param User $user
+ * @param User $user
*/
function User_reset_api_key(&$user) {
$user['api_key'] = md5($user['Nick'] . time() . rand());
@@ -43,4 +73,18 @@ function User_reset_api_key(&$user) {
engelsystem_log("API key resetted.");
}
+/**
+ * Generates a new password recovery token for given user.
+ *
+ * @param User $user
+ */
+function User_generate_password_recovery_token(&$user) {
+ $user['password_recovery_token'] = md5($user['Nick'] . time() . rand());
+ $result = sql_query("UPDATE `User` SET `password_recovery_token`='" . sql_escape($user['password_recovery_token']) . "' WHERE `UID`='" . sql_escape($user['UID']) . "' LIMIT 1");
+ if ($result === false)
+ return false;
+ engelsystem_log("Password recovery for " . $user['Nick'] . " started.");
+ return $user['password_recovery_token'];
+}
+
?>
\ No newline at end of file
diff --git a/includes/pages/guest_login.php b/includes/pages/guest_login.php
index f072e411..605d32b1 100644
--- a/includes/pages/guest_login.php
+++ b/includes/pages/guest_login.php
@@ -216,6 +216,9 @@ function guest_login() {
form_password('password', _("Password")),
form_submit('submit', _("Login"))
)),
+ buttons(array(
+ button(page_link_to('user_password_recovery'), _("I forgot my password"))
+ )),
info(_("Please note: You have to activate cookies!"), true)
));
}
diff --git a/includes/sys_auth.php b/includes/sys_auth.php
index 3902aea2..e9fa197d 100644
--- a/includes/sys_auth.php
+++ b/includes/sys_auth.php
@@ -30,7 +30,7 @@ function generate_salt($length = 16) {
// set the password of a user
function set_password($uid, $password) {
- return sql_query("UPDATE `User` SET `Passwort` = '" . sql_escape(crypt($password, CRYPT_ALG . '$' . generate_salt(16) . '$')) . "' WHERE `UID` = " . intval($uid) . " LIMIT 1");
+ return sql_query("UPDATE `User` SET `Passwort` = '" . sql_escape(crypt($password, CRYPT_ALG . '$' . generate_salt(16) . '$')) . "', `password_recovery_token`=NULL WHERE `UID` = " . intval($uid) . " LIMIT 1");
}
// verify a password given a precomputed salt.
diff --git a/includes/view/User_view.php b/includes/view/User_view.php
index ef4f9831..eda29d58 100644
--- a/includes/view/User_view.php
+++ b/includes/view/User_view.php
@@ -3,25 +3,55 @@
/**
* Available T-Shirt sizes
*/
-$tshirt_sizes = array (
- '' => _("Please select..."),
- 'S' => "S",
- 'M' => "M",
- 'L' => "L",
- 'XL' => "XL",
- '2XL' => "2XL",
- '3XL' => "3XL",
- '4XL' => "4XL",
- '5XL' => "5XL",
- 'S-G' => "S Girl",
- 'M-G' => "M Girl",
- 'L-G' => "L Girl",
- 'XL-G' => "XL Girl"
+$tshirt_sizes = array(
+ '' => _("Please select..."),
+ 'S' => "S",
+ 'M' => "M",
+ 'L' => "L",
+ 'XL' => "XL",
+ '2XL' => "2XL",
+ '3XL' => "3XL",
+ '4XL' => "4XL",
+ '5XL' => "5XL",
+ 'S-G' => "S Girl",
+ 'M-G' => "M Girl",
+ 'L-G' => "L Girl",
+ 'XL-G' => "XL Girl"
);
+/**
+ * View for password recovery step 1: E-Mail
+ */
+function User_password_recovery_view() {
+ return page(array(
+ msg(),
+ _("We will send you an e-mail with a password recovery link. Please use the email address you used for registration."),
+ form(array(
+ form_text('email', _("E-Mail"), ""),
+ form_submit('submit', _("Recover"))
+ ))
+ ));
+}
+
+/**
+ * View for password recovery step 2: New password
+ */
+function User_password_set_view() {
+ return page(array(
+ msg(),
+ _("Please enter a new password."),
+ form(array(
+ form_password('password', _("Password")),
+ form_password('password2', _("Confirm password")),
+ form_submit('submit', _("Save"))
+ ))
+ ));
+}
+
/**
* Render a users avatar.
- * @param User $user
+ *
+ * @param User $user
* @return string
*/
function User_Avatar_render($user) {
@@ -30,16 +60,16 @@ function User_Avatar_render($user) {
/**
* Render a user nickname.
- * @param User $user_source
+ *
+ * @param User $user_source
* @return string
*/
function User_Nick_render($user_source) {
global $user, $privileges;
- if($user['UID'] == $user_source['UID'] || in_array('user_shifts_admin', $privileges))
+ if ($user['UID'] == $user_source['UID'] || in_array('user_shifts_admin', $privileges))
return '' . htmlspecialchars($user_source['Nick']) . '';
else
return htmlspecialchars($user_source['Nick']);
}
-
?>
\ No newline at end of file
diff --git a/locale/de_DE.UTF-8/LC_MESSAGES/default.mo b/locale/de_DE.UTF-8/LC_MESSAGES/default.mo
index 47a0aa3f..224b676b 100644
Binary files a/locale/de_DE.UTF-8/LC_MESSAGES/default.mo and b/locale/de_DE.UTF-8/LC_MESSAGES/default.mo differ
diff --git a/locale/de_DE.UTF-8/LC_MESSAGES/default.po b/locale/de_DE.UTF-8/LC_MESSAGES/default.po
index 64d09ad7..2946965a 100644
--- a/locale/de_DE.UTF-8/LC_MESSAGES/default.po
+++ b/locale/de_DE.UTF-8/LC_MESSAGES/default.po
@@ -1,8 +1,8 @@
msgid ""
msgstr ""
"Project-Id-Version: Engelsystem 2.0\n"
-"POT-Creation-Date: 2013-12-03 16:58+0100\n"
-"PO-Revision-Date: 2013-12-03 16:59+0100\n"
+"POT-Creation-Date: 2013-12-23 21:57+0100\n"
+"PO-Revision-Date: 2013-12-23 23:16+0100\n"
"Last-Translator: msquare \n"
"Language-Team: \n"
"Language: de_DE\n"
@@ -21,7 +21,25 @@ msgstr ""
msgid "No data found."
msgstr "Nichts gefunden."
-#: /Users/msquare/workspace/projects/engelsystem/includes/helper/internationalization_helper.php:40
+#: /Users/msquare/workspace/projects/engelsystem/includes/helper/email_helper.php:6
+#, php-format
+msgid "Hi %s,"
+msgstr "Hallo %s,"
+
+#: /Users/msquare/workspace/projects/engelsystem/includes/helper/email_helper.php:6
+msgid "here is a message for you from the engelsystem:"
+msgstr "hier ist eine Nachricht aus dem Engelsystem für Dich:"
+
+#: /Users/msquare/workspace/projects/engelsystem/includes/helper/email_helper.php:6
+msgid ""
+"This email is autogenerated and has not to be signed. You got this email "
+"because you are registered in the engelsystem."
+msgstr ""
+"Diese E-Mail wurde automatisch generiert und muss daher nicht unterschrieben "
+"werden. Du hast diese E-Mail bekommen, weil Du im Engelsystem registriert "
+"bist."
+
+#: /Users/msquare/workspace/projects/engelsystem/includes/helper/internationalization_helper.php:47
msgid "Language"
msgstr "Sprache"
@@ -1016,11 +1034,11 @@ msgstr "Kommentar (nur für Dich):"
msgid "Please select..."
msgstr "Bitte auswählen..."
-#: /Users/msquare/workspace/projects/engelsystem/public/index.php:174
+#: /Users/msquare/workspace/projects/engelsystem/public/index.php:188
msgid "No Access"
msgstr "Kein Zugriff"
-#: /Users/msquare/workspace/projects/engelsystem/public/index.php:175
+#: /Users/msquare/workspace/projects/engelsystem/public/index.php:189
msgid ""
"You don't have permission to view this page. You probably have to sign in or "
"register in order to gain access!"
@@ -1028,7 +1046,7 @@ msgstr ""
"Du hast keinen Zugriff auf diese Seite. Registriere Dich und logge Dich "
"bitte ein, um Zugriff zu erhalten!"
-#: /Users/msquare/workspace/projects/engelsystem/public/index.php:188
+#: /Users/msquare/workspace/projects/engelsystem/public/index.php:202
msgid ""
"You are not marked as arrived. Please go to heaven's desk, get your angel "
"badge and/or tell them that you arrived already."
@@ -1036,11 +1054,11 @@ msgstr ""
"Du bist nicht als angekommen markiert. Bitte gehe zur Himmelsverwaltung, "
"hole Dein Badge ab und/oder erkläre ihnen, dass Du bereits angekommen bist."
-#: /Users/msquare/workspace/projects/engelsystem/public/index.php:191
+#: /Users/msquare/workspace/projects/engelsystem/public/index.php:205
msgid "You need to specify a tshirt size in your settings!"
msgstr ""
-#: /Users/msquare/workspace/projects/engelsystem/public/index.php:194
+#: /Users/msquare/workspace/projects/engelsystem/public/index.php:208
msgid ""
"You need to specify a DECT phone number in your settings! If you don't have "
"a DECT phone, just enter \"-\"."
diff --git a/public/index.php b/public/index.php
index fccbc69b..fb0d7966 100644
--- a/public/index.php
+++ b/public/index.php
@@ -24,6 +24,7 @@ require_once ('includes/view/User_view.php');
require_once ('includes/helper/internationalization_helper.php');
require_once ('includes/helper/message_helper.php');
require_once ('includes/helper/error_helper.php');
+require_once ('includes/helper/email_helper.php');
require_once ('config/config.default.php');
if (file_exists('../config/config.php'))
@@ -62,37 +63,40 @@ load_auth();
if (isset($_REQUEST['auth']))
json_auth_service();
-$api_pages = array(
+$free_pages = array(
'stats',
- 'shifts_json_export_all'
+ 'shifts_json_export_all',
+ 'user_password_recovery'
);
// Gewünschte Seite/Funktion
$p = isset($user) ? "news" : "login";
-if (isset($_REQUEST['p']) && preg_match("/^[a-z0-9_]*$/i", $_REQUEST['p']) && (in_array($_REQUEST['p'], $api_pages) || (sql_num_query("SELECT * FROM `Privileges` WHERE `name`='" . sql_escape($_REQUEST['p']) . "' LIMIT 1") > 0)))
+if (isset($_REQUEST['p']) && preg_match("/^[a-z0-9_]*$/i", $_REQUEST['p']) && (in_array($_REQUEST['p'], $free_pages) || in_array($_REQUEST['p'], $privileges))) {
$p = $_REQUEST['p'];
-
-$title = $p;
-$content = "";
-
-if ($p == "ical") {
- require_once ('includes/pages/user_ical.php');
- user_ical();
-} elseif ($p == "atom") {
- require_once ('includes/pages/user_atom.php');
- user_atom();
-} elseif ($p == "shifts_json_export") {
- require_once ('includes/controller/shifts_controller.php');
- shifts_json_export_controller();
-} elseif ($p == "shifts_json_export_all") {
- require_once ('includes/controller/shifts_controller.php');
- shifts_json_export_all_controller();
-} elseif ($p == "stats") {
- require_once ('includes/pages/guest_stats.php');
- guest_stats();
-} // Recht dafür vorhanden?
-elseif (in_array($p, $privileges)) {
- if ($p == "news") {
+
+ $title = $p;
+ $content = "";
+
+ if ($p == "ical") {
+ require_once ('includes/pages/user_ical.php');
+ user_ical();
+ } elseif ($p == "atom") {
+ require_once ('includes/pages/user_atom.php');
+ user_atom();
+ } elseif ($p == "shifts_json_export") {
+ require_once ('includes/controller/shifts_controller.php');
+ shifts_json_export_controller();
+ } elseif ($p == "shifts_json_export_all") {
+ require_once ('includes/controller/shifts_controller.php');
+ shifts_json_export_all_controller();
+ } elseif ($p == "stats") {
+ require_once ('includes/pages/guest_stats.php');
+ guest_stats();
+ } elseif ($p == "user_password_recovery") {
+ require_once ('includes/controller/users_controller.php');
+ $title = user_password_recovery_title();
+ $content = user_password_recovery_controller();
+ } elseif ($p == "news") {
$title = news_title();
$content = user_news();
} elseif ($p == "news_comments") {
@@ -171,14 +175,14 @@ elseif (in_array($p, $privileges)) {
} elseif ($p == "admin_log") {
$title = admin_log_title();
$content = admin_log();
+ } elseif ($p == "credits") {
+ require_once ('includes/pages/guest_credits.php');
+ $title = credits_title();
+ $content = guest_credits();
} else {
require_once ('includes/pages/guest_start.php');
$content = guest_start();
}
-} elseif ($p == "credits") {
- require_once ('includes/pages/guest_credits.php');
- $title = credits_title();
- $content = guest_credits();
} else {
// Wenn schon eingeloggt, keine-Berechtigung-Seite anzeigen
if (isset($user)) {
@@ -190,27 +194,29 @@ elseif (in_array($p, $privileges)) {
}
}
-// Hinweis für ungelesene Nachrichten
-if (isset($user) && $p != "user_messages")
- $content = user_unread_messages() . $content;
+if (isset($user)) {
+ // Hinweis für ungelesene Nachrichten
+ if ($p != "user_messages")
+ $content = user_unread_messages() . $content;
+
+ // Hinweis für Engel, die noch nicht angekommen sind
+ if ($user['Gekommen'] == 0)
+ $content = error(_("You are not marked as arrived. Please go to heaven's desk, get your angel badge and/or tell them that you arrived already."), true) . $content;
- // Hinweis für Engel, die noch nicht angekommen sind
-if (isset($user) && $user['Gekommen'] == 0)
- $content = error(_("You are not marked as arrived. Please go to heaven's desk, get your angel badge and/or tell them that you arrived already."), true) . $content;
-
-if (isset($user) && $enable_tshirt_size && $user['Size'] == "")
- $content = error(_("You need to specify a tshirt size in your settings!"), true) . $content;
-
-if (isset($user) && $user['DECT'] == "")
- $content = error(_("You need to specify a DECT phone number in your settings! If you don't have a DECT phone, just enter \"-\"."), true) . $content;
+ if ($enable_tshirt_size && $user['Size'] == "")
+ $content = error(_("You need to specify a tshirt size in your settings!"), true) . $content;
- // Erzengel Hinweis für unbeantwortete Fragen
-if (isset($user) && $p != "admin_questions")
- $content = admin_new_questions() . $content;
-
- // Erzengel Hinweis für freizuschaltende Engeltypen
-if (isset($user) && $p != "admin_user_angeltypes")
- $content = admin_new_user_angeltypes() . $content;
+ if ($user['DECT'] == "")
+ $content = error(_("You need to specify a DECT phone number in your settings! If you don't have a DECT phone, just enter \"-\"."), true) . $content;
+
+ // Erzengel Hinweis für unbeantwortete Fragen
+ if ($p != "admin_questions")
+ $content = admin_new_questions() . $content;
+
+ // Erzengel Hinweis für freizuschaltende Engeltypen
+ if ($p != "admin_user_angeltypes")
+ $content = admin_new_user_angeltypes() . $content;
+}
echo template_render('../templates/layout.html', array(
'theme' => isset($user) ? $user['color'] : $default_theme,