general: add usersearch cell; used in get_concerned_user() (#10479)

This commit is contained in:
Thomas NOËL 2016-03-30 14:45:16 +02:00
parent ea1d6abfcb
commit 835ff26e9f
10 changed files with 207 additions and 1 deletions

View File

@ -0,0 +1,26 @@
# combo - content management system
# Copyright (C) 2014-2016 Entr'ouvert
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import django.apps
class AppConfig(django.apps.AppConfig):
name = 'combo.apps.usersearch'
def get_before_urls(self):
from . import urls
return urls.urlpatterns
default_app_config = 'combo.apps.usersearch.AppConfig'

View File

@ -0,0 +1,32 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('auth', '0001_initial'),
('data', '0015_feedcell_title'),
]
operations = [
migrations.CreateModel(
name='UserSearchCell',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('placeholder', models.CharField(max_length=20)),
('order', models.PositiveIntegerField()),
('slug', models.SlugField(verbose_name='Slug', blank=True)),
('public', models.BooleanField(default=True, verbose_name='Public')),
('restricted_to_unlogged', models.BooleanField(default=False, verbose_name='Restrict to unlogged users')),
('groups', models.ManyToManyField(to='auth.Group', verbose_name='Groups', blank=True)),
('page', models.ForeignKey(to='data.Page')),
],
options={
'verbose_name': 'User Search',
},
bases=(models.Model,),
),
]

View File

@ -0,0 +1,39 @@
# combo - content management system
# Copyright (C) 2014-2016 Entr'ouvert
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from django.utils.translation import ugettext_lazy as _
from django.contrib.auth.models import User
from combo.data.models import CellBase
from combo.data.library import register_cell_class
@register_cell_class
class UserSearchCell(CellBase):
template_name = 'combo/usersearch.html'
class Media:
js = ('js/usersearch.js',)
class Meta:
verbose_name = _('User Search')
def is_visible(self, user=None):
return super(UserSearchCell, self).is_visible(user=user)
def modify_global_context(self, context, request):
if 'selected_user_id' in request.GET:
context['selected_user'] = User.objects.get(pk=request.GET['selected_user_id'])

View File

@ -0,0 +1,21 @@
$(function() {
$('.usersearch').delegate('input', 'keyup', function() {
var q = $(this).val();
var search_result_ul = $(this).parent().find('ul.result');
search_result_ul.empty();
$.getJSON($(this).data('autocomplete-json'),
{'q': q},
function (response) {
search_result_ul.empty();
$(response).each(function(idx, elem) {
var new_elem = '<li><a href="?selected_user_id=' + encodeURIComponent(elem.pk) + '">';
new_elem = new_elem + elem.fields.first_name + ' ' + elem.fields.last_name;
new_elem = new_elem + ' <span class="email">' + elem.fields.email + '</span>';
new_elem = new_elem + '</a></li>'
$(new_elem).appendTo(search_result_ul);
});
}
);
return false;
});
});

View File

@ -0,0 +1,11 @@
{% load i18n %}
<div class="usersearch">
<input type="text" autocomplete="off" placeholder="{% trans 'Name, email, etc.' %}" data-autocomplete-json="{% url 'combo-ajax-usersearch' %}" name="q" />
<ul class="result"></ul>
{% if selected_user %}
<div class="selected-user">
Selected user is: {{ selected_user.first_name }} {{ selected_user.last_name }}
<span class="email">{{ selected_user.email }}</span>
</div>
{% endif %}
</div>

View File

@ -0,0 +1,25 @@
# combo - content management system
# Copyright (C) 2014-2016 Entr'ouvert
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from django.conf.urls import patterns, url
from .views import ajax_usersearch
urlpatterns = patterns(
'',
url(r'^ajax/usersearch/$',
ajax_usersearch, name='combo-ajax-usersearch'),
)

View File

@ -0,0 +1,50 @@
# combo - content management system
# Copyright (C) 2014-2016 Entr'ouvert
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import json
from django.http import HttpResponse
from django.contrib.auth.models import User
from django.db.models import Q
from django.core import serializers
from django.core.exceptions import PermissionDenied
from .models import UserSearchCell
def ajax_usersearch(request):
# allow access if the user can see at least one UserSearch cell
for cell in UserSearchCell.objects.all():
if cell.is_visible(request.user) and cell.page.is_visible(request.user):
break
else:
raise PermissionDenied
query = request.GET.get('q')
if query:
users = User.objects.all()
# pseudo full-text search
for elem in query.split():
users = users.filter(Q(username__icontains=elem)
|Q(first_name__icontains=elem)
|Q(last_name__icontains=elem)
|Q(email__icontains=elem))
users = json.loads(serializers.serialize(
'json', users[:10], fields=('username', 'first_name', 'last_name', 'email')))
else:
users = []
response = HttpResponse(content_type='application/json')
json.dump(users, response, indent=2)
return response

View File

@ -397,7 +397,8 @@ class CellBase(models.Model):
return self.user_dependant
def get_concerned_user(self, context):
return getattr(context.get('request'), 'user', None)
'''Return user from UserSearch cell, or connected user.'''
return context.get('selected_user') or getattr(context.get('request'), 'user', None)
def get_cell_extra_context(self, context):
return {'cell': self}

View File

@ -68,6 +68,7 @@ INSTALLED_APPS = (
'combo.apps.lingo',
'combo.apps.newsletters',
'combo.apps.fargo',
'combo.apps.usersearch',
'xstatic.pkg.chartnew_js',
)