mirror of
https://github.com/Hopiu/wagtail.git
synced 2026-05-12 09:13:14 +00:00
resolving conflicts
This commit is contained in:
commit
45f209c266
31 changed files with 395 additions and 595 deletions
|
|
@ -15,11 +15,13 @@ Wagtail is a Django content management system built originally for the `Royal Co
|
|||
* Fast out of the box. `Varnish <https://www.varnish-cache.org/>`_-friendly if you need it
|
||||
* Tests! But not enough; we're working hard to improve this
|
||||
|
||||
Find out more at `wagtail.io <http://wagtail.io/>`_.
|
||||
Find out more at `wagtail.io <http://wagtail.io/>`_.
|
||||
|
||||
Got a question? Ask it on our `Google Group <https://groups.google.com/forum/#!forum/wagtail>`_.
|
||||
|
||||
Getting started
|
||||
~~~~~~~~~~~~~~~
|
||||
To get you up and running quickly, we've provided a demonstration site with all the configuration in place, at `github.com/torchbox/wagtaildemo <https://github.com/torchbox/wagtaildemo/>`_; see the `README <https://github.com/torchbox/wagtaildemo/blob/master/README.md>`_ for installation instructions.
|
||||
To get you up and running quickly, we've provided a demonstration site with all the configuration in place, at `github.com/torchbox/wagtaildemo <https://github.com/torchbox/wagtaildemo/>`_; see the `README <https://github.com/torchbox/wagtaildemo/blob/master/README.md>`_ for installation instructions. `Serafeim Papastefanos <https://github.com/spapas>`_ has written a `tutorial <http://spapas.github.io/2014/02/13/wagtail-tutorial/>`_ with all the steps to build a simple Wagtail site from scratch.
|
||||
|
||||
Contributing
|
||||
~~~~~~~~~~~~
|
||||
|
|
|
|||
1
setup.py
1
setup.py
|
|
@ -48,6 +48,7 @@ setup(
|
|||
"beautifulsoup4>=4.3.2",
|
||||
"lxml>=3.3.0",
|
||||
"BeautifulSoup==3.2.1", # django-compressor gets confused if we have lxml but not BS3 installed
|
||||
"requests==2.2.1",
|
||||
],
|
||||
zip_safe=False,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -106,4 +106,29 @@ $(function(){
|
|||
$('#menu-search').bind('focus click', function(){
|
||||
$(this).addClass('focussed');
|
||||
});
|
||||
|
||||
/* Header search behaviour */
|
||||
var search_current_index = 0;
|
||||
var search_next_index = 0;
|
||||
|
||||
$(window.headerSearch.termInput).on('input', function() {
|
||||
clearTimeout($.data(this, 'timer'));
|
||||
var wait = setTimeout(search, 200);
|
||||
$(this).data('timer', wait);
|
||||
});
|
||||
|
||||
function search () {
|
||||
search_next_index++;
|
||||
var index = search_next_index;
|
||||
$.ajax({
|
||||
url: window.headerSearch.url,
|
||||
data: {q: $(window.headerSearch.termInput).val()},
|
||||
success: function(data, status) {
|
||||
if (index > search_current_index) {
|
||||
search_current_index = index;
|
||||
$(window.headerSearch.targetOutput).html(data);
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
});
|
||||
|
|
|
|||
|
|
@ -378,6 +378,7 @@ li.focused > .help{
|
|||
color:$color-red;
|
||||
clear:both;
|
||||
}
|
||||
|
||||
.error input, .error textarea, .error select, .error .tagit{
|
||||
border-color:$color-red;
|
||||
background-color:$color-input-error-bg;
|
||||
|
|
@ -562,7 +563,7 @@ ul.inline li:first-child, li.inline:first-child{
|
|||
}
|
||||
|
||||
|
||||
/* search bars (search integrated into header area) */
|
||||
/* search bars (search integrated into header area) */
|
||||
.search-bar{
|
||||
margin-top:-2em;
|
||||
padding-top:1em;
|
||||
|
|
|
|||
|
|
@ -156,6 +156,7 @@ form{
|
|||
|
||||
&:before {
|
||||
content: '';
|
||||
width:0px;
|
||||
display: inline-block;
|
||||
height: 100%;
|
||||
vertical-align: middle;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
modal.ajaxifyForm($('form.search-bar', modal.body));
|
||||
|
||||
var searchUrl = $('form.search-bar', modal.body).attr('action');
|
||||
|
||||
function search() {
|
||||
$.ajax({
|
||||
url: searchUrl,
|
||||
|
|
@ -12,6 +13,7 @@ function search() {
|
|||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
$('#id_q', modal.body).on('input', function() {
|
||||
clearTimeout($.data(this, 'timer'));
|
||||
var wait = setTimeout(search, 200);
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@
|
|||
<script src="{{ STATIC_URL }}admin/js/urlify.js"></script>
|
||||
{% endcompress %}
|
||||
|
||||
<script type='text/javascript'>
|
||||
<script>
|
||||
window.chooserUrls = {
|
||||
'documentChooser': '{% url "wagtaildocs_chooser" %}',
|
||||
'imageChooser': '{% url "wagtailimages_chooser" %}',
|
||||
|
|
@ -39,9 +39,7 @@
|
|||
'pageChooser': '{% url "wagtailadmin_choose_page" %}',
|
||||
'snippetChooser': '{% url "wagtailsnippets_choose_generic" %}'
|
||||
};
|
||||
</script>
|
||||
|
||||
<script>
|
||||
(function() {
|
||||
function fixPrefix(str) {return str;}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,35 +3,11 @@
|
|||
{% block bodyclass %}menu-search{% endblock %}
|
||||
{% block extra_js %}
|
||||
<script>
|
||||
$('#id_q').on('input', function() {
|
||||
clearTimeout($.data(this, 'timer'));
|
||||
var wait = setTimeout(search, 200);
|
||||
$(this).data('timer', wait);
|
||||
});
|
||||
$('a.suggested-tag').click(function() {
|
||||
$('#id_q').val($(this).text());
|
||||
search();
|
||||
return false;
|
||||
})
|
||||
|
||||
// These variables keep track of ajax requests to prevent an older request from replacing a new one
|
||||
var search_current_index = 0;
|
||||
var search_next_index = 0;
|
||||
|
||||
function search () {
|
||||
search_next_index++;
|
||||
var index = search_next_index;
|
||||
$.ajax({
|
||||
url: "{%url 'wagtailadmin_pages_search' %}",
|
||||
data: {q: $('#id_q').val()},
|
||||
success: function(data, status) {
|
||||
if (index > search_current_index) {
|
||||
search_current_index = index;
|
||||
$('#page-results').html(data);
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
window.headerSearch = {
|
||||
url: "{% url 'wagtailadmin_pages_search' %}",
|
||||
termInput: "#id_q",
|
||||
targetOutput: "#page-results"
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
<li><a href="{% url 'wagtailadmin_pages_select_type' %}" class="icon teal icon-plus-inverse">New page</a></li>
|
||||
{% endcomment %}
|
||||
<li class="footer">
|
||||
<div class="avatar icon icon-user"><a href="{% url 'wagtailadmin_account' %}" title="Account settings">{% if request.user.email %}<img src="{% gravatar_url request.user.email %}" />{% else %}Account{% endif %}</a></div>
|
||||
<div class="avatar icon icon-user"><a href="{% url 'wagtailadmin_account' %}" title="Account settings">{% if request.user.email %}<img src="{% gravatar_url request.user.email %}" />{% endif %}</a></div>
|
||||
<a href="{% url 'django.contrib.auth.views.logout' %}">Log out</a>
|
||||
</li>
|
||||
{% if request.user.is_superuser %} {# for now, 'More' links will be superuser-only #}
|
||||
|
|
|
|||
|
|
@ -6,13 +6,6 @@ from wagtail.wagtailadmin.forms import LoginForm, PasswordResetForm
|
|||
|
||||
urlpatterns = patterns(
|
||||
'django.contrib.auth.views',
|
||||
url(
|
||||
r'^login/$', 'login', {
|
||||
'template_name': 'wagtailadmin/login.html',
|
||||
'authentication_form': LoginForm,
|
||||
'extra_context': {'show_password_reset': getattr(settings, 'WAGTAIL_PASSWORD_MANAGEMENT_ENABLED', True)},
|
||||
} , name='wagtailadmin_login'
|
||||
),
|
||||
url(r'^logout/$', 'logout', {'next_page': 'wagtailadmin_login'}),
|
||||
|
||||
# Password reset
|
||||
|
|
@ -79,4 +72,11 @@ urlpatterns += patterns(
|
|||
|
||||
url(r'^account/$', 'account.account', name='wagtailadmin_account'),
|
||||
url(r'^account/change_password/$', 'account.change_password', name='wagtailadmin_account_change_password'),
|
||||
)
|
||||
url(
|
||||
r'^login/$', 'account.login_wrapper', {
|
||||
'template_name': 'wagtailadmin/login.html',
|
||||
'authentication_form': LoginForm,
|
||||
'extra_context': {'show_password_reset': getattr(settings, 'WAGTAIL_PASSWORD_MANAGEMENT_ENABLED', True)},
|
||||
} , name='wagtailadmin_login'
|
||||
),
|
||||
)
|
||||
|
|
@ -2,6 +2,7 @@ from django.conf import settings
|
|||
from django.shortcuts import render, redirect
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.forms import SetPasswordForm
|
||||
from django.contrib.auth.views import login
|
||||
|
||||
|
||||
def account(request):
|
||||
|
|
@ -31,3 +32,10 @@ def change_password(request):
|
|||
'form': form,
|
||||
'can_change_password': can_change_password,
|
||||
})
|
||||
|
||||
# Wrap login view to prevent logged in users accessing the page
|
||||
def login_wrapper(request, **kwargs):
|
||||
if request.user.is_authenticated():
|
||||
return redirect(settings.LOGIN_REDIRECT_URL)
|
||||
else:
|
||||
return login(request, **kwargs)
|
||||
|
|
@ -3,34 +3,11 @@
|
|||
{% block bodyclass %}menu-documents{% endblock %}
|
||||
{% block extra_js %}
|
||||
<script>
|
||||
$('#id_q').on('input', function() {
|
||||
clearTimeout($.data(this, 'timer'));
|
||||
var wait = setTimeout(search, 200);
|
||||
$(this).data('timer', wait);
|
||||
});
|
||||
// $('a.suggested-tag').click(function() {
|
||||
// $('#id_q').val($(this).text());
|
||||
// search();
|
||||
// return false;
|
||||
// })
|
||||
|
||||
var search_current_index = 0;
|
||||
var search_next_index = 0;
|
||||
|
||||
function search () {
|
||||
search_next_index++;
|
||||
var index = search_next_index;
|
||||
$.ajax({
|
||||
url: "{% url 'wagtaildocs_index' %}",
|
||||
data: {q: $('#id_q').val()},
|
||||
success: function(data, status) {
|
||||
if (index > search_current_index) {
|
||||
search_current_index = index;
|
||||
$('#document-results').html(data);
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
window.headerSearch = {
|
||||
url: "{% url 'wagtaildocs_index' %}",
|
||||
termInput: "#id_q",
|
||||
targetOutput: "#document-results"
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
from .models import Embed
|
||||
from .embeds.embed import get_embed
|
||||
from .embeds import get_embed
|
||||
|
|
|
|||
|
|
@ -1,29 +1,53 @@
|
|||
from datetime import datetime
|
||||
|
||||
|
||||
import sys
|
||||
from importlib import import_module
|
||||
import requests
|
||||
from django.conf import settings
|
||||
|
||||
from .models import Embed
|
||||
|
||||
import os
|
||||
module_dir = os.path.dirname(__file__) # get current directory
|
||||
file_path = os.path.join(module_dir, 'endpoints.json')
|
||||
print file_path
|
||||
print open(file_path).read()
|
||||
from datetime import datetime
|
||||
from django.utils import six
|
||||
from wagtail.wagtailembeds.oembed_providers import get_oembed_provider
|
||||
from wagtail.wagtailembeds.models import Embed
|
||||
|
||||
|
||||
def get_embed_embedly(url, max_width=None):
|
||||
# Check database
|
||||
class EmbedNotFoundException(Exception): pass
|
||||
|
||||
class EmbedlyException(Exception): pass
|
||||
class AccessDeniedEmbedlyException(EmbedlyException): pass
|
||||
|
||||
|
||||
# Pinched from django 1.7 source code.
|
||||
# TODO: Replace this with "from django.utils.module_loading import import_string" when django 1.7 is released
|
||||
def import_string(dotted_path):
|
||||
"""
|
||||
Import a dotted module path and return the attribute/class designated by the
|
||||
last name in the path. Raise ImportError if the import failed.
|
||||
"""
|
||||
try:
|
||||
return Embed.objects.get(url=url, max_width=max_width)
|
||||
except Embed.DoesNotExist:
|
||||
pass
|
||||
module_path, class_name = dotted_path.rsplit('.', 1)
|
||||
except ValueError:
|
||||
msg = "%s doesn't look like a module path" % dotted_path
|
||||
six.reraise(ImportError, ImportError(msg), sys.exc_info()[2])
|
||||
|
||||
module = import_module(module_path)
|
||||
|
||||
try:
|
||||
# Call embedly API
|
||||
client = Embedly(key=settings.EMBEDLY_KEY)
|
||||
return getattr(module, class_name)
|
||||
except AttributeError:
|
||||
return None
|
||||
msg = 'Module "%s" does not define a "%s" attribute/class' % (
|
||||
dotted_path, class_name)
|
||||
six.reraise(ImportError, ImportError(msg), sys.exc_info()[2])
|
||||
|
||||
|
||||
def embedly(url, max_width=None, key=None):
|
||||
from embedly import Embedly
|
||||
|
||||
# Get embedly key
|
||||
if key is None:
|
||||
key = settings.EMBEDLY_KEY
|
||||
|
||||
# Get embedly client
|
||||
client = Embedly(key=settings.EMBEDLY_KEY)
|
||||
|
||||
# Call embedly
|
||||
if max_width is not None:
|
||||
oembed = client.oembed(url, maxwidth=max_width, better=False)
|
||||
else:
|
||||
|
|
@ -31,45 +55,98 @@ def get_embed_embedly(url, max_width=None):
|
|||
|
||||
# Check for error
|
||||
if oembed.get('error'):
|
||||
return None
|
||||
|
||||
# Save result to database
|
||||
row, created = Embed.objects.get_or_create(
|
||||
url=url,
|
||||
max_width=max_width,
|
||||
defaults={
|
||||
'type': oembed['type'],
|
||||
'title': oembed['title'],
|
||||
'thumbnail_url': oembed.get('thumbnail_url'),
|
||||
'width': oembed.get('width'),
|
||||
'height': oembed.get('height')
|
||||
}
|
||||
)
|
||||
if oembed['error_code'] in [401, 403]:
|
||||
raise AccessDeniedEmbedlyException
|
||||
elif oembed['error_code'] == 404:
|
||||
raise EmbedNotFoundException
|
||||
else:
|
||||
raise EmbedlyException
|
||||
|
||||
# Convert photos into HTML
|
||||
if oembed['type'] == 'photo':
|
||||
html = '<img src="%s" />' % (oembed['url'], )
|
||||
else:
|
||||
html = oembed.get('html')
|
||||
|
||||
if html:
|
||||
row.html = html
|
||||
row.last_updated = datetime.now()
|
||||
row.save()
|
||||
# Return embed as a dict
|
||||
return {
|
||||
'title': oembed['title'],
|
||||
'type': oembed['type'],
|
||||
'thumbnail_url': oembed.get('thumbnail_url'),
|
||||
'width': oembed.get('width'),
|
||||
'height': oembed.get('height'),
|
||||
'html': html,
|
||||
}
|
||||
|
||||
# Return new embed
|
||||
return row
|
||||
|
||||
def get_embed_oembed(url, max_width=None):
|
||||
pass
|
||||
|
||||
get_embed = get_embed_oembed
|
||||
try:
|
||||
from embedly import Embedly
|
||||
if hasattr(settings,'EMBEDLY_KEY'):
|
||||
get_embed = get_embed_embedly
|
||||
except:
|
||||
pass
|
||||
|
||||
print get_embed
|
||||
def oembed(url, max_width=None):
|
||||
# Find provider
|
||||
provider = get_oembed_provider(url)
|
||||
if provider is None:
|
||||
raise EmbedNotFoundException
|
||||
|
||||
|
||||
# Work out params
|
||||
params = {'url': url, 'format': 'json', }
|
||||
if max_width:
|
||||
params['maxwidth'] = max_width
|
||||
|
||||
# Perform request
|
||||
r = requests.get(provider, params=params)
|
||||
if r.status_code != 200:
|
||||
raise EmbedNotFoundException
|
||||
oembed = r.json()
|
||||
|
||||
# Convert photos into HTML
|
||||
if oembed['type'] == 'photo':
|
||||
html = '<img src="%s" />' % (oembed['url'], )
|
||||
else:
|
||||
html = oembed.get('html')
|
||||
|
||||
# Return embed as a dict
|
||||
return {
|
||||
'title': oembed['title'],
|
||||
'type': oembed['type'],
|
||||
'thumbnail_url': oembed.get('thumbnail_url'),
|
||||
'width': oembed.get('width'),
|
||||
'height': oembed.get('height'),
|
||||
'html': html,
|
||||
}
|
||||
|
||||
|
||||
def get_default_finder():
|
||||
# Check if the user has set the embed finder manually
|
||||
if hasattr(settings, 'WAGTAILEMBEDS_EMBED_FINDER'):
|
||||
return import_string(settings.WAGTAILEMBEDS_EMBED_FINDER)
|
||||
|
||||
# Use embedly if the embedly key is set
|
||||
if hasattr(settings, 'EMBEDLY_KEY'):
|
||||
return embedly
|
||||
|
||||
# Fall back to oembed
|
||||
return oembed
|
||||
|
||||
|
||||
def get_embed(url, max_width=None, finder=None):
|
||||
# Check database
|
||||
try:
|
||||
return Embed.objects.get(url=url, max_width=max_width)
|
||||
except Embed.DoesNotExist:
|
||||
pass
|
||||
|
||||
# Get/Call finder
|
||||
if not finder:
|
||||
finder = get_default_finder()
|
||||
embed_dict = finder(url, max_width)
|
||||
|
||||
# Create database record
|
||||
embed, created = Embed.objects.get_or_create(
|
||||
url=url,
|
||||
max_width=max_width,
|
||||
defaults=embed_dict,
|
||||
)
|
||||
|
||||
# Save
|
||||
embed.last_updated = datetime.now()
|
||||
embed.save()
|
||||
|
||||
return embed
|
||||
|
|
|
|||
|
|
@ -1,80 +0,0 @@
|
|||
from datetime import datetime
|
||||
from django.conf import settings
|
||||
from ..models import Embed
|
||||
import oembed_api
|
||||
|
||||
class EmbedlyException(Exception): pass
|
||||
class AccessDeniedEmbedlyException(Exception): pass
|
||||
class NotFoundEmbedlyException(Exception): pass
|
||||
|
||||
def get_embed_embedly(url, max_width=None):
|
||||
# Check database
|
||||
try:
|
||||
return Embed.objects.get(url=url, max_width=max_width)
|
||||
except Embed.DoesNotExist:
|
||||
pass
|
||||
|
||||
client = Embedly(key=settings.EMBEDLY_KEY)
|
||||
|
||||
if max_width is not None:
|
||||
oembed = client.oembed(url, maxwidth=max_width, better=False)
|
||||
else:
|
||||
oembed = client.oembed(url, better=False)
|
||||
|
||||
# Check for error
|
||||
if oembed.get('error'):
|
||||
if oembed['error_code'] in [401,403]:
|
||||
raise AccessDeniedEmbedlyException
|
||||
elif oembed['error_code'] == 404:
|
||||
raise NotFoundEmbedlyException
|
||||
else:
|
||||
raise EmbedlyException
|
||||
|
||||
return save_embed(url, max_width, oembed)
|
||||
|
||||
|
||||
def get_embed_oembed(url, max_width=None):
|
||||
# Check database
|
||||
try:
|
||||
return Embed.objects.get(url=url, max_width=max_width)
|
||||
except Embed.DoesNotExist:
|
||||
pass
|
||||
|
||||
oembed = oembed_api.get_embed_oembed(url, max_width)
|
||||
return save_embed(url, max_width, oembed)
|
||||
|
||||
|
||||
def save_embed(url, max_width, oembed):
|
||||
row, created = Embed.objects.get_or_create(
|
||||
url=url,
|
||||
max_width=max_width,
|
||||
defaults={
|
||||
'type': oembed['type'],
|
||||
'title': oembed['title'],
|
||||
'thumbnail_url': oembed.get('thumbnail_url'),
|
||||
'width': oembed.get('width'),
|
||||
'height': oembed.get('height')
|
||||
}
|
||||
)
|
||||
|
||||
if oembed['type'] == 'photo':
|
||||
html = '<img src="%s" />' % (oembed['url'], )
|
||||
else:
|
||||
html = oembed.get('html')
|
||||
|
||||
if html:
|
||||
row.html = html
|
||||
row.last_updated = datetime.now()
|
||||
row.save()
|
||||
|
||||
return row
|
||||
|
||||
# As a default use oembed
|
||||
get_embed = get_embed_oembed
|
||||
try:
|
||||
from embedly import Embedly
|
||||
# if EMBEDLY_KEY is set and embedly library found the use embedly
|
||||
if hasattr(settings,'EMBEDLY_KEY'):
|
||||
get_embed = get_embed_embedly
|
||||
except:
|
||||
pass
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
import os, re
|
||||
import urllib2, urllib
|
||||
from datetime import datetime
|
||||
import json
|
||||
|
||||
class NotImplementedOembedException(Exception):
|
||||
pass
|
||||
|
||||
ENDPOINTS = {}
|
||||
|
||||
def get_embed_oembed(url, max_width=None):
|
||||
provider = None
|
||||
for endpoint in ENDPOINTS.keys():
|
||||
for pattern in ENDPOINTS[endpoint]:
|
||||
if re.match(pattern, url):
|
||||
provider = endpoint
|
||||
break
|
||||
if not provider:
|
||||
raise NotImplementedOembedException
|
||||
params = {'url': url, 'format': 'json', }
|
||||
if max_width:
|
||||
params['maxwidth'] = max_width
|
||||
req = provider+'?' +urllib.urlencode(params)
|
||||
request = urllib2.Request(req)
|
||||
opener = urllib2.build_opener()
|
||||
# Some provicers were not working without a user agent
|
||||
request.add_header('User-Agent','Mozilla/5.0')
|
||||
return json.loads(opener.open(request).read())
|
||||
|
||||
|
||||
# Uses the public domain collection of oembed endpoints by Mathias Panzenbpeck (panzi)
|
||||
# at https://github.com/panzi/oembedendpoints/blob/master/endpoints-regexp.json
|
||||
|
||||
def load_oembed_endpoints():
|
||||
module_dir = os.path.dirname(__file__)
|
||||
endpoints_path = os.path.join(module_dir, 'endpoints.json')
|
||||
with open( endpoints_path) as f:
|
||||
endpoints = json.loads(f.read())
|
||||
|
||||
for endpoint in endpoints.keys():
|
||||
endpoint_key = endpoint.replace('{format}', 'json')
|
||||
|
||||
ENDPOINTS[endpoint_key]=[]
|
||||
for pattern in endpoints[endpoint]:
|
||||
ENDPOINTS[endpoint_key].append(re.compile(pattern))
|
||||
|
||||
|
||||
|
||||
load_oembed_endpoints()
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
import unittest
|
||||
import oembed
|
||||
|
||||
# Test that a bunch of oembed examples is working
|
||||
# If any of these is removed or changed then the unit test will fail
|
||||
# This is a unittest TestCase (and not a django.test one) since django
|
||||
# database is not actually needed for these tests
|
||||
|
||||
TEST_DATA = [
|
||||
{
|
||||
'url':'http://www.youtube.com/watch?v=S3xAeTmsJfg',
|
||||
'title':'Animation: Ferret dance (A series of tubes)'
|
||||
},
|
||||
{
|
||||
'url':'http://vimeo.com/86036070',
|
||||
'title':'Wagtail: A new Django CMS'
|
||||
},
|
||||
{
|
||||
'url':'https://speakerdeck.com/harmstyler/an-introduction-to-django',
|
||||
'title':'An Introduction to Django'
|
||||
},
|
||||
{
|
||||
'url':'https://ifttt.com/recipes/144705-new-twitter-followers-in-a-google-spreadsheet',
|
||||
'title':'New Twitter followers in a Google spreadsheet'
|
||||
},
|
||||
{
|
||||
'url':'http://www.hulu.com/watch/20807/late-night-with-conan-obrien-wed-may-21-2008',
|
||||
'title':'Wed, May 21, 2008 (Late Night With Conan O\'Brien)'
|
||||
},
|
||||
{
|
||||
'url':'http://www.flickr.com/photos/dfluke/5995957175/',
|
||||
'title':'Django pony!?'
|
||||
},
|
||||
{
|
||||
'url':'http://www.slideshare.net/simon/the-django-web-application-framework',
|
||||
'title':'The Django Web Application Framework'
|
||||
},
|
||||
{
|
||||
'url':'http://www.rdio.com/artist/The_Black_Keys/album/Brothers/',
|
||||
'title':'Brothers'
|
||||
},
|
||||
{
|
||||
'url':'http://instagram.com/p/kFKCcEKmBq/',
|
||||
'title':'Family holidays in #Greece!'
|
||||
},
|
||||
{
|
||||
'url':'https://www.kickstarter.com/projects/noujaimfilms/the-square-a-film-about-the-egyptian-revolution',
|
||||
'title':'Sundance Award Winning Film on the Egyptian Revolution'
|
||||
},
|
||||
{
|
||||
'url':'http://www.dailymotion.com/video/xoxulz_babysitter_animals',
|
||||
'title':'Babysitter!'
|
||||
}
|
||||
]
|
||||
|
||||
class TestEmbeds(unittest.TestCase):
|
||||
def test_get_embed_oembed(self):
|
||||
for td in TEST_DATA:
|
||||
embed = oembed.get_embed_oembed_low(td['url'])
|
||||
self.assertEqual(embed['title'], td['title'] )
|
||||
self.assertIsNotNone(embed['type'] )
|
||||
self.assertIsNotNone(embed['width'] )
|
||||
self.assertIsNotNone(embed['height'] )
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
@ -1,114 +0,0 @@
|
|||
[
|
||||
{
|
||||
"url": "http://*.blip.tv/*",
|
||||
"url_re": "blip\\.tv/.+",
|
||||
"example_url": "http://pycon.blip.tv/file/2058801/",
|
||||
"endpoint_url": "http://blip.tv/oembed/",
|
||||
"title": "blip.tv"
|
||||
},
|
||||
{
|
||||
"url": "http://*.dailymotion.com/*",
|
||||
"url_re": "dailymotion\\.com/.+",
|
||||
"example_url": "http://www.dailymotion.com/video/x5ioet_phoenix-mars-lander_tech",
|
||||
"endpoint_url": "http://www.dailymotion.com/api/oembed/",
|
||||
"title": "Dailymotion"
|
||||
},
|
||||
{
|
||||
"url": "http://*.flickr.com/photos/*",
|
||||
"url_re": "flickr\\.com/photos/[-.\\w@]+/\\d+/?",
|
||||
"example_url": "http://www.flickr.com/photos/fuffer2005/2435339994/",
|
||||
"endpoint_url": "http://www.flickr.com/services/oembed/",
|
||||
"title": "Flickr Photos"
|
||||
},
|
||||
{
|
||||
"url": "http://www.hulu.com/watch/*",
|
||||
"url_re": "hulu\\.com/watch/.*",
|
||||
"example_url": "http://www.hulu.com/watch/20807/late-night-with-conan",
|
||||
"endpoint_url": "http://www.hulu.com/api/oembed.json",
|
||||
"title": "Hulu"
|
||||
},
|
||||
{
|
||||
"url": "http://*.nfb.ca/film/*",
|
||||
"url_re": "nfb\\.ca/film/[-\\w]+/?",
|
||||
"example_url": "http://www.nfb.ca/film/blackfly/",
|
||||
"endpoint_url": "http://www.nfb.ca/remote/services/oembed/",
|
||||
"title": "National Film Board of Canada"
|
||||
},
|
||||
{
|
||||
"url": "http://qik.com/*",
|
||||
"url_re": "qik\\.com/\\w+",
|
||||
"example_url": "http://qik.com/video/86776",
|
||||
"endpoint_url": "http://qik.com/api/oembed.json",
|
||||
"title": "Qik Video"
|
||||
},
|
||||
{
|
||||
"url": "http://*.revision3.com/*",
|
||||
"url_re": "revision3\\.com/.+",
|
||||
"example_url": "http://revision3.com/diggnation/2008-04-17xsanned/",
|
||||
"endpoint_url": "http://revision3.com/api/oembed/",
|
||||
"title": "Revision3"
|
||||
},
|
||||
{
|
||||
"url": "http://*.scribd.com/*",
|
||||
"url_re": "scribd\\.com/.+",
|
||||
"example_url": "http://www.scribd.com/doc/17896323/Indian-Automobile-industryPEST",
|
||||
"endpoint_url": "http://www.scribd.com/services/oembed",
|
||||
"title": "Scribd"
|
||||
},
|
||||
{
|
||||
"url": "http://*.viddler.com/explore/*",
|
||||
"url_re": "viddler\\.com/explore/.*/videos/\\w+/?",
|
||||
"example_url": "http://www.viddler.com/explore/engadget/videos/14/",
|
||||
"endpoint_url": "http://lab.viddler.com/services/oembed/",
|
||||
"title": "Viddler Video"
|
||||
},
|
||||
{
|
||||
"url": "http://www.vimeo.com/* and http://www.vimeo.com/groups/*/videos/*",
|
||||
"url_re": "vimeo\\.com/.*",
|
||||
"example_url": "http://www.vimeo.com/1211060",
|
||||
"endpoint_url": "http://www.vimeo.com/api/oembed.json",
|
||||
"title": "Vimeo"
|
||||
},
|
||||
{
|
||||
"url": "http://*.youtube.com/watch*",
|
||||
"url_re": "youtube\\.com/watch.+v=[\\w-]+&?",
|
||||
"example_url": "http://www.youtube.com/watch?v=vk1HvP7NO5w",
|
||||
"endpoint_url": "http://www.youtube.com/oembed",
|
||||
"title": "YouTube"
|
||||
},
|
||||
{
|
||||
"url": "http://dotsub.com/view/*",
|
||||
"url_re": "dotsub\\.com/view/[-\\da-zA-Z]+$",
|
||||
"example_url": "http://dotsub.com/view/10e3cb5e-96c7-4cfb-bcea-8ab11e04e090",
|
||||
"endpoint_url": "http://dotsub.com/services/oembed",
|
||||
"title": "dotSUB.com"
|
||||
},
|
||||
{
|
||||
"url": "http://yfrog.(com|ru|com.tr|it|fr|co.il|co.uk|com.pl|pl|eu|us)/*",
|
||||
"url_re": "yfrog\\.(com|ru|com\\.tr|it|fr|co\\.il|co\\.uk|com\\.pl|pl|eu|us)/[a-zA-Z0-9]+$",
|
||||
"example_url": "http://yfrog.com/0wgvcpj",
|
||||
"endpoint_url": "http://www.yfrog.com/api/oembed",
|
||||
"title": "YFrog"
|
||||
},
|
||||
{
|
||||
"url": "http://*.clikthrough.com/theater/video/*",
|
||||
"url_re": "clikthrough\\.com/theater/video/\\d+$",
|
||||
"example_url": "http://www.clikthrough.com/theater/video/55",
|
||||
"endpoint_url": "http://clikthrough.com/services/oembed",
|
||||
"title": "Clikthrough"
|
||||
},
|
||||
{
|
||||
"url": "http://*.kinomap.com/*",
|
||||
"url_re": "kinomap\\.com/.+",
|
||||
"example_url": "http://www.kinomap.com/kms-vzkpc7",
|
||||
"endpoint_url": "http://www.kinomap.com/oembed",
|
||||
"title": "Kinomap"
|
||||
},
|
||||
{
|
||||
"url": "http://*.photobucket.com/albums/*|http://*.photobucket.com/groups/*",
|
||||
"url_re": "photobucket\\.com/(albums|groups)/.+$",
|
||||
"example_url": "http://img.photobucket.com/albums/v211/JAV123/Michael%20Holland%20Candle%20Burning/_MG_5661.jpg",
|
||||
"endpoint_url": "http://photobucket.com/oembed",
|
||||
"title": "Photobucket"
|
||||
}
|
||||
]
|
||||
|
|
@ -2,7 +2,7 @@ from __future__ import division # Use true division
|
|||
|
||||
from django.utils.html import escape
|
||||
|
||||
from .embeds.embed import get_embed
|
||||
from wagtail.wagtailembeds import get_embed
|
||||
|
||||
|
||||
def embed_to_frontend_html(url):
|
||||
|
|
@ -24,8 +24,8 @@ def embed_to_frontend_html(url):
|
|||
|
||||
|
||||
def embed_to_editor_html(url):
|
||||
# Check that the embed exists
|
||||
embed = get_embed(url)
|
||||
if embed is None:
|
||||
return ''
|
||||
return
|
||||
|
||||
return '<div class="embed-placeholder" contenteditable="false" data-embedtype="media" data-url="%s"><h3>%s</h3><p>%s</p><img src="%s"></div>' % (url, escape(embed.title), url, embed.thumbnail_url)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
{
|
||||
OEMBED_ENDPOINTS = {
|
||||
"https://speakerdeck.com/oembed.{format}": [
|
||||
"^http(?:s)?://speakerdeck\\.com/.+$"
|
||||
],
|
||||
|
|
@ -292,4 +292,30 @@
|
|||
"http://www.ifttt.com/oembed/": [
|
||||
"^http(?:s)?://ifttt\\.com/recipes/.+$"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Compile endpoints into regular expression objects
|
||||
import re
|
||||
|
||||
def compile_endpoints():
|
||||
endpoints = {}
|
||||
for endpoint in OEMBED_ENDPOINTS.keys():
|
||||
endpoint_key = endpoint.replace('{format}', 'json')
|
||||
|
||||
endpoints[endpoint_key] = []
|
||||
for pattern in OEMBED_ENDPOINTS[endpoint]:
|
||||
endpoints[endpoint_key].append(re.compile(pattern))
|
||||
|
||||
return endpoints
|
||||
|
||||
OEMBED_ENDPOINTS_COMPILED = compile_endpoints()
|
||||
|
||||
|
||||
def get_oembed_provider(url):
|
||||
for endpoint in OEMBED_ENDPOINTS_COMPILED.keys():
|
||||
for pattern in OEMBED_ENDPOINTS_COMPILED[endpoint]:
|
||||
if re.match(pattern, url):
|
||||
return endpoint
|
||||
|
||||
return
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
from django import template
|
||||
from django.utils.safestring import mark_safe
|
||||
|
||||
from wagtail.wagtailembeds.embeds.embed import get_embed
|
||||
from wagtail.wagtailembeds import get_embed
|
||||
|
||||
|
||||
register = template.Library()
|
||||
|
|
|
|||
|
|
@ -1,13 +1,45 @@
|
|||
from django.test import TestCase
|
||||
|
||||
#from .embeds import get_embed
|
||||
from unittest import skip
|
||||
from wagtail.wagtailembeds import get_embed
|
||||
|
||||
|
||||
class TestEmbeds(TestCase):
|
||||
# FIXME: test currently depends on a valid EMBEDLY_KEY being set - we don't particularly
|
||||
# want to put one in runtests.py. See https://github.com/torchbox/wagtail/issues/26 for
|
||||
# progress on eliminating Embedly as a dependency
|
||||
def DISABLEDtest_get_embed(self):
|
||||
# This test will fail if the video is removed or the title is changed
|
||||
embed = get_embed('http://www.youtube.com/watch?v=S3xAeTmsJfg')
|
||||
self.assertEqual(embed.title, 'Animation: Ferret dance (A series of tubes)')
|
||||
def setUp(self):
|
||||
self.hit_count = 0
|
||||
|
||||
def test_get_embed(self):
|
||||
embed = get_embed('www.test.com/1234', max_width=400, finder=self.dummy_finder)
|
||||
|
||||
# Check that the embed is correct
|
||||
self.assertEqual(embed.title, "Test: www.test.com/1234")
|
||||
self.assertEqual(embed.type, 'video')
|
||||
self.assertEqual(embed.width, 400)
|
||||
|
||||
# Check that there has only been one hit to the backend
|
||||
self.assertEqual(self.hit_count, 1)
|
||||
|
||||
# Look for the same embed again and check the hit count hasn't increased
|
||||
embed = get_embed('www.test.com/1234', max_width=400, finder=self.dummy_finder)
|
||||
self.assertEqual(self.hit_count, 1)
|
||||
|
||||
# Look for a different embed, hit count should increase
|
||||
embed = get_embed('www.test.com/4321', max_width=400, finder=self.dummy_finder)
|
||||
self.assertEqual(self.hit_count, 2)
|
||||
|
||||
# Look for the same embed with a different width, this should also increase hit count
|
||||
embed = get_embed('www.test.com/4321', finder=self.dummy_finder)
|
||||
self.assertEqual(self.hit_count, 3)
|
||||
|
||||
def dummy_finder(self, url, max_width=None):
|
||||
# Up hit count
|
||||
self.hit_count += 1
|
||||
|
||||
# Return a pretend record
|
||||
return {
|
||||
'title': "Test: " + url,
|
||||
'type': 'video',
|
||||
'thumbnail_url': '',
|
||||
'width': max_width if max_width else 640,
|
||||
'height': 480,
|
||||
'html': "<p>Blah blah blah</p>",
|
||||
}
|
||||
|
|
@ -5,8 +5,7 @@ from wagtail.wagtailadmin.modal_workflow import render_modal_workflow
|
|||
from wagtail.wagtailembeds.forms import EmbedForm
|
||||
from wagtail.wagtailembeds.format import embed_to_editor_html
|
||||
|
||||
from wagtail.wagtailembeds.embeds.oembed_api import NotImplementedOembedException
|
||||
from wagtail.wagtailembeds.embeds.embed import EmbedlyException, AccessDeniedEmbedlyException, NotFoundEmbedlyException
|
||||
from wagtail.wagtailembeds.embeds import EmbedNotFoundException, EmbedlyException, AccessDeniedEmbedlyException
|
||||
|
||||
|
||||
|
||||
|
|
@ -23,27 +22,24 @@ def chooser_upload(request):
|
|||
form = EmbedForm(request.POST, request.FILES)
|
||||
|
||||
if form.is_valid():
|
||||
error = None
|
||||
try:
|
||||
embed_html = embed_to_editor_html(form.cleaned_data['url'])
|
||||
print embed_html
|
||||
return render_modal_workflow(
|
||||
request, None, 'wagtailembeds/chooser/embed_chosen.js',
|
||||
{'embed_html': embed_html}
|
||||
)
|
||||
except Exception as e :
|
||||
#print e
|
||||
#import traceback
|
||||
#traceback.print_exc()
|
||||
except AccessDeniedEmbedlyException:
|
||||
error = "There seems to be a problem with your embedly API key. Please check your settings."
|
||||
except EmbedNotFoundException:
|
||||
error = "Cannot find an embed for this URL."
|
||||
except EmbedlyException:
|
||||
error = "There seems to be an error with Embedly while trying to embed this URL. Please try again later."
|
||||
|
||||
if error:
|
||||
errors = form._errors.setdefault('url', ErrorList())
|
||||
if type(e) == NotImplementedOembedException:
|
||||
errors.append("This URL is not supported by an oembed provider. You may try embedding it using Embedly by setting a propery EMBEDLY_KEY in your settings.")
|
||||
elif type(e) == AccessDeniedEmbedlyException:
|
||||
errors.append("There seems to be a problem with your embedly API key. Please check your settings.")
|
||||
elif type(e) == NotFoundEmbedlyException:
|
||||
errors.append("The URL you are trying to embed cannot be found.")
|
||||
elif type(e) == EmbedlyException:
|
||||
errors.append("There seems to be an error with Embedly while trying to embed this URL. Please try again later.")
|
||||
else:
|
||||
errors.append(str(e) )
|
||||
errors.append(error)
|
||||
return render_modal_workflow(request, 'wagtailembeds/chooser/chooser.html', 'wagtailembeds/chooser/chooser.js', {
|
||||
'form': form,
|
||||
})
|
||||
|
|
|
|||
|
|
@ -5,35 +5,11 @@
|
|||
{% block bodyclass %}menu-images{% endblock %}
|
||||
{% block extra_js %}
|
||||
<script>
|
||||
$('#id_q').on('input', function() {
|
||||
clearTimeout($.data(this, 'timer'));
|
||||
var wait = setTimeout(search, 200);
|
||||
$(this).data('timer', wait);
|
||||
});
|
||||
$('a.suggested-tag').click(function() {
|
||||
$('#id_q').val($(this).text());
|
||||
search();
|
||||
return false;
|
||||
})
|
||||
|
||||
// These variables keep track of ajax requests to prevent an older request from replacing a new one
|
||||
var search_current_index = 0;
|
||||
var search_next_index = 0;
|
||||
|
||||
function search () {
|
||||
search_next_index++;
|
||||
var index = search_next_index;
|
||||
$.ajax({
|
||||
url: "{% url 'wagtailimages_index' %}",
|
||||
data: {q: $('#id_q').val()},
|
||||
success: function(data, status) {
|
||||
if (index > search_current_index) {
|
||||
search_current_index = index;
|
||||
$('#image-results').html(data);
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
window.headerSearch = {
|
||||
url: "{% url 'wagtailimages_index' %}",
|
||||
termInput: "#id_q",
|
||||
targetOutput: "#image-results"
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,30 +4,11 @@
|
|||
|
||||
{% block extra_js %}
|
||||
<script>
|
||||
$('#id_q').on('input', function() {
|
||||
clearTimeout($.data(this, 'timer'));
|
||||
var wait = setTimeout(search, 200);
|
||||
$(this).data('timer', wait);
|
||||
});
|
||||
|
||||
var search_current_index = 0;
|
||||
var search_next_index = 0;
|
||||
|
||||
function search () {
|
||||
search_next_index++;
|
||||
var index = search_next_index;
|
||||
$.ajax({
|
||||
url: "{%url 'wagtailredirects_index' %}",
|
||||
data: {q: $('#id_q').val()},
|
||||
success: function(data, status) {
|
||||
console.log('here')
|
||||
if (index > search_current_index) {
|
||||
search_current_index = index;
|
||||
$('#redirects-results').html(data);
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
window.headerSearch = {
|
||||
url: "{% url 'wagtailredirects_index' %}",
|
||||
termInput: "#id_q",
|
||||
targetOutput: "#redirects-results"
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,30 +4,11 @@
|
|||
|
||||
{% block extra_js %}
|
||||
<script>
|
||||
$('#id_q').on('input', function() {
|
||||
clearTimeout($.data(this, 'timer'));
|
||||
var wait = setTimeout(search, 200);
|
||||
$(this).data('timer', wait);
|
||||
});
|
||||
|
||||
var search_current_index = 0;
|
||||
var search_next_index = 0;
|
||||
|
||||
function search () {
|
||||
search_next_index++;
|
||||
var index = search_next_index;
|
||||
$.ajax({
|
||||
url: "{%url 'wagtailsearch_editorspicks_index' %}",
|
||||
data: {q: $('#id_q').val()},
|
||||
success: function(data, status) {
|
||||
console.log('here')
|
||||
if (index > search_current_index) {
|
||||
search_current_index = index;
|
||||
$('#editorspicks-results').html(data);
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
window.headerSearch = {
|
||||
url: "{% url 'wagtailsearch_editorspicks_index' %}",
|
||||
termInput: "#id_q",
|
||||
targetOutput: "#editorspicks-results"
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,51 +2,22 @@
|
|||
{% load gravatar %}
|
||||
{% block titletag %}Users{% endblock %}
|
||||
{% block bodyclass %}menu-users{% endblock %}
|
||||
{% block content %}
|
||||
{% block extra_js %}
|
||||
<script>
|
||||
window.headerSearch = {
|
||||
url: "{% url 'wagtailusers_index' %}",
|
||||
termInput: "#id_q",
|
||||
targetOutput: "#user-results"
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
{% include "wagtailadmin/shared/header.html" with title="Users" add_link="wagtailusers_create" add_text="Add a user" %}
|
||||
{% block content %}
|
||||
{% include "wagtailadmin/shared/header.html" with title="Users" add_link="wagtailusers_create" add_text="Add a user" search_url="wagtailusers_index" %}
|
||||
|
||||
<div class="nice-padding">
|
||||
<table class="listing">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="name">
|
||||
Name
|
||||
{% if ordering == "name" %}
|
||||
<a href="{% url 'wagtailusers_index' %}" class="icon icon-arrow-down-after teal"></a>
|
||||
{% else %}
|
||||
<a href="{% url 'wagtailusers_index' %}?ordering=name" class="icon icon-arrow-down-after"></a>
|
||||
{% endif %}
|
||||
</th>
|
||||
<th class="username">
|
||||
Username
|
||||
{% if ordering == "username" %}
|
||||
<a href="{% url 'wagtailusers_index' %}" class="icon icon-arrow-down-after teal"></a>
|
||||
{% else %}
|
||||
<a href="{% url 'wagtailusers_index' %}?ordering=username" class="icon icon-arrow-down-after"></a>
|
||||
{% endif %}
|
||||
</th>
|
||||
<th class="level">Level</th>
|
||||
<th class="status">Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for user in users %}
|
||||
<tr>
|
||||
<td class="title">
|
||||
<h2>
|
||||
<span class="avatar small icon icon-user"><img src="{% gravatar_url user.email 25 %}" /></span>
|
||||
<a href="{% url 'wagtailusers_edit' user.id %}">{{ user.get_full_name|default:user.username }}</a>
|
||||
</h2>
|
||||
</td>
|
||||
<td class="username">{{ user.username }}</td>
|
||||
<td class="level">{% if user.is_superuser %}Admin{% endif %}</td>
|
||||
<td class="status"><div class="status-tag {% if user.is_active %}primary{% endif %}">{% if user.is_active %}Active{% else %}Inactive{% endif %}</div></td>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
{% include "wagtailadmin/shared/pagination_nav.html" with items=users linkurl="wagtailusers_index" %}
|
||||
<div id="user-results" class="users">
|
||||
{% include "wagtailusers/results.html" %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
|
|||
40
wagtail/wagtailusers/templates/wagtailusers/list.html
Normal file
40
wagtail/wagtailusers/templates/wagtailusers/list.html
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
{% load gravatar %}
|
||||
<table class="listing">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="name">
|
||||
Name
|
||||
{% if ordering == "name" %}
|
||||
<a href="{% url 'wagtailusers_index' %}" class="icon icon-arrow-down-after teal"></a>
|
||||
{% else %}
|
||||
<a href="{% url 'wagtailusers_index' %}?ordering=name" class="icon icon-arrow-down-after"></a>
|
||||
{% endif %}
|
||||
</th>
|
||||
<th class="username">
|
||||
Username
|
||||
{% if ordering == "username" %}
|
||||
<a href="{% url 'wagtailusers_index' %}" class="icon icon-arrow-down-after teal"></a>
|
||||
{% else %}
|
||||
<a href="{% url 'wagtailusers_index' %}?ordering=username" class="icon icon-arrow-down-after"></a>
|
||||
{% endif %}
|
||||
</th>
|
||||
<th class="level">Level</th>
|
||||
<th class="status">Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for user in users %}
|
||||
<tr>
|
||||
<td class="title">
|
||||
<h2>
|
||||
<span class="avatar small icon icon-user"><img src="{% gravatar_url user.email 25 %}" /></span>
|
||||
<a href="{% url 'wagtailusers_edit' user.id %}">{{ user.get_full_name|default:user.username }}</a>
|
||||
</h2>
|
||||
</td>
|
||||
<td class="username">{{ user.username }}</td>
|
||||
<td class="level">{% if user.is_superuser %}Admin{% endif %}</td>
|
||||
<td class="status"><div class="status-tag {% if user.is_active %}primary{% endif %}">{% if user.is_active %}Active{% else %}Inactive{% endif %}</div></td>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
15
wagtail/wagtailusers/templates/wagtailusers/results.html
Normal file
15
wagtail/wagtailusers/templates/wagtailusers/results.html
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
{% if users %}
|
||||
{% if is_searching %}
|
||||
<h2>{{ users|length }} match{{ users|pluralize:"es" }}</h2>
|
||||
{% endif %}
|
||||
|
||||
{% include "wagtailusers/list.html" %}
|
||||
|
||||
{% include "wagtailadmin/shared/pagination_nav.html" with items=users is_searching=is_searching linkurl="wagtailusers_index" %}
|
||||
{% else %}
|
||||
{% if is_searching %}
|
||||
<p>Sorry, no users match "<em>{{ search_query }}</em>"
|
||||
{% else %}
|
||||
<p>There are no users configured. Why not <a href="{% url 'wagtailusers_create' %}">add some</a>?</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
|
@ -3,15 +3,31 @@ from django.contrib.auth.models import User
|
|||
from django.contrib.auth.decorators import permission_required
|
||||
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
|
||||
from django.contrib import messages
|
||||
from django.db.models import Q
|
||||
|
||||
from wagtail.wagtailadmin.forms import SearchForm
|
||||
from wagtail.wagtailusers.forms import UserCreationForm, UserEditForm
|
||||
|
||||
|
||||
@permission_required('auth.change_user')
|
||||
def index(request):
|
||||
q = None
|
||||
p = request.GET.get("p", 1)
|
||||
is_searching = False
|
||||
|
||||
users = User.objects.order_by('last_name', 'first_name')
|
||||
if 'q' in request.GET:
|
||||
form = SearchForm(request.GET, placeholder_suffix="users")
|
||||
if form.is_valid():
|
||||
q = form.cleaned_data['q']
|
||||
|
||||
is_searching = True
|
||||
users = User.objects.filter(Q(username__icontains=q) | Q(first_name__icontains=q) | Q(last_name__icontains=q) | Q(email__icontains=q))
|
||||
else:
|
||||
form = SearchForm(placeholder_suffix="users")
|
||||
|
||||
if not is_searching:
|
||||
users = User.objects
|
||||
|
||||
users = users.order_by('last_name', 'first_name')
|
||||
|
||||
if 'ordering' in request.GET:
|
||||
ordering = request.GET['ordering']
|
||||
|
|
@ -31,11 +47,21 @@ def index(request):
|
|||
except EmptyPage:
|
||||
users = paginator.page(paginator.num_pages)
|
||||
|
||||
return render(request, 'wagtailusers/index.html', {
|
||||
'users': users,
|
||||
'ordering': ordering,
|
||||
})
|
||||
|
||||
if request.is_ajax():
|
||||
return render(request, "wagtailusers/results.html", {
|
||||
'users': users,
|
||||
'is_searching': is_searching,
|
||||
'search_query': q,
|
||||
'ordering': ordering,
|
||||
})
|
||||
else:
|
||||
return render(request, "wagtailusers/index.html", {
|
||||
'search_form': form,
|
||||
'users': users,
|
||||
'is_searching': is_searching,
|
||||
'ordering': ordering,
|
||||
'search_query': q,
|
||||
})
|
||||
|
||||
@permission_required('auth.change_user')
|
||||
def create(request):
|
||||
|
|
|
|||
Loading…
Reference in a new issue