Skip to content

Commit

Permalink
implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
chosak committed Mar 23, 2017
1 parent 1b2385d commit 10402d3
Show file tree
Hide file tree
Showing 11 changed files with 321 additions and 0 deletions.
3 changes: 3 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
include LICENSE
include README.md
recursive-include wagtailinventory/templates *.html
65 changes: 65 additions & 0 deletions wagtailinventory/forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
from __future__ import absolute_import, unicode_literals

from django import forms
from django.db.models.fields import BLANK_CHOICE_DASH
from django.forms import formset_factory
from wagtail.wagtailcore.models import Page

from wagtailinventory.models import PageBlock


class PageBlockQueryForm(forms.Form):
INCLUDES_BLOCK = 'includes'
EXCLUDES_BLOCK = 'excludes'

block = forms.ChoiceField(
choices=(),
required=False,
label='Block type',
widget=forms.Select(attrs={'style': 'width: 50%'})
)

has = forms.ChoiceField(
choices=((c, c) for c in (INCLUDES_BLOCK, EXCLUDES_BLOCK)),
label=None,
widget=forms.Select(attrs={'style': 'width: 100px'})
)

def __init__(self, *args, **kwargs):
super(PageBlockQueryForm, self).__init__(*args, **kwargs)
block_choices = BLANK_CHOICE_DASH + [
(b, b) for b in
PageBlock.objects.values_list('block', flat=True).distinct()
]
self.fields['block'].choices = block_choices


class BasePageBlockQueryFormSet(forms.BaseFormSet):
def get_query(self):
qs = Page.objects.all()

for form in self.forms:
if not form.is_valid():
continue

form_block = form.cleaned_data.get('block')

if not form_block:
continue

condition = {'page_blocks__block': form_block}

if form.cleaned_data['has'] == form.INCLUDES_BLOCK:
qs = qs.filter(**condition)
else:
qs = qs.exclude(**condition)

return qs


PageBlockQueryFormSet = formset_factory(
PageBlockQueryForm,
formset=BasePageBlockQueryFormSet,
extra=3,
max_num=3
)
77 changes: 77 additions & 0 deletions wagtailinventory/helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
from wagtail.wagtailcore.blocks import StreamValue, StructValue
from wagtail.wagtailcore.fields import StreamField

from wagtailinventory.models import PageBlock


def get_block_name(block):
return block.__module__ + '.' + block.__class__.__name__


def create_page_block(page, block, value):
page_block, _ = PageBlock.objects.get_or_create(
page=page,
block=get_block_name(block)
)

page_blocks = [page_block]

if isinstance(value, list):
for subvalue in value:
page_blocks.extend(create_page_block(
page,
block.child_block,
subvalue
))
elif isinstance(value, StructValue):
for key, subvalue in value.bound_blocks.items():
page_blocks.extend(create_page_block(
page,
block.child_blocks[key],
subvalue
))
elif isinstance(value, StreamValue):
for subvalue in value:
page_blocks.extend(create_page_block(
page,
subvalue.block,
subvalue.value
))

return page_blocks


def create_page_inventory(page):
page_blocks = []

for field in page.specific._meta.fields:
if not isinstance(field, StreamField):
continue

value = getattr(page.specific, field.name)

for item in value:
page_blocks.extend(create_page_block(page, item.block, item.value))

return page_blocks


def get_page_inventory(page=None):
inventory = PageBlock.objects.all()

if page:
inventory = inventory.filter(page=page)

return inventory


def delete_page_inventory(page=None):
get_page_inventory(page).delete()


def update_page_inventory(page):
page_blocks = create_page_inventory(page)

for page_block in get_page_inventory(page):
if page_block not in page_blocks:
page_block.delete()
Empty file.
Empty file.
18 changes: 18 additions & 0 deletions wagtailinventory/management/commands/block_inventory.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from __future__ import print_function

from django.core.management import BaseCommand
from wagtail.wagtailcore.models import Page

from wagtailinventory.helpers import (
create_page_inventory, delete_page_inventory
)


class Command(BaseCommand):
def handle(self, *args, **options):
delete_page_inventory()

count = Page.objects.count()
for i, page in enumerate(Page.objects.all()):
print(i + 1, '/', count, page)
create_page_inventory(page)
14 changes: 14 additions & 0 deletions wagtailinventory/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from __future__ import absolute_import, unicode_literals

from django.db import models
from django.utils.encoding import python_2_unicode_compatible
from wagtail.wagtailcore.models import Page


@python_2_unicode_compatible
class PageBlock(models.Model):
page = models.ForeignKey(Page, related_name='page_blocks')
block = models.CharField(max_length=255, db_index=True)

def __str__(self):
return '<{}, {}>'.format(self.page, self.block)
45 changes: 45 additions & 0 deletions wagtailinventory/templates/wagtailinventory/search.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
{% extends "wagtailadmin/base.html" %}
{% load i18n %}
{% load static %}
{% load wagtailadmin_tags %}

{% block titletag %}{% trans "Block Inventory" %}{% endblock %}

{% block content %}
{% trans "Block Inventory" as header_str %}
{% include "wagtailadmin/shared/header.html" with title=header_str icon="placeholder" %}

<form class="nice-padding" action="{% url 'wagtailinventory:search' %}">
{{ formset.management_form }}
{% for form in formset %}
<div>
{{ form.has }}
{{ form.block }}
</div>
{% endfor %}
<input type="submit" value="Find matching pages" style="width: 240px; padding: 10px; margin: 10px 0" />
</form>

<div id="search-results">
{% if pages %}
<div class="nice-padding">
<h2>
{% blocktrans count counter=pages.paginator.count %}
There is one match
{% plural %}
There are {{ counter }} matches
{% endblocktrans %}
</h2>

{% include "wagtailadmin/pages/listing/_list_explore.html" with show_parent=1 allow_navigation=0 %}
{% paginate pages base_url=base_url classnames="navigate-pages" %}
</div>
{% else %}
<div class="nice-padding">
<h2>
{% blocktrans %}Sorry, there are no matching pages.{% endblocktrans %}
</h2>
</div>
{% endif %}
</div>
{% endblock %}
15 changes: 15 additions & 0 deletions wagtailinventory/tests/test_models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from __future__ import absolute_import, unicode_literals

from django.test import TestCase

from wagtail.wagtailcore.models import Page
from wagtailinventory.models import PageBlock


class TestPageBlock(TestCase):
def test_page_str(self):
page_block = PageBlock(
page=Page(title='Title', slug='title'),
block='path.to.block'
)
self.assertEqual(str(page_block), '<Title, path.to.block>')
35 changes: 35 additions & 0 deletions wagtailinventory/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from __future__ import absolute_import, unicode_literals

from django.http import HttpResponseBadRequest
from django.shortcuts import render
from django.views.generic import View
from wagtail.utils.pagination import paginate, replace_page_in_query
from wagtail.wagtailcore.models import Page

from wagtailinventory.forms import PageBlockQueryFormSet


class SearchView(View):
template_name = 'wagtailinventory/search.html'

def get(self, request):
if len(request.GET) > 1:
formset = PageBlockQueryFormSet(request.GET)
if not formset.is_valid():
return HttpResponseBadRequest('invalid query')

pages = formset.get_query()
else:
formset = PageBlockQueryFormSet()
pages = Page.objects.all()

paginator, pages = paginate(request, pages.order_by('title'))

for page in pages:
page.can_choose = True

return render(request, self.template_name, {
'base_url': replace_page_in_query(request.GET.urlencode(), None),
'formset': formset,
'pages': pages,
})
49 changes: 49 additions & 0 deletions wagtailinventory/wagtail_hooks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
from __future__ import absolute_import, unicode_literals

from django.conf.urls import include, url
from django.core.urlresolvers import reverse
from wagtail.wagtailadmin.menu import MenuItem
from wagtail.wagtailcore import hooks

from wagtailinventory.helpers import (
create_page_inventory, delete_page_inventory, update_page_inventory
)
from wagtailinventory.views import SearchView


@hooks.register('after_create_page')
def do_after_page_create(request, page):
create_page_inventory(page)


@hooks.register('after_edit_page')
def do_after_page_edit(request, page):
update_page_inventory(page)


@hooks.register('after_delete_page')
def do_after_page_dete(request, page):
delete_page_inventory(page)


@hooks.register('register_admin_urls')
def register_inventory_urls():
return [
url(
r'^inventory/',
include(
[url(r'$', SearchView.as_view(), name='search')],
namespace='wagtailinventory'
)
),
]


@hooks.register('register_settings_menu_item')
def register_inventory_menu_item():
return MenuItem(
'Block Inventory',
reverse('wagtailinventory:search'),
classnames='icon icon-placeholder',
order=11000
)

0 comments on commit 10402d3

Please sign in to comment.