Browse Source

- Improve Search widget

- Move some query parts in scopes
- Add a "show complete roster" button
- Cleanup code
pull/872/head
Timothée Jaussoin 6 years ago
parent
commit
487a8f47a6
  1. 32
      app/Contact.php
  2. 112
      app/widgets/Search/Search.php
  3. 13
      app/widgets/Search/_search_results_contacts.tpl
  4. 13
      app/widgets/Search/_search_roster.tpl
  5. 3
      app/widgets/Search/locales.ini
  6. 2
      app/widgets/Search/search.css
  7. 16
      app/widgets/Search/search.js
  8. 1
      app/widgets/Tabs/tabs.js
  9. 12
      composer.lock

32
app/Contact.php

@ -3,6 +3,7 @@
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Capsule\Manager as DB;
use Respect\Validation\Validator;
use Movim\Picture;
@ -17,6 +18,37 @@ class Contact extends Model
return $this->belongsTo('App\User', 'id');
}
public function scopePublic($query, $like = false)
{
return $query->whereIn('id', function ($query) use ($like) {
$query->select('id')
->from('users')
->where('public', true)
->when($like !== false, function ($query) use ($like) {
$query->where('id', 'like', '%'. $like . '%');
});
});
}
public function scopeNotInRoster($query, $sessionId)
{
return $query->whereNotIn('id', function ($query) use ($sessionId) {
$query->select('jid')
->from('rosters')
->where('session_id', $sessionId);
});
}
public function scopeOrderByPresence($query)
{
return $query->leftJoin(DB::raw('(
select min(value) as value, jid
from presences
group by jid) as presences
'), 'presences.jid', '=', 'contacts.id')
->orderBy('presences.value');
}
public function save(array $options = [])
{
unset($this->photobin);

112
app/widgets/Search/Search.php

@ -6,6 +6,13 @@ use Respect\Validation\Validator;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Capsule\Manager as DB;
use App\Post;
use App\Tag;
use App\Contact;
use App\Info;
use Post as PostWidget;
class Search extends Base
{
public function load()
@ -41,25 +48,35 @@ class Search extends Base
$key = str_replace(['#', 'xmpp:'], '', $key);
if (Validator::stringType()->length(1, 64)->validate($key)) {
if (Validator::stringType()->length(2, 64)->validate($key)) {
$view->assign('posts', new Collection);
if ($this->user->hasPubsub()) {
$posts = \App\Post::whereIn('id', function ($query) use ($key) {
$tagIds = Tag::where('name', 'like', '%' . strtolower($key) . '%')->pluck('id');
$tags = DB::table('post_tag')
->select(DB::raw('count(*) as count, name'))
->join('tags', 'tag_id', '=', 'tags.id')
->whereIn('tag_id', $tagIds)
->groupBy('name')
->orderBy('count', 'desc')
->take(4)
->get()
->pluck('name', 'count');
$view->assign('tags', $tags);
$posts = Post::whereIn('id', function ($query) use ($tagIds) {
$query->select('post_id')
->from('post_tag')
->whereIn('tag_id', function ($query) use ($key) {
$query->select('id')
->from('tags')
->where('name', 'like', '%' . strtolower($key) . '%');
});
->whereIn('tag_id', $tagIds);
})
->whereIn('id', function ($query) {
$query = $query->select('id')->from('posts');
$query = \App\Post::withContactsScope($query);
$query = \App\Post::withMineScope($query);
$query = \App\Post::withSubscriptionsScope($query);
$query = Post::withContactsScope($query);
$query = Post::withMineScope($query);
$query = Post::withSubscriptionsScope($query);
})
->orderBy('published', 'desc')
->take(5)
@ -68,51 +85,23 @@ class Search extends Base
$view->assign('posts', $posts);
}
$contacts = \App\Contact::whereIn('id', function ($query) use ($key) {
$query->select('id')
->from('users')
->where('public', true)
->where('id', 'like', '%'. $key . '%');
})->leftJoin(DB::raw('(
select min(value) as value, jid
from presences
group by jid) as presences
'), 'presences.jid', '=', 'contacts.id')
->whereNotIn('id', function ($query) {
$query->select('jid')
->from('rosters')
->where('session_id', $this->user->session->id);
})
->where('id', '!=', $this->user->id)
->orderBy('presences.value')
->limit(10)
->get();
$contacts = Contact::public($key)
->notInRoster($this->user->session->id)
->orderByPresence()
->where('id', '!=', $this->user->id)
->limit(10)
->get();
if (Validator::email()->validate($key)) {
$contact = new \App\Contact;
$contact = new Contact;
$contact->id = $key;
$contacts->push($contact);
}
$view->assign('contacts', $contacts);
$tags = DB::table('post_tag')
->select(DB::raw('count(*) as count, name'))
->join('tags', 'tag_id', '=', 'tags.id')
->whereIn('tag_id', function ($query) use ($key) {
$query->select('id')
->from('tags')
->where('name', 'like', '%' . strtolower($key) . '%');
})
->groupBy('name')
->orderBy('count', 'desc')
->take(4)
->get()
->pluck('name', 'count');
$view->assign('tags', $tags);
$communities = \App\Info::whereRaw('lower(node) like ?', '%'.strtolower($key).'%')
$communities = Info::whereRaw('lower(node) like ?', '%'.strtolower($key).'%')
->whereRaw('lower(node) not like ?', 'urn:xmpp:microblog:0%')
->where('category', 'pubsub')
->where('type', 'leaf')
->where('pubsubaccessmodel', 'open')
@ -131,25 +120,12 @@ class Search extends Base
{
$view = $this->tpl();
$users = \App\Contact::whereIn('id', function ($query) {
$query->select('id')
->from('users')
->where('public', true);
})
->leftJoin(DB::raw('(
select min(value) as value, jid
from presences
group by jid) as presences
'), 'presences.jid', '=', 'contacts.id')
->whereNotIn('id', function ($query) {
$query->select('jid')
->from('rosters')
->where('session_id', $this->user->session->id);
})
->where('id', '!=', $this->user->id)
->orderBy('presences.value')
->limit(16)
->get();
$users = Contact::public()
->notInRoster($this->user->session->id)
->orderByPresence()
->where('id', '!=', $this->user->id)
->limit(16)
->get();
$view->assign('users', $users);
@ -168,9 +144,9 @@ class Search extends Base
$contact->ajaxChat($jid);
}
public function prepareTicket(\App\Post $post)
public function prepareTicket(Post $post)
{
return (new Post)->prepareTicket($post);
return (new PostWidget)->prepareTicket($post);
}
public function prepareUsers($users)

13
app/widgets/Search/_search_results_contacts.tpl

@ -25,18 +25,15 @@
<span class="control icon active gray" onclick="MovimUtils.reload('{$c->route('contact', $value->jid)}')">
<i class="material-icons">person</i>
</span>
<span class="control icon active gray" onclick="Search.chat('{$value->jid|echapJS}')">
<i class="material-icons">comment</i>
</span>
<p class="normal line">
{$value->truename}
{if="!empty($value->description)"}
<span class="second" title="{$value->description|strip_tags}">
{$value->description|strip_tags|truncate:80}
</span>
{/if}
</p>
{if="!empty($value->description)"}
<p class="line" title="{$value->description|strip_tags}">
{$value->description|strip_tags|truncate:80}
</p>
{/if}
</li>
{/loop}
</ul>

13
app/widgets/Search/_search_roster.tpl

@ -69,6 +69,19 @@
{/if}
</li>
{/loop}
{if="$contacts->count() > 7"}
<br />
<li class="showall active" onclick="Search.showCompleteRoster(this)">
<span class="primary icon gray">
<i class="material-icons">expand_more</i>
</span>
<p class="normal line">
{$c->__('search.show_complete_roster')}
<span class="second">{$contacts->count()} <i class="material-icons">people</i></span>
</p>
</li>
{/if}
{else}
<ul class="list thick">
<li>

3
app/widgets/Search/locales.ini

@ -4,4 +4,5 @@ subtitle = Open me using Ctrl + M
placeholder = "#cats, username@server.com, John…"
no_contacts_title = No contacts yet?
no_contacts_text = Find one by searching for his name or id
tags = Tags
tags = Tags
show_complete_roster = Show all the contacts

2
app/widgets/Search/search.css

@ -20,6 +20,6 @@
top: -1rem;
}
#search ul#roster li:not(.found) {
#search ul#roster li:not(.found):not(.showall) {
display: none;
}

16
app/widgets/Search/search.js

@ -1,17 +1,19 @@
var Search = {
timer : null,
rosterLimit: 7,
rosterLimit: false,
init : function() {
if (window.matchMedia("(min-width: 1025px)").matches) {
document.querySelector('input[name=keyword]').focus();
}
Search.rosterLimit = 7;
Search_ajaxInitRoster();
},
roster : function(key) {
var selector = '#search > #roster > li';
var selector = '#search > #roster > li:not(.showall)';
var subheader = document.querySelector(selector + '.subheader')
document.querySelectorAll(selector)
@ -35,6 +37,13 @@ var Search = {
}
},
showCompleteRoster : function(li)
{
li.style.display = 'none';
Search.rosterLimit = document.querySelectorAll('#search > #roster > li:not(.showall)').length;
Search.searchCurrent();
},
chat : function(jid) {
if (MovimUtils.urlParts().page === 'chat') {
Drawer_ajaxClear();
@ -59,8 +68,7 @@ var Search = {
Search.timer = setTimeout(() => {
Search_ajaxSearch(value);
},
700);
}, 700);
Search.roster(value);
},

1
app/widgets/Tabs/tabs.js

@ -5,7 +5,6 @@ var Tabs = {
var current = null;
// We create the list
var html = '';
for (var i=0; i<tabs.length; i++) {
if (window.location.hash == '#' + tabs[i].id + '_tab') {
current = tabs[i].id;

12
composer.lock

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "66e70487188700ff25ea818774ed0944",
"content-hash": "9296958a7f433005792cee88a49ef85b",
"packages": [
{
"name": "cakephp/cache",
@ -1547,16 +1547,16 @@
},
{
"name": "nesbot/carbon",
"version": "2.25.1",
"version": "2.25.2",
"source": {
"type": "git",
"url": "https://github.com/briannesbitt/Carbon.git",
"reference": "d59c6cea9c4a3547bb6c0dfec451319abdaa4fb1"
"reference": "443fe5f1498147e0fbc792142b5dc43e2e8a533f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/d59c6cea9c4a3547bb6c0dfec451319abdaa4fb1",
"reference": "d59c6cea9c4a3547bb6c0dfec451319abdaa4fb1",
"url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/443fe5f1498147e0fbc792142b5dc43e2e8a533f",
"reference": "443fe5f1498147e0fbc792142b5dc43e2e8a533f",
"shasum": ""
},
"require": {
@ -1610,7 +1610,7 @@
"datetime",
"time"
],
"time": "2019-10-05T15:52:23+00:00"
"time": "2019-10-14T14:18:59+00:00"
},
{
"name": "paragonie/random_compat",

Loading…
Cancel
Save