Commits

Rajeesh Nair  committed 8ae23bb

Django-monitor: New feature to summarize moderation

* Now there is single place showing the summary of moderated objects
of all models under the change-link, ``Moderation Queue``. User can
check this page to know how many objects are to be moderated for
each model.

  • Participants
  • Parent commits 8654e3f
  • Tags 0.1.4a

Comments (0)

Files changed (24)

 Django-monitor: CHANGE LOG
 ==========================
 
+0.1.4
+======
+
+* Now we have finished implementation of one more TODO things: A single place
+  to manage monitored objects. The model change-link, ``Moderation Queue``,
+  under the app, ``Monitor`` in admin-home page leads user to a page listing
+  the counts of pending/challenged objects for each monitored models.
+
+* ERROR_FIX: In ``monitor.admin.has_delete_permission``, we tried to retrieve
+  the model class as ``self.opts.model``. It should be ``self.model``. Fixed.
+
 0.1.3
 ======
 
 ----------------
 Any object created by a user with add permission will have an ``In Pending``
 status. If the user has got moderate permission also, the object created will
-automatically get approved (status is ``Approved``).
+automatically get approved (status becomes ``Approved``).
 
 Moderation from within admin changelist
 ----------------------------------------
 More details at http://django-monitor.readthedocs.org. Or check the `docs/`
 directory inside the source path, if you are working offline.
 
-To Do
-======
-
-* There should be a notification area to show counts of pending as well as
-  challenged objects for each moderated model. So user need not routinely check
-  every changelist just to know if there exists entries to be moderated.
-

File docs/build/doctrees/admin_howto.doctree

Binary file modified.

File docs/build/doctrees/dev_howto.doctree

Binary file modified.

File docs/build/doctrees/environment.pickle

Binary file modified.

File docs/build/doctrees/intro.doctree

Binary file modified.

File docs/build/html/_images/custom_changelist2.jpg

Removed
Old image

File docs/build/html/_images/custom_changelist4.jpg

Added
New image

File docs/build/html/_sources/admin_howto.txt

    :scale: 70
    :alt: Change-list
 
-Who can moderate?
+Who can moderate
 ==================
 
 Django-monitor creates a moderate permission for each moderated model. Only
 model. The superuser must assign those permissions to the appropriate users
 as they would do with other commonly found permissions.
 
-How to know the status of objects in change-list?
-=================================================
-By default, all existing objects of each model appear in its change-list. For
-moderated models, we add one more column, ``status`` to the right of each row.
-That column, as its name indicates, displays the current moderation status of
-each object you see in the list. Also, you can filter the objects by their
+What to moderate & from where
+===============================
+
+To see and moderate the pending/challenged objects of a particualr model, visit
+the change-list page of that model. By default, all existing objects appear
+there. For moderated models, we add one more column, ``status`` to the right of
+each row. That column, as its name indicates, displays the current moderation
+status of each object you see in the list. This helps you to identify the
+pending as well as challenged objects. Also, you can filter the objects by their
 ``moderation status`` using the filter options provided in the box to the right
 of change-list. Refer to the screen-shot given above.
 
-How to moderate?
+You need not regularly visit change-lists of all models to know whether there
+are any objects to be moderated. ``Moderation Queue`` is the shortcut for this.
+It will summarize the moderation status for all models in one page. Click on
+the ``Moderation Queue`` change-link under the ``Monitor`` app in your admin
+home page. You can see the number of pending and challenged objects for each
+moderated model arranged in a nice table in the resulting page. Clicking on
+each number will lead you to the corresponding change-list filtered by the
+respective status. eg, if you clicked on the number of pending objects of the
+model, say, `Book`, the change-list showing all pending book objects will be
+loaded.
+
+How to moderate
 =================
 
 Moderation is performed through 3 special change-list actions. They are,

File docs/build/html/_sources/dev_howto.txt

 ``monitor.get_monitor_entry`` and then invoke applicable public method of it.
 Available methods of monitor_entry are as follows:
 
+.. note::
+
+   ``user`` is an optional parameter in all those methods described below.
+   Please pass the current user to the methods in all possible cases.
+   ``request.user`` can be used for this whenever ``request`` is available.
+   Otherwise, you can use ``get_current_user`` from ``monitor.middleware``.
+
 #. approve:
     ::
 

File docs/build/html/_sources/intro.txt

 
 .. _`intro`:
 
-===============
-Introduction
-===============
+===============================
+Introduction to Django-monitor
+===============================
+
+.. note::
+   You can skip this chapter if you have already read the README document in
+   source path.
 
 About
 =====
 
 Moderation seems to be some job each one want to do in their own way.
-Django-monitor is yet another django-app to help moderate model objects.
-It was started by cloning the project `django-gatekeeper` but offers
-different set of features. The name ``monitor`` is just to distinguish it
-from the existing app, `django-moderation`. (The terms, ``monitor`` and
-``moderate`` are used with same meaning everywhere in the source code.)
+Django-monitor is a django-app to moderate model objects. It was started as
+a clone of the `django-gatekeeper` project but with a different set of
+requirements. The name ``monitor`` is just to distinguish it from an existing
+project, `django-moderation`. (The terms, ``monitor`` and ``moderate`` are used
+with same meaning everywhere in the source.)
 
 Here, the moderation process is well integrated with django-admin. That is,
 all moderation actvities are performed from within the changelist page itself.
 Install
 ========
 
-Grab the Source
-----------------
 * Download the latest version from bitbucket repo:
   http://bitbucket.org/rajeesh/django-monitor.
 
-Place it in your path
-----------------------
 * Copy the ``monitor`` directory to some place in your python path.
 
-Add to your project
---------------------
 * Add to your django project by including it in settings.INSTALLED_APPS.
 
 Features
 
 Model-specific permission
 --------------------------
-Each moderated model will have an associated moderate permission of the form,
-``moderate_<model_name>`` where `<model_name>` represents the name of the
-model. Only those users with that permission will be able to approve or
-challenge any object created for that model.
+Each moderated model will have an associated moderate permission. To approve
+or challenge any object created for a particular model, users need to have
+the corresponding permission.
 
 Auto-moderation
 ----------------
 Any object created by a user with add permission will have an ``In Pending``
 status. If the user has got moderate permission also, the object created will
-automatically get approved (status is ``Approved``).
+automatically get approved (status becomes ``Approved``).
 
 Moderation from within admin changelist
 ----------------------------------------
-The changelist view displays an additional column showing current moderation
-status of each object. Also, you can filter the changelist entries by their
-moderation status. Three actions, ``approve``, ``challenge`` and
-``reset to pending`` are provided for moderation. The user just need to select
-the objects, choose appropriate action and press ``Go`` to moderate.
+The changelist of a moderated model displays the current moderation status of
+all objects. Also, you can filter the objects by their moderation status. Three
+actions are available for moderation. To moderate, user just need to select the
+objects, choose appropriate action and press ``Go``.
 
 Related moderation
 -------------------
 model objects which also can get moderated along with the original ones. The
 developer can specify such related models to be moderated during registration.
 
-Edit-Lock
-----------
-The developer can protect the approved objects from further modification to
-maintain data integrity. The fields which are not meant to be changed after
-approval can be specified in the model-admin using ``protected_fields`` option.
-The model-admin will club them with readonly_fields if the object is approved.
+Data protection
+----------------
+The developer can prevent admin-users from changing values of selected fields
+of approved objects. Deleting approved objects also can be prevented if your
+client's business requires that.
 
-TODO
-======
-* There should be a facility to lock deletion of approved objects too.
-
-* There should be a notification area to show counts of pending as well as
-  challenged objects for each moderated model. So user need not routinely check
-  every changelist just to know if there exists entries to be moderated.
-

File docs/build/html/admin_howto.html

 <p>All moderation activities can be performed from within the admin changelist
 itself. The changelist view of a moderated model will look like that in the
 screen-shot below :</p>
-<a class="reference internal image-reference" href="_images/custom_changelist2.jpg"><img alt="Change-list" src="_images/custom_changelist2.jpg" style="width: 715.4px; height: 396.9px;" /></a>
+<a class="reference internal image-reference" href="_images/custom_changelist4.jpg"><img alt="Change-list" src="_images/custom_changelist4.jpg" style="width: 715.4px; height: 396.9px;" /></a>
 <div class="section" id="who-can-moderate">
-<h2>Who can moderate?<a class="headerlink" href="#who-can-moderate" title="Permalink to this headline">¶</a></h2>
+<h2>Who can moderate<a class="headerlink" href="#who-can-moderate" title="Permalink to this headline">¶</a></h2>
 <p>Django-monitor creates a moderate permission for each moderated model. Only
 those users with required permission can moderate any object of a particular
 model. The superuser must assign those permissions to the appropriate users
 as they would do with other commonly found permissions.</p>
 </div>
-<div class="section" id="how-to-know-the-status-of-objects-in-change-list">
-<h2>How to know the status of objects in change-list?<a class="headerlink" href="#how-to-know-the-status-of-objects-in-change-list" title="Permalink to this headline">¶</a></h2>
-<p>By default, all existing objects of each model appear in its change-list. For
-moderated models, we add one more column, <tt class="docutils literal"><span class="pre">status</span></tt> to the right of each row.
-That column, as its name indicates, displays the current moderation status of
-each object you see in the list. Also, you can filter the objects by their
+<div class="section" id="what-to-moderate-from-where">
+<h2>What to moderate &amp; from where<a class="headerlink" href="#what-to-moderate-from-where" title="Permalink to this headline">¶</a></h2>
+<p>To see and moderate the pending/challenged objects of a particualr model, visit
+the change-list page of that model. By default, all existing objects appear
+there. For moderated models, we add one more column, <tt class="docutils literal"><span class="pre">status</span></tt> to the right of
+each row. That column, as its name indicates, displays the current moderation
+status of each object you see in the list. This helps you to identify the
+pending as well as challenged objects. Also, you can filter the objects by their
 <tt class="docutils literal"><span class="pre">moderation</span> <span class="pre">status</span></tt> using the filter options provided in the box to the right
 of change-list. Refer to the screen-shot given above.</p>
+<p>You need not regularly visit change-lists of all models to know whether there
+are any objects to be moderated. <tt class="docutils literal"><span class="pre">Moderation</span> <span class="pre">Queue</span></tt> is the shortcut for this.
+It will summarize the moderation status for all models in one page. Click on
+the <tt class="docutils literal"><span class="pre">Moderation</span> <span class="pre">Queue</span></tt> change-link under the <tt class="docutils literal"><span class="pre">Monitor</span></tt> app in your admin
+home page. You can see the number of pending and challenged objects for each
+moderated model arranged in a nice table in the resulting page. Clicking on
+each number will lead you to the corresponding change-list filtered by the
+respective status. eg, if you clicked on the number of pending objects of the
+model, say, <cite>Book</cite>, the change-list showing all pending book objects will be
+loaded.</p>
 </div>
 <div class="section" id="how-to-moderate">
-<h2>How to moderate?<a class="headerlink" href="#how-to-moderate" title="Permalink to this headline">¶</a></h2>
+<h2>How to moderate<a class="headerlink" href="#how-to-moderate" title="Permalink to this headline">¶</a></h2>
 <p>Moderation is performed through 3 special change-list actions. They are,
 <tt class="docutils literal"><span class="pre">Approve</span> <span class="pre">selected</span></tt>, <tt class="docutils literal"><span class="pre">Challenge</span> <span class="pre">selected</span></tt> and <tt class="docutils literal"><span class="pre">Reset</span> <span class="pre">selected</span> <span class="pre">to</span> <span class="pre">pending</span></tt>.
 If the manager selects few objects, choose the action <tt class="docutils literal"><span class="pre">Approve</span> <span class="pre">selected</span></tt> and
   <h3><a href="index.html">Table Of Contents</a></h3>
   <ul>
 <li><a class="reference internal" href="#">How to use (for admin-users)</a><ul>
-<li><a class="reference internal" href="#who-can-moderate">Who can moderate?</a></li>
-<li><a class="reference internal" href="#how-to-know-the-status-of-objects-in-change-list">How to know the status of objects in change-list?</a></li>
-<li><a class="reference internal" href="#how-to-moderate">How to moderate?</a></li>
+<li><a class="reference internal" href="#who-can-moderate">Who can moderate</a></li>
+<li><a class="reference internal" href="#what-to-moderate-from-where">What to moderate &amp; from where</a></li>
+<li><a class="reference internal" href="#how-to-moderate">How to moderate</a></li>
 </ul>
 </li>
 </ul>

File docs/build/html/dev_howto.html

     <script type="text/javascript" src="_static/doctools.js"></script>
     <link rel="top" title="Django-monitor v0.1 documentation" href="index.html" />
     <link rel="next" title="How to use (for admin-users)" href="admin_howto.html" />
-    <link rel="prev" title="Introduction" href="intro.html" /> 
+    <link rel="prev" title="Introduction to Django-monitor" href="intro.html" /> 
   </head>
   <body>
     <div class="related">
           <a href="admin_howto.html" title="How to use (for admin-users)"
              accesskey="N">next</a> |</li>
         <li class="right" >
-          <a href="intro.html" title="Introduction"
+          <a href="intro.html" title="Introduction to Django-monitor"
              accesskey="P">previous</a> |</li>
         <li><a href="index.html">Django-monitor v0.1 documentation</a> &raquo;</li> 
       </ul>
 such an object as you wish, get its associated monitor_entry using
 <tt class="docutils literal"><span class="pre">monitor.get_monitor_entry</span></tt> and then invoke applicable public method of it.
 Available methods of monitor_entry are as follows:</p>
+<div class="admonition note">
+<p class="first admonition-title">Note</p>
+<p class="last"><tt class="docutils literal"><span class="pre">user</span></tt> is an optional parameter in all those methods described below.
+Please pass the current user to the methods in all possible cases.
+<tt class="docutils literal"><span class="pre">request.user</span></tt> can be used for this whenever <tt class="docutils literal"><span class="pre">request</span></tt> is available.
+Otherwise, you can use <tt class="docutils literal"><span class="pre">get_current_user</span></tt> from <tt class="docutils literal"><span class="pre">monitor.middleware</span></tt>.</p>
+</div>
 <ol class="arabic">
 <li><dl class="first docutils">
 <dt>approve:</dt>
 
   <h4>Previous topic</h4>
   <p class="topless"><a href="intro.html"
-                        title="previous chapter">Introduction</a></p>
+                        title="previous chapter">Introduction to Django-monitor</a></p>
   <h4>Next topic</h4>
   <p class="topless"><a href="admin_howto.html"
                         title="next chapter">How to use (for admin-users)</a></p>
           <a href="admin_howto.html" title="How to use (for admin-users)"
              >next</a> |</li>
         <li class="right" >
-          <a href="intro.html" title="Introduction"
+          <a href="intro.html" title="Introduction to Django-monitor"
              >previous</a> |</li>
         <li><a href="index.html">Django-monitor v0.1 documentation</a> &raquo;</li> 
       </ul>

File docs/build/html/index.html

     <script type="text/javascript" src="_static/underscore.js"></script>
     <script type="text/javascript" src="_static/doctools.js"></script>
     <link rel="top" title="Django-monitor v0.1 documentation" href="#" />
-    <link rel="next" title="Introduction" href="intro.html" /> 
+    <link rel="next" title="Introduction to Django-monitor" href="intro.html" /> 
   </head>
   <body>
     <div class="related">
           <a href="genindex.html" title="General Index"
              accesskey="I">index</a></li>
         <li class="right" >
-          <a href="intro.html" title="Introduction"
+          <a href="intro.html" title="Introduction to Django-monitor"
              accesskey="N">next</a> |</li>
         <li><a href="#">Django-monitor v0.1 documentation</a> &raquo;</li> 
       </ul>
 <p>Contents:</p>
 <div class="toctree-wrapper compound">
 <ul>
-<li class="toctree-l1"><a class="reference internal" href="intro.html">Introduction</a><ul>
+<li class="toctree-l1"><a class="reference internal" href="intro.html">Introduction to Django-monitor</a><ul>
 <li class="toctree-l2"><a class="reference internal" href="intro.html#about">About</a></li>
 <li class="toctree-l2"><a class="reference internal" href="intro.html#install">Install</a></li>
 <li class="toctree-l2"><a class="reference internal" href="intro.html#features">Features</a></li>
-<li class="toctree-l2"><a class="reference internal" href="intro.html#todo">TODO</a></li>
 </ul>
 </li>
 <li class="toctree-l1"><a class="reference internal" href="dev_howto.html">How to use (for developers)</a><ul>
 </ul>
 </li>
 <li class="toctree-l1"><a class="reference internal" href="admin_howto.html">How to use (for admin-users)</a><ul>
-<li class="toctree-l2"><a class="reference internal" href="admin_howto.html#who-can-moderate">Who can moderate?</a></li>
-<li class="toctree-l2"><a class="reference internal" href="admin_howto.html#how-to-know-the-status-of-objects-in-change-list">How to know the status of objects in change-list?</a></li>
-<li class="toctree-l2"><a class="reference internal" href="admin_howto.html#how-to-moderate">How to moderate?</a></li>
+<li class="toctree-l2"><a class="reference internal" href="admin_howto.html#who-can-moderate">Who can moderate</a></li>
+<li class="toctree-l2"><a class="reference internal" href="admin_howto.html#what-to-moderate-from-where">What to moderate &amp; from where</a></li>
+<li class="toctree-l2"><a class="reference internal" href="admin_howto.html#how-to-moderate">How to moderate</a></li>
 </ul>
 </li>
 </ul>
 
   <h4>Next topic</h4>
   <p class="topless"><a href="intro.html"
-                        title="next chapter">Introduction</a></p>
+                        title="next chapter">Introduction to Django-monitor</a></p>
   <h3>This Page</h3>
   <ul class="this-page-menu">
     <li><a href="_sources/index.txt"
           <a href="genindex.html" title="General Index"
              >index</a></li>
         <li class="right" >
-          <a href="intro.html" title="Introduction"
+          <a href="intro.html" title="Introduction to Django-monitor"
              >next</a> |</li>
         <li><a href="#">Django-monitor v0.1 documentation</a> &raquo;</li> 
       </ul>

File docs/build/html/intro.html

   <head>
     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
     
-    <title>Introduction &mdash; Django-monitor v0.1 documentation</title>
+    <title>Introduction to Django-monitor &mdash; Django-monitor v0.1 documentation</title>
     <link rel="stylesheet" href="_static/default.css" type="text/css" />
     <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
     <script type="text/javascript">
         <div class="bodywrapper">
           <div class="body">
             
-  <div class="section" id="introduction">
-<span id="intro"></span><h1>Introduction<a class="headerlink" href="#introduction" title="Permalink to this headline">¶</a></h1>
+  <div class="section" id="introduction-to-django-monitor">
+<span id="intro"></span><h1>Introduction to Django-monitor<a class="headerlink" href="#introduction-to-django-monitor" title="Permalink to this headline">¶</a></h1>
+<div class="admonition note">
+<p class="first admonition-title">Note</p>
+<p class="last">You can skip this chapter if you have already read the README document in
+source path.</p>
+</div>
 <div class="section" id="about">
 <h2>About<a class="headerlink" href="#about" title="Permalink to this headline">¶</a></h2>
 <p>Moderation seems to be some job each one want to do in their own way.
-Django-monitor is yet another django-app to help moderate model objects.
-It was started by cloning the project <cite>django-gatekeeper</cite> but offers
-different set of features. The name <tt class="docutils literal"><span class="pre">monitor</span></tt> is just to distinguish it
-from the existing app, <cite>django-moderation</cite>. (The terms, <tt class="docutils literal"><span class="pre">monitor</span></tt> and
-<tt class="docutils literal"><span class="pre">moderate</span></tt> are used with same meaning everywhere in the source code.)</p>
+Django-monitor is a django-app to moderate model objects. It was started as
+a clone of the <cite>django-gatekeeper</cite> project but with a different set of
+requirements. The name <tt class="docutils literal"><span class="pre">monitor</span></tt> is just to distinguish it from an existing
+project, <cite>django-moderation</cite>. (The terms, <tt class="docutils literal"><span class="pre">monitor</span></tt> and <tt class="docutils literal"><span class="pre">moderate</span></tt> are used
+with same meaning everywhere in the source.)</p>
 <p>Here, the moderation process is well integrated with django-admin. That is,
 all moderation actvities are performed from within the changelist page itself.</p>
 </div>
 <div class="section" id="install">
 <h2>Install<a class="headerlink" href="#install" title="Permalink to this headline">¶</a></h2>
-<div class="section" id="grab-the-source">
-<h3>Grab the Source<a class="headerlink" href="#grab-the-source" title="Permalink to this headline">¶</a></h3>
 <ul class="simple">
 <li>Download the latest version from bitbucket repo:
 <a class="reference external" href="http://bitbucket.org/rajeesh/django-monitor">http://bitbucket.org/rajeesh/django-monitor</a>.</li>
-</ul>
-</div>
-<div class="section" id="place-it-in-your-path">
-<h3>Place it in your path<a class="headerlink" href="#place-it-in-your-path" title="Permalink to this headline">¶</a></h3>
-<ul class="simple">
 <li>Copy the <tt class="docutils literal"><span class="pre">monitor</span></tt> directory to some place in your python path.</li>
-</ul>
-</div>
-<div class="section" id="add-to-your-project">
-<h3>Add to your project<a class="headerlink" href="#add-to-your-project" title="Permalink to this headline">¶</a></h3>
-<ul class="simple">
 <li>Add to your django project by including it in settings.INSTALLED_APPS.</li>
 </ul>
 </div>
-</div>
 <div class="section" id="features">
 <h2>Features<a class="headerlink" href="#features" title="Permalink to this headline">¶</a></h2>
 <div class="section" id="model-specific-permission">
 <h3>Model-specific permission<a class="headerlink" href="#model-specific-permission" title="Permalink to this headline">¶</a></h3>
-<p>Each moderated model will have an associated moderate permission of the form,
-<tt class="docutils literal"><span class="pre">moderate_&lt;model_name&gt;</span></tt> where <cite>&lt;model_name&gt;</cite> represents the name of the
-model. Only those users with that permission will be able to approve or
-challenge any object created for that model.</p>
+<p>Each moderated model will have an associated moderate permission. To approve
+or challenge any object created for a particular model, users need to have
+the corresponding permission.</p>
 </div>
 <div class="section" id="auto-moderation">
 <h3>Auto-moderation<a class="headerlink" href="#auto-moderation" title="Permalink to this headline">¶</a></h3>
 <p>Any object created by a user with add permission will have an <tt class="docutils literal"><span class="pre">In</span> <span class="pre">Pending</span></tt>
 status. If the user has got moderate permission also, the object created will
-automatically get approved (status is <tt class="docutils literal"><span class="pre">Approved</span></tt>).</p>
+automatically get approved (status becomes <tt class="docutils literal"><span class="pre">Approved</span></tt>).</p>
 </div>
 <div class="section" id="moderation-from-within-admin-changelist">
 <h3>Moderation from within admin changelist<a class="headerlink" href="#moderation-from-within-admin-changelist" title="Permalink to this headline">¶</a></h3>
-<p>The changelist view displays an additional column showing current moderation
-status of each object. Also, you can filter the changelist entries by their
-moderation status. Three actions, <tt class="docutils literal"><span class="pre">approve</span></tt>, <tt class="docutils literal"><span class="pre">challenge</span></tt> and
-<tt class="docutils literal"><span class="pre">reset</span> <span class="pre">to</span> <span class="pre">pending</span></tt> are provided for moderation. The user just need to select
-the objects, choose appropriate action and press <tt class="docutils literal"><span class="pre">Go</span></tt> to moderate.</p>
+<p>The changelist of a moderated model displays the current moderation status of
+all objects. Also, you can filter the objects by their moderation status. Three
+actions are available for moderation. To moderate, user just need to select the
+objects, choose appropriate action and press <tt class="docutils literal"><span class="pre">Go</span></tt>.</p>
 </div>
 <div class="section" id="related-moderation">
 <h3>Related moderation<a class="headerlink" href="#related-moderation" title="Permalink to this headline">¶</a></h3>
 model objects which also can get moderated along with the original ones. The
 developer can specify such related models to be moderated during registration.</p>
 </div>
-<div class="section" id="edit-lock">
-<h3>Edit-Lock<a class="headerlink" href="#edit-lock" title="Permalink to this headline">¶</a></h3>
-<p>The developer can protect the approved objects from further modification to
-maintain data integrity. The fields which are not meant to be changed after
-approval can be specified in the model-admin using <tt class="docutils literal"><span class="pre">protected_fields</span></tt> option.
-The model-admin will club them with readonly_fields if the object is approved.</p>
+<div class="section" id="data-protection">
+<h3>Data protection<a class="headerlink" href="#data-protection" title="Permalink to this headline">¶</a></h3>
+<p>The developer can prevent admin-users from changing values of selected fields
+of approved objects. Deleting approved objects also can be prevented if your
+client&#8217;s business requires that.</p>
 </div>
 </div>
-<div class="section" id="todo">
-<h2>TODO<a class="headerlink" href="#todo" title="Permalink to this headline">¶</a></h2>
-<ul class="simple">
-<li>There should be a facility to lock deletion of approved objects too.</li>
-<li>There should be a notification area to show counts of pending as well as
-challenged objects for each moderated model. So user need not routinely check
-every changelist just to know if there exists entries to be moderated.</li>
-</ul>
-</div>
 </div>
 
 
         <div class="sphinxsidebarwrapper">
   <h3><a href="index.html">Table Of Contents</a></h3>
   <ul>
-<li><a class="reference internal" href="#">Introduction</a><ul>
+<li><a class="reference internal" href="#">Introduction to Django-monitor</a><ul>
 <li><a class="reference internal" href="#about">About</a></li>
-<li><a class="reference internal" href="#install">Install</a><ul>
-<li><a class="reference internal" href="#grab-the-source">Grab the Source</a></li>
-<li><a class="reference internal" href="#place-it-in-your-path">Place it in your path</a></li>
-<li><a class="reference internal" href="#add-to-your-project">Add to your project</a></li>
-</ul>
-</li>
+<li><a class="reference internal" href="#install">Install</a></li>
 <li><a class="reference internal" href="#features">Features</a><ul>
 <li><a class="reference internal" href="#model-specific-permission">Model-specific permission</a></li>
 <li><a class="reference internal" href="#auto-moderation">Auto-moderation</a></li>
 <li><a class="reference internal" href="#moderation-from-within-admin-changelist">Moderation from within admin changelist</a></li>
 <li><a class="reference internal" href="#related-moderation">Related moderation</a></li>
-<li><a class="reference internal" href="#edit-lock">Edit-Lock</a></li>
+<li><a class="reference internal" href="#data-protection">Data protection</a></li>
 </ul>
 </li>
-<li><a class="reference internal" href="#todo">TODO</a></li>
 </ul>
 </li>
 </ul>

File docs/build/html/objects.inv

Binary file modified.

File docs/build/html/searchindex.js

-Search.setIndex({objects:{},terms:{all:[0,2,3],code:[0,1,3],shot:2,help:[0,1,3],just:[0,3],show:3,also:[2,3],when:[0,3],yourmodeladmin:0,approv:[0,2,3],model_nam:3,supplement:0,through:2,permiss:[2,3],follow:0,still:0,yet:3,row:2,current:[2,3],onli:[0,2,3],monitoradmin:0,monitor:[0,1,2,3],field:[0,3],field2:0,copi:3,field1:0,activ:[0,2],specif:3,should:[0,3],alwai:0,add:[2,3],pend:[0,2,3],certain:0,must:2,might:0,modul:1,is_challeng:0,meant:3,reset:[2,3],non:2,sourc:3,everi:3,rememb:0,thei:[0,2],get:[0,2,3],read:0,prefer:0,watch:0,repo:3,know:[0,1,2,3],got:3,press:[2,3],requir:[0,2],introduct:[1,3],term:3,name:[0,2,3],organ:0,hook:[0,1],edit:3,signal:0,list:[0,1,2],correct:2,separ:0,provid:[2,3],either:0,each:[0,2,3],found:2,grab:3,get_monitor_entri:0,where:3,manag:[0,2,3],view:[2,3],few:2,prevent:0,right:2,mai:[0,2,3],replac:0,creation:[0,1],some:[0,2,3],moderate_:3,is_approv:0,similarli:2,see:[0,2],connect:0,pass:0,download:3,further:3,todo:[1,3],moder:[0,1,2,3],special:[0,1,2],after:[0,2,3],index:1,statu:[0,1,2,3],appear:2,assum:0,section:0,abl:3,below:[0,2],your:[0,3],content:1,delet:[0,3],written:0,version:3,leav:0,directori:3,method:0,django:[0,1,2,3],"import":0,paramet:0,"public":0,modeladmin:0,refer:[0,2],signatur:0,particular:[0,2],full:0,deriv:0,kei:0,whose:0,screen:2,usag:0,given:2,here:[0,3],like:2,job:3,let:0,your_model:0,put:0,org:3,gatekeep:3,modifi:0,valu:0,addit:3,box:2,both:0,search:1,is_pend:0,column:[2,3],someth:0,page:[1,3],queue:0,related_nam:0,place:3,monitorentri:0,fals:0,charfield:0,chang:[0,1,2,3],mean:3,handler_func:0,commonli:2,origin:[0,3],readonly_field:[0,3],own:3,onc:[0,2],app:3,within:[2,3],reset_to_pend:0,automat:3,two:0,distinguish:3,set:[0,3],done:0,path:3,instal:[1,3],installed_app:3,facil:3,post:[0,1],select:[2,3],differ:[0,3],rajeesh:3,modif:3,would:[0,2],area:3,data:[0,1,3],regist:0,three:[0,3],custom:0,avail:0,start:3,busi:0,includ:3,arg1:0,other:[0,2,3],challeng:[0,2,3],python:3,too:[0,2,3],"function":0,verifi:[0,2],from:[0,2,3],assign:2,option:[0,2,3],form:3,manager_nam:0,club:3,handler:0,notif:3,protect:[0,1,3],specifi:[0,3],argument:0,indic:[1,2],enqueu:[0,1],rel_field:0,max_length:0,inlin:0,"true":0,former:0,those:[0,2,3],sender:0,count:3,admin:[0,1,2,3],none:0,bookadmin:0,my_inst:0,instanc:0,"default":[0,2],wish:0,monitor_entri:0,monitor_nam:0,displai:[2,3],exampl:0,project:3,defin:0,invok:0,kwarg:0,can:[0,1,2,3],abov:[0,2],foreignkei:0,about:[0,1,3],more:[0,2],def:0,note:0,featur:[1,3],want:[0,3],creat:[0,2,3],look:2,process:3,lock:3,dure:[0,3],registr:[0,1,3],share:0,them:[2,3],changelist:[2,3],repres:3,handl:0,wai:3,shell:0,exist:[2,3],inherit:0,have:[0,3],tabl:1,need:3,seem:3,foreign:0,routin:3,check:[0,2,3],integr:3,everywher:3,filter:[2,3],develop:[0,1,3],built:0,perform:[0,2,3],anoth:3,self:1,offer:3,tip:0,detail:0,same:3,write:0,how:[0,1,2],book:0,build:0,which:[0,3],auto:3,instead:0,you:[0,2,3],prepar:0,enabl:0,protected_field:[0,3],relat:[0,1,3],http:3,thi:0,again:2,status_nam:0,clone:3,who:[1,2],my_model:0,what:0,superus:2,action:[2,3],user:[0,1,2,3],applic:0,along:[0,3],supplementinlin:0,associ:[0,3],"class":[0,1],bitbucket:3,appropri:[2,3],base_manag:0,ani:[2,3],entri:[2,3],mymodel:0,well:3,can_delete_approv:0,object:[0,1,2,3],actviti:3,post_moder:0,itself:[2,3],maintain:3,runtim:0,allow:0,choos:[2,3],model:[0,1,2,3],usual:0,make:[0,2],latest:3},objtypes:{},titles:["How to use (for developers)","Django-monitor self-help","How to use (for admin-users)","Introduction"],objnames:{},filenames:["dev_howto","index","admin_howto","intro"]})
+Search.setIndex({objects:{},terms:{origin:[0,3],all:[0,2,3],code:[0,1],shot:2,help:[0,1,2],just:[0,3],show:2,also:[2,3],when:[0,3],yourmodeladmin:0,approv:[0,2,3],supplement:0,through:2,particualr:2,permiss:[2,3],skip:3,identifi:2,still:0,row:2,current:[0,2,3],onli:[0,2],monitoradmin:0,monitor:[0,1,2,3],field:[0,3],field2:0,copi:3,field1:0,activ:[0,2],specif:3,shortcut:2,should:0,add:[2,3],pend:[0,2,3],about:[0,1,3],under:2,set:[0,3],must:2,might:0,app:[2,3],is_challeng:0,"case":0,non:2,sourc:3,rememb:0,thei:[0,2],get:[0,2,3],read:[0,3],prefer:0,watch:0,regularli:2,know:[0,2],got:3,press:[2,3],requir:[0,2,3],introduct:[1,3],well:[2,3],term:3,verifi:[0,2],name:[0,2,3],organ:0,hook:[0,1],signal:0,possibl:0,list:[0,2],correct:2,separ:0,"default":[0,2],follow:0,either:0,each:[0,2,3],found:2,get_monitor_entri:0,where:[1,2],page:[1,2,3],view:2,pleas:0,prevent:[0,3],right:2,nice:2,mai:[0,2,3],regist:0,replac:0,creation:[0,1],some:[0,2,3],is_approv:0,see:[0,2],result:2,pass:0,download:3,home:2,click:2,special:[0,1,2],after:[0,2],index:1,what:[0,1,2],appear:2,lead:2,section:0,below:[0,2],summar:2,content:1,delet:[0,3],written:0,version:3,leav:0,select:[2,3],method:0,django:[0,1,2,3],"import":0,paramet:0,"public":0,modeladmin:0,integr:3,signatur:0,particular:[0,2,3],full:0,deriv:0,kei:0,whose:0,post:[0,1],screen:2,usag:0,given:2,here:[0,3],like:2,job:3,let:0,arrang:2,put:0,path:3,gatekeep:3,becom:3,modifi:0,refer:[0,2],valu:[0,3],box:2,both:0,search:1,is_pend:0,column:2,someth:0,manag:[0,2,3],queue:[0,2],related_nam:0,place:3,monitorentri:0,fals:0,charfield:0,chang:[0,2,3],mean:3,handler_func:0,commonli:2,load:2,readonly_field:0,own:3,onc:[0,2],modul:1,within:[2,3],reset_to_pend:0,number:2,automat:3,two:0,distinguish:3,alreadi:3,done:0,org:3,respect:2,installed_app:3,assum:0,your:[0,2,3],middlewar:0,differ:[0,3],rajeesh:3,from:[0,1,2,3],describ:0,would:[0,2],few:2,data:[0,1,3],visit:2,three:[0,3],custom:0,avail:[0,3],start:3,again:2,busi:[0,3],includ:3,arg1:0,other:[0,2,3],instanc:0,instal:[1,3],challeng:[0,2,3],too:[0,2],"function":0,chapter:3,assign:2,option:[0,2],filter:[2,3],manager_nam:0,python:3,handler:0,similarli:2,protect:[0,1,3],specifi:[0,3],argument:0,provid:2,link:2,indic:[1,2],enqueu:[0,1],rel_field:0,max_length:0,inlin:0,"true":0,former:0,those:[0,2],sender:0,reset:2,admin:[0,1,2,3],none:0,bookadmin:0,my_inst:0,whenev:0,whether:2,wish:0,monitor_entri:0,moder:[0,1,2,3],monitor_nam:0,displai:[2,3],exampl:0,project:3,defin:0,invok:0,kwarg:0,can:[0,1,2,3],abov:[0,2],foreignkei:0,your_model:0,more:[0,2],def:0,connect:0,note:[0,3],sai:2,featur:[1,3],want:[0,3],creat:[0,2,3],look:2,process:3,certain:0,dure:[0,3],registr:[0,1,3],readm:3,them:2,changelist:[2,3],correspond:[2,3],handl:0,wai:3,shell:0,exist:[2,3],inherit:0,have:[0,3],tabl:[1,2],need:[2,3],seem:3,foreign:0,check:[0,2],everywher:3,alwai:0,develop:[0,1,3],built:0,perform:[0,2,3],otherwis:0,self:1,tip:0,detail:0,same:3,write:0,how:[0,1,2],book:[0,2],build:0,which:[0,3],auto:3,instead:0,you:[0,2,3],document:3,prepar:0,enabl:0,protected_field:0,relat:[0,1,3],http:3,thi:[0,2,3],get_current_us:0,status_nam:0,clone:3,who:[1,2],my_model:0,statu:[0,2,3],superus:2,action:[2,3],user:[0,1,2,3],applic:0,share:0,along:[0,3],supplementinlin:0,associ:[0,3],"class":[0,1],directori:3,repo:3,bitbucket:3,appropri:[2,3],base_manag:0,ani:[2,3],entri:2,mymodel:0,request:0,can_delete_approv:0,object:[0,1,2,3],actviti:3,post_moder:0,itself:[2,3],client:3,runtim:0,allow:0,choos:[2,3],model:[0,1,2,3],usual:0,make:[0,2],latest:3},objtypes:{},titles:["How to use (for developers)","Django-monitor self-help","How to use (for admin-users)","Introduction to Django-monitor"],objnames:{},filenames:["dev_howto","index","admin_howto","intro"]})

File docs/source/admin_howto.rst

    :scale: 70
    :alt: Change-list
 
-Who can moderate?
+Who can moderate
 ==================
 
 Django-monitor creates a moderate permission for each moderated model. Only
 model. The superuser must assign those permissions to the appropriate users
 as they would do with other commonly found permissions.
 
-How to know the status of objects in change-list?
-=================================================
-By default, all existing objects of each model appear in its change-list. For
-moderated models, we add one more column, ``status`` to the right of each row.
-That column, as its name indicates, displays the current moderation status of
-each object you see in the list. Also, you can filter the objects by their
+What to moderate & from where
+===============================
+
+To see and moderate the pending/challenged objects of a particualr model, visit
+the change-list page of that model. By default, all existing objects appear
+there. For moderated models, we add one more column, ``status`` to the right of
+each row. That column, as its name indicates, displays the current moderation
+status of each object you see in the list. This helps you to identify the
+pending as well as challenged objects. Also, you can filter the objects by their
 ``moderation status`` using the filter options provided in the box to the right
 of change-list. Refer to the screen-shot given above.
 
-How to moderate?
+You need not regularly visit change-lists of all models to know whether there
+are any objects to be moderated. ``Moderation Queue`` is the shortcut for this.
+It will summarize the moderation status for all models in one page. Click on
+the ``Moderation Queue`` change-link under the ``Monitor`` app in your admin
+home page. You can see the number of pending and challenged objects for each
+moderated model arranged in a nice table in the resulting page. Clicking on
+each number will lead you to the corresponding change-list filtered by the
+respective status. eg, if you clicked on the number of pending objects of the
+model, say, `Book`, the change-list showing all pending book objects will be
+loaded.
+
+How to moderate
 =================
 
 Moderation is performed through 3 special change-list actions. They are,

File docs/source/dev_howto.rst

 ``monitor.get_monitor_entry`` and then invoke applicable public method of it.
 Available methods of monitor_entry are as follows:
 
+.. note::
+
+   ``user`` is an optional parameter in all those methods described below.
+   Please pass the current user to the methods in all possible cases.
+   ``request.user`` can be used for this whenever ``request`` is available.
+   Otherwise, you can use ``get_current_user`` from ``monitor.middleware``.
+
 #. approve:
     ::
 

File docs/source/intro.rst

 
 .. _`intro`:
 
-===============
-Introduction
-===============
+===============================
+Introduction to Django-monitor
+===============================
+
+.. note::
+   You can skip this chapter if you have already read the README document in
+   source path.
 
 About
 =====
 
 Moderation seems to be some job each one want to do in their own way.
-Django-monitor is yet another django-app to help moderate model objects.
-It was started by cloning the project `django-gatekeeper` but offers
-different set of features. The name ``monitor`` is just to distinguish it
-from the existing app, `django-moderation`. (The terms, ``monitor`` and
-``moderate`` are used with same meaning everywhere in the source code.)
+Django-monitor is a django-app to moderate model objects. It was started as
+a clone of the `django-gatekeeper` project but with a different set of
+requirements. The name ``monitor`` is just to distinguish it from an existing
+project, `django-moderation`. (The terms, ``monitor`` and ``moderate`` are used
+with same meaning everywhere in the source.)
 
 Here, the moderation process is well integrated with django-admin. That is,
 all moderation actvities are performed from within the changelist page itself.
 Install
 ========
 
-Grab the Source
-----------------
 * Download the latest version from bitbucket repo:
   http://bitbucket.org/rajeesh/django-monitor.
 
-Place it in your path
-----------------------
 * Copy the ``monitor`` directory to some place in your python path.
 
-Add to your project
---------------------
 * Add to your django project by including it in settings.INSTALLED_APPS.
 
 Features
 
 Model-specific permission
 --------------------------
-Each moderated model will have an associated moderate permission of the form,
-``moderate_<model_name>`` where `<model_name>` represents the name of the
-model. Only those users with that permission will be able to approve or
-challenge any object created for that model.
+Each moderated model will have an associated moderate permission. To approve
+or challenge any object created for a particular model, users need to have
+the corresponding permission.
 
 Auto-moderation
 ----------------
 Any object created by a user with add permission will have an ``In Pending``
 status. If the user has got moderate permission also, the object created will
-automatically get approved (status is ``Approved``).
+automatically get approved (status becomes ``Approved``).
 
 Moderation from within admin changelist
 ----------------------------------------
-The changelist view displays an additional column showing current moderation
-status of each object. Also, you can filter the changelist entries by their
-moderation status. Three actions, ``approve``, ``challenge`` and
-``reset to pending`` are provided for moderation. The user just need to select
-the objects, choose appropriate action and press ``Go`` to moderate.
+The changelist of a moderated model displays the current moderation status of
+all objects. Also, you can filter the objects by their moderation status. Three
+actions are available for moderation. To moderate, user just need to select the
+objects, choose appropriate action and press ``Go``.
 
 Related moderation
 -------------------
 model objects which also can get moderated along with the original ones. The
 developer can specify such related models to be moderated during registration.
 
-Edit-Lock
-----------
-The developer can protect the approved objects from further modification to
-maintain data integrity. The fields which are not meant to be changed after
-approval can be specified in the model-admin using ``protected_fields`` option.
-The model-admin will club them with readonly_fields if the object is approved.
+Data protection
+----------------
+The developer can prevent admin-users from changing values of selected fields
+of approved objects. Deleting approved objects also can be prevented if your
+client's business requires that.
 
-TODO
-======
-* There should be a facility to lock deletion of approved objects too.
-
-* There should be a notification area to show counts of pending as well as
-  challenged objects for each moderated model. So user need not routinely check
-  every changelist just to know if there exists entries to be moderated.
-

File monitor/__init__.py

 __author__ = "Rajeesh Nair"
-__version__ = "0.1.3a"
+__version__ = "0.1.4a"
 __copyright__ = "Copyright (c) 2011 Rajeesh"
 __license__ = "BSD"
 

File monitor/admin.py

 
+from django.contrib.contenttypes.models import ContentType
 from django.contrib import admin
 from django.contrib.admin.filterspecs import FilterSpec
+from django.shortcuts import render_to_response
+from django.utils.functional import update_wrapper
+from django.template import RequestContext
+from django.utils.safestring import mark_safe
 
 from monitor.actions import (
     approve_selected, challenge_selected, reset_to_pending
 )
 from monitor.filter import MonitorFilter
-from monitor import model_from_queue, get_monitor_entry
+from monitor import model_from_queue, get_monitor_entry, queued_models
 from monitor.conf import (
-    PENDING_STATUS, CHALLENGED_STATUS, APPROVED_STATUS
+    PENDING_STATUS, CHALLENGED_STATUS, APPROVED_STATUS,
+    PENDING_DESCR, CHALLENGED_DESCR
 )
+from monitor.models import MonitorEntry
 
 # Our objective is to place the custom monitor-filter on top
 FilterSpec.filter_specs.insert(
     0, (lambda f: getattr(f, 'monitor_filter', False), MonitorFilter)
 )
 
+
+class MEAdmin(admin.ModelAdmin):
+    """
+    A special admin-class for aggregating moderation summary, not to let users
+    add/edit/delete MonitorEntry objects directly. MonitorEntry works from
+    behind the curtain. This admin class is to provide a single stop for users
+    to get notified about pending/challenged model objects.
+    """
+    change_list_template = 'admin/monitor/monitorentry/change_list.html'
+
+    def get_urls(self):
+        """ The only url allowed is that for changelist_view. """
+        from django.conf.urls.defaults import patterns, url
+
+        def wrap(view):
+            def wrapper(*args, **kwargs):
+                return self.admin_site.admin_view(view)(*args, **kwargs)
+            return update_wrapper(wrapper, view)
+
+        info = self.model._meta.app_label, self.model._meta.module_name
+
+        urlpatterns = patterns('',
+            url(r'^$',
+                wrap(self.changelist_view),
+                name = '%s_%s_changelist' % info
+            ),
+        )
+        return urlpatterns
+
+    def has_add_permission(self, request, obj = None):
+        """ Returns False so that no add button is displayed in admin index"""
+        return False
+
+    def has_change_permission(self, request, obj = None):
+        """
+        Users will be lead to the moderation summary page when they click on
+        the link for changelist, which has a url like,
+        ``/admin/monitor/monitorentry/``. The admin site index page will show
+        the link to user, only if they have change_permission. So lets grant
+        that perm to all admin-users.
+        """
+        if obj is None and request.user.is_active and request.user.is_staff:
+            return True
+        return super(MEAdmin, self).has_change_permission(request, obj)
+
+    def changelist_view(self, request, extra_context = None):
+        """
+        The 'change list' admin view is overridden to return a page showing the
+        moderation summary aggregated for each model.
+        """
+        query_set = self.queryset(request)
+        model_list = []
+        for model in queued_models():
+            c_type = ContentType.objects.get_for_model(model)
+            q_set = query_set.filter(content_type = c_type)
+            ip_count = q_set.filter(status = PENDING_STATUS).count()
+            ch_count = q_set.filter(status = CHALLENGED_STATUS).count() 
+            app_label = model._meta.app_label
+            if ip_count or ch_count:
+                model_list.append({
+                    'model_name': model._meta.verbose_name,
+                    'app_name': app_label.title(),
+                    'pending': ip_count, 'challenged': ch_count,
+                    'admin_url': mark_safe(
+                        '/admin/%s/%s/' % (app_label, model.__name__.lower())
+                    ),
+                })
+        model_list.sort(key = lambda x: (x['app_name'], x['model_name']))
+        return render_to_response(
+            self.change_list_template,
+            {
+                'model_list': model_list,
+                'ip_status': PENDING_STATUS, 'ip_descr': PENDING_DESCR,
+                'ch_status': CHALLENGED_STATUS, 'ch_descr': CHALLENGED_DESCR
+            },
+            context_instance = RequestContext(request)
+        )
+
+admin.site.register(MonitorEntry, MEAdmin)
+
 class MonitorAdmin(admin.ModelAdmin):
-    """Use this for monitored models."""
+    """ModelAdmin for monitored models should inherit this."""
 
     # Which fields are to be made readonly after approval.
     protected_fields = ()
         the given object is approved, this will return False. Otherwise,
         this behaves the same way as the parent class method does.
         """
-        model = model_from_queue(self.opts.model)
+        model = model_from_queue(self.model)
         if (
             model and (not model['can_delete_approved']) and
             obj is not None and get_monitor_entry(obj).is_approved()

File monitor/models.py

 
     class Meta:
         app_label = 'monitor'
+        verbose_name = 'moderation Queue'
+        verbose_name_plural = 'moderation Queue'
 
     def __unicode__(self):
         return "[%s] %s" % (self.get_status_display(), self.content_object)

File monitor/templates/admin/monitor/monitorentry/change_list.html

+{% extends "admin/base_site.html" %}
+{% load adminmedia admin_list i18n %}
+{% load url from future %}
+{% block extrastyle %}
+  {{ block.super }}
+  <link rel="stylesheet" type="text/css" href="{% admin_media_prefix %}css/changelists.css" />
+  {{ media.css }}
+    <style>
+      #changelist table thead th:first-child {width: inherit}
+    </style>
+{% endblock %}
+
+{% block extrahead %}
+{{ block.super }}
+{{ media.js }}
+{% endblock %}
+
+{% block bodyclass %}change-list{% endblock %}
+
+  {% block breadcrumbs %}
+    <div class="breadcrumbs">
+      <a href="../../">
+        {% trans "Home" %}
+      </a>
+       &rsaquo;
+       <a href="../">
+         Monitor
+      </a>
+      &rsaquo;
+      Moderation Queue
+    </div>
+  {% endblock %}
+
+{% block coltype %}flex{% endblock %}
+
+{% block content %}
+  <div id="content-main">
+    <div>
+      {% block result_list %}
+      <table width = "100%" class="module" id="changelist">
+      <caption>Moderation Queue</caption>
+      <thead>
+      <tr>
+            <th>App</th><th>Model</th>
+            <th>{{ ip_descr }}</th><th>{{ ch_descr }}</th></tr>
+      </thead>
+      {% for model in model_list %}
+      <tr class="{% cycle row1,row2 %}">
+          <td>{{ model.app_name }}</td>
+          <td>{{ model.model_name|capfirst }}</td>
+          <td>{% if model.pending %}
+                  <a href="{{ model.admin_url }}?status={{ ip_status }}">{{ model.pending }}</a>
+              {% else %}
+                  &nbsp;
+              {% endif %}
+          </td>
+          <td>{% if model.challenged %}
+                  <a href="{{ model.admin_url }}?status={{ ch_status }}">{{ model.challenged }}</a>
+              {% else %}
+                  &nbsp;
+              {% endif %}
+          </td>
+      </tr>
+      {% empty %}
+          <tr class="row1"><th span="row">No pending/challenged objects in queue.</th>
+          <th>&nbsp;</th><th>&nbsp;</th><th>&nbsp;</th>
+          </tr>
+      {% endfor %}
+      </table>
+      {% endblock %}
+    </div>
+  </div>
+{% endblock %}
+