Added account report

This commit is contained in:
Marc Aymerich 2014-11-21 17:18:59 +00:00
parent 7382018f94
commit e962e5d7b2
7 changed files with 87 additions and 32 deletions

31
TODO.md
View File

@ -14,35 +14,17 @@
* use Code: https://github.com/django/django/blob/master/django/forms/forms.py#L415 for domain.refresh_serial() * use Code: https://github.com/django/django/blob/master/django/forms/forms.py#L415 for domain.refresh_serial()
* Permissions .filter_queryset() * Permissions .filter_queryset()
* git deploy in addition to FTP?
* env vars instead of multiple settings files: https://devcenter.heroku.com/articles/config-vars ? * env vars instead of multiple settings files: https://devcenter.heroku.com/articles/config-vars ?
* optional chroot shell?
* make sure prefetch_related() is used correctly
Remember that, as always with QuerySets, any subsequent chained methods which imply a different database query will ignore previously cached results, and retrieve data using a fresh database query.
* profile select_related vs prefetch_related
* Log changes from rest api (serialized objects) * Log changes from rest api (serialized objects)
* passlib; nano /usr/local/lib/python2.7/dist-packages/passlib/ext/django/utils.py SortedDict -> collections.OrderedDict
* pip install pyinotify
* Timezone awareness on monitoring system (reading server-side logs with different TZ than orchestra) maybe a settings value? (use UTC internally, timezone.localtime() when interacting with servers)
* EMAIL backend operations which contain stderr messages (because under certain failures status code is still 0) * EMAIL backend operations which contain stderr messages (because under certain failures status code is still 0)
* Settings dictionary like DRF2 in order to better override large settings like WEBSITES_APPLICATIONS.etc * Settings dictionary like DRF2 in order to better override large settings like WEBSITES_APPLICATIONS.etc
* DOCUMENT: orchestration.middleware: we need to know when an operation starts and ends in order to perform bulk server updates and also to wait for related objects to be saved (base object is saved first and then related)
orders.signales: we perform changes right away because data model state can change under monitoring and other periodik task, and we should keep orders consistency under any situation.
dependency collector with max_recursion that matches the number of dots on service.match and service.metric
* backend logs with hal logo * backend logs with hal logo
* Use logs for storing monitored values
* set_password orchestration method? * set_password orchestration method?
* make account_link to autoreplace account on change view. * make account_link to autoreplace account on change view.
* LAST version of this shit http://wkhtmltopdf.org/downloads.html * LAST version of this shit http://wkhtmltopdf.org/downloads.html
@ -50,12 +32,9 @@ Remember that, as always with QuerySets, any subsequent chained methods which im
* translations * translations
from django.utils import translation from django.utils import translation
with translation.override('en'): with translation.override('en'):
* Plurals!
* help_text on readonly_fields specialy Bill.state. (eg. A bill is in OPEN state when bla bla ) * help_text on readonly_fields specialy Bill.state. (eg. A bill is in OPEN state when bla bla )
* underescore *every* private function
* create log file at /var/log/orchestra.log and rotate * create log file at /var/log/orchestra.log and rotate
* order.register_at * order.register_at
@ -71,7 +50,7 @@ Remember that, as always with QuerySets, any subsequent chained methods which im
* move icons to apps, and use appconfig to cleanup config stuff * move icons to apps, and use appconfig to cleanup config stuff
* when using modeladmin to store shit like self.account, make sure to have a cleanslate in each request * when using modeladmin to store shit like self.account, make sure to have a cleanslate in each request?
* jabber with mailbox accounts (dovecto mail notification) * jabber with mailbox accounts (dovecto mail notification)
@ -114,10 +93,8 @@ Remember that, as always with QuerySets, any subsequent chained methods which im
* ignore_fields = () * ignore_fields = ()
* based on a merge set of save(update_fields) * based on a merge set of save(update_fields)
* textwrap.dedent( \\)
* parmiko write to a channel instead of transfering files? http://sysadmin.circularvale.com/programming/paramiko-channel-hangs/ * parmiko write to a channel instead of transfering files? http://sysadmin.circularvale.com/programming/paramiko-channel-hangs/
* proforma without billing contact? * proforma without billing contact?
* env ORCHESTRA_MASTER_SERVER='test1.orchestra.lan' ORCHESTRA_SECOND_SERVER='test2.orchestra.lan' ORCHESTRA_SLAVE_SERVER='test3.orchestra.lan' python manage.py test orchestra.apps.domains.tests.functional_tests.tests:AdminBind9BackendDomainTest * env ORCHESTRA_MASTER_SERVER='test1.orchestra.lan' ORCHESTRA_SECOND_SERVER='test2.orchestra.lan' ORCHESTRA_SLAVE_SERVER='test3.orchestra.lan' python manage.py test orchestra.apps.domains.tests.functional_tests.tests:AdminBind9BackendDomainTest
@ -140,12 +117,8 @@ Remember that, as always with QuerySets, any subsequent chained methods which im
* consider removing mailbox support on forward (user@pangea.org instead) * consider removing mailbox support on forward (user@pangea.org instead)
* remove ordering in account admin and others admininlines
* Databases.User add reverse M2M databases widget (like mailbox.addresses) * Databases.User add reverse M2M databases widget (like mailbox.addresses)
* Change (correct) permissions periodically on the web server, to ensure security ?
* Root owned logs on user's home ? yes * Root owned logs on user's home ? yes
* reconsider binding webapps to systemusers (pangea multiple users wordpress-ftp, moodle-pangea, etc) * reconsider binding webapps to systemusers (pangea multiple users wordpress-ftp, moodle-pangea, etc)
@ -191,3 +164,5 @@ Remember that, as always with QuerySets, any subsequent chained methods which im
* Fix ftp traffic * Fix ftp traffic
* Resource graph for each related object * Resource graph for each related object
* contacts filter by email_usage fix exact for contains

View File

@ -1,10 +1,12 @@
from django.contrib import messages from django.contrib import messages
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.db import transaction from django.db import transaction
from django.shortcuts import redirect from django.shortcuts import redirect, render
from django.utils import timezone
from django.utils.translation import ungettext, ugettext_lazy as _ from django.utils.translation import ungettext, ugettext_lazy as _
from orchestra.admin.decorators import action_with_confirmation from orchestra.admin.decorators import action_with_confirmation
from orchestra.core import services
@transaction.atomic @transaction.atomic
@ -33,3 +35,19 @@ def list_contacts(modeladmin, request, queryset):
url += '?account__in=%s' % ','.join(map(str, ids)) url += '?account__in=%s' % ','.join(map(str, ids))
return redirect(url) return redirect(url)
list_contacts.verbose_name = _("List contacts") list_contacts.verbose_name = _("List contacts")
def service_report(modeladmin, request, queryset):
accounts = []
for account in queryset:
items = []
for service in services.get():
if service != type(account):
items.append((service._meta, service.objects.filter(account=account)))
sorted(items, key=lambda i: i[0].verbose_name_plural.lower())
accounts.append((account, items))
context = {
'accounts': accounts,
'date': timezone.now().today()
}
return render(request, 'admin/accounts/account/service_report.html', context)

View File

@ -18,7 +18,7 @@ from orchestra.core import services, accounts
from orchestra.forms import UserChangeForm from orchestra.forms import UserChangeForm
from . import settings from . import settings
from .actions import disable, list_contacts from .actions import disable, list_contacts, service_report
from .filters import HasMainUserListFilter from .filters import HasMainUserListFilter
from .forms import AccountCreationForm from .forms import AccountCreationForm
from .models import Account from .models import Account
@ -61,8 +61,8 @@ class AccountAdmin(ChangePasswordAdminMixin, auth.UserAdmin, ExtendedModelAdmin)
filter_horizontal = () filter_horizontal = ()
change_readonly_fields = ('username', 'main_systemuser_link') change_readonly_fields = ('username', 'main_systemuser_link')
change_form_template = 'admin/accounts/account/change_form.html' change_form_template = 'admin/accounts/account/change_form.html'
actions = [disable, list_contacts] actions = [disable, list_contacts, service_report]
change_view_actions = [disable] change_view_actions = [disable, service_report]
list_select_related = ('billcontact',) list_select_related = ('billcontact',)
ordering = () ordering = ()

View File

@ -0,0 +1,54 @@
{% load utils %}
<html>
<head>
<title>{% block title %}Service Report{% endblock %}</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
{% block head %}{% endblock %}
<style type="text/css">
body {
max-width: 670px;
margin: 20 auto !important;
float: none !important;
font-family: Arial, 'Liberation Sans', 'DejaVu Sans', sans-serif;
font-size: 12px;
color: #2E2E2E;
}
#date {
float: right;
color: #666;
}
.account-content {
margin: 0px 0px 40px 20px;
}
.item-title {
list-style-type: none;
font-weight: bold;
}
.items-ul {
padding: 0px;
margin: 5px 0px 10px 20px;
}
</style>
</head>
<body>
<div id="date">Service report generated on {{ date | date }}</div>
{% for account, items in accounts %}
<h3>{{ account.get_full_name }} ({{ account.username }})</h3>
<hr>
<div class="account-content">
{{ account.get_type_display }} account registered on {{ account.date_joined | date }}<br>
<ul class="items-ul">
{% for opts, related in items %}
<li class="item-title">{{ opts.verbose_name_plural|capfirst }}</li>
<ul>
{% for obj in related %}
<li>{{ obj }}{% if not obj|isactive %} (disabled){% endif %}</li>
{% endfor %}
</ul>
{% endfor %}
</ul>
</div>
{% endfor %}
</body>
</html>

View File

@ -2,6 +2,8 @@ from django import forms
from django.core import validators from django.core import validators
from django.utils.translation import ungettext, ugettext_lazy as _ from django.utils.translation import ungettext, ugettext_lazy as _
from orchestra.forms.widgets import ShowTextWidget
from . import settings from . import settings

View File

@ -174,6 +174,7 @@ function install_requirements () {
django-debug-toolbar==1.2.1 \ django-debug-toolbar==1.2.1 \
django-nose==1.2 \ django-nose==1.2 \
sqlparse \ sqlparse \
pyinotify \
--allow-external orchestra-orm --allow-unverified orchestra-orm" --allow-external orchestra-orm --allow-unverified orchestra-orm"
fi fi

View File

@ -56,3 +56,8 @@ def is_checkbox(field):
@register.filter @register.filter
def admin_url(obj): def admin_url(obj):
return change_url(obj) return change_url(obj)
@register.filter
def isactive(obj):
return getattr(obj, 'is_active', True)