invidious/invidious.php aktualisiert #1497

Closed
loma-one wants to merge 14 commits from (deleted):develop into develop
7 changed files with 485 additions and 103 deletions
Showing only changes of commit bd7b8f0f01 - Show all commits

View file

@ -8,7 +8,6 @@
* Note: Please use Group Directory instead
*/
use Friendica\App;
use Friendica\Content\Nav;
use Friendica\Content\Pager;
use Friendica\Content\Widget;
@ -16,8 +15,8 @@ use Friendica\Core\Hook;
use Friendica\Core\Renderer;
use Friendica\Database\DBA;
use Friendica\DI;
use Friendica\Model\Profile;
use Friendica\Model\User;
use Friendica\Security\OpenWebAuth;
global $forumdirectory_search;
@ -82,7 +81,7 @@ function forumdirectory_content()
$gdirpath = '';
$dirurl = DI::config()->get('system', 'directory');
if (strlen($dirurl)) {
$gdirpath = Profile::zrl($dirurl, true);
$gdirpath = OpenWebAuth::getZrlUrl($dirurl, true);
}
$sql_extra = '';

View file

@ -13,8 +13,8 @@ use Friendica\Core\Hook;
use Friendica\Core\Renderer;
use Friendica\Database\DBA;
use Friendica\DI;
use Friendica\Model\Profile;
use Friendica\Model\User;
use Friendica\Security\OpenWebAuth;
global $groupdirectory_search;
@ -79,7 +79,7 @@ function groupdirectory_content()
$gdirpath = '';
$dirurl = DI::config()->get('system', 'directory');
if (strlen($dirurl)) {
$gdirpath = Profile::zrl($dirurl, true);
$gdirpath = OpenWebAuth::getZrlUrl($dirurl, true);
}
$sql_extra = '';

View file

@ -7,11 +7,11 @@
* Maintainer: Hypolite Petovan <https://friendica.mrpetovan.com/profile/hypolite>
*/
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\Core\Renderer;
use Friendica\DI;
use Friendica\Util\Images;
use Friendica\Util\Strings;
global $js_upload_jsonresponse;
@ -20,9 +20,9 @@ global $js_upload_result;
function js_upload_install()
{
Hook::register('photo_upload_form', __FILE__, 'js_upload_form');
Hook::register('photo_post_init', __FILE__, 'js_upload_post_init');
Hook::register('photo_post_file', __FILE__, 'js_upload_post_file');
Hook::register('photo_post_end', __FILE__, 'js_upload_post_end');
Hook::register('photo_post_init', __FILE__, 'js_upload_post_init');
Hook::register('photo_post_file', __FILE__, 'js_upload_post_file');
Hook::register('photo_post_end', __FILE__, 'js_upload_post_end');
}
function js_upload_form(array &$b)
@ -34,11 +34,11 @@ function js_upload_form(array &$b)
$tpl = Renderer::getMarkupTemplate('js_upload.tpl', 'addon/js_upload');
$b['addon_text'] .= Renderer::replaceMacros($tpl, [
'$upload_msg' => DI::l10n()->t('Select files for upload'),
'$drop_msg' => DI::l10n()->t('Drop files here to upload'),
'$cancel' => DI::l10n()->t('Cancel'),
'$failed' => DI::l10n()->t('Failed'),
'$post_url' => $b['post_url'],
'$upload_msg' => DI::l10n()->t('Select files for upload'),
'$drop_msg' => DI::l10n()->t('Drop files here to upload'),
'$cancel' => DI::l10n()->t('Cancel'),
'$failed' => DI::l10n()->t('Failed'),
'$post_url' => $b['post_url'],
'$maximagesize' => Strings::getBytesFromShorthand(DI::config()->get('system', 'maximagesize')),
]);
}
@ -48,7 +48,10 @@ function js_upload_post_init(array &$b)
global $js_upload_result, $js_upload_jsonresponse;
// list of valid extensions
$allowedExtensions = ['jpeg', 'gif', 'png', 'jpg'];
$allowedExtensions = [];
foreach (Images::IMAGETYPES as $type) {
$allowedExtensions[] = image_type_to_extension($type, false);
}
// max file size in bytes
$sizeLimit = Strings::getBytesFromShorthand(DI::config()->get('system', 'maximagesize'));
@ -75,10 +78,9 @@ function js_upload_post_file(array &$b)
$result = $js_upload_result;
$b['src'] = $result['path'];
$b['src'] = $result['path'];
$b['filename'] = $result['filename'];
$b['filesize'] = filesize($b['src']);
}
function js_upload_post_end(int &$b)
@ -179,11 +181,11 @@ class qqUploadedFileForm
class qqFileUploader
{
private $allowedExtensions = [];
private $sizeLimit = 10485760;
private $allowedExtensions;
private $sizeLimit;
private $file;
function __construct(array $allowedExtensions = [], $sizeLimit = 10485760)
function __construct(array $allowedExtensions = [], $sizeLimit)
{
$allowedExtensions = array_map('strtolower', $allowedExtensions);
@ -197,7 +199,6 @@ class qqFileUploader
} else {
$this->file = false;
}
}
/**
@ -216,11 +217,9 @@ class qqFileUploader
}
// if ($size > $this->sizeLimit) {
// return array('error' => DI::l10n()->t('Uploaded file is too large'));
// }
$maximagesize = Strings::getBytesFromShorthand(DI::config()->get('system', 'maximagesize'));
if (($maximagesize) && ($size > $maximagesize)) {
@ -241,14 +240,14 @@ class qqFileUploader
if ($this->file->save()) {
return [
'success' => true,
'path' => $this->file->getPath(),
'success' => true,
'path' => $this->file->getPath(),
'filename' => $filename . '.' . $ext
];
} else {
return [
'error' => DI::l10n()->t('Upload was cancelled, or server error encountered'),
'path' => $this->file->getPath(),
'error' => DI::l10n()->t('Upload was cancelled, or server error encountered'),
'path' => $this->file->getPath(),
'filename' => $filename . '.' . $ext
];
}

View file

@ -34,26 +34,7 @@ function mailstream_install()
Hook::register('post_remote_end', 'addon/mailstream/mailstream.php', 'mailstream_post_hook');
Hook::register('mailstream_send_hook', 'addon/mailstream/mailstream.php', 'mailstream_send_hook');
Logger::info("mailstream: installed");
}
/**
* Enforces that mailstream_install has set up the current version
*/
function mailstream_check_version()
{
if (!is_null(DI::config()->get('mailstream', 'dbversion'))) {
DI::config()->delete('mailstream', 'dbversion');
Logger::info("mailstream_check_version: old version detected, reinstalling");
mailstream_install();
Hook::loadHooks();
Hook::add(
'mailstream_convert_table_entries',
'addon/mailstream/mailstream.php',
'mailstream_convert_table_entries'
);
Hook::fork(Worker::PRIORITY_LOW, 'mailstream_convert_table_entries');
}
Logger::info("installed mailstream");
}
/**
@ -105,7 +86,7 @@ function mailstream_generate_id(string $uri): string
$host = DI::baseUrl()->getHost();
$resource = hash('md5', $uri);
$message_id = "<" . $resource . "@" . $host . ">";
Logger::debug('mailstream: Generated message ID ' . $message_id . ' for URI ' . $uri);
Logger::debug('generated message ID', ['id' => $message_id, 'uri' => $uri]);
return $message_id;
}
@ -114,20 +95,20 @@ function mailstream_send_hook(array $data)
$criteria = array('uid' => $data['uid'], 'contact-id' => $data['contact-id'], 'uri' => $data['uri']);
$item = Post::selectFirst([], $criteria);
if (empty($item)) {
Logger::error('mailstream_send_hook could not find item');
Logger::error('could not find item');
return;
}
$user = User::getById($item['uid']);
if (empty($user)) {
Logger::error('mailstream_send_hook could not fund user', ['uid' => $item['uid']]);
Logger::error('could not find user', ['uid' => $item['uid']]);
return;
}
if (!mailstream_send($data['message_id'], $item, $user)) {
Logger::debug('mailstream_send_hook send failed, will retry', $data);
Logger::debug('send failed, will retry', $data);
if (!Worker::defer()) {
Logger::error('mailstream_send_hook failed and could not defer', $data);
Logger::error('failed and could not defer', $data);
}
}
}
@ -142,35 +123,33 @@ function mailstream_send_hook(array $data)
*/
function mailstream_post_hook(array &$item)
{
mailstream_check_version();
if ($item['uid'] === 0) {
Logger::debug('mailstream: root user, skipping item ' . $item['id']);
return;
}
if (!DI::pConfig()->get($item['uid'], 'mailstream', 'enabled')) {
Logger::debug('mailstream: not enabled.', ['item' => $item['id'], ' uid ' => $item['uid']]);
return;
}
if (!$item['uid']) {
Logger::debug('mailstream: no uid for item ' . $item['id']);
return;
}
if (!$item['contact-id']) {
Logger::debug('mailstream: no contact-id for item ' . $item['id']);
Logger::debug('no contact-id', ['item' => $item['id']]);
return;
}
if (!$item['uri']) {
Logger::debug('mailstream: no uri for item ' . $item['id']);
Logger::debug('no uri', ['item' => $item['id']]);
return;
}
if ($item['verb'] == Activity::ANNOUNCE) {
Logger::debug('mailstream: announce item ', ['item' => $item['id']]);
Logger::debug('ignoring announce', ['item' => $item['id']]);
return;
}
if (DI::pConfig()->get($item['uid'], 'mailstream', 'nolikes')) {
if ($item['verb'] == Activity::LIKE) {
Logger::debug('mailstream: like item ' . $item['id']);
Logger::debug('ignoring like', ['item' => $item['id']]);
return;
}
if ($item['verb'] == Activity::DISLIKE) {
Logger::debug('mailstream: dislike item ' . $item['id']);
Logger::debug('ignoring dislike', ['item' => $item['id']]);
return;
}
}
@ -221,7 +200,7 @@ function mailstream_do_images(array &$item, array &$attachments)
try {
$curlResult = DI::httpClient()->fetchFull($url, HttpClientAccept::DEFAULT, 0, $cookiejar);
} catch (InvalidArgumentException $e) {
Logger::error('mailstream_do_images exception fetching url', ['url' => $url, 'item_id' => $item['id']]);
Logger::error('exception fetching url', ['url' => $url, 'item_id' => $item['id']]);
continue;
}
$attachments[$url] = [
@ -322,13 +301,12 @@ function mailstream_subject(array $item): string
}
$contact = Contact::selectFirst([], ['id' => $item['contact-id'], 'uid' => $item['uid']]);
if (!DBA::isResult($contact)) {
Logger::error(
'mailstream_subject no contact for item',
['id' => $item['id'],
'plink' => $item['plink'],
'contact id' => $item['contact-id'],
'uid' => $item['uid']]
);
Logger::error('no contact', [
'item' => $item['id'],
'plink' => $item['plink'],
'contact id' => $item['contact-id'],
'uid' => $item['uid']
]);
return DI::l10n()->t("Friendica post");
}
if ($contact['network'] === 'dfrn') {
@ -365,17 +343,16 @@ function mailstream_subject(array $item): string
function mailstream_send(string $message_id, array $item, array $user): bool
{
if (!is_array($item)) {
Logger::error('mailstream_send item is empty', ['message_id' => $message_id]);
Logger::error('item is empty', ['message_id' => $message_id]);
return false;
}
if (!$item['visible']) {
Logger::debug('mailstream_send item not yet visible', ['item uri' => $item['uri']]);
Logger::debug('item not yet visible', ['item uri' => $item['uri']]);
return false;
}
if (!$message_id) {
Logger::error('mailstream_send no message ID supplied', ['item uri' => $item['uri'],
'user email' => $user['email']]);
Logger::error('no message ID supplied', ['item uri' => $item['uri'], 'user email' => $user['email']]);
return true;
}
@ -432,13 +409,15 @@ function mailstream_send(string $message_id, array $item, array $user): bool
if (!$mail->Send()) {
throw new Exception($mail->ErrorInfo);
}
Logger::debug('mailstream_send sent message', ['message ID' => $mail->MessageID,
'subject' => $mail->Subject,
'address' => $address]);
Logger::debug('sent message', [
'message ID' => $mail->MessageID,
'subject' => $mail->Subject,
'address' => $address
]);
} catch (phpmailerException $e) {
Logger::debug('mailstream_send PHPMailer exception sending message ' . $message_id . ': ' . $e->errorMessage());
Logger::debug('PHPMailer exception sending message', ['id' => $message_id, 'error' => $e->errorMessage()]);
} catch (Exception $e) {
Logger::debug('mailstream_send exception sending message ' . $message_id . ': ' . $e->getMessage());
Logger::debug('exception sending message', ['id' => $message_id, 'error' => $e->getMessage()]);
}
return true;
@ -462,29 +441,6 @@ function mailstream_html_wrap(string &$text)
return $text;
}
/**
* Convert v1 mailstream table entries to v2 workerqueue items
*/
function mailstream_convert_table_entries()
{
$ms_item_ids = DBA::selectToArray('mailstream_item', [], ['message-id', 'uri', 'uid', 'contact-id'], ["`mailstream_item`.`completed` IS NULL"]);
Logger::debug('mailstream_convert_table_entries processing ' . count($ms_item_ids) . ' items');
foreach ($ms_item_ids as $ms_item_id) {
$send_hook_data = array('uid' => $ms_item_id['uid'],
'contact-id' => $ms_item_id['contact-id'],
'uri' => $ms_item_id['uri'],
'message_id' => $ms_item_id['message-id'],
'tries' => 0);
if (!$ms_item_id['message-id'] || !strlen($ms_item_id['message-id'])) {
Logger::info('mailstream_convert_table_entries: item has no message-id.', ['item' => $ms_item_id['id'], 'uri' => $ms_item_id['uri']]);
continue;
}
Logger::info('mailstream_convert_table_entries: convert item to workerqueue', $send_hook_data);
Hook::fork(Worker::PRIORITY_LOW, 'mailstream_send_hook', $send_hook_data);
}
DBA::e('DROP TABLE `mailstream_item`');
}
/**
* Form for configuring mailstream features for a user
*

206
ratioed/RatioedPanel.php Normal file
View file

@ -0,0 +1,206 @@
<?php
namespace Friendica\Addon\ratioed;
use Friendica\Content\Pager;
use Friendica\Core\Logger;
use Friendica\Core\Renderer;
use Friendica\Database\DBA;
use Friendica\Model\User;
use Friendica\Module\Moderation\Users\Active;
/**
* This class implements the "Behaviour" panel in Moderation/Users
*/
class RatioedPanel extends Active
{
protected function content(array $request = []): string
{
Active::content();
$action = $this->parameters['action'] ?? '';
$uid = $this->parameters['uid'] ?? 0;
if ($uid) {
$user = User::getById($uid, ['username', 'blocked']);
if (!$user) {
$this->systemMessages->addNotice($this->t('User not found'));
$this->baseUrl->redirect('moderation/users');
}
}
switch ($action) {
case 'delete':
if ($this->session->getLocalUserId() != $uid) {
self::checkFormSecurityTokenRedirectOnError('moderation/users/active', 'moderation_users_active', 't');
// delete user
User::remove($uid);
$this->systemMessages->addNotice($this->t('User "%s" deleted', $user['username']));
} else {
$this->systemMessages->addNotice($this->t('You can\'t remove yourself'));
}
$this->baseUrl->redirect('moderation/users/active');
break;
case 'block':
self::checkFormSecurityTokenRedirectOnError('moderation/users/active', 'moderation_users_active', 't');
User::block($uid);
$this->systemMessages->addNotice($this->t('User "%s" blocked', $user['username']));
$this->baseUrl->redirect('moderation/users/active');
break;
}
$pager = new Pager($this->l10n, $this->args->getQueryString(), 100);
$valid_orders = [
'name',
'email',
'register_date',
'last-activity',
'last-item',
'page-flags',
];
$order = 'last-item';
$order_direction = '-';
if (!empty($request['o'])) {
$new_order = $request['o'];
if ($new_order[0] === '-') {
$order_direction = '-';
$new_order = substr($new_order, 1);
}
if (in_array($new_order, $valid_orders)) {
$order = $new_order;
}
}
$users = User::getList($pager->getStart(), $pager->getItemsPerPage(), 'active', $order, ($order_direction == '-'));
$users = array_map($this->setupUserCallback(), $users);
$header_titles = [
$this->t('Name'),
$this->t('Email'),
$this->t('Register date'),
$this->t('Last login'),
$this->t('Last public item'),
$this->t('Type'),
$this->t('Blocked by'),
$this->t('Comments last 24h'),
$this->t('Reactions last 24h'),
$this->t('Ratio last 24h'),
];
$field_names = [
'name',
'email',
'register_date',
'login_date',
'lastitem_date',
'page_flags',
'blocked_by',
'comments',
'reactions',
'ratio',
];
$th_users = array_map(null, $header_titles, $valid_orders, $field_names);
$count = $this->database->count('user', ["`verified` AND NOT `blocked` AND NOT `account_removed` AND NOT `account_expired` AND `uid` != ?", 0]);
$t = Renderer::getMarkupTemplate('ratioed.tpl', 'addon/ratioed');
return self::getTabsHTML('ratioed') . Renderer::replaceMacros($t, [
// strings //
'$title' => $this->t('Moderation'),
'$page' => $this->t('Behaviour'),
'$select_all' => $this->t('select all'),
'$delete' => $this->t('Delete'),
'$block' => $this->t('Block'),
'$blocked' => $this->t('User blocked'),
'$siteadmin' => $this->t('Site admin'),
'$accountexpired' => $this->t('Account expired'),
'$h_newuser' => $this->t('Create a new user'),
'$th_users' => $th_users,
'$order_users' => $order,
'$order_direction_users' => $order_direction,
'$confirm_delete_multi' => $this->t('Selected users will be deleted!\n\nEverything these users had posted on this site will be permanently deleted!\n\nAre you sure?'),
'$confirm_delete' => $this->t('The user {0} will be deleted!\n\nEverything this user has posted on this site will be permanently deleted!\n\nAre you sure?'),
'$form_security_token' => self::getFormSecurityToken('moderation_users_active'),
// values //
'$baseurl' => $this->baseUrl,
'$query_string' => $this->args->getQueryString(),
'$users' => $users,
'$count' => $count,
'$pager' => $pager->renderFull($count),
]);
}
protected function setupUserCallback(): \Closure
{
Logger::debug("ratioed: setupUserCallback");
$parentCallback = parent::setupUserCallback();
return function ($user) use ($parentCallback) {
$blocked_count = DBA::count('user-contact', ['uid' => $user['uid'], 'is-blocked' => 1]);
$user['blocked_by'] = $blocked_count;
$self_contact_result = DBA::p('SELECT admin_contact.id AS user_contact_uid FROM contact AS admin_contact JOIN contact AS user_contact ON admin_contact.`uri-id` = user_contact.`uri-id` AND admin_contact.self = 0 AND user_contact.self = 1 WHERE user_contact.uid = ?', $user['uid']);
if (DBA::isResult($self_contact_result)) {
$self_contact_result_row = DBA::fetch($self_contact_result);
$user['user_contact_uid'] = $self_contact_result_row['user_contact_uid'];
}
else {
$user['user_contact_uid'] = NULL;
}
if ($user['user_contact_uid']) {
$post_engagement_result = DBA::p('SELECT SUM(`comments`) AS `comment_count`, SUM(`activities`) AS `activities_count` FROM `post-engagement` WHERE `post-engagement`.created > DATE_SUB(now(), INTERVAL 1 DAY) AND `post-engagement`.`owner-id` = ?', $user['user_contact_uid']);
if (DBA::isResult($post_engagement_result)) {
$post_engagement_result_row = DBA::fetch($post_engagement_result);
$user['comments'] = $post_engagement_result_row['comment_count'];
$user['reactions'] = $post_engagement_result_row['activities_count'];
if ($user['reactions'] > 0) {
$user['ratio'] = number_format($user['comments'] / $user['reactions'], 1, '.', '');
$user['ratioed'] = (float)($user['ratio']) >= 2.0;
}
else {
if ($user['comments'] == 0) {
$user['ratio'] = '0';
$user['ratioed'] = false;
}
else {
$user['ratio'] = '∞';
$user['ratioed'] = false;
}
}
}
else {
$user['comments'] = 'error';
$user['reactions'] = 'error';
$user['ratio'] = 'error';
$user['ratioed'] = false;
}
}
else {
$user['comments'] = 'error';
$user['reactions'] = 'error';
$user['ratio'] = 'error';
$user['ratioed'] = false;
}
$user = $parentCallback($user);
Logger::debug("ratioed: setupUserCallback", [
'uid' => $user['uid'],
'blocked_by' => $user['blocked_by'],
'comments' => $user['comments'],
'reactions' => $user['reactions'],
'ratio' => $user['ratio'],
'ratioed' => $user['ratioed'],
]);
return $user;
};
}
}

58
ratioed/ratioed.php Normal file
View file

@ -0,0 +1,58 @@
<?php
/**
* Name: Ratioed
* Description: Additional moderation user table with statistics about user behaviour
* Version: 0.1
* Author: Matthew Exon <http://mat.exon.name>
*/
use Friendica\Addon\ratioed\RatioedPanel;
use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\DI;
/**
* Sets up the addon hooks and updates data in the database if needed
*/
function ratioed_install()
{
Hook::register('moderation_users_tabs', 'addon/ratioed/ratioed.php', 'ratioed_users_tabs');
Logger::info("ratioed: installed");
}
/**
* This is a statement rather than an actual function definition. The simple
* existence of this method is checked to figure out if the addon offers a
* module.
*/
function ratioed_module() {}
/**
* @brief Adds additional users tab to the moderation panel
*
* @param array $arr Parameters, including "tabs" which is the list to modify, and "selectedTab", which is the currently selected tab ID
*/
function ratioed_users_tabs(array &$arr) {
Logger::debug("ratioed: users tabs");
array_push($arr['tabs'], [
'label' => DI::l10n()->t('Behaviour'),
'url' => 'ratioed',
'sel' => $arr['selectedTab'] == 'ratioed' ? 'active' : '',
'title' => DI::l10n()->t('Statistics about users behaviour'),
'id' => 'admin-users-ratioed',
'accesskey' => 'r',
]);
}
/**
* @brief Displays the ratioed tab in the moderation panel
*/
function ratioed_content() {
Logger::debug("ratioed: content");
$ratioed = DI::getDice()->create(RatioedPanel::class, [$_SERVER]);
$httpException = DI::getDice()->create(Friendica\Module\Special\HTTPException::class);
$ratioed->run($httpException);
}

View file

@ -0,0 +1,164 @@
<script type="text/javascript" src="view/theme/frio/js/mod_admin.js?v={{constant('\Friendica\App::VERSION')}}"></script>
<link rel="stylesheet" href="view/theme/frio/css/mod_admin.css?v={{constant('\Friendica\App::VERSION')}}" type="text/css" media="screen"/>
<div id="admin-users" class="adminpage generic-page-wrapper">
<h1>{{$title}} - {{$page}} ({{$count}})</h1>
<p>
<a href="{{$base_url}}/moderation/users/create" class="btn btn-primary"><i class="fa fa-user-plus"></i> {{$h_newuser}}</a>
</p>
<form action="{{$baseurl}}/{{$query_string}}" method="post">
<input type="hidden" name="form_security_token" value="{{$form_security_token}}">
<table id="users" class="table table-hover">
<thead>
<tr>
<th>
<div class="checkbox">
<input type="checkbox" id="admin-settings-users-select" class="selecttoggle" data-select-class="users_ckbx"/>
<label for="admin-settings-users-select"></label>
</div>
</th>
<th></th>
{{foreach $th_users as $k=>$th}}
{{if $k < 2 || $order_users == $th.1 || ($k==5 && !in_array($order_users,[$th_users.2.1, $th_users.3.1, $th_users.4.1])) }}
<th class="th-{{$k}}">
<a href="{{$baseurl}}/moderation/users/active?o={{if $order_direction_users == "+"}}-{{/if}}{{$th.1}}" class="table-order">
{{if $order_users == $th.1}}
{{if $order_direction_users == "+"}}
&#8595;
{{else}}
&#8593;
{{/if}}
{{else}}
&#8597;
{{/if}}
{{$th.0}}
</a>
</th>
{{/if}}
{{/foreach}}
<th></th>
</tr>
</thead>
<tbody>
{{foreach $users as $u}}
<tr id="user-{{$u.uid}}" class="{{if $u.ratioed}}blocked{{/if}}">
<td>
{{if $u.is_deletable}}
<div class="checkbox">
<input type="checkbox" class="users_ckbx" id="id_user_{{$u.uid}}" name="user[]" value="{{$u.uid}}"/>
<label for="id_user_{{$u.uid}}"></label>
</div>
{{else}}
&nbsp;
{{/if}}
</td>
<td><img class="avatar-nano" src="{{$u.micro}}" title="{{$u.nickname}}"></td>
<td><a href="{{$u.url}}" title="{{$u.nickname}}"> {{$u.name}}</a></td>
<td>{{$u.email}}</td>
{{if $order_users == $th_users.2.1}}
<td>{{$u.register_date}}</td>
{{/if}}
{{if $order_users == $th_users.3.1}}
<td>{{$u.login_date}}</td>
{{/if}}
{{if $order_users == $th_users.4.1}}
<td>{{$u.lastitem_date}}</td>
{{/if}}
{{if !in_array($order_users,[$th_users.2.1, $th_users.3.1, $th_users.4.1]) }}
<td>
<i class="fa
{{if $u.page_flags_raw==0}}fa-user{{/if}} {{* PAGE_NORMAL *}}
{{if $u.page_flags_raw==1}}fa-bullhorn{{/if}} {{* PAGE_SOAPBOX *}}
{{if $u.page_flags_raw==2}}fa-users{{/if}} {{* PAGE_COMMUNITY *}}
{{if $u.page_flags_raw==3}}fa-heart{{/if}} {{* PAGE_FREELOVE *}}
{{if $u.page_flags_raw==4}}fa-rss{{/if}} {{* PAGE_BLOG *}}
{{if $u.page_flags_raw==5}}fa-user-secret{{/if}} {{* PAGE_PRVGROUP *}}
" title="{{$u.page_flags}}">
</i>
{{if $u.page_flags_raw==0 && $u.account_type_raw > 0}}
<i class="fa
{{if $u.account_type_raw==1}}fa-sitemap{{/if}} {{* ACCOUNT_TYPE_ORGANISATION *}}
{{if $u.account_type_raw==2}}fa-newspaper-o{{/if}} {{* ACCOUNT_TYPE_NEWS *}}
{{if $u.account_type_raw==3}}fa-comments{{/if}} {{* ACCOUNT_TYPE_COMMUNITY *}}
" title="{{$u.account_type}}">
</i>
{{/if}}
{{if $u.is_admin}}<i class="fa fa-user-secret text-primary" title="{{$siteadmin}}"></i>{{/if}}
{{if $u.account_expired}}<i class="fa fa-clock-o text-warning" title="{{$accountexpired}}"></i>{{/if}}
</td>
{{/if}}
<td class="text-right">
<button type="button" class="btn-link admin-settings-action-link" onclick="return details({{$u.uid}})"><span class="caret"></span></button>
</td>
</tr>
<tr id="user-{{$u.uid}}-detail" class=" details hidden {{if $u.blocked != 0}}blocked{{/if}}">
<td>&nbsp;</td>
<td colspan="4">
{{if $order_users != $th_users.2.1}}
<p>
<a href="{{$baseurl}}/ratioed?o={{if $order_direction_users == "+"}}-{{/if}}{{$th_users.2.1}}" class="btn-link table-order">
&#8597; {{$th_users.2.0}}</a> : {{$u.register_date}}
</p>
{{/if}}
{{if $order_users != $th_users.3.1}}
<p>
<a href="{{$baseurl}}/ratioed?o={{if $order_direction_users == "+"}}-{{/if}}{{$th_users.3.1}}" class="btn-link table-order">
&#8597; {{$th_users.3.0}}</a> : {{$u.login_date}}
</p>
{{/if}}
{{if $order_users != $th_users.4.1}}
<p>
<a href="{{$baseurl}}/ratioed?o={{if $order_direction_users == "+"}}-{{/if}}{{$th_users.4.1}}" class="btn-link table-order">
&#8597; {{$th_users.4.0}}</a> : {{$u.lastitem_date}}
</p>
{{/if}}
{{if in_array($order_users,[$th_users.2.1, $th_users.3.1, $th_users.4.1]) }}
<p>
<a href="{{$baseurl}}/ratioed?o={{if $order_direction_users == "+"}}-{{/if}}{{$th_users.5.1}}" class="btn-link table-order">
&#8597; {{$th_users.5.0}}</a> : {{$u.page_flags}}{{if $u.page_flags_raw==0 && $u.account_type_raw > 0}}, {{$u.account_type}}{{/if}} {{if $u.is_admin}}({{$siteadmin}}){{/if}} {{if $u.account_expired}}({{$accountexpired}}){{/if}}
</p>
{{/if}}
{{foreach $th_users as $k=>$th}}
{{if $order_users != $th.1 && $k > 5}}
<p>
{{$th.0}} : {{$u[$th.2]}}
</p>
{{/if}}
{{/foreach}}
</td>
<td class="text-right">
{{if $u.is_deletable}}
<a href="{{$baseurl}}/moderation/users/active/block/{{$u.uid}}?t={{$form_security_token}}" class="admin-settings-action-link" title="{{$block}}">
<i class="fa fa-ban" aria-hidden="true"></i>
</a>
<a href="{{$baseurl}}/moderation/users/active/delete/{{$u.uid}}?t={{$form_security_token}}" class="admin-settings-action-link" title="{{$delete}}" onclick="return confirm_delete('{{$confirm_delete}}','{{$u.name}}')">
<i class="fa fa-trash" aria-hidden="true"></i>
</a>
{{else}}
&nbsp;
{{/if}}
</td>
</tr>
{{/foreach}}
</tbody>
</table>
<div class="panel-footer">
<button type="submit" name="page_users_block" value="1" class="btn btn-warning">
<i class="fa fa-ban" aria-hidden="true"></i> {{$block}}
</button>
<button type="submit" name="page_users_delete" value="1" class="btn btn-danger" onclick="return confirm_delete('{{$confirm_delete_multi}}')">
<i class="fa fa-trash" aria-hidden="true"></i> {{$delete}}
</button>
</div>
{{$pager nofilter}}
</form>
</div>