|
|
@ -36,48 +36,22 @@ class Room |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Validate room name compatible with settings |
|
|
|
|
|
|
|
if (!preg_match((string) $this->_config->kevachat->room->key->regex, $namespace['displayName'])) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Calculate room totals |
|
|
|
// Calculate room totals |
|
|
|
$total = 0; |
|
|
|
$total = 0; |
|
|
|
|
|
|
|
|
|
|
|
foreach ((array) $this->_kevacoin->kevaFilter($namespace['namespaceId']) as $record) |
|
|
|
foreach ((array) $this->_kevacoin->kevaFilter($namespace['namespaceId']) as $record) |
|
|
|
{ |
|
|
|
{ |
|
|
|
// Skip values with meta keys |
|
|
|
// Is protocol compatible post |
|
|
|
if (str_starts_with($record['key'], '_')) |
|
|
|
if ($this->post($namespace['namespaceId'], $record['key'], 'txid')) |
|
|
|
{ |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Validate value format allowed in settings |
|
|
|
|
|
|
|
if (!preg_match((string) $this->_config->kevachat->post->value->regex, $record['value'])) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Validate key format allowed in settings |
|
|
|
|
|
|
|
if (!preg_match($this->_config->kevachat->post->key->regex, $record['key'], $matches)) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Timestamp required in key |
|
|
|
|
|
|
|
if (empty($matches[1])) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Username required in key |
|
|
|
|
|
|
|
if (empty($matches[2])) |
|
|
|
|
|
|
|
{ |
|
|
|
{ |
|
|
|
continue; |
|
|
|
$total++; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Legacy usernames backport (used to replace undefined names to @anon) |
|
|
|
|
|
|
|
/* |
|
|
|
|
|
|
|
if (!preg_match((string) $this->_config->kevachat->user->name->regex, $matches[2])) |
|
|
|
|
|
|
|
{} |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$total++; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Add to room list |
|
|
|
// Add to room list |
|
|
@ -159,4 +133,208 @@ class Room |
|
|
|
) |
|
|
|
) |
|
|
|
); |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function posts(string $namespace): ?string |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
$posts = []; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
foreach ((array) $this->_kevacoin->kevaFilter($namespace) as $record) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if (empty($record['key'])) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ($post = $this->post($namespace, $record['key'])) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
$posts[] = $post; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return str_replace( |
|
|
|
|
|
|
|
[ |
|
|
|
|
|
|
|
'{logo}', |
|
|
|
|
|
|
|
'{subject}', |
|
|
|
|
|
|
|
'{posts}' |
|
|
|
|
|
|
|
], |
|
|
|
|
|
|
|
[ |
|
|
|
|
|
|
|
file_get_contents( |
|
|
|
|
|
|
|
__DIR__ . '/../../logo.ascii' |
|
|
|
|
|
|
|
), |
|
|
|
|
|
|
|
$namespace, |
|
|
|
|
|
|
|
implode( |
|
|
|
|
|
|
|
PHP_EOL, |
|
|
|
|
|
|
|
$posts |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
], |
|
|
|
|
|
|
|
file_get_contents( |
|
|
|
|
|
|
|
__DIR__ . '/../view/posts.gemini' |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function post(string $namespace, string $key, ?string $field = null): ?string |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
// Check record exists |
|
|
|
|
|
|
|
if (!$record = (array) $this->_kevacoin->kevaGet($namespace, $key)) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return null; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Skip values with meta keys |
|
|
|
|
|
|
|
if (str_starts_with($record['key'], '_')) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return null; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Validate value format allowed in settings |
|
|
|
|
|
|
|
if (!preg_match((string) $this->_config->kevachat->post->value->regex, $record['value'])) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return null; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Validate key format allowed in settings |
|
|
|
|
|
|
|
if (!preg_match($this->_config->kevachat->post->key->regex, $record['key'], $matches)) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return null; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Timestamp required in key |
|
|
|
|
|
|
|
if (empty($matches[1])) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return null; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Username required in key |
|
|
|
|
|
|
|
if (empty($matches[2])) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return null; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Is raw field request |
|
|
|
|
|
|
|
if ($field && isset($record[$field])) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return $record[$field]; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Legacy usernames backport |
|
|
|
|
|
|
|
if (!preg_match((string) $this->_config->kevachat->user->name->regex, $matches[2])) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
$matches[2] = '@anon'; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Try to find related quote value |
|
|
|
|
|
|
|
$quote = null; |
|
|
|
|
|
|
|
if (preg_match('/^@([A-z0-9]{64})/', $record['value'], $mention)) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if (!empty($mention[1])) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
$quote = '@' . $mention[1]; // @TODO replace to post message by txid |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Remove mention from message |
|
|
|
|
|
|
|
$record['value'] = preg_replace('/^@([A-z0-9]{64})/', null, $record['value']); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Build final view and send to response |
|
|
|
|
|
|
|
return str_replace( |
|
|
|
|
|
|
|
[ |
|
|
|
|
|
|
|
'{time}', |
|
|
|
|
|
|
|
'{author}', |
|
|
|
|
|
|
|
'{quote}', |
|
|
|
|
|
|
|
'{message}', |
|
|
|
|
|
|
|
], |
|
|
|
|
|
|
|
[ |
|
|
|
|
|
|
|
$this->_ago( |
|
|
|
|
|
|
|
$matches[1] |
|
|
|
|
|
|
|
), |
|
|
|
|
|
|
|
'@' . $matches[2], |
|
|
|
|
|
|
|
trim( |
|
|
|
|
|
|
|
$quote |
|
|
|
|
|
|
|
), |
|
|
|
|
|
|
|
trim( |
|
|
|
|
|
|
|
$record['value'] |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
], |
|
|
|
|
|
|
|
file_get_contents( |
|
|
|
|
|
|
|
__DIR__ . '/../view/post.gemini' |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private function _ago(int $time): string |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
$diff = time() - $time; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ($diff < 1) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return _('now'); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$values = |
|
|
|
|
|
|
|
[ |
|
|
|
|
|
|
|
365 * 24 * 60 * 60 => |
|
|
|
|
|
|
|
[ |
|
|
|
|
|
|
|
_('year ago'), |
|
|
|
|
|
|
|
_('years ago'), |
|
|
|
|
|
|
|
_(' years ago') |
|
|
|
|
|
|
|
], |
|
|
|
|
|
|
|
30 * 24 * 60 * 60 => |
|
|
|
|
|
|
|
[ |
|
|
|
|
|
|
|
_('month ago'), |
|
|
|
|
|
|
|
_('months ago'), |
|
|
|
|
|
|
|
_(' months ago') |
|
|
|
|
|
|
|
], |
|
|
|
|
|
|
|
24 * 60 * 60 => |
|
|
|
|
|
|
|
[ |
|
|
|
|
|
|
|
_('day ago'), |
|
|
|
|
|
|
|
_('days ago'), |
|
|
|
|
|
|
|
_(' days ago') |
|
|
|
|
|
|
|
], |
|
|
|
|
|
|
|
60 * 60 => |
|
|
|
|
|
|
|
[ |
|
|
|
|
|
|
|
_('hour ago'), |
|
|
|
|
|
|
|
_('hours ago'), |
|
|
|
|
|
|
|
_(' hours ago') |
|
|
|
|
|
|
|
], |
|
|
|
|
|
|
|
60 => |
|
|
|
|
|
|
|
[ |
|
|
|
|
|
|
|
_('minute ago'), |
|
|
|
|
|
|
|
_('minutes ago'), |
|
|
|
|
|
|
|
_(' minutes ago') |
|
|
|
|
|
|
|
], |
|
|
|
|
|
|
|
1 => |
|
|
|
|
|
|
|
[ |
|
|
|
|
|
|
|
_('second ago'), |
|
|
|
|
|
|
|
_('seconds ago'), |
|
|
|
|
|
|
|
_(' seconds ago') |
|
|
|
|
|
|
|
] |
|
|
|
|
|
|
|
]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
foreach ($values as $key => $value) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
$result = $diff / $key; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ($result >= 1) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
$round = round($result); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return sprintf( |
|
|
|
|
|
|
|
'%s %s', |
|
|
|
|
|
|
|
$round, |
|
|
|
|
|
|
|
$this->_plural( |
|
|
|
|
|
|
|
$round, |
|
|
|
|
|
|
|
$value |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private function _plural(int $number, array $texts) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
$cases = [2, 0, 1, 1, 1, 2]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return $texts[(($number % 100) > 4 && ($number % 100) < 20) ? 2 : $cases[min($number % 10, 5)]]; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |