mirror of
https://github.com/kevachat/geminiapp.git
synced 2025-03-13 05:51:39 +00:00
draft room threads feature
This commit is contained in:
parent
7706bc705d
commit
e4804170f0
@ -14,7 +14,7 @@ KevaChat Application for Gemini Protocol
|
||||
|
||||
* [x] Multiple host support
|
||||
* [x] Room list
|
||||
* [ ] Room threads
|
||||
* [x] Room threads
|
||||
* [ ] Post publication
|
||||
* [ ] Media viewer
|
||||
* [ ] Users auth
|
||||
|
@ -22,6 +22,10 @@
|
||||
{
|
||||
"room":
|
||||
{
|
||||
"key":
|
||||
{
|
||||
"regex":"/^[\\w\\s\\._-]{2,64}$/ui"
|
||||
},
|
||||
"pin":[]
|
||||
},
|
||||
"post":
|
||||
|
@ -36,48 +36,22 @@ class Room
|
||||
continue;
|
||||
}
|
||||
|
||||
// Validate room name compatible with settings
|
||||
if (!preg_match((string) $this->_config->kevachat->room->key->regex, $namespace['displayName']))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Calculate room totals
|
||||
$total = 0;
|
||||
|
||||
foreach ((array) $this->_kevacoin->kevaFilter($namespace['namespaceId']) as $record)
|
||||
{
|
||||
// Skip values with meta keys
|
||||
if (str_starts_with($record['key'], '_'))
|
||||
// Is protocol compatible post
|
||||
if ($this->post($namespace['namespaceId'], $record['key'], 'txid'))
|
||||
{
|
||||
continue;
|
||||
$total++;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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
|
||||
@ -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)]];
|
||||
}
|
||||
}
|
@ -100,9 +100,25 @@ foreach ((array) scandir(__DIR__ . '/../host') as $host)
|
||||
// Dynamical requests
|
||||
default:
|
||||
|
||||
if (str_starts_with($request->getPath(), '/room/'))
|
||||
// Room posts by namespace
|
||||
if (preg_match('/^\/room\/(N[A-z0-9]{33})$/', $request->getPath(), $matches))
|
||||
{
|
||||
// @TODO
|
||||
if (!empty($matches[1]))
|
||||
{
|
||||
include_once __DIR__ . '/controller/room.php';
|
||||
|
||||
$room = new \Kevachat\Geminiapp\Controller\Room(
|
||||
$config
|
||||
);
|
||||
|
||||
$response->setContent(
|
||||
$room->posts(
|
||||
$matches[1]
|
||||
)
|
||||
);
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
## {author}
|
||||
|
||||
> {quote}
|
||||
|
||||
``` {time}
|
||||
|
||||
{message}
|
||||
{message}
|
||||
```
|
||||
{time}
|
||||
```
|
5
src/view/posts.gemini
Normal file
5
src/view/posts.gemini
Normal file
@ -0,0 +1,5 @@
|
||||
```{logo}```
|
||||
|
||||
# {subject}
|
||||
|
||||
{posts}
|
Loading…
x
Reference in New Issue
Block a user