diff --git a/TODO.md b/TODO.md
index a32ec73c..39218e4e 100644
--- a/TODO.md
+++ b/TODO.md
@@ -65,3 +65,5 @@ Remember that, as always with QuerySets, any subsequent chained methods which im
* Be consistent with dates: name_on, created ?
+
+* backend logs with hal logo
diff --git a/orchestra/admin/decorators.py b/orchestra/admin/decorators.py
index 898da675..141fccf8 100644
--- a/orchestra/admin/decorators.py
+++ b/orchestra/admin/decorators.py
@@ -1,4 +1,4 @@
-from functools import wraps
+from functools import wraps, partial
from django.contrib import messages
from django.contrib.admin import helpers
@@ -7,6 +7,22 @@ from django.utils.decorators import available_attrs
from django.utils.encoding import force_text
+def admin_field(method):
+ def admin_field_wrapper(*args, **kwargs):
+ """ utility function for creating admin links """
+ kwargs['field'] = args[0] if args else ''
+ kwargs['order'] = kwargs.get('order', kwargs['field'])
+ kwargs['popup'] = kwargs.get('popup', False)
+ kwargs['description'] = kwargs.get('description',
+ kwargs['field'].split('__')[-1].replace('_', ' ').capitalize())
+ admin_method = partial(method, **kwargs)
+ admin_method.short_description = kwargs['description']
+ admin_method.allow_tags = True
+ admin_method.admin_order_field = kwargs['order']
+ return admin_method
+ return admin_field_wrapper
+
+
def action_with_confirmation(action_name, extra_context={},
template='admin/orchestra/generic_confirmation.html'):
"""
@@ -14,7 +30,6 @@ def action_with_confirmation(action_name, extra_context={},
If custom template is provided the form must contain:
"""
-
def decorator(func, extra_context=extra_context, template=template):
@wraps(func, assigned=available_attrs(func))
def inner(modeladmin, request, queryset):
@@ -23,16 +38,16 @@ def action_with_confirmation(action_name, extra_context={},
stay = func(modeladmin, request, queryset)
if not stay:
return
-
+
opts = modeladmin.model._meta
app_label = opts.app_label
action_value = func.__name__
-
+
if len(queryset) == 1:
objects_name = force_text(opts.verbose_name)
else:
objects_name = force_text(opts.verbose_name_plural)
-
+
context = {
"title": "Are you sure?",
"content_message": "Are you sure you want to %s the selected %s?" %
@@ -45,12 +60,11 @@ def action_with_confirmation(action_name, extra_context={},
"app_label": app_label,
'action_checkbox_name': helpers.ACTION_CHECKBOX_NAME,
}
-
+
context.update(extra_context)
-
+
# Display the confirmation page
return TemplateResponse(request, template,
context, current_app=modeladmin.admin_site.name)
return inner
return decorator
-
diff --git a/orchestra/admin/menu.py b/orchestra/admin/menu.py
index c3e7b4f1..cb9c1927 100644
--- a/orchestra/admin/menu.py
+++ b/orchestra/admin/menu.py
@@ -32,7 +32,8 @@ def get_services():
for model, options in services.get().iteritems():
if options.get('menu', True):
opts = model._meta
- url = reverse('admin:%s_%s_changelist' % (opts.app_label, opts.model_name))
+ url = reverse('admin:{}_{}_changelist'.format(
+ opts.app_label, opts.model_name))
name = capfirst(options.get('verbose_name_plural'))
result.append(items.MenuItem(name, url))
return sorted(result, key=lambda i: i.title)
@@ -40,24 +41,27 @@ def get_services():
def get_account_items():
childrens = [
- items.MenuItem(_("Accounts"), reverse('admin:accounts_account_changelist'))
+ items.MenuItem(_("Accounts"),
+ reverse('admin:accounts_account_changelist'))
]
if isinstalled('orchestra.apps.contacts'):
url = reverse('admin:contacts_contact_changelist')
childrens.append(items.MenuItem(_("Contacts"), url))
if isinstalled('orchestra.apps.users'):
url = reverse('admin:users_user_changelist')
- users = [items.MenuItem(_("Users"), url)]
- if isinstalled('rest_framework.authtoken'):
- tokens = reverse('admin:authtoken_token_changelist')
- users.append(items.MenuItem(_("Tokens"), tokens))
- childrens.append(items.MenuItem(_("Users"), url, children=users))
+ childrens.append(items.MenuItem(_("Users"), url))
if isinstalled('orchestra.apps.prices'):
url = reverse('admin:prices_pack_changelist')
childrens.append(items.MenuItem(_("Packs"), url))
if isinstalled('orchestra.apps.orders'):
url = reverse('admin:orders_order_changelist')
childrens.append(items.MenuItem(_("Orders"), url))
+ if isinstalled('orchestra.apps.bills'):
+ url = reverse('admin:bills_bill_changelist')
+ childrens.append(items.MenuItem(_("Bills"), url))
+ if isinstalled('orchestra.apps.payments'):
+ url = reverse('admin:payments_transaction_changelist')
+ childrens.append(items.MenuItem(_("Transactions"), url))
if isinstalled('orchestra.apps.issues'):
url = reverse('admin:issues_ticket_changelist')
childrens.append(items.MenuItem(_("Tickets"), url))
@@ -92,7 +96,7 @@ def get_administration_items():
childrens.append(items.MenuItem(_("Miscellaneous"), url))
if isinstalled('orchestra.apps.issues'):
url = reverse('admin:issues_queue_changelist')
- childrens.append(items.MenuItem(_("Issue queues"), url))
+ childrens.append(items.MenuItem(_("Ticket queues"), url))
if isinstalled('djcelery'):
task = reverse('admin:djcelery_taskstate_changelist')
periodic = reverse('admin:djcelery_periodictask_changelist')
diff --git a/orchestra/admin/utils.py b/orchestra/admin/utils.py
index 70a0c77d..2de55a03 100644
--- a/orchestra/admin/utils.py
+++ b/orchestra/admin/utils.py
@@ -12,6 +12,8 @@ from django.utils.translation import ugettext_lazy as _
from orchestra.models.utils import get_field_value
from orchestra.utils.humanize import naturaldate
+from .decorators import admin_field
+
def get_modeladmin(model, import_module=True):
""" returns the modeladmin registred for model """
@@ -44,7 +46,9 @@ def insertattr(model, name, value, weight=0):
weights = {}
if hasattr(modeladmin, 'weights') and name in modeladmin.weights:
weights = modeladmin.weights.get(name)
- inserted_attrs[name] = [ (attr, weights.get(attr, 0)) for attr in getattr(modeladmin, name) ]
+ inserted_attrs[name] = [
+ (attr, weights.get(attr, 0)) for attr in getattr(modeladmin, name)
+ ]
inserted_attrs[name].append((value, weight))
inserted_attrs[name].sort(key=lambda a: a[1])
@@ -70,85 +74,40 @@ def set_default_filter(queryarg, request, value):
request.META['QUERY_STRING'] = request.GET.urlencode()
+@admin_field
def admin_link(*args, **kwargs):
- """ utility function for creating admin links """
- field = args[0] if args else ''
- order = kwargs.pop('order', field)
- popup = kwargs.pop('popup', False)
-
- def display_link(*args):
- instance = args[-1]
- obj = getattr(instance, field, instance)
- if not getattr(obj, 'pk', None):
- return '---'
- opts = obj._meta
- view_name = 'admin:%s_%s_change' % (opts.app_label, opts.model_name)
- url = reverse(view_name, args=(obj.pk,))
- extra = ''
- if popup:
- extra = 'onclick="return showAddAnotherPopup(this);"'
- return '%s' % (url, extra, obj)
- display_link.allow_tags = True
- display_link.short_description = _(field.replace('_', ' '))
- display_link.admin_order_field = order
- return display_link
+ instance = args[-1]
+ obj = get_field_value(instance, kwargs['field'])
+ if not getattr(obj, 'pk', None):
+ return '---'
+ opts = obj._meta
+ view_name = 'admin:%s_%s_change' % (opts.app_label, opts.model_name)
+ url = reverse(view_name, args=(obj.pk,))
+ extra = ''
+ if kwargs['popup']:
+ extra = 'onclick="return showAddAnotherPopup(this);"'
+ return '%s' % (url, extra, obj)
-def colored(field_name, colours, description='', verbose=False, bold=True):
- """ returns a method that will render obj with colored html """
- def colored_field(obj, field=field_name, colors=colours, verbose=verbose):
- value = escape(get_field_value(obj, field))
- color = colors.get(value, "black")
- if verbose:
- # Get the human-readable value of a choice field
- value = getattr(obj, 'get_%s_display' % field)()
- colored_value = '%s' % (color, value)
- if bold:
- colored_value = '%s' % colored_value
- return mark_safe(colored_value)
- if not description:
- description = field_name.split('__').pop().replace('_', ' ').capitalize()
- colored_field.short_description = description
- colored_field.allow_tags = True
- colored_field.admin_order_field = field_name
- return colored_field
+@admin_field
+def admin_colored(*args, **kwargs):
+ instance = args[-1]
+ field = kwargs['field']
+ value = escape(get_field_value(instance, field))
+ color = kwargs.get('colors', {}).get(value, 'black')
+ value = getattr(instance, 'get_%s_display' % field)().upper()
+ colored_value = '%s' % (color, value)
+ if kwargs.get('bold', True):
+ colored_value = '%s' % colored_value
+ return mark_safe(colored_value)
-#def display_timesince(date, double=False):
-# """
-# Format date for messages create_on: show a relative time
-# with contextual helper to show fulltime format.
-# """
-# if not date:
-# return 'Never'
-# date_rel = timesince(date)
-# if not double:
-# date_rel = date_rel.split(',')[0]
-# date_rel += ' ago'
-# date_abs = date.strftime("%Y-%m-%d %H:%M:%S %Z")
-# return mark_safe("%s" % (date_abs, date_rel))
-
-
-def admin_date(field, **kwargs):
- """ utility function for creating admin dates """
- default = kwargs.pop('default', '')
- order = kwargs.pop('order', field)
-
- def display_date(*args):
- instance = args[-1]
- value = get_field_value(instance, field)
- if not value:
- return default
- return '{1}'.format(
- escape(str(value)), escape(naturaldate(value)),
- )
- display_date.short_description = _(field.replace('_', ' '))
- display_date.admin_order_field = order
- display_date.allow_tags = True
- return display_date
-
-
-#def display_timeuntil(date):
-# date_rel = timeuntil(date) + ' left'
-# date_abs = date.strftime("%Y-%m-%d %H:%M:%S %Z")
-# return mark_safe("%s" % (date_abs, date_rel))
+@admin_field
+def admin_date(*args, **kwargs):
+ instance = args[-1]
+ value = get_field_value(instance, kwargs['field'])
+ if not value:
+ return kwargs.get('default', '')
+ return '{1}'.format(
+ escape(str(value)), escape(naturaldate(value)),
+ )
diff --git a/orchestra/apps/issues/admin.py b/orchestra/apps/issues/admin.py
index d0c43ea8..0f4896ed 100644
--- a/orchestra/apps/issues/admin.py
+++ b/orchestra/apps/issues/admin.py
@@ -12,7 +12,8 @@ from django.utils.translation import ugettext_lazy as _
from markdown import markdown
from orchestra.admin import ChangeListDefaultFilter, ExtendedModelAdmin#, ChangeViewActions
-from orchestra.admin.utils import admin_link, colored, wrap_admin_view, admin_date
+from orchestra.admin.utils import (admin_link, admin_colored, wrap_admin_view,
+ admin_date)
from orchestra.apps.contacts import settings as contacts_settings
from .actions import (reject_tickets, resolve_tickets, take_tickets, close_tickets,
@@ -111,19 +112,13 @@ class TicketInline(admin.TabularInline):
owner_link = admin_link('owner')
created = admin_link('created_on')
last_modified = admin_link('last_modified_on')
+ colored_state = admin_colored('state', colors=STATE_COLORS, bold=False)
+ colored_priority = admin_colored('priority', colors=PRIORITY_COLORS, bold=False)
def ticket_id(self, instance):
return '%s' % admin_link()(instance)
ticket_id.short_description = '#'
ticket_id.allow_tags = True
-
- def colored_state(self, instance):
- return colored('state', STATE_COLORS, bold=False)(instance)
- colored_state.short_description = _("State")
-
- def colored_priority(self, instance):
- return colored('priority', PRIORITY_COLORS, bold=False)(instance)
- colored_priority.short_description = _("Priority")
class TicketAdmin(ChangeListDefaultFilter, ExtendedModelAdmin): #TODO ChangeViewActions,
@@ -198,6 +193,8 @@ class TicketAdmin(ChangeListDefaultFilter, ExtendedModelAdmin): #TODO ChangeView
display_queue = admin_link('queue')
display_owner = admin_link('owner')
last_modified = admin_date('last_modified_on')
+ display_state = admin_colored('state', colors=STATE_COLORS, bold=False)
+ display_priority = admin_colored('priority', colors=PRIORITY_COLORS, bold=False)
def display_summary(self, ticket):
context = {
@@ -216,18 +213,6 @@ class TicketAdmin(ChangeListDefaultFilter, ExtendedModelAdmin): #TODO ChangeView
display_summary.short_description = 'Summary'
display_summary.allow_tags = True
- def display_priority(self, ticket):
- """ State colored for change_form """
- return colored('priority', PRIORITY_COLORS, bold=False, verbose=True)(ticket)
- display_priority.short_description = _("Priority")
- display_priority.admin_order_field = 'priority'
-
- def display_state(self, ticket):
- """ State colored for change_form """
- return colored('state', STATE_COLORS, bold=False, verbose=True)(ticket)
- display_state.short_description = _("State")
- display_state.admin_order_field = 'state'
-
def unbold_id(self, ticket):
""" Unbold id if ticket is read """
if ticket.is_read_by(self.user):
diff --git a/orchestra/apps/orchestration/admin.py b/orchestra/apps/orchestration/admin.py
index 6cdd0059..cff38be3 100644
--- a/orchestra/apps/orchestration/admin.py
+++ b/orchestra/apps/orchestration/admin.py
@@ -4,7 +4,7 @@ from django.utils.html import escape
from django.utils.translation import ugettext_lazy as _
from orchestra.admin.html import monospace_format
-from orchestra.admin.utils import admin_link, admin_date, colored
+from orchestra.admin.utils import admin_link, admin_date, admin_colored
from .models import Server, Route, BackendLog, BackendOperation
@@ -90,7 +90,7 @@ class BackendLogAdmin(admin.ModelAdmin):
server_link = admin_link('server')
display_last_update = admin_date('last_update')
display_created = admin_date('created')
- display_state = colored('state', STATE_COLORS)
+ display_state = admin_colored('state', colors=STATE_COLORS)
def mono_script(self, log):
return monospace_format(escape(log.script))
diff --git a/orchestra/apps/payments/admin.py b/orchestra/apps/payments/admin.py
index 4c150b72..6a7122a5 100644
--- a/orchestra/apps/payments/admin.py
+++ b/orchestra/apps/payments/admin.py
@@ -1,7 +1,30 @@
from django.contrib import admin
+from orchestra.admin.utils import admin_colored, admin_link
+
from .models import PaymentSource, Transaction
+STATE_COLORS = {
+ Transaction.WAITTING_PROCESSING: 'darkorange',
+ Transaction.WAITTING_CONFIRMATION: 'orange',
+ Transaction.CONFIRMED: 'green',
+ Transaction.REJECTED: 'red',
+ Transaction.LOCKED: 'magenta',
+ Transaction.DISCARTED: 'blue',
+}
+
+
+class TransactionAdmin(admin.ModelAdmin):
+ list_display = (
+ 'id', 'bill_link', 'account_link', 'method', 'display_state', 'amount'
+ )
+ list_filter = ('method', 'state')
+
+ bill_link = admin_link('bill')
+ account_link = admin_link('bill__account')
+ display_state = admin_colored('state', colors=STATE_COLORS)
+
+
admin.site.register(PaymentSource)
-admin.site.register(Transaction)
+admin.site.register(Transaction, TransactionAdmin)
diff --git a/orchestra/apps/payments/models.py b/orchestra/apps/payments/models.py
index a2f7a79c..b225f6c5 100644
--- a/orchestra/apps/payments/models.py
+++ b/orchestra/apps/payments/models.py
@@ -12,6 +12,7 @@ class PaymentSource(models.Model):
method = models.CharField(_("method"), max_length=32,
choices=PaymentMethod.get_plugin_choices())
data = JSONField(_("data"))
+ is_active = models.BooleanField(_("is active"), default=True)
class Transaction(models.Model):
@@ -22,14 +23,15 @@ class Transaction(models.Model):
LOCKED = 'LOCKED'
DISCARTED = 'DISCARTED'
STATES = (
- (WAITTING_PROCESSING, _("Waitting for processing")),
- (WAITTING_CONFIRMATION, _("Waitting for confirmation")),
+ (WAITTING_PROCESSING, _("Waitting processing")),
+ (WAITTING_CONFIRMATION, _("Waitting confirmation")),
(CONFIRMED, _("Confirmed")),
(REJECTED, _("Rejected")),
(LOCKED, _("Locked")),
(DISCARTED, _("Discarted")),
)
+ # TODO account fk?
bill = models.ForeignKey('bills.bill', verbose_name=_("bill"),
related_name='transactions')
method = models.CharField(_("payment method"), max_length=32,
@@ -42,3 +44,6 @@ class Transaction(models.Model):
created_on = models.DateTimeField(auto_now_add=True)
modified_on = models.DateTimeField(auto_now=True)
related = models.ForeignKey('self', null=True, blank=True)
+
+ def __unicode__(self):
+ return "Transaction {}".format(self.id)
diff --git a/orchestra/apps/resources/admin.py b/orchestra/apps/resources/admin.py
index eefb22e6..023dccda 100644
--- a/orchestra/apps/resources/admin.py
+++ b/orchestra/apps/resources/admin.py
@@ -15,8 +15,8 @@ from .models import Resource, ResourceData, MonitorData
class ResourceAdmin(ExtendedModelAdmin):
list_display = (
- 'id', 'name', 'verbose_name', 'content_type', 'period', 'ondemand',
- 'default_allocation', 'disable_trigger', 'crontab',
+ 'id', 'verbose_name', 'content_type', 'period', 'ondemand',
+ 'default_allocation', 'unit', 'disable_trigger', 'crontab',
)
list_filter = (UsedContentTypeFilter, 'period', 'ondemand', 'disable_trigger')
fieldsets = (
diff --git a/orchestra/conf/base_settings.py b/orchestra/conf/base_settings.py
index 213deac4..57b1f41f 100644
--- a/orchestra/conf/base_settings.py
+++ b/orchestra/conf/base_settings.py
@@ -179,7 +179,7 @@ FLUENT_DASHBOARD_APP_ICONS = {
'miscellaneous/miscellaneous': 'applications-other.png',
# Accounts
'accounts/account': 'Face-monkey.png',
- 'contacts/contact': 'contact.png',
+ 'contacts/contact': 'contact_book.png',
'orders/order': 'basket.png',
'orders/service': 'price.png',
'prices/pack': 'Pack.png',
diff --git a/orchestra/static/orchestra/icons/Pack.png b/orchestra/static/orchestra/icons/Pack.png
index 24d48ced..e7d2a8d4 100644
Binary files a/orchestra/static/orchestra/icons/Pack.png and b/orchestra/static/orchestra/icons/Pack.png differ
diff --git a/orchestra/static/orchestra/icons/Pack.svg b/orchestra/static/orchestra/icons/Pack.svg
index 7afdb383..5675e5c5 100644
--- a/orchestra/static/orchestra/icons/Pack.svg
+++ b/orchestra/static/orchestra/icons/Pack.svg
@@ -15,8 +15,8 @@
width="48"
version="1.0"
inkscape:version="0.48.3.1 r9886"
- sodipodi:docname="TuxBox.svg"
- inkscape:export-filename="/home/glic3rinu/orchestra/django-orchestra/orchestra/static/orchestra/icons/Pack.png"
+ sodipodi:docname="Pack.svg"
+ inkscape:export-filename="/home/glic3/orchestra/django-orchestra/orchestra/static/orchestra/icons/Pack.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90">
-
-
-
+ transform="matrix(0.67441404,0,0,0.67441404,-1.7640493,12.799498)">
diff --git a/orchestra/static/orchestra/icons/contact_alt.png b/orchestra/static/orchestra/icons/contact_alt.png
new file mode 100644
index 00000000..ff123948
Binary files /dev/null and b/orchestra/static/orchestra/icons/contact_alt.png differ
diff --git a/orchestra/static/orchestra/icons/contact_book.png b/orchestra/static/orchestra/icons/contact_book.png
new file mode 100644
index 00000000..7d3dce3d
Binary files /dev/null and b/orchestra/static/orchestra/icons/contact_book.png differ