Commit ed56d73d authored by Dominik George's avatar Dominik George

New upstream version 0.14.1~rc5

parent f409cd91
......@@ -19,6 +19,11 @@ v0.14.1 (trunk)
* Display Gateway connection status
* CSS fixes in Forms
* Disable the dropdown in Form if there is only one choice
* Add support for embeded images in Forms (for CAPTCHA)
* Chat bubbles a bit more compact
* Display single emojis as small stickers
* Display chat states in MUC, handle the chat states with a new ChatStates class
* Allow setting Avatars on Communities by combining XEP-0084 (metadata + url) and XEP-0060
v0.14
---------------------------
......
0.14.1rc4
\ No newline at end of file
0.14.1rc5
......@@ -10,15 +10,6 @@ class Capability extends Model
protected $fillable = ['features'];
public $incrementing = false;
public function save(array $options = [])
{
try {
parent::save($options);
} catch (\Exception $e) {
// Race condition
}
}
public function set($query, $node = false)
{
if (!$node) {
......
......@@ -15,17 +15,6 @@ class Conference extends Model
'session_id' => SESSION_ID
];
public function save(array $options = [])
{
try {
parent::save($options);
} catch (\Exception $e) {
/*
* Race condition
*/
}
}
public function session()
{
return $this->hasOne('App\Session');
......
......@@ -8,18 +8,18 @@ class Info extends Model
{
protected $primaryKey = ['server', 'node'];
public $incrementing = false;
protected $fillable = ['server', 'node'];
protected $fillable = ['server', 'node', 'avatarhash'];
public function setAdminaddressesAttribute(array $arr)
{
$this->attributes['adminaddresses'] = serialize($arr);
}
public function getAdminaddressesAttribute()
public function getAdminaddressesAttribute(): array
{
return (isset($this->attributes['adminaddresses']))
? unserialize($this->attributes['adminaddresses'])
: null;
: [];
}
public function setAbuseaddressesAttribute(array $arr)
......@@ -27,11 +27,11 @@ class Info extends Model
$this->attributes['abuseaddresses'] = serialize($arr);
}
public function getAbuseaddressesAttribute()
public function getAbuseaddressesAttribute(): array
{
return (isset($this->attributes['abuseaddresses']))
? unserialize($this->attributes['abuseaddresses'])
: null;
: [];
}
public function setFeedbackaddressesAttribute(array $arr)
......@@ -39,11 +39,11 @@ class Info extends Model
$this->attributes['feedbackaddresses'] = serialize($arr);
}
public function getFeedbackaddressesAttribute()
public function getFeedbackaddressesAttribute(): array
{
return (isset($this->attributes['feedbackaddresses']))
? unserialize($this->attributes['feedbackaddresses'])
: null;
: [];
}
public function setSalesaddressesAttribute(array $arr)
......@@ -51,22 +51,22 @@ class Info extends Model
$this->attributes['salesaddresses'] = serialize($arr);
}
public function getSalesaddressesAttribute()
public function getSalesaddressesAttribute(): array
{
return (isset($this->attributes['salesaddresses']))
? unserialize($this->attributes['salesaddresses'])
: null;
: [];
}
public function setSecurityaddressesAttribute(array $arr)
{
$this->attributes['securityaddresses'] = serialize($arr);
}
public function getSecurityaddressesAttribute()
public function getSecurityaddressesAttribute(): array
{
return (isset($this->attributes['securityaddresses']))
? unserialize($this->attributes['securityaddresses'])
: null;
: [];
}
public function setSupportaddressesAttribute(array $arr)
......@@ -74,11 +74,11 @@ class Info extends Model
$this->attributes['supportaddresses'] = serialize($arr);
}
public function getSupportaddressesAttribute()
public function getSupportaddressesAttribute(): array
{
return (isset($this->attributes['supportaddresses']))
? unserialize($this->attributes['supportaddresses'])
: null;
: [];
}
public function getNameAttribute()
......@@ -121,6 +121,13 @@ class Info extends Model
->first();
}
public function getPhoto($size = 'm')
{
return isset($this->attributes['avatarhash'])
? getPhoto($this->attributes['avatarhash'], $size)
: null;
}
public function set($query)
{
$from = (string)$query->attributes()->from;
......
......@@ -22,15 +22,6 @@ class Message extends Model
'markable' => 'boolean'
];
public function save(array $options = [])
{
try {
parent::save($options);
} catch (\Exception $e) {
// Race condition
}
}
public function user()
{
return $this->belongsTo('App\User');
......@@ -283,12 +274,6 @@ class Message extends Model
}
}
public function convertEmojis()
{
$emoji = \Movim\Emoji::getInstance();
$this->body = addHFR($emoji->replace($this->body));
}
public function isTrusted()
{
/*$rd = new \Modl\RosterLinkDAO;
......
......@@ -3,6 +3,7 @@ var MovimAvatar = {
var f = files[0];
if (!f.type.match(/image.*/)) {
console.log("Not a picture !");
MovimAvatar.clear(formname);
} else {
var reader = new FileReader();
reader.readAsDataURL(f);
......@@ -14,8 +15,11 @@ var MovimAvatar = {
};
};
},
clear : function(formname) {
document.querySelector('form[name=' + formname + '] img').src = '';
document.querySelector('form[name=' + formname + '] input[name="photobin"]').value = '';
},
preview : function(src, orientation, formname) {
console.log(formname);
var canvas = document.createElement('canvas');
width = height = canvas.width = canvas.height = 350;
......
......@@ -85,7 +85,7 @@ var MovimWebsocket = {
if (obj.func == 'started') {
// If the linker was started but we're not on the login page
if (!['login', 'account', 'accountnext', 'tag'].includes(MovimUtils.urlParts().page)) {
if (!['login', 'account', 'accountnext', 'tag', 'admin'].includes(MovimUtils.urlParts().page)) {
MovimUtils.disconnect();
} else {
MovimWebsocket.launchStarted();
......@@ -100,11 +100,6 @@ var MovimWebsocket = {
MovimWebsocket.pong = true;
}
if (obj.func == 'block') {
MovimWebsocket.clearAttached();
document.body.classList.add('disabled');
}
MovimWebsocket.handle(obj);
}
};
......
......@@ -38,7 +38,7 @@ class Account extends \Movim\Widget\Base
if (isset($content->x)) {
$xml = new \XMPPtoForm;
$form = $xml->getHTML($content->x->asXML());
$form = $xml->getHTML($content->x);
$view->assign('form', $form);
$view->assign('from', $package->from);
......
......@@ -39,11 +39,8 @@ class AccountNext extends \Movim\Widget\Base
switch($form->x->attributes()->xmlns) {
case 'jabber:x:data' :
$formview = $this->tpl();
$formh = $xtf->getHTML($form->x->asXML());
$formview->assign('submitdata', $this->call('ajaxRegister', "MovimUtils.formToJson('data')"));
$formview->assign('formh', $formh);
$formview->assign('formh', $xtf->getHTML($form->x, $form));
$html = $formview->draw('_accountnext_form');
break;
case 'jabber:x:oob' :
......@@ -52,11 +49,8 @@ class AccountNext extends \Movim\Widget\Base
}
} else {
$formview = $this->tpl();
$formh = $xtf->getHTML($form->asXML());
$formview->assign('submitdata', $this->call('ajaxRegister', "MovimUtils.formToJson('data')"));
$formview->assign('formh', $formh);
$formview->assign('formh', $xtf->getHTML($form));
$html = $formview->draw('_accountnext_form');
}
......
......@@ -40,7 +40,7 @@ class AdHoc extends \Movim\Widget\Base
$this->rpc('AdHoc.initForm');
} elseif (isset($command->x)) {
$xml = new \XMPPtoForm();
$form = $xml->getHTML($command->x->asXML());
$form = $xml->getHTML($command->x);
$view->assign('form', $form);
$view->assign('attributes', $command->attributes());
......
......@@ -10,7 +10,7 @@ class AdminMain extends \Movim\Widget\Base
$configuration = Configuration::get();
if (isset($form) && !empty($form)) {
if (isset($form) && !empty($form) && isset($form['adminform'])) {
if (isset($form['password'])
&& isset($form['repassword'])
&& $form['password'] != '' && $form['repassword'] != ''
......@@ -23,6 +23,7 @@ class AdminMain extends \Movim\Widget\Base
unset($form['password']);
unset($form['repassword']);
unset($form['submit']);
unset($form['adminform']);
foreach ($form as $key => $value) {
$configuration->$key = $value;
......
<div id="admingen" class="tabelem padded_top_bottom" title="{$c->__('admin.general')}">
<form name="admin" id="adminform" action="#" method="post">
<input type="hidden" name="adminform" id="adminform" value="true"/>
<br />
<h3>{$c->__('admin.general')}</h3>
<div>
......
......@@ -7,18 +7,14 @@
<div>
<form name="avatarform" id="avatarform">
{if="isset($photobin) && $photobin != ''"}
<img src="data:image/jpeg;base64,{$photobin}">
<img class="avatar" src="data:image/jpeg;base64,{$photobin}">
{else}
<img src="#" class="error">
<ul class="list thick">
<li>
<span class="primary icon bubble color {$me->jid|stringToColor}">
<i class="material-icons">person</i>
</span>
<p class="normal line">{$c->__('avatar.missing')}</p>
</li>
</ul>
<img class="avatar" src="">
{/if}
<div class="placeholder">
<i class="material-icons">image</i>
<h1>{$c->__('avatar.missing')}</h1>
</div>
<input type="hidden" name="photobin" value="{$photobin}"/>
</form>
</div>
......
......@@ -3,14 +3,3 @@
text-align: center;
padding-top: 2rem;
}
#avatar_form div#avatar_preview > div,
#avatar_form div#avatar_preview img {
max-width: 250px;
border-radius: 0.25rem;
margin: 0 auto;
}
#avatar_form div#avatar_preview img.error {
display: none;
}
......@@ -71,12 +71,14 @@ class Blog extends Base
return;
}
$this->title = __('blog.title', $this->_contact->truename);
$this->description = $this->_contact->description;
if ($this->_contact) {
$this->title = __('blog.title', $this->_contact->truename);
$this->description = $this->_contact->description;
$avatar = $this->_contact->getPhoto('l');
if ($avatar) {
$this->image = $avatar;
$avatar = $this->_contact->getPhoto('l');
if ($avatar) {
$this->image = $avatar;
}
}
$this->_mode = 'blog';
......
......@@ -52,9 +52,19 @@
{else}
<ul class="list thick">
<li>
<span class="primary icon gray">
<i class="material-icons">group_work</i>
</span>
{$url = null}
{if="$item != null"}
{$url = $item->getPhoto('m')}
{/if}
{if="$url"}
<span class="primary icon bubble">
<img src="{$url}"/>
</span>
{else}
<span class="primary icon gray">
<i class="material-icons">group_work</i>
</span>
{/if}
<span class="control icon active">
<a
href="{$c->route('feed', [$server, $node])}"
......@@ -74,10 +84,14 @@
{if="$item != null"}
{if="$item->description"}
<p title="{$item->description|stripTags}">
<i class="material-icons">people</i> {$c->__('communitydata.sub', $item->occupants)}
{$item->description|stripTags}
</p>
{else}
<p>{$item->server}</p>
<p>
<i class="material-icons">people</i> {$c->__('communitydata.sub', $item->occupants)}
{$item->server}
</p>
{/if}
{/if}
</li>
......@@ -93,7 +107,7 @@
<span class="primary icon gray">
<i class="material-icons">comment</i>
</span>
<p class="normal">{$c->__('blog.empty')}</p>
<p class="normal">{$c->__('post.empty')}</p>
</li>
</ul>
</article>
......
[blog]
title = "%s’s feed"
empty = This user has not posted anything right now
private = This content is private, please login to see it
......@@ -16,6 +16,8 @@ use Respect\Validation\Validator;
use Illuminate\Database\Capsule\Manager as DB;
use Movim\Picture;
use Movim\Session;
use Movim\ChatStates;
include_once WIDGETS_PATH.'ContactActions/ContactActions.php';
......@@ -38,10 +40,8 @@ class Chat extends \Movim\Widget\Base
$this->registerEvent('mam_get_handle', 'onMAMRetrieved', 'chat');
$this->registerEvent('composing', 'onComposing', 'chat');
$this->registerEvent('paused', 'onPaused', 'chat');
$this->registerEvent('gone', 'onGone', 'chat');
$this->registerEvent('subject', 'onConferenceSubject', 'chat');
$this->registerEvent('muc_setsubject_handle', 'onConferenceSubject', 'chat');
$this->registerEvent('muc_getconfig_handle', 'onRoomConfig', 'chat');
$this->registerEvent('muc_setconfig_handle', 'onRoomConfigSaved', 'chat');
$this->registerEvent('muc_setconfig_error', 'onRoomConfigError', 'chat');
......@@ -85,6 +85,7 @@ class Chat extends \Movim\Widget\Base
{
$message = $packet->content;
$from = null;
$chatStates = ChatStates::getInstance();
if ($message->isEmpty()) return;
......@@ -107,6 +108,8 @@ class Chat extends \Movim\Widget\Base
&& !$message->isOTR()
&& $message->type != 'groupchat'
&& !$message->oldid) {
$chatStates->clearState($from);
Notification::append(
'chat|'.$from,
$roster ? $roster->truename : $contact->truename,
......@@ -120,6 +123,7 @@ class Chat extends \Movim\Widget\Base
elseif ($message->type == 'groupchat'
&& $message->quoted
&& !$receipt) {
$conference = $this->user->session
->conferences()->where('conference', $from)
->first();
......@@ -132,9 +136,11 @@ class Chat extends \Movim\Widget\Base
$message->resource.': '.$message->body,
false,
4);
} elseif ($message->type == 'groupchat') {
$chatStates->clearState($from, $message->resource);
}
$this->rpc('MovimTpl.fill', '#' . cleanupId($from.'_state'), $contact->jid);
$this->onPaused($chatStates->getState($from));
} else {
// If the message is from me we reset the notif counter
$n = new Notification;
......@@ -152,19 +158,24 @@ class Chat extends \Movim\Widget\Base
$this->ajaxGet($to);
}
public function onComposing($array)
public function onComposing(array $array)
{
$this->setState($array, $this->__('message.composing'));
$this->setState(
$array[0],
is_array($array[1]) && !empty($array[1])
? $this->prepareComposeList(array_keys($array[1]))
: $this->__('message.composing')
);
}
public function onPaused($array)
public function onPaused(array $array)
{
$this->setState($array, $this->__('message.paused'));
}
public function onGone($array)
{
$this->setState($array, $this->__('message.gone'));
$this->setState(
$array[0],
is_array($array[1]) && !empty($array[1])
? $this->prepareComposeList(array_keys($array[1]))
: ''
);
}
public function onConferenceSubject($packet)
......@@ -179,7 +190,7 @@ class Chat extends \Movim\Widget\Base
public function onMucConnected($packet)
{
$this->ajaxGetRoom($packet->content->jid);
$this->ajaxGetRoom($packet->content->jid, false, true);
}
public function onRoomConfigError($packet)
......@@ -194,7 +205,7 @@ class Chat extends \Movim\Widget\Base
$view = $this->tpl();
$xml = new \XMPPtoForm;
$form = $xml->getHTML($config->x->asXML());
$form = $xml->getHTML($config->x);
$view->assign('form', $form);
$view->assign('room', $room);
......@@ -207,18 +218,9 @@ class Chat extends \Movim\Widget\Base
Notification::append(false, $this->__('chatroom.config_saved'));
}
private function setState($array, $message)
private function setState(string $jid, string $message)
{
list($from, $to) = $array;
$jid = ($from == $this->user->id) ? $to : $from;
$view = $this->tpl();
$view->assign('message', $message);
$html = $view->draw('_chat_state');
$this->rpc('MovimTpl.fill', '#' . cleanupId($jid.'_state'), $html);
$this->rpc('MovimTpl.fill', '#' . cleanupId($jid.'_state'), $message);
}
public function ajaxInit()
......@@ -258,14 +260,14 @@ class Chat extends \Movim\Widget\Base
* @brief Get a chatroom
* @param string $jid
*/
public function ajaxGetRoom($room, $light = false)
public function ajaxGetRoom($room, $light = false, $noConnect = false)
{
if (!$this->validateJid($room)) return;
$r = $this->user->session->conferences()->where('conference', $room)->first();
if ($r) {
if (!$r->connected) {
if (!$r->connected && !$noConnect) {
$this->rpc('Rooms_ajaxJoin', $r->conference, $r->nick);
}
......@@ -446,11 +448,16 @@ class Chat extends \Movim\Widget\Base
* @param string $to
* @return void
*/
public function ajaxSendComposing($to)
public function ajaxSendComposing($to, $muc = false)
{
if (!$this->validateJid($to)) return;
$mc = new Composing;
if ($muc) {
$mc->setMuc();
}
$mc->setTo($to)->request();
}
......@@ -460,11 +467,16 @@ class Chat extends \Movim\Widget\Base
* @param string $to
* @return void
*/
public function ajaxSendPaused($to)
public function ajaxSendPaused($to, $muc = false)
{
if (!$this->validateJid($to)) return;
$mp = new Paused;
if ($muc) {
$mp->setMuc();
}
$mp->setTo($to)->request();
}
......@@ -583,8 +595,6 @@ class Chat extends \Movim\Widget\Base
$view->assign('jid', $jid);
$jid = echapJS($jid);
$view->assign('smiley', $this->call('ajaxSmiley'));
$view->assign('emoji', prepareString('😀'));
$view->assign('muc', $muc);
......@@ -667,11 +677,14 @@ class Chat extends \Movim\Widget\Base
$message->jidto = echapJS($message->jidto);
$message->jidfrom = echapJS($message->jidfrom);
$emoji = \Movim\Emoji::getInstance();
if (isset($message->html)) {
$message->body = $message->html;
} else {
$message->addUrls();
$message->convertEmojis();
$message->body = $emoji->replace($message->body);
$message->body = addHFR($message->body);
}
if (isset($message->subject) && $message->type == 'headline') {
......@@ -700,6 +713,14 @@ class Chat extends \Movim\Widget\Base
}
}
// Jumbo emoji
if ($emoji->isSingleEmoji()) {
$message->sticker = [
'url' => $emoji->getLastSingleEmojiURL(),
'height' => 60
];
}
// Attached file
if (isset($message->file)) {
// We proxify pictures links even if they are advertized as small ones
......@@ -832,6 +853,13 @@ class Chat extends \Movim\Widget\Base
return $view->draw('_chat_empty');
}
private function prepareComposeList(array $list)
{
$view = $this->tpl();
$view->assign('list', implode(', ', $list));
return $view->draw('_chat_compose_list');
}
/**
* @brief Validate the jid
*
......
......@@ -28,7 +28,9 @@
<span class="primary icon bubble color active {$conference->name|stringToColor}
{if="!$conference->connected"}disabled{/if}"
onclick="Rooms_ajaxList('{$jid|echapJS}')">
{$conference->name|firstLetterCapitalize}
{autoescape="off"}
{$conference->name|firstLetterCapitalize|addEmojis}
{/autoescape}
</span>
{/if}
......@@ -58,9 +60,12 @@
{$conference->name}
</p>
{else}
<p class="line">{$room}</p>
<p class="line">
{$room}
</p>
{/if}
<p class="compose" id="{$jid|cleanupId}-state"></p>
{if="$conference && !$conference->connected"}
<p>{$c->__('button.connecting')}</p>
{elseif="$conference && $conference->subject"}
......@@ -74,7 +79,7 @@
{$conference->subject}
</p>
{else}
<p class="line">
<p class="line" id="{$jid|cleanupId}-state">
{if="$conference->info && !$conference->info->mucsemianonymous"}
<span title="{$c->__('room.public_muc_text')}">
{$c->__('room.public_muc')} <i class="material-icons">wifi_tethering</i>
......@@ -134,12 +139,15 @@
{$url = $contact->getPhoto()}
{if="$url"}