def display_summary(self, ticket): context = { 'creator': admin_link('creator')(self, ticket) if ticket.creator else ticket.creator_name, 'created': admin_date('created_at')(ticket), 'updated': '', } msg = ticket.messages.last() if msg: context.update({ 'updated': admin_date('created_at')(msg), 'updater': admin_link('author')(self, msg) if msg.author else msg.author_name, }) context['updated'] = '. Updated by %(updater)s about %(updated)s' % context return '<h4>Added by %(creator)s about %(created)s%(updated)s</h4>' % context
def display_summary(self, ticket): context = { 'creator': admin_link('creator')(self, ticket) if ticket.creator else ticket.creator_name, 'created': admin_date('created_on')(ticket), 'updated': '', } msg = ticket.messages.last() if msg: context.update({ 'updated': admin_date('created_on')(msg), 'updater': admin_link('author')(self, msg) if msg.author else msg.author_name, }) context['updated'] = '. Updated by %(updater)s about %(updated)s' % context return '<h4>Added by %(creator)s about %(created)s%(updated)s</h4>' % context
class MonitorDataAdmin(ExtendedModelAdmin): list_display = ('id', 'monitor', content_object_link, 'display_created', 'value') list_filter = ('monitor', ResourceDataListFilter) add_fields = ('monitor', 'content_type', 'object_id', 'created_at', 'value') fields = ('monitor', 'content_type', content_object_link, 'display_created', 'value', 'state') change_readonly_fields = fields list_select_related = ('content_type', ) search_fields = ('content_object_repr', ) date_hierarchy = 'created_at' display_created = admin_date('created_at', short_description=_("Created")) def filter_used_monitordata(self, request, queryset): query_string = parse_qs(request.META['QUERY_STRING']) resource_data = query_string.get('resource_data') if resource_data: mdata = ResourceData.objects.get(pk=int(resource_data[0])) resource = mdata.resource ids = [] for monitor, dataset in mdata.get_monitor_datasets(): dataset = resource.aggregation_instance.filter(dataset) if isinstance(dataset, MonitorData): ids.append(dataset.id) else: ids += dataset.values_list('id', flat=True) return queryset.filter(id__in=ids) return queryset def get_queryset(self, request): queryset = super(MonitorDataAdmin, self).get_queryset(request) queryset = self.filter_used_monitordata(request, queryset) return queryset.prefetch_related('content_object')
class SMTPLogAdmin(admin.ModelAdmin): list_display = ('id', 'message_link', 'colored_result', 'date_delta', 'log_message') list_filter = ('result', ) fields = ('message_link', 'colored_result', 'date_delta', 'log_message') readonly_fields = fields message_link = admin_link('message') colored_result = admin_colored('result', colors=COLORS, bold=False) date_delta = admin_date('date')
def content_html(self, msg): context = { 'number': msg.number, 'time': admin_date('created_on')(msg), 'author': admin_link('author')(msg) if msg.author else msg.author_name, } summary = _("#%(number)i Updated by %(author)s about %(time)s") % context header = '<strong style="color:#666;">%s</strong><hr />' % summary content = markdown(msg.content) content = content.replace('>\n', '>') content = '<div style="padding-left:20px;">%s</div>' % content return header + content
def content_html(self, msg): context = { 'number': msg.number, 'time': admin_date('created_at')(msg), 'author': admin_link('author')(msg) if msg.author else msg.author_name, } summary = _("#%(number)i Updated by %(author)s about %(time)s") % context header = '<strong style="color:#666;">%s</strong><hr />' % summary content = markdown(msg.content) content = content.replace('>\n', '>') content = '<div style="padding-left:20px;">%s</div>' % content return header + content
class BackendLogAdmin(ChangeViewActionsMixin, admin.ModelAdmin): list_display = ( 'id', 'backend', 'server_link', 'display_state', 'exit_code', 'display_created', 'execution_time', ) list_display_links = ('id', 'backend') list_filter = ('state', 'server', 'backend', 'operations__action') search_fields = ('script', ) date_hierarchy = 'created_at' inlines = (BackendOperationInline, ) fields = ('backend', 'server_link', 'state', 'display_script', 'mono_stdout', 'mono_stderr', 'mono_traceback', 'exit_code', 'task_id', 'display_created', 'execution_time') readonly_fields = fields actions = (retry_backend, ) change_view_actions = actions server_link = admin_link('server') display_created = admin_date('created_at', short_description=_("Created")) display_state = admin_colored('state', colors=STATE_COLORS) display_script = display_code('script') mono_stdout = display_mono('stdout') mono_stderr = display_mono('stderr') mono_traceback = display_mono('traceback') class Media: css = {'all': ('orchestra/css/pygments/github.css', )} def get_queryset(self, request): """ Order by structured name and imporve performance """ qs = super(BackendLogAdmin, self).get_queryset(request) return qs.select_related('server').defer('script', 'stdout') def has_add_permission(self, *args, **kwargs): return False
class LogEntryAdmin(admin.ModelAdmin): list_display = ( 'display_action_time', 'user_link', 'display_message', ) list_filter = ( 'action_flag', ('user', admin.RelatedOnlyFieldListFilter), ('content_type', admin.RelatedOnlyFieldListFilter), ) date_hierarchy = 'action_time' search_fields = ('object_repr', 'change_message', 'user__username') fields = ('user_link', 'content_object_link', 'display_action_time', 'display_action', 'change_message') readonly_fields = ( 'user_link', 'content_object_link', 'display_action_time', 'display_action', ) actions = None list_select_related = ('user', 'content_type') list_display_links = None user_link = admin_link('user') display_action_time = admin_date('action_time', short_description=_("Time")) @mark_safe def display_message(self, log): edit = format_html( '<a href="{url}"><img src="{img}"></img></a>', **{ 'url': reverse('admin:admin_logentry_change', args=(log.pk, )), 'img': static('admin/img/icon-changelink.svg'), }) if log.is_addition(): return _('Added "%(link)s". %(edit)s') % { 'link': self.content_object_link(log), 'edit': edit } elif log.is_change(): return _('Changed "%(link)s" - %(changes)s %(edit)s') % { 'link': self.content_object_link(log), 'changes': log.get_change_message(), 'edit': edit, } elif log.is_deletion(): return _('Deleted "%(object)s." %(edit)s') % { 'object': log.object_repr, 'edit': edit, } display_message.short_description = _("Message") display_message.admin_order_field = 'action_flag' def display_action(self, log): if log.is_addition(): return _("Added") elif log.is_change(): return _("Changed") return _("Deleted") display_action.short_description = _("Action") display_action.admin_order_field = 'action_flag' def content_object_link(self, log): ct = log.content_type view = 'admin:%s_%s_change' % (ct.app_label, ct.model) try: url = reverse(view, args=(log.object_id, )) except NoReverseMatch: return log.object_repr return format_html('<a href="{}">{}</a>', url, log.object_repr) content_object_link.short_description = _("Content object") content_object_link.admin_order_field = 'object_repr' def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None): """ Add rel_opts and object to context """ if not add and 'edit' in request.GET.urlencode(): context.update({ 'rel_opts': obj.content_type.model_class()._meta, 'object': obj, }) return super(LogEntryAdmin, self).render_change_form(request, context, add, change, form_url, obj) def response_change(self, request, obj): """ save and continue preserve edit query string """ response = super(LogEntryAdmin, self).response_change(request, obj) if 'edit' in request.GET.urlencode() and 'edit' not in response.url: return HttpResponseRedirect(response.url + '?edit=True') return response def response_post_save_change(self, request, obj): """ save redirect to object history """ if 'edit' in request.GET.urlencode(): opts = obj.content_type.model_class()._meta view = 'admin:%s_%s_history' % (opts.app_label, opts.model_name) post_url = reverse(view, args=(obj.object_id, )) preserved_filters = self.get_preserved_filters(request) post_url = add_preserved_filters( { 'preserved_filters': preserved_filters, 'opts': opts }, post_url) return HttpResponseRedirect(post_url) return super(LogEntryAdmin, self).response_post_save_change(request, obj) def has_add_permission(self, *args, **kwargs): return False def has_delete_permission(self, *args, **kwargs): return False def log_addition(self, *args, **kwargs): pass def log_change(self, *args, **kwargs): pass def log_deletion(self, *args, **kwargs): pass
class MessageAdmin(ExtendedModelAdmin): list_display = ( 'display_subject', 'colored_state', 'priority', 'to_address', 'from_address', 'created_at_delta', 'display_retries', 'last_try_delta', ) list_filter = ('state', 'priority', 'retries') list_prefetch_related = ('logs', ) search_fields = ( 'to_address', 'from_address', 'subject', ) fieldsets = ( (None, { 'fields': ('state', 'priority', ('retries', 'last_try_delta', 'created_at_delta'), 'display_full_subject', 'display_from', 'display_to', 'display_content'), }), (_("Edit"), { 'classes': ('collapse', ), 'fields': ('subject', 'from_address', 'to_address', 'content'), }), ) readonly_fields = ( 'retries', 'last_try_delta', 'created_at_delta', 'display_full_subject', 'display_to', 'display_from', 'display_content', ) date_hierarchy = 'created_at' change_view_actions = (last, ) colored_state = admin_colored('state', colors=COLORS) created_at_delta = admin_date('created_at') last_try_delta = admin_date('last_try') def display_subject(self, instance): subject = instance.subject if len(subject) > 64: return mark_safe(subject[:64] + '…') return subject display_subject.short_description = _("Subject") display_subject.admin_order_field = 'subject' def display_retries(self, instance): num_logs = instance.logs__count if num_logs == 1: pk = instance.logs.all()[0].id url = reverse('admin:mailer_smtplog_change', args=(pk, )) else: url = reverse('admin:mailer_smtplog_changelist') url += '?&message=%i' % instance.pk return format_html( '<a href="{}" onclick="return showAddAnotherPopup(this);">{}</a>', url, instance.retries) display_retries.short_description = _("Retries") display_retries.admin_order_field = 'retries' def display_content(self, instance): part = email.message_from_string(instance.content) payload = part.get_payload() if isinstance(payload, list): for cpart in payload: cpayload = cpart.get_payload() if cpart.get_content_type().startswith('text/'): part = cpart payload = cpayload if cpart.get_content_type() == 'text/html': payload = '<div style="padding-left:110px">%s</div>' % payload # prioritize HTML break if part.get('Content-Transfer-Encoding') == 'base64': payload = base64.b64decode(payload) charset = part.get_charsets()[0] if charset: payload = payload.decode(charset) if part.get_content_type() == 'text/plain': payload = payload.replace('\n', '<br>').replace(' ', ' ') return mark_safe(payload) display_content.short_description = _("Content") def display_full_subject(self, instance): return instance.subject display_full_subject.short_description = _("Subject") def display_from(self, instance): return instance.from_address display_from.short_description = _("From") def display_to(self, instance): return instance.to_address display_to.short_description = _("To") def get_urls(self): from django.conf.urls import url urls = super().get_urls() info = self.model._meta.app_label, self.model._meta.model_name urls.insert( 0, url(r'^send-pending/$', wrap_admin_view(self, self.send_pending_view), name='%s_%s_send_pending' % info)) return urls def get_queryset(self, request): qs = super().get_queryset(request) return qs.annotate(Count('logs')).defer('content') def send_pending_view(self, request): task(send_pending).apply_async() self.message_user( request, _("Pending messages are being sent on the background.")) return redirect('..') def formfield_for_dbfield(self, db_field, **kwargs): if db_field.name == 'subject': kwargs['widget'] = forms.TextInput(attrs={'size': '100'}) return super().formfield_for_dbfield(db_field, **kwargs)
class BillAdmin(BillAdminMixin, ExtendedModelAdmin): list_display = ('number', 'type_link', 'account_link', 'closed_on_display', 'updated_on_display', 'num_lines', 'display_total', 'display_payment_state', 'is_sent') list_filter = ( BillTypeListFilter, 'is_open', 'is_sent', TotalListFilter, PaymentStateListFilter, AmendedListFilter, 'account__is_active', ) add_fields = ('account', 'type', 'amend_of', 'is_open', 'due_on', 'comments') change_list_template = 'admin/bills/bill/change_list.html' fieldsets = ( (None, { 'fields': [ 'number', 'type', (), 'account_link', 'display_total_with_subtotals', 'display_payment_state', 'is_sent', 'comments' ], }), (_("Dates"), { 'classes': ('collapse', ), 'fields': ('created_on_display', 'closed_on_display', 'updated_on_display', 'due_on'), }), (_("Raw"), { 'classes': ('collapse', ), 'fields': ('html', ), }), ) list_prefetch_related = ('transactions', 'lines__sublines') search_fields = ('number', 'account__username', 'comments') change_view_actions = [ actions.manage_lines, actions.view_bill, actions.download_bills, actions.send_bills, actions.close_bills, actions.amend_bills, actions.close_send_download_bills, ] actions = [ actions.manage_lines, actions.download_bills, actions.close_bills, actions.send_bills, actions.amend_bills, actions.bill_report, actions.service_report, actions.close_send_download_bills, list_accounts, ] change_readonly_fields = ('account_link', 'type', 'is_open', 'amend_of_link') readonly_fields = ( 'number', 'display_total', 'is_sent', 'display_payment_state', 'created_on_display', 'closed_on_display', 'updated_on_display', 'display_total_with_subtotals', ) date_hierarchy = 'closed_on' created_on_display = admin_date('created_on', short_description=_("Created")) closed_on_display = admin_date('closed_on', short_description=_("Closed")) updated_on_display = admin_date('updated_on', short_description=_("Updated")) amend_of_link = admin_link('amend_of') # def amend_links(self, bill): # links = [] # for amend in bill.amends.all(): # url = reverse('admin:bills_bill_change', args=(amend.id,)) # links.append('<a href="{url}">{num}</a>'.format(url=url, num=amend.number)) # return '<br>'.join(links) # amend_links.short_description = _("Amends") # amend_links.allow_tags = True def num_lines(self, bill): return bill.lines__count num_lines.admin_order_field = 'lines__count' num_lines.short_description = _("lines") def display_total(self, bill): currency = settings.BILLS_CURRENCY.lower() return '%s &%s;' % (bill.compute_total(), currency) display_total.allow_tags = True display_total.short_description = _("total") display_total.admin_order_field = 'approx_total' def type_link(self, bill): bill_type = bill.type.lower() url = reverse('admin:bills_%s_changelist' % bill_type) return '<a href="%s">%s</a>' % (url, bill.get_type_display()) type_link.allow_tags = True type_link.short_description = _("type") type_link.admin_order_field = 'type' def get_urls(self): """ Hook bill lines management URLs on bill admin """ urls = super().get_urls() admin_site = self.admin_site extra_urls = [ url("^manage-lines/$", admin_site.admin_view( BillLineManagerAdmin(BillLine, admin_site).changelist_view), name='bills_bill_manage_lines'), ] return extra_urls + urls def get_readonly_fields(self, request, obj=None): fields = super().get_readonly_fields(request, obj) if obj and not obj.is_open: fields += self.add_fields return fields def get_fieldsets(self, request, obj=None): fieldsets = super().get_fieldsets(request, obj) if obj: # Switches between amend_of_link and amend_links fields fields = fieldsets[0][1]['fields'] if obj.amend_of_id: fields[2] = 'amend_of_link' else: fields[2] = () if obj.is_open: fieldsets = fieldsets[0:-1] return fieldsets def get_change_view_actions(self, obj=None): actions = super().get_change_view_actions(obj) exclude = [] if obj: if not obj.is_open: exclude += ['close_bills', 'close_send_download_bills'] if obj.type not in obj.AMEND_MAP: exclude += ['amend_bills'] return [action for action in actions if action.__name__ not in exclude] def get_inline_instances(self, request, obj=None): cls = type(self) if obj and not obj.is_open: if obj.amends.all(): cls.inlines = [AmendInline, ClosedBillLineInline] else: cls.inlines = [ClosedBillLineInline] else: cls.inlines = [BillLineInline] return super().get_inline_instances(request, obj) def formfield_for_dbfield(self, db_field, **kwargs): """ Make value input widget bigger """ if db_field.name == 'comments': kwargs['widget'] = forms.Textarea(attrs={'cols': 70, 'rows': 4}) elif db_field.name == 'html': kwargs['widget'] = forms.Textarea(attrs={'cols': 150, 'rows': 20}) formfield = super().formfield_for_dbfield(db_field, **kwargs) if db_field.name == 'amend_of': formfield.queryset = formfield.queryset.filter(is_open=False) return formfield def change_view(self, request, object_id, **kwargs): # TODO raise404, here and everywhere bill = self.get_object(request, unquote(object_id)) actions.validate_contact(request, bill, error=False) return super().change_view(request, object_id, **kwargs)
class OrderAdmin(AccountAdminMixin, ExtendedModelAdmin): list_display = ('display_description', 'service_link', 'account_link', 'content_object_link', 'display_registered_on', 'display_billed_until', 'display_cancelled_on', 'display_metric') list_filter = ( ActiveOrderListFilter, IgnoreOrderListFilter, BilledOrderListFilter, 'account__type', 'service', ) default_changelist_filters = (('ignore', '0'), ) actions = (BillSelectedOrders(), mark_as_ignored, mark_as_not_ignored, report, list_accounts) change_view_actions = (BillSelectedOrders(), mark_as_ignored, mark_as_not_ignored) date_hierarchy = 'registered_on' inlines = (MetricStorageInline, ) add_inlines = () search_fields = ( 'account__username', 'content_object_repr', 'description', ) list_prefetch_related = ( 'content_object', Prefetch('metrics', queryset=MetricStorage.objects.order_by('-id')), ) list_select_related = ('account', 'service') add_fieldsets = ( (None, { 'fields': ('account', 'service') }), (_("Object"), { 'fields': ( 'content_type', 'object_id', ), }), (_("State"), { 'fields': ('registered_on', 'cancelled_on', 'billed_on', 'billed_metric', 'billed_until') }), (None, { 'fields': ( 'description', 'ignore', ), }), ) fieldsets = ( (None, { 'fields': ('account_link', 'service_link', 'content_object_link'), }), (_("State"), { 'fields': ('registered_on', 'cancelled_on', 'billed_on', 'billed_metric', 'billed_until') }), (None, { 'fields': ('description', 'ignore', 'bills_links'), }), ) readonly_fields = ('content_object_repr', 'content_object_link', 'bills_links', 'account_link', 'service_link') service_link = admin_link('service') display_registered_on = admin_date('registered_on') display_cancelled_on = admin_date('cancelled_on') def display_description(self, order): return order.description[:64] display_description.short_description = _("Description") display_description.allow_tags = True display_description.admin_order_field = 'description' def content_object_link(self, order): if order.content_object: try: url = change_url(order.content_object) except NoReverseMatch: # Does not has admin return order.content_object_repr description = str(order.content_object) return '<a href="{url}">{description}</a>'.format( url=url, description=description) return order.content_object_repr content_object_link.short_description = _("Content object") content_object_link.allow_tags = True content_object_link.admin_order_field = 'content_object_repr' def bills_links(self, order): bills = [] make_link = admin_link() for line in order.lines.select_related('bill').distinct('bill'): bills.append(make_link(line.bill)) return '<br>'.join(bills) bills_links.short_description = _("Bills") bills_links.allow_tags = True def display_billed_until(self, order): billed_until = order.billed_until red = False human = escape(naturaldate(billed_until)) if billed_until: if order.cancelled_on and order.cancelled_on <= billed_until: pass elif order.service.billing_period == order.service.NEVER: human = _("Forever") elif order.service.payment_style == order.service.POSTPAY: boundary = order.service.handler.get_billing_point(order) if billed_until < boundary: red = True elif billed_until < timezone.now().date(): red = True color = 'style="color:red;"' if red else '' return '<span title="{raw}" {color}>{human}</span>'.format( raw=escape(str(billed_until)), color=color, human=human, ) display_billed_until.short_description = _("billed until") display_billed_until.allow_tags = True display_billed_until.admin_order_field = 'billed_until' def display_metric(self, order): """ dispalys latest metric value, don't uses latest() because not loosing prefetch_related """ try: metric = order.metrics.all()[0] except IndexError: return '' return metric.value display_metric.short_description = _("Metric") def formfield_for_dbfield(self, db_field, **kwargs): """ Make value input widget bigger """ if db_field.name == 'description': kwargs['widget'] = forms.Textarea(attrs={'cols': 70, 'rows': 2}) return super().formfield_for_dbfield(db_field, **kwargs)
class TransactionAdmin(SelectAccountAdminMixin, ExtendedModelAdmin): list_display = ('id', 'bill_link', 'account_link', 'source_link', 'display_created_at', 'display_modified_at', 'display_state', 'amount', 'process_link') list_filter = ('source__method', 'state') fieldsets = ( (None, { 'classes': ('wide', ), 'fields': ('account_link', 'bill_link', 'source_link', 'display_state', 'amount', 'currency', 'process_link') }), (_("Dates"), { 'classes': ('wide', ), 'fields': ('display_created_at', 'display_modified_at'), }), ) add_fieldsets = ((None, { 'classes': ('wide', ), 'fields': ( 'bill', 'source', 'display_state', 'amount', 'currency', ) }), ) change_view_actions = (actions.process_transactions, actions.mark_as_executed, actions.mark_as_secured, actions.mark_as_rejected, actions.reissue) search_fields = ('bill__number', 'bill__account__username', 'id') actions = change_view_actions + ( actions.report, list_accounts, ) filter_by_account_fields = ('bill', 'source') readonly_fields = ('bill_link', 'display_state', 'process_link', 'account_link', 'source_link', 'display_created_at', 'display_modified_at') list_select_related = ('source', 'bill__account', 'process') date_hierarchy = 'created_at' bill_link = admin_link('bill') source_link = admin_link('source') process_link = admin_link('process', short_description=_("proc")) account_link = admin_link('bill__account') display_created_at = admin_date('created_at', short_description=_("Created")) display_modified_at = admin_date('modified_at', short_description=_("Modified")) def has_delete_permission(self, *args, **kwargs): return False def get_actions(self, request): actions = super().get_actions(request) if 'delete_selected' in actions: del actions['delete_selected'] return actions def get_change_readonly_fields(self, request, obj): if obj.state in (Transaction.WAITTING_PROCESSING, Transaction.WAITTING_EXECUTION): return () return ('amount', 'currency') def get_change_view_actions(self, obj=None): actions = super(TransactionAdmin, self).get_change_view_actions() exclude = [] if obj: if obj.state == Transaction.WAITTING_PROCESSING: exclude = ['mark_as_executed', 'mark_as_secured', 'reissue'] elif obj.state == Transaction.WAITTING_EXECUTION: exclude = [ 'process_transactions', 'mark_as_secured', 'reissue' ] if obj.state == Transaction.EXECUTED: exclude = [ 'process_transactions', 'mark_as_executed', 'reissue' ] elif obj.state == Transaction.REJECTED: exclude = [ 'process_transactions', 'mark_as_executed', 'mark_as_secured', 'mark_as_rejected' ] elif obj.state == Transaction.SECURED: return [] return [action for action in actions if action.__name__ not in exclude] def display_state(self, obj): state = admin_colored('state', colors=STATE_COLORS)(obj) help_text = obj.get_state_help() state = state.replace('<span ', '<span title="%s" ' % help_text) return state display_state.admin_order_field = 'state' display_state.short_description = _("State") display_state.allow_tags = True
class ResourceInline(GenericTabularInline): model = ResourceData verbose_name_plural = _("resources") form = ResourceForm formset = ResourceInlineFormSet can_delete = False fields = ( 'verbose_name', 'display_used', 'display_updated', 'allocated', 'unit', ) readonly_fields = ( 'display_used', 'display_updated', ) class Media: css = {'all': ('orchestra/css/hide-inline-id.css', )} display_updated = admin_date('updated_at', default=_("Never")) def get_fieldsets(self, request, obj=None): if obj: opts = self.parent_model._meta url = reverse('admin:resources_resourcedata_list_related', args=(opts.app_label, opts.model_name, obj.id)) link = '<a href="%s">%s</a>' % (url, _("List related")) self.verbose_name_plural = mark_safe( _("Resources") + ' ' + link) return super(ResourceInline, self).get_fieldsets(request, obj) @mark_safe def display_used(self, rdata): update = '' history = '' if rdata.pk: context = { 'title': _("Update"), 'url': reverse('admin:resources_resourcedata_monitor', args=(rdata.pk, )), 'image': '<img src="%s"></img>' % static('orchestra/images/reload.png'), } update = '<a href="%(url)s" title="%(title)s">%(image)s</a>' % context context.update({ 'title': _("Show history"), 'image': '<img src="%s"></img>' % static('orchestra/images/history.png'), 'url': reverse('admin:resources_resourcedata_show_history', args=(rdata.pk, )), 'popup': 'onclick="return showAddAnotherPopup(this);"', }) history = '<a href="%(url)s" title="%(title)s" %(popup)s>%(image)s</a>' % context if rdata.used is not None: used_url = reverse( 'admin:resources_resourcedata_used_monitordata', args=(rdata.pk, )) used = '<a href="%s">%s %s</a>' % (used_url, rdata.used, rdata.unit) return ' '.join(map(str, (used, update, history))) if rdata.resource.monitors: return _("Unknonw %s %s") % (update, history) return _("No monitor") display_used.short_description = _("Used") def has_add_permission(self, *args, **kwargs): """ Hidde add another """ return False
class ResourceDataAdmin(ExtendedModelAdmin): list_display = ('id', 'resource_link', content_object_link, 'allocated', 'display_used', 'display_updated') list_filter = ('resource', ) fields = ( 'resource_link', 'content_type', content_object_link, 'display_updated', 'display_used', 'allocated', ) search_fields = ('content_object_repr', ) readonly_fields = fields actions = (run_monitor, show_history) change_view_actions = actions ordering = ('-updated_at', ) list_select_related = ('resource__content_type', 'content_type') resource_link = admin_link('resource') display_updated = admin_date('updated_at', short_description=_("Updated")) def get_urls(self): """Returns the additional urls for the change view links""" urls = super(ResourceDataAdmin, self).get_urls() admin_site = self.admin_site opts = self.model._meta return [ url('^(\d+)/used-monitordata/$', admin_site.admin_view(self.used_monitordata_view), name='%s_%s_used_monitordata' % (opts.app_label, opts.model_name)), url('^history_data/$', admin_site.admin_view(history_data), name='%s_%s_history_data' % (opts.app_label, opts.model_name)), url('^list-related/(.+)/(.+)/(\d+)/$', admin_site.admin_view(self.list_related_view), name='%s_%s_list_related' % (opts.app_label, opts.model_name)), ] + urls def display_used(self, rdata): if rdata.used is None: return '' url = reverse('admin:resources_resourcedata_used_monitordata', args=(rdata.pk, )) return format_html('<a href="{}">{} {}</a>', url, rdata.used, rdata.unit) display_used.short_description = _("Used") display_used.admin_order_field = 'used' def has_add_permission(self, *args, **kwargs): return False def used_monitordata_view(self, request, object_id): url = reverse('admin:resources_monitordata_changelist') url += '?resource_data=%s' % object_id return redirect(url) def list_related_view(self, request, app_name, model_name, object_id): resources = Resource.objects.select_related('content_type') resource_models = { r.content_type.model_class(): r.content_type_id for r in resources } # Self model = apps.get_model(app_name, model_name) obj = model.objects.get(id=int(object_id)) ct_id = resource_models[model] qset = Q(content_type_id=ct_id, object_id=obj.id, resource__is_active=True) # Related for field, rel in obj._meta.fields_map.items(): try: ct_id = resource_models[rel.related_model] except KeyError: pass else: manager = getattr(obj, field) ids = manager.values_list('id', flat=True) qset = Q(qset) | Q(content_type_id=ct_id, object_id__in=ids, resource__is_active=True) related = ResourceData.objects.filter(qset) related_ids = related.values_list('id', flat=True) related_ids = ','.join(map(str, related_ids)) url = reverse('admin:resources_resourcedata_changelist') url += '?id__in=%s' % related_ids return redirect(url)
class TicketAdmin(ExtendedModelAdmin): list_display = ( 'unbold_id', 'bold_subject', 'display_creator', 'display_owner', 'display_queue', 'display_priority', 'display_state', 'updated' ) list_display_links = ('unbold_id', 'bold_subject') list_filter = ( MyTicketsListFilter, 'queue', 'priority', TicketStateListFilter, ) default_changelist_filters = ( ('state', 'OPEN'), ) date_hierarchy = 'created_at' search_fields = ( 'id', 'subject', 'creator__username', 'creator__email', 'queue__name', 'owner__username' ) actions = ( mark_as_unread, mark_as_read, 'delete_selected', reject_tickets, resolve_tickets, close_tickets, take_tickets ) sudo_actions = ('delete_selected',) change_view_actions = ( resolve_tickets, close_tickets, reject_tickets, take_tickets ) # change_form_template = "admin/orchestra/change_form.html" form = TicketForm add_inlines = () inlines = (MessageReadOnlyInline, MessageInline) readonly_fields = ( 'display_summary', 'display_queue', 'display_owner', 'display_state', 'display_priority' ) readonly_fieldsets = ( (None, { 'fields': ('display_summary', ('display_queue', 'display_owner'), ('display_state', 'display_priority'), 'display_description') }), ) fieldsets = readonly_fieldsets + ( ('Update', { 'classes': ('collapse',), 'fields': ('subject', ('queue', 'owner',), ('state', 'priority'), 'description') }), ) add_fieldsets = ( (None, { 'fields': ('subject', ('queue', 'owner',), ('state', 'priority'), 'description') }), ) list_select_related = ('queue', 'owner', 'creator') class Media: css = { 'all': ('issues/css/ticket-admin.css',) } js = ( 'issues/js/ticket-admin.js', ) display_creator = admin_link('creator') display_queue = admin_link('queue') display_owner = admin_link('owner') updated = admin_date('updated_at') display_state = admin_colored('state', colors=STATE_COLORS, bold=False) display_priority = admin_colored('priority', colors=PRIORITY_COLORS, bold=False) @mark_safe def display_summary(self, ticket): context = { 'creator': admin_link('creator')(self, ticket) if ticket.creator else ticket.creator_name, 'created': admin_date('created_at')(ticket), 'updated': '', } msg = ticket.messages.last() if msg: context.update({ 'updated': admin_date('created_at')(msg), 'updater': admin_link('author')(self, msg) if msg.author else msg.author_name, }) context['updated'] = '. Updated by %(updater)s about %(updated)s' % context return '<h4>Added by %(creator)s about %(created)s%(updated)s</h4>' % context display_summary.short_description = 'Summary' def unbold_id(self, ticket): """ Unbold id if ticket is read """ if ticket.is_read_by(self.user): return format_html('<span style="font-weight:normal;font-size:11px;">{}</span>', ticket.pk) return ticket.pk unbold_id.short_description = "#" unbold_id.admin_order_field = 'id' def bold_subject(self, ticket): """ Bold subject when tickets are unread for request.user """ if ticket.is_read_by(self.user): return ticket.subject return format_html("<strong class='unread'>{}</strong>", ticket.subject) bold_subject.short_description = _("Subject") bold_subject.admin_order_field = 'subject' def formfield_for_dbfield(self, db_field, **kwargs): """ Make value input widget bigger """ if db_field.name == 'subject': kwargs['widget'] = forms.TextInput(attrs={'size':'120'}) return super(TicketAdmin, self).formfield_for_dbfield(db_field, **kwargs) def save_model(self, request, obj, *args, **kwargs): """ Define creator for new tickets """ if not obj.pk: obj.creator = request.user super(TicketAdmin, self).save_model(request, obj, *args, **kwargs) obj.mark_as_read_by(request.user) def get_urls(self): """ add markdown preview url """ return [ url(r'^preview/$', wrap_admin_view(self, self.message_preview_view)) ] + super(TicketAdmin, self).get_urls() def add_view(self, request, form_url='', extra_context=None): """ Do not sow message inlines """ return super(TicketAdmin, self).add_view(request, form_url, extra_context) def change_view(self, request, object_id, form_url='', extra_context=None): """ Change view actions based on ticket state """ ticket = get_object_or_404(Ticket, pk=object_id) # Change view actions based on ticket state self.change_view_actions = filter_actions(self, ticket, request) if request.method == 'POST': # Hack: Include the ticket changes on the request.POST # other approaches get really messy changes = get_ticket_changes(self, request, ticket) if changes: content = markdown_formated_changes(changes) content += request.POST['messages-2-0-content'] request.POST['messages-2-0-content'] = content ticket.mark_as_read_by(request.user) context = {'title': "Issue #%i - %s" % (ticket.id, ticket.subject)} context.update(extra_context or {}) return super(TicketAdmin, self).change_view(request, object_id, form_url=form_url, extra_context=context) def changelist_view(self, request, extra_context=None): # Hook user for bold_subject self.user = request.user return super(TicketAdmin,self).changelist_view(request, extra_context=extra_context) def message_preview_view(self, request): """ markdown preview render via ajax """ data = request.POST.get("data") data_formated = markdown(strip_tags(data)) return HttpResponse(data_formated)
from django.utils.translation import ugettext_lazy as _ from djcelery.admin import PeriodicTaskAdmin from orchestra.admin.utils import admin_date display_last_run_at = admin_date('last_run_at', short_description=_("Last run")) PeriodicTaskAdmin.list_display = ('__unicode__', display_last_run_at, 'total_run_count', 'enabled')
class TransactionProcessAdmin(ChangeViewActionsMixin, admin.ModelAdmin): list_display = ( 'id', 'file_url', 'display_transactions', 'display_state', 'display_created_at', ) list_filter = ('state', ) fields = ('data', 'file_url', 'created_at') search_fields = ('transactions__bill__number', 'transactions__bill__account__username', 'id') readonly_fields = ('data', 'file_url', 'display_transactions', 'created_at') list_prefetch_related = ('transactions', ) inlines = [TransactionInline] change_view_actions = (actions.mark_process_as_executed, actions.abort, actions.commit, actions.report) actions = change_view_actions + (actions.delete_selected, ) display_state = admin_colored('state', colors=PROCESS_STATE_COLORS) display_created_at = admin_date('created_at', short_description=_("Created")) def file_url(self, process): if process.file: return '<a href="%s">%s</a>' % (process.file.url, process.file.name) file_url.allow_tags = True file_url.admin_order_field = 'file' def display_transactions(self, process): ids = [] lines = [] counter = 0 for trans in process.transactions.all(): color = STATE_COLORS.get(trans.state, 'black') state = trans.get_state_display() ids.append('<span style="color:%s" title="%s">%i</span>' % (color, state, trans.id)) counter += 1 + len(str(trans.id)) if counter > 100: counter = 0 lines.append(','.join(ids)) ids = [] lines.append(','.join(ids)) transactions = '<br>'.join(lines) url = reverse('admin:payments_transaction_changelist') url += '?process_id=%i' % process.id return '<a href="%s">%s</a>' % (url, transactions) display_transactions.short_description = _("Transactions") display_transactions.allow_tags = True def has_add_permission(self, *args, **kwargs): return False def get_change_view_actions(self, obj=None): actions = super().get_change_view_actions() exclude = [] if obj: if obj.state == TransactionProcess.EXECUTED: exclude.append('mark_process_as_executed') elif obj.state == TransactionProcess.COMMITED: exclude = ['mark_process_as_executed', 'abort', 'commit'] elif obj.state == TransactionProcess.ABORTED: exclude = ['mark_process_as_executed', 'abort', 'commit'] return [action for action in actions if action.__name__ not in exclude] def delete_view(self, request, object_id, extra_context=None): queryset = self.model.objects.filter(id=object_id) related_transactions = helpers.pre_delete_processes( self, request, queryset) response = super().delete_view(request, object_id, extra_context) if isinstance(response, HttpResponseRedirect): helpers.post_delete_processes(self, request, related_transactions) return response