base dashboard module class all dashboard modules widgets should inherit it path to widget s template there is no need to extend such templates from any base templates specify if module can be draggable or has static position specify if module can be collapsed specify if module can be deleted default widget title that will be displayed for widget in the dashboard user can change it later for every widget specify title url none if title shouldn t be clickable html content that will be displayed before widget content html content that will be displayed after widget content a django forms form class which may contain custom widget settings not required a django forms form class which may contain custom widget child settings if it has any not required child name that will be displayed when editing module contents required if childform set same as child name but plural a boolean field which specify if widget should be rendered on dashboard page load or fetched later via ajax a boolean field which makes widget ui color contrast optional style attributes which will be applied to widget content container should be implemented to restore saved in database settings required if you have custom settings specify if children field should be saved to database should be implemented to save settings to database this method should return dict which will be serialized using json required if you have custom settings allows you to load data and initialize module s state list of links widget usage example codeblock python from django utils translation import ugettextlazy as from jet dashboard import modules from jet dashboard dashboard import dashboard appindexdashboard class customindexdashboarddashboard columns 3 def initwithcontextself context self availablechildren appendmodules linklist self children appendmodules linklist support children title django documentation url http docs djangoproject com external true title django djangousers mailing list url http groups google comgroupdjangousers external true title django irc channel url irc irc freenode netdjango external true column0 order0 specify widget layout allowed values stacked and inline links are contained in children attribute which you can pass as constructor parameter to make your own preinstalled link lists children is an array of dictinaries title django documentation url http docs djangoproject com external true shows applications and containing models links for each model created and change links are displayed usage example codeblock python from django utils translation import ugettextlazy as from jet dashboard import modules from jet dashboard dashboard import dashboard appindexdashboard class customindexdashboarddashboard columns 3 def initwithcontextself context self children appendmodules applist applications exclude auth column0 order0 specify models which should be displayed models is an array of string formatted as applabel model also its possible to specify all application models with sign e g auth specify models which should not be displayed exclude is an array of string formatted as applabel model also its possible to specify all application models with sign e g auth shows models links for each model created and change links are displayed usage example codeblock python from django utils translation import ugettextlazy as from jet dashboard import modules from jet dashboard dashboard import dashboard appindexdashboard class customindexdashboarddashboard columns 3 def initwithcontextself context self children appendmodules modellist models exclude auth column0 order0 specify models which should be displayed models is an array of string formatted as applabel model also its possible to specify all application models with sign e g auth specify models which should not be displayed exclude is an array of string formatted as applabel model also its possible to specify all application models with sign e g auth display list of most recent admin actions with following information entity name type of action date usage example codeblock python from django utils translation import ugettextlazy as from jet dashboard import modules from jet dashboard dashboard import dashboard appindexdashboard class customindexdashboarddashboard columns 3 def initwithcontextself context self children appendmodules recentactions recent actions 10 column0 order0 number if entries to be shown may be changed by each user personally specify actions of which models should be displayed includelist is an array of string formatted as applabel model also its possible to specify all application models with sign e g auth specify actions of which models should not be displayed excludelist is an array of string formatted as applabel model also its possible to specify all application models with sign e g auth display rss feed entries with following information entry title date and link to the full version usage example codeblock python from django utils translation import ugettextlazy as from jet dashboard import modules from jet dashboard dashboard import dashboard appindexdashboard class customindexdashboarddashboard columns 3 def initwithcontextself context self children appendmodules feed latest django news feedurl http www djangoproject comrssweblog limit5 column0 order0 url of the rss feed may be changed by each user personally number if entries to be shown may be changed by each user personally base dashboard module class all dashboard modules widgets should inherit it path to widget s template there is no need to extend such templates from any base templates specify if module can be draggable or has static position specify if module can be collapsed specify if module can be deleted default widget title that will be displayed for widget in the dashboard user can change it later for every widget specify title url none if title shouldn t be clickable html content that will be displayed before widget content html content that will be displayed after widget content a django forms form class which may contain custom widget settings not required a django forms form class which may contain custom widget child settings if it has any not required child name that will be displayed when editing module contents required if child_form set same as child name but plural a boolean field which specify if widget should be rendered on dashboard page load or fetched later via ajax a boolean field which makes widget ui color contrast optional style attributes which will be applied to widget content container should be implemented to restore saved in database settings required if you have custom settings specify if children field should be saved to database should be implemented to save settings to database this method should return dict which will be serialized using json required if you have custom settings allows you to load data and initialize module s state list of links widget usage example code block python from django utils translation import ugettext_lazy as _ from jet dashboard import modules from jet dashboard dashboard import dashboard appindexdashboard class customindexdashboard dashboard columns 3 def init_with_context self context self available_children append modules linklist self children append modules linklist _ support children title _ django documentation url http docs djangoproject com external true title _ django django users mailing list url http groups google com group django users external true title _ django irc channel url irc irc freenode net django external true column 0 order 0 specify widget layout allowed values stacked and inline links are contained in children attribute which you can pass as constructor parameter to make your own preinstalled link lists children is an array of dictinaries title _ django documentation url http docs djangoproject com external true shows applications and containing models links for each model created and change links are displayed usage example code block python from django utils translation import ugettext_lazy as _ from jet dashboard import modules from jet dashboard dashboard import dashboard appindexdashboard class customindexdashboard dashboard columns 3 def init_with_context self context self children append modules applist _ applications exclude auth column 0 order 0 specify models which should be displayed models is an array of string formatted as app_label model also its possible to specify all application models with sign e g auth specify models which should not be displayed exclude is an array of string formatted as app_label model also its possible to specify all application models with sign e g auth shows models links for each model created and change links are displayed usage example code block python from django utils translation import ugettext_lazy as _ from jet dashboard import modules from jet dashboard dashboard import dashboard appindexdashboard class customindexdashboard dashboard columns 3 def init_with_context self context self children append modules modellist _ models exclude auth column 0 order 0 specify models which should be displayed models is an array of string formatted as app_label model also its possible to specify all application models with sign e g auth specify models which should not be displayed exclude is an array of string formatted as app_label model also its possible to specify all application models with sign e g auth display list of most recent admin actions with following information entity name type of action date usage example code block python from django utils translation import ugettext_lazy as _ from jet dashboard import modules from jet dashboard dashboard import dashboard appindexdashboard class customindexdashboard dashboard columns 3 def init_with_context self context self children append modules recentactions _ recent actions 10 column 0 order 0 number if entries to be shown may be changed by each user personally specify actions of which models should be displayed include_list is an array of string formatted as app_label model also its possible to specify all application models with sign e g auth specify actions of which models should not be displayed exclude_list is an array of string formatted as app_label model also its possible to specify all application models with sign e g auth display rss feed entries with following information entry title date and link to the full version usage example code block python from django utils translation import ugettext_lazy as _ from jet dashboard import modules from jet dashboard dashboard import dashboard appindexdashboard class customindexdashboard dashboard columns 3 def init_with_context self context self children append modules feed _ latest django news feed_url http www djangoproject com rss weblog limit 5 column 0 order 0 url of the rss feed may be changed by each user personally number if entries to be shown may be changed by each user personally
import json
from django import forms
from django.contrib.admin.models import LogEntry
from django.db.models import Q
from django.template.loader import render_to_string
from django.utils.translation import ugettext_lazy as _
from jet.utils import get_app_list, LazyDateTimeEncoder, context_to_dict
import datetime


class DashboardModule(object):
    

    
    template = 'jet.dashboard/module.html'
    enabled = True

    
    draggable = True

    
    collapsible = True

    
    deletable = True
    show_title = True

    
    
    title = ''

    
    title_url = None
    css_classes = None

    
    pre_content = None

    
    post_content = None
    children = None

    
    settings_form = None

    
    child_form = None

    
    child_name = None

    
    child_name_plural = None
    settings = None
    column = None
    order = None

    
    
    ajax_load = False

    
    contrast = False

    
    style = False

    class Media:
        css = ()
        js = ()

    def __init__(self, title=None, model=None, context=None, **kwargs):
        if title is not None:
            self.title = title
        self.model = model
        self.context = context or {}

        for key in kwargs:
            if hasattr(self.__class__, key):
                setattr(self, key, kwargs[key])

        self.children = self.children or []

        if self.model:
            self.load_from_model()

    def fullname(self):
        return self.__module__ + "." + self.__class__.__name__

    def load_settings(self, settings):
        
        pass

    def load_children(self, children):
        self.children = children

    def store_children(self):
        
        return False

    def settings_dict(self):
        
        pass

    def dump_settings(self, settings=None):
        settings = settings or self.settings_dict()
        if settings:
            return json.dumps(settings, cls=LazyDateTimeEncoder)
        else:
            return ''

    def dump_children(self):
        if self.store_children():
            return json.dumps(self.children, cls=LazyDateTimeEncoder)
        else:
            return ''

    def load_from_model(self):
        self.title = self.model.title

        if self.model.settings:
            try:
                self.settings = json.loads(self.model.settings)
                self.load_settings(self.settings)
            except ValueError:
                pass

        if self.store_children() and self.model.children:
            try:
                children = json.loads(self.model.children)
                self.load_children(children)
            except ValueError:
                pass

    def init_with_context(self, context):
        
        pass

    def get_context_data(self):
        context = context_to_dict(self.context)
        context.update({
            'module': self
        })
        return context

    def render(self):
        self.init_with_context(self.context)
        return render_to_string(self.template, self.get_context_data())


class LinkListItemForm(forms.Form):
    url = forms.CharField(label=_('URL'))
    title = forms.CharField(label=_('Title'))
    external = forms.BooleanField(label=_('External link'), required=False)


class LinkListSettingsForm(forms.Form):
    layout = forms.ChoiceField(label=_('Layout'), choices=(('stacked', _('Stacked')), ('inline', _('Inline'))))


class LinkList(DashboardModule):
    

    title = _('Links')
    template = 'jet.dashboard/modules/link_list.html'

    
    
    layout = 'stacked'

    
    
    
    
    
    
    
    
    
    
    
    
    
    children = []
    settings_form = LinkListSettingsForm
    child_form = LinkListItemForm
    child_name = _('Link')
    child_name_plural = _('Links')

    def __init__(self, title=None, children=list(), **kwargs):
        children = list(map(self.parse_link, children))
        kwargs.update({'children': children})
        super(LinkList, self).__init__(title, **kwargs)

    def settings_dict(self):
        return {
            'draggable': self.draggable,
            'deletable': self.deletable,
            'collapsible': self.collapsible,
            'layout': self.layout
        }

    def load_settings(self, settings):
        self.draggable = settings.get('draggable', self.draggable)
        self.deletable = settings.get('deletable', self.deletable)
        self.collapsible = settings.get('collapsible', self.collapsible)
        self.layout = settings.get('layout', self.layout)

    def store_children(self):
        return True

    def parse_link(self, link):
        if isinstance(link, (tuple, list)):
            link_dict = {'title': link[0], 'url': link[1]}
            if len(link) >= 3:
                link_dict['external'] = link[2]
            return link_dict
        elif isinstance(link, (dict,)):
            return link


class AppList(DashboardModule):
    

    title = _('Applications')
    template = 'jet.dashboard/modules/app_list.html'

    
    
    models = None

    
    
    exclude = None
    hide_empty = True

    def settings_dict(self):
        return {
            'models': self.models,
            'exclude': self.exclude
        }

    def load_settings(self, settings):
        self.models = settings.get('models')
        self.exclude = settings.get('exclude')

    def init_with_context(self, context):
        app_list = get_app_list(context)
        app_to_remove = []

        for app in app_list:
            app_name = app.get('app_label', app.get('name', ''))
            app['models'] = filter(
                lambda model: self.models is None or ('%s.%s' % (app_name, model['object_name'])) in self.models or ('%s.*' % app_name) in self.models,
                app['models']
            )
            app['models'] = filter(
                lambda model: self.exclude is None or (('%s.%s' % (app_name, model['object_name'])) not in self.exclude and ('%s.*' % app_name) not in self.exclude),
                app['models']
            )
            app['models'] = list(app['models'])

            if self.hide_empty and len(list(app['models'])) == 0:
                app_to_remove.append(app)

        for app in app_to_remove:
            app_list.remove(app)

        self.children = app_list


class ModelList(DashboardModule):
    

    title = _('Models')
    template = 'jet.dashboard/modules/model_list.html'

    
    
    models = None

    
    
    exclude = None
    hide_empty = True

    def settings_dict(self):
        return {
            'models': self.models,
            'exclude': self.exclude
        }

    def load_settings(self, settings):
        self.models = settings.get('models')
        self.exclude = settings.get('exclude')

    def init_with_context(self, context):
        app_list = get_app_list(context)
        models = []

        for app in app_list:
            app_name = app.get('app_label', app.get('name', ''))
            app['models'] = filter(
                lambda model: self.models is None or ('%s.%s' % (app_name, model['object_name'])) in self.models or ('%s.*' % app_name) in self.models,
                app['models']
            )
            app['models'] = filter(
                lambda model: self.exclude is None or (('%s.%s' % (app_name, model['object_name'])) not in self.exclude and ('%s.*' % app_name) not in self.exclude),
                app['models']
            )
            app['models'] = list(app['models'])

            models.extend(app['models'])

        self.children = models


class RecentActionsSettingsForm(forms.Form):
    limit = forms.IntegerField(label=_('Items limit'), min_value=1)


class RecentActions(DashboardModule):
    

    title = _('Recent Actions')
    template = 'jet.dashboard/modules/recent_actions.html'

    
    limit = 10

    
    
    
    include_list = None

    
    
    
    exclude_list = None
    settings_form = RecentActionsSettingsForm
    user = None

    def __init__(self, title=None, limit=10, **kwargs):
        kwargs.update({'limit': limit})
        super(RecentActions, self).__init__(title, **kwargs)

    def settings_dict(self):
        return {
            'limit': self.limit,
            'include_list': self.include_list,
            'exclude_list': self.exclude_list,
            'user': self.user
        }

    def load_settings(self, settings):
        self.limit = settings.get('limit', self.limit)
        self.include_list = settings.get('include_list')
        self.exclude_list = settings.get('exclude_list')
        self.user = settings.get('user', None)

    def init_with_context(self, context):
        def get_qset(list):
            qset = None
            for contenttype in list:
                try:
                    app_label, model = contenttype.split('.')

                    if model == '*':
                        current_qset = Q(
                            content_type__app_label=app_label
                        )
                    else:
                        current_qset = Q(
                            content_type__app_label=app_label,
                            content_type__model=model
                        )
                except:
                    raise ValueError('Invalid contenttype: "%s"' % contenttype)

                if qset is None:
                    qset = current_qset
                else:
                    qset = qset | current_qset
            return qset

        qs = LogEntry.objects

        if self.user:
            qs = qs.filter(
                user__pk=int(self.user)
            )

        if self.include_list:
            qs = qs.filter(get_qset(self.include_list))
        if self.exclude_list:
            qs = qs.exclude(get_qset(self.exclude_list))

        self.children = qs.select_related('content_type', 'user')[:int(self.limit)]


class FeedSettingsForm(forms.Form):
    limit = forms.IntegerField(label=_('Items limit'), min_value=1)
    feed_url = forms.URLField(label=_('Feed URL'))


class Feed(DashboardModule):
    

    title = _('RSS Feed')
    template = 'jet.dashboard/modules/feed.html'

    
    feed_url = None

    
    limit = None
    settings_form = FeedSettingsForm
    ajax_load = True

    def __init__(self, title=None, feed_url=None, limit=None, **kwargs):
        kwargs.update({'feed_url': feed_url, 'limit': limit})
        super(Feed, self).__init__(title, **kwargs)

    def settings_dict(self):
        return {
            'feed_url': self.feed_url,
            'limit': self.limit
        }

    def load_settings(self, settings):
        self.feed_url = settings.get('feed_url')
        self.limit = settings.get('limit')

    def init_with_context(self, context):
        if self.feed_url is not None:
            try:
                import feedparser

                feed = feedparser.parse(self.feed_url)

                if self.limit is not None:
                    entries = feed['entries'][:self.limit]
                else:
                    entries = feed['entries']

                for entry in entries:
                    try:
                        entry.date = datetime.date(*entry.published_parsed[0:3])
                    except:
                        pass

                    self.children.append(entry)
            except ImportError:
                self.children.append({
                    'title': _('You must install the FeedParser python module'),
                    'warning': True,
                })
        else:
            self.children.append({
                'title': _('You must provide a valid feed URL'),
                'warning': True,
            })