Browse Source

Start the implementation of https://xmpp.org/extensions/xep-0444.html#disco-restricted for MUC

pull/1256/head
Timothée Jaussoin 2 years ago
parent
commit
f8c1200d9f
  1. 1
      CHANGELOG.md
  2. 58
      app/Info.php
  3. 6
      app/helpers/StringHelper.php
  4. 2
      app/widgets/Chat/_chat.tpl
  5. 74
      app/widgets/Stickers/Stickers.php
  6. 202
      app/widgets/Stickers/_stickers_emojis.tpl
  7. 21
      database/migrations/20231108190801_add_reactions_restrictions_to_infos_table.php
  8. 1
      public/theme/css/style.css

1
CHANGELOG.md

@ -9,6 +9,7 @@ v0.22.6 (trunk)
* Move the file message related logic to the Message model
* Refactor the Stickers and File display and cleanup the related CSS
* Complete the Manifest content to have a better PWA integration
* Start the implementation of https://xmpp.org/extensions/xep-0444.html#disco-restricted for MUC
v0.22.5
---------------------------

58
app/Info.php

@ -43,14 +43,14 @@ class Info extends Model
public function scopeWhereCategory($query, $category)
{
return $query->whereHas('identities', function($query) use ($category) {
return $query->whereHas('identities', function ($query) use ($category) {
$query->where('category', $category);
});
}
public function scopeWhereType($query, $type)
{
return $query->whereHas('identities', function($query) use ($type) {
return $query->whereHas('identities', function ($query) use ($type) {
$query->where('type', $type);
});
}
@ -63,12 +63,24 @@ class Info extends Model
$query->whereIn('server', function ($query) {
$host = \App\User::me()->session->host;
$query->select('server')
->from('infos')
->where('server', 'like', '%.' . $host);
->from('infos')
->where('server', 'like', '%.' . $host);
});
}
}
public function setReactionsrestrictionsAttribute(array $arr)
{
$this->attributes['reactionsrestrictions'] = serialize($arr);
}
public function getReactionsrestrictionsAttribute(): array
{
return (isset($this->attributes['reactionsrestrictions']))
? unserialize($this->attributes['reactionsrestrictions'])
: [];
}
public function setAdminaddressesAttribute(array $arr)
{
$this->attributes['adminaddresses'] = serialize($arr);
@ -167,8 +179,10 @@ class Info extends Model
->first();
}*/
if (isset($this->attributes['related'])
&& $this->identities->contains('category', 'conference') && $this->identities->contains('type', 'text')) {
if (
isset($this->attributes['related'])
&& $this->identities->contains('category', 'conference') && $this->identities->contains('type', 'text')
) {
$uri = parse_url($this->attributes['related']);
if (isset($uri['query']) && isset($uri['path'])) {
@ -189,13 +203,14 @@ class Info extends Model
public function getPresenceAttribute()
{
return \App\User::me()->session->presences()
->where('jid', $this->attributes['server'])
->first();
->where('jid', $this->attributes['server'])
->first();
}
public function getGatewayTypeAttribute(): ?string
{
$identityType = $this->identities->filter(fn ($value, $key) =>
$identityType = $this->identities->filter(
fn ($value, $key) =>
$value->category == 'gateway'
)->first();
@ -209,8 +224,10 @@ class Info extends Model
public function getDeviceIcon()
{
if ($this->identities->contains('type', 'handheld')
|| $this->identities->contains('type', 'phone')) {
if (
$this->identities->contains('type', 'handheld')
|| $this->identities->contains('type', 'phone')
) {
return 'smartphone';
}
if ($this->identities->contains('type', 'bot')) {
@ -360,9 +377,22 @@ class Info extends Model
}
$this->attributes['features'] = serialize($features);
if (isset($query->query->x)) {
foreach ($query->query->x->field as $field) {
foreach ($query->query->x as $x) {
$results = $x->xpath('.//field[@var="FORM_TYPE"]/value/text()');
$formType = $results ? (string)$results[0] : null;
foreach ($x->field as $field) {
switch ((string)$field->attributes()->var) {
// https://xmpp.org/extensions/xep-0444.html#disco-restricted
case 'allowlist':
if ($formType == 'urn:xmpp:reactions:0:restrictions') {
$arr = [];
foreach ($field->children() as $value) {
$arr[] = (string)$value;
}
$this->reactionsrestrictions = $arr;
}
break;
case 'pubsub#title':
$this->name = (string)$field->value;
break;
@ -480,7 +510,7 @@ class Info extends Model
public function isPubsubService()
{
return ($this->identities->contains('category', 'pubsub')
&& $this->identities->contains('type', 'service'));
&& $this->identities->contains('type', 'service'));
}
public function isMicroblogCommentsNode()

6
app/helpers/StringHelper.php

@ -66,6 +66,12 @@ function addUrls($string, bool $preview = false)
);
}
function emojiToCodePoint(string $emoji): string {
$emoji = mb_convert_encoding($emoji, 'UTF-32', 'UTF-8');
$unicode = strtolower(preg_replace("/^[0]+/","",bin2hex($emoji)));
return $unicode;
}
function addHashtagsLinks($string)
{
return preg_replace_callback("/([\n\r\s>]|^)#(\w+)/u", function ($match) {

2
app/widgets/Chat/_chat.tpl

@ -40,7 +40,7 @@
{/if}
<span class="emojis control icon gray primary_action on_desktop"
title="{$c->__('sticker.title')}"
onclick="Stickers_ajaxReaction()">
onclick="Stickers_ajaxReaction(null, '{$jid}')">
<i class="material-icons">emoji_emotions</i>
</span>
{if="$c->getUser()->hasUpload()"}

74
app/widgets/Stickers/Stickers.php

@ -6,6 +6,7 @@ use Moxl\Xec\Action\BOB\Answer;
use Psr\Http\Message\ResponseInterface;
use App\Configuration;
use App\Info;
use App\MessageFile;
use Movim\Image;
@ -31,18 +32,18 @@ class Stickers extends \Movim\Widget\Base
list($c, $ext) = explode('@', $cid);
list($sh, $key) = explode('+', $c);
if ($sh !== "sha1") {
$key = $sh.'+'.$key;
$key = $sh . '+' . $key;
}
$base64 = base64_encode(file_get_contents(PUBLIC_CACHE_PATH.hash(Image::$hash, $key).'.png'));
$base64 = base64_encode(file_get_contents(PUBLIC_CACHE_PATH . hash(Image::$hash, $key) . '.png'));
$a = new Answer;
$a->setTo($to)
->setId($id)
->setCid($cid)
->setType('image/png')
->setBase64($base64)
->request();
->setId($id)
->setCid($cid)
->setType('image/png')
->setBase64($base64)
->request();
}
public function ajaxSend(string $to, string $pack, $file, bool $muc = false)
@ -53,15 +54,15 @@ class Stickers extends \Movim\Widget\Base
list($key, $ext) = explode('.', $file);
$filepath = PUBLIC_PATH.'/stickers/'.$pack.'/'.$key.'.png';
$filepath = PUBLIC_PATH . '/stickers/' . $pack . '/' . $key . '.png';
if (!file_exists($filepath)) {
return;
}
// Caching the picture
if (!file_exists(PUBLIC_CACHE_PATH.hash(Image::$hash, $key).'.png')) {
copy($filepath, PUBLIC_CACHE_PATH.hash(Image::$hash, $key).'.png');
if (!file_exists(PUBLIC_CACHE_PATH . hash(Image::$hash, $key) . '.png')) {
copy($filepath, PUBLIC_CACHE_PATH . hash(Image::$hash, $key) . '.png');
}
// Creating a message
@ -81,13 +82,13 @@ class Stickers extends \Movim\Widget\Base
$m->resource = $this->user->session->resource;
// Sending the sticker
$html = "<p><img alt='Sticker' src='cid:sha1+".$key."@bob.xmpp.org'/></p>";
$html = "<p><img alt='Sticker' src='cid:sha1+" . $key . "@bob.xmpp.org'/></p>";
$p = new Publish;
$p->setTo($m->jidto)
->setContent($m->body)
->setHTML($html)
->setId($m->id);
->setContent($m->body)
->setHTML($html)
->setId($m->id);
if ($muc) {
$p->setMuc();
@ -126,7 +127,7 @@ class Stickers extends \Movim\Widget\Base
}
if (isset($pack)) {
$files = scandir(PUBLIC_PATH.'/stickers/'.$pack);
$files = scandir(PUBLIC_PATH . '/stickers/' . $pack);
array_shift($files);
array_shift($files);
@ -137,7 +138,7 @@ class Stickers extends \Movim\Widget\Base
$view->assign('packs', $packs);
$view->assign('pack', $pack);
$view->assign('gifEnabled', $isGifEnabled);
$view->assign('info', parse_ini_file(PUBLIC_PATH.'/stickers/'.$pack.'/info.ini'));
$view->assign('info', parse_ini_file(PUBLIC_PATH . '/stickers/' . $pack . '/info.ini'));
$view->assign('path', $this->respath('stickers', false, false, true));
Drawer::fill($view->draw('_stickers'), true);
@ -154,12 +155,21 @@ class Stickers extends \Movim\Widget\Base
/**
* @brief Show the smiley Poppin
*/
public function ajaxReaction(string $mid = null)
public function ajaxReaction(string $mid = null, string $jid = null)
{
$info = $mid
? Info::where('server', function ($query) use ($mid) {
$query->select('jidfrom')
->from('messages')
->where('mid', $mid);
})->first()
: null;
$view = $this->tpl();
$emojis = $this->tpl();
$emojis->assign('mid', $mid);
$emojis->assign('reactionsrestrictions', $info ? $info->reactionsrestrictions : null);
$view->assign('emojis', $emojis->draw('_stickers_emojis'));
@ -177,14 +187,14 @@ class Stickers extends \Movim\Widget\Base
if (empty($apiKey)) return;
$keyword = filter_var($keyword, FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_HIGH);
$keyword = filter_var($keyword, FILTER_FLAG_STRIP_HIGH);
$keyword = str_replace(' ', '+', $keyword);
requestAsyncURL(
'https://api.tenor.com/v1/search?q='.$keyword.
'&key='.$apiKey.
'&limit='.$this->paginate.
'&pos='.($page*$this->paginate)
'https://api.tenor.com/v1/search?q=' . $keyword .
'&key=' . $apiKey .
'&limit=' . $this->paginate .
'&pos=' . ($page * $this->paginate)
)->then(function (ResponseInterface $response) {
$view = $this->tpl();
@ -206,8 +216,8 @@ class Stickers extends \Movim\Widget\Base
? '.first'
: '.second';
$this->rpc('MovimTpl.append', '#gifs .masonry'.$column, $view->draw('_stickers_gifs_result'));
$i ++;
$this->rpc('MovimTpl.append', '#gifs .masonry' . $column, $view->draw('_stickers_gifs_result'));
$i++;
}
}
@ -226,8 +236,8 @@ class Stickers extends \Movim\Widget\Base
if (empty($apiKey)) return;
requestAsyncURL(
'https://api.tenor.com/v1/gifs?ids='.$gifId.
'&key='.$apiKey
'https://api.tenor.com/v1/gifs?ids=' . $gifId .
'&key=' . $apiKey
)->then(function (ResponseInterface $response) use ($to, $muc) {
$results = \json_decode($response->getBody());
@ -248,8 +258,12 @@ class Stickers extends \Movim\Widget\Base
$chat = new \Chat;
$chat->sendMessage(
$to, false, $muc,
null, $messageFile);
$to,
false,
$muc,
null,
$messageFile
);
}
});
}
@ -267,7 +281,7 @@ class Stickers extends \Movim\Widget\Base
*/
public function getPacks()
{
$dirs = scandir(PUBLIC_PATH.'/stickers/');
$dirs = scandir(PUBLIC_PATH . '/stickers/');
$packs = [];
@ -276,7 +290,7 @@ class Stickers extends \Movim\Widget\Base
// Get the packs
foreach ($dirs as $dir) {
if (is_dir(PUBLIC_PATH.'/stickers/'.$dir)) {
if (is_dir(PUBLIC_PATH . '/stickers/' . $dir)) {
array_push($packs, $dir);
}
}

202
app/widgets/Stickers/_stickers_emojis.tpl

@ -1,108 +1,118 @@
<ul id="emojisearchbar" class="list fill thin">
<li>
<span class="primary icon gray">
<i class="material-icons">search</i>
</span>
<form name="search" onsubmit="return false;">
<div>
<input name="keyword" autocomplete="off"
title="{$c->__('message.emoji_help')}"
placeholder="{$c->__('message.emoji_help')}"
oninput="
Chat.checkEmojis(this.value, true, true);
Stickers.setEmojisEvent({if="$mid"}{$mid}{/if});
"
type="text">
</div>
</form>
</li>
</ul>
<div class="emojis results"></div>
{if="$reactionsrestrictions"}
<ul id="emojisearchbar"></ul>
<div class="emojis">
{loop="$reactionsrestrictions"}
{$codepoint = emojiToCodePoint($value)}
<div class="emojis main">
<img data-emoji="♥" alt=":hearts:" class="emoji large" src="{$c->getSmileyPath('2665')}">
<img data-emoji="👍" class="emoji large" src="{$c->getSmileyPath('1f44d')}">
<img data-emoji="👎" class="emoji large" src="{$c->getSmileyPath('1f44e')}">
<img data-emoji="😂" class="emoji large" src="{$c->getSmileyPath('1f602')}">
<img data-emoji="😊" class="emoji large" src="{$c->getSmileyPath('1f60a')}">
<img data-emoji="😉" class="emoji large" src="{$c->getSmileyPath('1f609')}">
</div>
{if="strlen($codepoint) < 6"}
<img data-emoji="{$value}" class="emoji large" src="{$c->getSmileyPath($codepoint)}">
{/if}
{/loop}
</div>
{else}
<ul id="emojisearchbar" class="list fill thin">
<li>
<span class="primary icon gray">
<i class="material-icons">search</i>
</span>
<form name="search" onsubmit="return false;">
<div>
<input name="keyword" autocomplete="off" title="{$c->__('message.emoji_help')}"
placeholder="{$c->__('message.emoji_help')}" oninput="
Chat.checkEmojis(this.value, true, true);
Stickers.setEmojisEvent({if=" $mid"}{$mid}{/if}); "
type=" text">
</div>
</form>
</li>
</ul>
<div class="emojis results"></div>
<div class="emojis">
<img data-emoji="😀" class="emoji large" src="{$c->getSmileyPath('1f600')}">
<img data-emoji="😁" class="emoji large" src="{$c->getSmileyPath('1f601')}">
<img data-emoji="😃" class="emoji large" src="{$c->getSmileyPath('1f603')}">
<img data-emoji="😄" class="emoji large" src="{$c->getSmileyPath('1f604')}">
<img data-emoji="😅" class="emoji large" src="{$c->getSmileyPath('1f605')}">
<img data-emoji="🤭" class="emoji large" src="{$c->getSmileyPath('1f92d')}">
<div class="emojis main">
<img data-emoji="♥" alt=":hearts:" class="emoji large" src="{$c->getSmileyPath('2665')}">
<img data-emoji="👍" class="emoji large" src="{$c->getSmileyPath('1f44d')}">
<img data-emoji="👎" class="emoji large" src="{$c->getSmileyPath('1f44e')}">
<img data-emoji="😂" class="emoji large" src="{$c->getSmileyPath('1f602')}">
<img data-emoji="😊" class="emoji large" src="{$c->getSmileyPath('1f60a')}">
<img data-emoji="😉" class="emoji large" src="{$c->getSmileyPath('1f609')}">
</div>
<img data-emoji="🧐" class="emoji large" src="{$c->getSmileyPath('1f9d0')}">
<img data-emoji="🤯" class="emoji large" src="{$c->getSmileyPath('1f92f')}">
<img data-emoji="🤑" class="emoji large" src="{$c->getSmileyPath('1f911')}">
<img data-emoji="🤤" class="emoji large" src="{$c->getSmileyPath('1f924')}">
<img data-emoji="🙄" class="emoji large" src="{$c->getSmileyPath('1f644')}">
<img data-emoji="🤔" class="emoji large" src="{$c->getSmileyPath('1f914')}">
<div class="emojis">
<img data-emoji="😀" class="emoji large" src="{$c->getSmileyPath('1f600')}">
<img data-emoji="😁" class="emoji large" src="{$c->getSmileyPath('1f601')}">
<img data-emoji="😃" class="emoji large" src="{$c->getSmileyPath('1f603')}">
<img data-emoji="😄" class="emoji large" src="{$c->getSmileyPath('1f604')}">
<img data-emoji="😅" class="emoji large" src="{$c->getSmileyPath('1f605')}">
<img data-emoji="🤭" class="emoji large" src="{$c->getSmileyPath('1f92d')}">
<img data-emoji="🤗" class="emoji large" src="{$c->getSmileyPath('1f917')}">
<img data-emoji="🤩" class="emoji large" src="{$c->getSmileyPath('1f929')}">
<img data-emoji="🤨" class="emoji large" src="{$c->getSmileyPath('1f928')}">
<img data-emoji="🤪" class="emoji large" src="{$c->getSmileyPath('1f92a')}">
<img data-emoji="🤢" class="emoji large" src="{$c->getSmileyPath('1f922')}">
<img data-emoji="😆" class="emoji large" src="{$c->getSmileyPath('1f606')}">
<img data-emoji="🧐" class="emoji large" src="{$c->getSmileyPath('1f9d0')}">
<img data-emoji="🤯" class="emoji large" src="{$c->getSmileyPath('1f92f')}">
<img data-emoji="🤑" class="emoji large" src="{$c->getSmileyPath('1f911')}">
<img data-emoji="🤤" class="emoji large" src="{$c->getSmileyPath('1f924')}">
<img data-emoji="🙄" class="emoji large" src="{$c->getSmileyPath('1f644')}">
<img data-emoji="🤔" class="emoji large" src="{$c->getSmileyPath('1f914')}">
<img data-emoji="😇" class="emoji large" src="{$c->getSmileyPath('1f607')}">
<img data-emoji="😈" class="emoji large" src="{$c->getSmileyPath('1f608')}">
<img data-emoji="😋" class="emoji large" src="{$c->getSmileyPath('1f60b')}">
<img data-emoji="😌" class="emoji large" src="{$c->getSmileyPath('1f60c')}">
<img data-emoji="😍" class="emoji large" src="{$c->getSmileyPath('1f60d')}">
<img data-emoji="😎" class="emoji large" src="{$c->getSmileyPath('1f60e')}">
<img data-emoji="🤗" class="emoji large" src="{$c->getSmileyPath('1f917')}">
<img data-emoji="🤩" class="emoji large" src="{$c->getSmileyPath('1f929')}">
<img data-emoji="🤨" class="emoji large" src="{$c->getSmileyPath('1f928')}">
<img data-emoji="🤪" class="emoji large" src="{$c->getSmileyPath('1f92a')}">
<img data-emoji="🤢" class="emoji large" src="{$c->getSmileyPath('1f922')}">
<img data-emoji="😆" class="emoji large" src="{$c->getSmileyPath('1f606')}">
<img data-emoji="😏" class="emoji large" src="{$c->getSmileyPath('1f60f')}">
<img data-emoji="😐" class="emoji large" src="{$c->getSmileyPath('1f610')}">
<img data-emoji="😑" class="emoji large" src="{$c->getSmileyPath('1f611')}">
<img data-emoji="😒" class="emoji large" src="{$c->getSmileyPath('1f612')}">
<img data-emoji="😓" class="emoji large" src="{$c->getSmileyPath('1f613')}">
<img data-emoji="😔" class="emoji large" src="{$c->getSmileyPath('1f614')}">
<img data-emoji="😇" class="emoji large" src="{$c->getSmileyPath('1f607')}">
<img data-emoji="😈" class="emoji large" src="{$c->getSmileyPath('1f608')}">
<img data-emoji="😋" class="emoji large" src="{$c->getSmileyPath('1f60b')}">
<img data-emoji="😌" class="emoji large" src="{$c->getSmileyPath('1f60c')}">
<img data-emoji="😍" class="emoji large" src="{$c->getSmileyPath('1f60d')}">
<img data-emoji="😎" class="emoji large" src="{$c->getSmileyPath('1f60e')}">
<img data-emoji="😕" class="emoji large" src="{$c->getSmileyPath('1f615')}">
<img data-emoji="😖" class="emoji large" src="{$c->getSmileyPath('1f616')}">
<img data-emoji="😗" class="emoji large" src="{$c->getSmileyPath('1f617')}">
<img data-emoji="😘" class="emoji large" src="{$c->getSmileyPath('1f618')}">
<img data-emoji="😙" class="emoji large" src="{$c->getSmileyPath('1f619')}">
<img data-emoji="😚" class="emoji large" src="{$c->getSmileyPath('1f61a')}">
<img data-emoji="😏" class="emoji large" src="{$c->getSmileyPath('1f60f')}">
<img data-emoji="😐" class="emoji large" src="{$c->getSmileyPath('1f610')}">
<img data-emoji="😑" class="emoji large" src="{$c->getSmileyPath('1f611')}">
<img data-emoji="😒" class="emoji large" src="{$c->getSmileyPath('1f612')}">
<img data-emoji="😓" class="emoji large" src="{$c->getSmileyPath('1f613')}">
<img data-emoji="😔" class="emoji large" src="{$c->getSmileyPath('1f614')}">
<img data-emoji="😛" class="emoji large" src="{$c->getSmileyPath('1f61b')}">
<img data-emoji="😜" class="emoji large" src="{$c->getSmileyPath('1f61c')}">
<img data-emoji="😝" class="emoji large" src="{$c->getSmileyPath('1f61d')}">
<img data-emoji="😞" class="emoji large" src="{$c->getSmileyPath('1f61e')}">
<img data-emoji="😟" class="emoji large" src="{$c->getSmileyPath('1f61f')}">
<img data-emoji="😠" class="emoji large" src="{$c->getSmileyPath('1f620')}">
<img data-emoji="😕" class="emoji large" src="{$c->getSmileyPath('1f615')}">
<img data-emoji="😖" class="emoji large" src="{$c->getSmileyPath('1f616')}">
<img data-emoji="😗" class="emoji large" src="{$c->getSmileyPath('1f617')}">
<img data-emoji="😘" class="emoji large" src="{$c->getSmileyPath('1f618')}">
<img data-emoji="😙" class="emoji large" src="{$c->getSmileyPath('1f619')}">
<img data-emoji="😚" class="emoji large" src="{$c->getSmileyPath('1f61a')}">
<img data-emoji="😡" class="emoji large" src="{$c->getSmileyPath('1f621')}">
<img data-emoji="😢" class="emoji large" src="{$c->getSmileyPath('1f622')}">
<img data-emoji="😣" class="emoji large" src="{$c->getSmileyPath('1f623')}">
<img data-emoji="😤" class="emoji large" src="{$c->getSmileyPath('1f624')}">
<img data-emoji="😥" class="emoji large" src="{$c->getSmileyPath('1f625')}">
<img data-emoji="😦" class="emoji large" src="{$c->getSmileyPath('1f626')}">
<img data-emoji="😛" class="emoji large" src="{$c->getSmileyPath('1f61b')}">
<img data-emoji="😜" class="emoji large" src="{$c->getSmileyPath('1f61c')}">
<img data-emoji="😝" class="emoji large" src="{$c->getSmileyPath('1f61d')}">
<img data-emoji="😞" class="emoji large" src="{$c->getSmileyPath('1f61e')}">
<img data-emoji="😟" class="emoji large" src="{$c->getSmileyPath('1f61f')}">
<img data-emoji="😠" class="emoji large" src="{$c->getSmileyPath('1f620')}">
<img data-emoji="😧" class="emoji large" src="{$c->getSmileyPath('1f627')}">
<img data-emoji="😨" class="emoji large" src="{$c->getSmileyPath('1f628')}">
<img data-emoji="😩" class="emoji large" src="{$c->getSmileyPath('1f629')}">
<img data-emoji="😪" class="emoji large" src="{$c->getSmileyPath('1f62a')}">
<img data-emoji="😫" class="emoji large" src="{$c->getSmileyPath('1f62b')}">
<img data-emoji="😬" class="emoji large" src="{$c->getSmileyPath('1f62c')}">
<img data-emoji="😡" class="emoji large" src="{$c->getSmileyPath('1f621')}">
<img data-emoji="😢" class="emoji large" src="{$c->getSmileyPath('1f622')}">
<img data-emoji="😣" class="emoji large" src="{$c->getSmileyPath('1f623')}">
<img data-emoji="😤" class="emoji large" src="{$c->getSmileyPath('1f624')}">
<img data-emoji="😥" class="emoji large" src="{$c->getSmileyPath('1f625')}">
<img data-emoji="😦" class="emoji large" src="{$c->getSmileyPath('1f626')}">
<img data-emoji="😭" class="emoji large" src="{$c->getSmileyPath('1f62d')}">
<img data-emoji="😮" class="emoji large" src="{$c->getSmileyPath('1f62e')}">
<img data-emoji="😯" class="emoji large" src="{$c->getSmileyPath('1f62f')}">
<img data-emoji="😰" class="emoji large" src="{$c->getSmileyPath('1f630')}">
<img data-emoji="😱" class="emoji large" src="{$c->getSmileyPath('1f631')}">
<img data-emoji="😲" class="emoji large" src="{$c->getSmileyPath('1f632')}">
<img data-emoji="😧" class="emoji large" src="{$c->getSmileyPath('1f627')}">
<img data-emoji="😨" class="emoji large" src="{$c->getSmileyPath('1f628')}">
<img data-emoji="😩" class="emoji large" src="{$c->getSmileyPath('1f629')}">
<img data-emoji="😪" class="emoji large" src="{$c->getSmileyPath('1f62a')}">
<img data-emoji="😫" class="emoji large" src="{$c->getSmileyPath('1f62b')}">
<img data-emoji="😬" class="emoji large" src="{$c->getSmileyPath('1f62c')}">
<img data-emoji="😳" class="emoji large" src="{$c->getSmileyPath('1f633')}">
<img data-emoji="😴" class="emoji large" src="{$c->getSmileyPath('1f634')}">
<img data-emoji="👊" class="emoji large" src="{$c->getSmileyPath('1f44a')}">
<img data-emoji="👋" class="emoji large" src="{$c->getSmileyPath('1f44b')}">
<img data-emoji="👌" class="emoji large" src="{$c->getSmileyPath('1f44c')}">
<img data-emoji="👏" class="emoji large" src="{$c->getSmileyPath('1f44f')}">
</div>
<img data-emoji="😭" class="emoji large" src="{$c->getSmileyPath('1f62d')}">
<img data-emoji="😮" class="emoji large" src="{$c->getSmileyPath('1f62e')}">
<img data-emoji="😯" class="emoji large" src="{$c->getSmileyPath('1f62f')}">
<img data-emoji="😰" class="emoji large" src="{$c->getSmileyPath('1f630')}">
<img data-emoji="😱" class="emoji large" src="{$c->getSmileyPath('1f631')}">
<img data-emoji="😲" class="emoji large" src="{$c->getSmileyPath('1f632')}">
<img data-emoji="😳" class="emoji large" src="{$c->getSmileyPath('1f633')}">
<img data-emoji="😴" class="emoji large" src="{$c->getSmileyPath('1f634')}">
<img data-emoji="👊" class="emoji large" src="{$c->getSmileyPath('1f44a')}">
<img data-emoji="👋" class="emoji large" src="{$c->getSmileyPath('1f44b')}">
<img data-emoji="👌" class="emoji large" src="{$c->getSmileyPath('1f44c')}">
<img data-emoji="👏" class="emoji large" src="{$c->getSmileyPath('1f44f')}">
</div>
{/if}

21
database/migrations/20231108190801_add_reactions_restrictions_to_infos_table.php

@ -0,0 +1,21 @@
<?php
use Movim\Migration;
use Illuminate\Database\Schema\Blueprint;
class AddReactionsRestrictionsToInfosTable extends Migration
{
public function up()
{
$this->schema->table('infos', function (Blueprint $table) {
$table->text('reactionsrestrictions')->nullable();
});
}
public function down()
{
$this->schema->table('infos', function (Blueprint $table) {
$table->dropColumn('reactionsrestrictions');
});
}
}

1
public/theme/css/style.css

@ -300,6 +300,7 @@ main>div:first-child:nth-last-child(2)+div {
text-align: right;
bottom: 0;
padding: 0.5rem;
padding-top: 0;
position: absolute;
border-top: 1px solid rgba(var(--movim-font), 0.12);
}

Loading…
Cancel
Save