Skip to content

Commit ea9785b

Browse files
initial commit
0 parents  commit ea9785b

24 files changed

+780
-0
lines changed

.coveragerc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# .coveragerc to control coverage.py
2+
[run]
3+
omit =
4+
setup.py
5+
admin_appmenu/tests/*
6+
.tox/*
7+
doc/*
8+
build/*
9+
dist/*

.gitignore

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
*.py[co]
2+
.project
3+
.pydevproject
4+
.settings
5+
*.egg
6+
*.egg-info
7+
dist
8+
build
9+
.coverage
10+
*.pid
11+
.DS_Store
12+
doc/_build
13+
htmlcov/
14+
.tox/

.travis.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
language: python
2+
sudo: required
3+
cache:
4+
directories:
5+
- $HOME/.cache/pip
6+
install: pip install --upgrade pip tox wheel
7+
script: tox
8+
env:
9+
- TOXENV=py27-django-19
10+
- TOXENV=py34-django-19
11+
- TOXENV=coveralls

LICENSE

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
Copyright (C) 2013-2016 Collab
2+
3+
Permission is hereby granted, free of charge, to any person obtaining a copy of
4+
this software and associated documentation files (the "Software"), to deal in
5+
the Software without restriction, including without limitation the rights to use,
6+
copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
7+
Software, and to permit persons to whom the Software is furnished to do so,
8+
subject to the following conditions:
9+
10+
The above copyright notice and this permission notice shall be included in all
11+
copies or substantial portions of the Software.
12+
13+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
14+
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
15+
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
16+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
18+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

MANIFEST.in

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
include README.rst LICENSE tox.ini .coveragerc
2+
3+
recursive-include admin_appmenu/tests *
4+
recursive-include admin_appmenu/locale *
5+
recursive-include admin_appmenu/templates *
6+
7+
recursive-exclude * __pycache__
8+
recursive-exclude * *.py[co]
9+
recursive-exclude * *~
10+
recursive-exclude * .coverage

README.rst

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
django-admin-appmenu
2+
====================
3+
4+
``django-admin-appmenu`` provides a templatetag that renders an application
5+
menu in the `Django <https://www.djangoproject.com>`_ admin.
6+
7+
.. image:: https://img.shields.io/pypi/v/django-admin-appmenu.svg
8+
:target: https://pypi.python.org/pypi/django-admin-appmenu
9+
.. image:: https://img.shields.io/pypi/pyversions/django-admin-appmenu.svg
10+
:target: https://pypi.python.org/pypi/django-admin-appmenu
11+
.. image:: https://travis-ci.org/collab-project/django-admin-appmenu.svg?branch=master
12+
:target: https://travis-ci.org/collab-project/django-admin-appmenu
13+
.. image:: https://coveralls.io/repos/collab-project/django-admin-appmenu/badge.svg
14+
:target: https://coveralls.io/r/collab-project/django-admin-appmenu
15+
.. image:: https://img.shields.io/badge/license-MIT-blue.svg
16+
:target: https://raw.githubusercontent.com/collab-project/django-admin-appmenu/master/LICENSE
17+
18+
Installation
19+
------------
20+
21+
Use pip_ to install the download and install the package from PyPi_::
22+
23+
pip install django-admin-appmenu
24+
25+
Or checkout the source code from Github_::
26+
27+
git clone https://github.com/collab-project/django-admin-appmenu.git
28+
cd django-admin-appmenu
29+
pip install -e .
30+
31+
Add ``admin_appmenu`` to ``INSTALLED_APPS`` in your Django project settings:
32+
33+
.. code-block:: python
34+
35+
INSTALLED_APPS = (
36+
...
37+
38+
'admin_appmenu',
39+
)
40+
41+
.. _pip: https://pypi.python.org/pypi/pip
42+
.. _PyPi: https://pypi.python.org/pypi/django-admin-appmenu
43+
.. _Github: https://github.com/collab-project/django-admin-appmenu

admin_appmenu/__init__.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Copyright Collab 2013-2016
2+
# See LICENSE for details.
3+
4+
"""
5+
`django-admin-appmenu` application.
6+
"""
7+
8+
from __future__ import unicode_literals
9+
10+
11+
#: Application version.
12+
__version__ = (1, 0, 0, 'b1')
13+
14+
15+
def short_version(version=None):
16+
"""
17+
Return short application version. For example: ``1.0.0``.
18+
"""
19+
v = version or __version__
20+
return '.'.join([str(x) for x in v[:3]])
21+
22+
23+
def get_version(version=None):
24+
"""
25+
Return full version nr, inc. rc, beta etc tags.
26+
27+
For example: ``2.0.0a1``
28+
:rtype: str
29+
"""
30+
v = version or __version__
31+
if len(v) == 4:
32+
return '{0}{1}'.format(short_version(v), v[3])
33+
34+
return short_version(v)
35+
36+
37+
#: Full version number.
38+
version = get_version()
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<ul>
2+
{% for app in nav_list %}
3+
<li id="menu{{ forloop.counter0 }}" class="dropdown"><a href="{{ app.app_url }}">{{ app.app_label }}</a></li>
4+
5+
{% if app.models|length > 0 %}
6+
<ul>
7+
{% for model in app.models %}
8+
9+
{% if model.admin_url %}
10+
11+
<li><a href="{{ model.admin_url }}">{{ model.name }}</a></li>
12+
13+
{% else %}
14+
<li>&nbsp;</li>
15+
{% endif %}
16+
17+
{% endfor %}
18+
</ul>
19+
{% endif %}
20+
21+
</li>
22+
{% endfor %}
23+
</ul>

admin_appmenu/templatetags/__init__.py

Whitespace-only changes.
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Copyright Collab 2013-2016
2+
3+
"""
4+
Navigation template tags for the :py:mod:`admin_appmenu` application.
5+
"""
6+
7+
from __future__ import unicode_literals
8+
9+
import logging
10+
11+
from django import template
12+
from django.template import base, loader
13+
14+
from ..util import get_admin_site
15+
16+
17+
register = template.Library()
18+
logger = logging.getLogger(__name__)
19+
20+
21+
class AdminUserNavigationNode(template.Node):
22+
"""
23+
Build navigation tree with the admin's :py:func:`get_app_list` and render
24+
the resulting context into the navigation template.
25+
"""
26+
def render(self, context):
27+
data = None
28+
try:
29+
admin = get_admin_site()
30+
data = admin.get_app_list(context['request'])
31+
except (ValueError, KeyError):
32+
pass
33+
except Exception as e: # pragma: no cover
34+
logger.exception(e)
35+
36+
tpl = loader.get_template('admin_appmenu/navigation.html')
37+
return tpl.render({'nav_list': data})
38+
39+
40+
@register.tag
41+
def admin_navigation(parser, token):
42+
"""
43+
Template tag that renders the main admin navigation tree based on the
44+
authenticated user's permissions.
45+
"""
46+
# split_contents() knows not to split quoted strings.
47+
tag_name = token.split_contents()
48+
49+
if len(tag_name) > 1:
50+
raise base.TemplateSyntaxError(
51+
'{} tag does not accept any argument(s): {}'.format(
52+
token.contents.split()[0],
53+
', '.join(token.contents.split()[1:])
54+
))
55+
56+
return AdminUserNavigationNode()

admin_appmenu/tests/__init__.py

Whitespace-only changes.

admin_appmenu/tests/admin.py

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
# Copyright Collab 2013-2016
2+
3+
"""
4+
Custom admin used for testing.
5+
"""
6+
7+
from __future__ import unicode_literals
8+
9+
from django.conf.urls import url
10+
from django.core.urlresolvers import reverse
11+
from django.template.response import TemplateResponse
12+
from django.utils.translation import ugettext_lazy as _
13+
14+
from django.contrib.admin import AdminSite
15+
16+
from .models import Location
17+
18+
19+
class CustomAdminSite(AdminSite):
20+
site_header = 'Custom admin site'
21+
22+
def custom_view(self, request):
23+
"""
24+
An additional admin view.
25+
"""
26+
context = dict(
27+
# include common variables for rendering the admin template
28+
self.admin_site.each_context(request),
29+
)
30+
return TemplateResponse(request, 'sometemplate.html', context)
31+
32+
def get_urls(self):
33+
"""
34+
Extend admin URL patterns.
35+
"""
36+
urls = super(CustomAdminSite, self).get_urls()
37+
extra_urls = [
38+
url(r'^customview/$', self.custom_view, name='customview')
39+
]
40+
return urls + extra_urls
41+
42+
def get_app_list(self, request):
43+
app_list = super(CustomAdminSite, self).get_app_list(request)
44+
45+
# categorize apps
46+
categorized_list = [
47+
{'label': _('General'), 'apps': []},
48+
{'label': _('Custom'), 'apps': []},
49+
]
50+
51+
def add_app(key, app):
52+
for i, dic in enumerate(categorized_list):
53+
if dic['label'] == key:
54+
categorized_list[i]['apps'].append(app)
55+
break
56+
57+
for category in categorized_list:
58+
for app in app_list:
59+
name = app['name']
60+
label = category['label']
61+
if label == _('General'):
62+
if name in ['Admin_Appmenu']:
63+
add_app(label, app)
64+
65+
# add custom links for superusers
66+
if request.user.is_superuser:
67+
categorized_list[1]['apps'].append(
68+
{
69+
'name': _('Custom views'),
70+
'models': [
71+
{
72+
'name': _('My custom view'),
73+
'admin_url': reverse('admin:customview')
74+
}
75+
]}
76+
)
77+
else:
78+
categorized_list = []
79+
80+
# from pprint import pprint
81+
# pprint(categorized_list)
82+
return categorized_list
83+
84+
85+
admin_site = CustomAdminSite(name='customadmin')
86+
admin_site.register(Location)
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Copyright Collab 2013-2016
2+
# See LICENSE for details.
3+
4+
"""
5+
URLConf for custom admin used in tests.
6+
"""
7+
8+
from __future__ import unicode_literals
9+
10+
from .admin import admin_site
11+
12+
from django.conf.urls import url
13+
14+
15+
urlpatterns = [
16+
url(r'^', admin_site.urls),
17+
]

admin_appmenu/tests/models.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Copyright Collab 2016
2+
3+
"""
4+
Models used for testing.
5+
"""
6+
7+
from __future__ import unicode_literals
8+
9+
from django.db import models
10+
from django.utils.translation import ugettext as _
11+
from django.utils.encoding import python_2_unicode_compatible
12+
13+
14+
@python_2_unicode_compatible
15+
class Location(models.Model):
16+
"""
17+
Location.
18+
"""
19+
name = models.CharField(
20+
_('name'),
21+
help_text=_('Name of the location.'),
22+
max_length=255,
23+
blank=False,
24+
null=False
25+
)
26+
slug = models.SlugField(
27+
_('slug'),
28+
help_text=_('Location name as used in links.'),
29+
max_length=255,
30+
blank=False,
31+
null=False,
32+
unique=True
33+
)
34+
address = models.CharField(
35+
_('address'),
36+
help_text=_('Location address.'),
37+
max_length=255,
38+
blank=False,
39+
null=False
40+
)
41+
42+
class Meta:
43+
verbose_name = _('location')
44+
verbose_name_plural = _('locations')
45+
46+
def __str__(self):
47+
return self.name

admin_appmenu/tests/requirements.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
tox
2+
coverage
3+
flake8

0 commit comments

Comments
 (0)