feature #392, authentication keys, album notification

* On album notification (for a group), sends one distinct email for each user
  with a new authentication key.

* When someone clicks the link with auth=<key> in URL, if the user is not
  already connected, Piwigo will automatically connect the user.
This commit is contained in:
plegall 2015-12-31 19:59:08 +01:00
parent eee57a5d2e
commit 4aeedb5a2e
7 changed files with 181 additions and 21 deletions

View file

@ -54,6 +54,8 @@ if (isset($_POST['submitEmail']) and !empty($_POST['group']))
is empty find child representative_picture_id */
if (!empty($category['representative_picture_id']))
{
$img = array();
$query = '
SELECT id, file, path, representative_ext
FROM '.IMAGES_TABLE.'
@ -65,21 +67,19 @@ SELECT id, file, path, representative_ext
{
$element = pwg_db_fetch_assoc($result);
$img_url = '<a href="'.
make_picture_url(array(
'image_id' => $element['id'],
'image_file' => $element['file'],
'category' => $category
))
.'" class="thumblnk"><img src="'.DerivativeImage::url(IMG_THUMB, $element).'"></a>';
$img = array(
'link' => make_picture_url(
array(
'image_id' => $element['id'],
'image_file' => $element['file'],
'category' => $category
)
),
'src' => DerivativeImage::url(IMG_THUMB, $element),
);
}
}
if (!isset($img_url))
{
$img_url = '';
}
pwg_mail_group(
$_POST['group'],
array(
@ -90,7 +90,7 @@ SELECT id, file, path, representative_ext
array(
'filename' => 'cat_group_info',
'assign' => array(
'IMG_URL' => $img_url,
'IMG' => $img,
'CAT_NAME' => trigger_change('render_category_name', $category['name'], 'admin_cat_list'),
'LINK' => make_index_url(array(
'category' => array(

View file

@ -646,6 +646,10 @@ $conf['recent_post_dates'] = array(
// the author shown in the RSS feed <author> element
$conf['rss_feed_author'] = 'Piwigo notifier';
// how long does the authentication key stays valid, in seconds. 3 days by
// default. 0 to disable.
$conf['auth_key_duration'] = 3*24*60*60;
// +-----------------------------------------------------------------------+
// | Set admin layout |
// +-----------------------------------------------------------------------+

View file

@ -81,6 +81,8 @@ if (!defined('USER_FEED_TABLE'))
define('USER_FEED_TABLE', $prefixeTable.'user_feed');
if (!defined('RATE_TABLE'))
define('RATE_TABLE', $prefixeTable.'rate');
if (!defined('USER_AUTH_KEYS_TABLE'))
define('USER_AUTH_KEYS_TABLE', $prefixeTable.'user_auth_keys');
if (!defined('USER_CACHE_TABLE'))
define('USER_CACHE_TABLE', $prefixeTable.'user_cache');
if (!defined('USER_CACHE_CATEGORIES_TABLE'))

View file

@ -514,6 +514,8 @@ SELECT DISTINCT language
// get subset of users in this group for a specific language
$query = '
SELECT
ui.user_id,
ui.status,
u.'.$conf['user_fields']['username'].' AS name,
u.'.$conf['user_fields']['email'].' AS email
FROM '.USER_GROUP_TABLE.' AS ug
@ -534,13 +536,27 @@ SELECT
switch_lang_to($language);
$return&= pwg_mail(null,
array_merge(
$args,
array('Bcc' => $users)
),
$tpl
);
foreach ($users as $u)
{
$authkey = create_user_auth_key($u['user_id'], $u['status']);
$user_tpl = $tpl;
if ($authkey !== false)
{
$user_tpl['assign']['LINK'] = add_url_params($tpl['assign']['LINK'], array('auth' => $authkey['auth_key']));
if (isset($user_tpl['assign']['IMG']['link']))
{
$user_tpl['assign']['IMG']['link'] = add_url_params(
$user_tpl['assign']['IMG']['link'],
array('auth' => $authkey['auth_key'])
);
}
}
$return &= pwg_mail($u['email'], $args, $user_tpl);
}
switch_lang_back();
}

View file

@ -1462,4 +1462,136 @@ function get_recent_photos_sql($db_field)
.pwg_db_get_recent_period_expression($user['recent_period'])
.','.pwg_db_get_recent_period_expression(1,$user['last_photo_date']).')';
}
/**
* Performs auto-connection if authentication key is valid.
*
* @since 2.8
*
* @return bool
*/
function auth_key_login($auth_key)
{
global $conf, $user;
if ($user['id'] != $conf['guest_id'])
{
return false;
}
if (!preg_match('/^[a-z0-9]{30}$/i', $auth_key))
{
return false;
}
$query = '
SELECT
*,
'.$conf['user_fields']['username'].' AS username,
NOW() AS dbnow
FROM '.USER_AUTH_KEYS_TABLE.' AS uak
JOIN '.USER_INFOS_TABLE.' AS ui ON uak.user_id = ui.user_id
JOIN '.USERS_TABLE.' AS u ON u.'.$conf['user_fields']['id'].' = ui.user_id
WHERE auth_key = \''.$auth_key.'\'
;';
$keys = query2array($query);
if (count($keys) == 0)
{
return false;
}
$key = $keys[0];
// is the key still valid?
if (strtotime($key['expired_on']) < strtotime($key['dbnow']))
{
return false;
}
// admin/webmaster/guest can't get connected with authentication keys
if (!in_array($key['status'], array('normal','generic')))
{
return false;
}
$user['id'] = $key['user_id'];
log_user($user['id'], false);
trigger_notify('login_success', stripslashes($key['username']));
return true;
}
/**
* Creates an authentication key.
*
* @since 2.8
* @param int $user_id
* @return array
*/
function create_user_auth_key($user_id, $user_status=null)
{
global $conf;
if (0 == $conf['auth_key_duration'])
{
return false;
}
if (!isset($user_status))
{
// we have to find the user status
$query = '
SELECT
status
FROM '.USER_INFOS_TABLE.'
WHERE user_id = '.$user_id.'
;';
$user_infos = query2array($query);
if (count($user_infos) == 0)
{
return false;
}
$user_status = $user_infos[0]['status'];
}
if (!in_array($user_status, array('normal','generic')))
{
return false;
}
$candidate = generate_key(30);
$query = '
SELECT
COUNT(*),
NOW(),
ADDDATE(NOW(), INTERVAL '.$conf['auth_key_duration'].' SECOND)
FROM '.USER_AUTH_KEYS_TABLE.'
WHERE auth_key = \''.$candidate.'\'
;';
list($counter, $now, $expiration) = pwg_db_fetch_row(pwg_query($query));
if (0 == $counter)
{
$key = array(
'auth_key' => $candidate,
'user_id' => $user_id,
'created_on' => $now,
'duration' => $conf['auth_key_duration'],
'expired_on' => $expiration,
);
single_insert(USER_AUTH_KEYS_TABLE, $key);
$key['auth_key_id'] = pwg_db_insert_id();
return $key;
}
else
{
return create_user_auth_key($user_id);
}
}
?>

View file

@ -65,6 +65,12 @@ if ($conf['apache_authentication'])
}
}
// automatic login by authentication key
if (isset($_GET['auth']))
{
auth_key_login($_GET['auth']);
}
$user = build_user( $user['id'],
( defined('IN_ADMIN') and IN_ADMIN ) ? false : true // use cache ?
);

View file

@ -1,6 +1,6 @@
<div id="cat_group_info">
<h2>{'Informations'|@translate}</h2>
<p>{$IMG_URL}</p>
<p><a href="{$IMG.link}" class="thumblnk"><img src="{$IMG.src}"></a></p>
<p>{'Hello,'|@translate}</p>
<p>{'Discover album:'|@translate} <a href="{$LINK}">{$CAT_NAME}</a></p>
<p>{$CPL_CONTENT}</p>