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] Multiple host support
|
||||||
* [x] Room list
|
* [x] Room list
|
||||||
* [ ] Room threads
|
* [x] Room threads
|
||||||
* [ ] Post publication
|
* [ ] Post publication
|
||||||
* [ ] Media viewer
|
* [ ] Media viewer
|
||||||
* [ ] Users auth
|
* [ ] Users auth
|
||||||
|
@ -22,6 +22,10 @@
|
|||||||
{
|
{
|
||||||
"room":
|
"room":
|
||||||
{
|
{
|
||||||
|
"key":
|
||||||
|
{
|
||||||
|
"regex":"/^[\\w\\s\\._-]{2,64}$/ui"
|
||||||
|
},
|
||||||
"pin":[]
|
"pin":[]
|
||||||
},
|
},
|
||||||
"post":
|
"post":
|
||||||
|
@ -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;
|
$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
|
// 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
|
// Dynamical requests
|
||||||
default:
|
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}
|
## {author}
|
||||||
|
|
||||||
> {quote}
|
> {quote}
|
||||||
|
{message}
|
||||||
``` {time}
|
```
|
||||||
|
{time}
|
||||||
{message}
|
```
|
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