You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@allura.apache.org by tv...@apache.org on 2013/03/21 15:21:54 UTC

[18/48] [5453] adding support for user stats

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/25f7657c/ForgeUserStats/forgeuserstats/templates/.svn/text-base/artifacts.html.svn-base
----------------------------------------------------------------------
diff --git a/ForgeUserStats/forgeuserstats/templates/.svn/text-base/artifacts.html.svn-base b/ForgeUserStats/forgeuserstats/templates/.svn/text-base/artifacts.html.svn-base
new file mode 100644
index 0000000..0b3cfb8
--- /dev/null
+++ b/ForgeUserStats/forgeuserstats/templates/.svn/text-base/artifacts.html.svn-base
@@ -0,0 +1,48 @@
+{% set hide_left_bar = True %}
+{% extends g.theme.master %}
+
+{% block title %}User stats{% endblock %}
+
+{% block header %}
+    Statistics about {{user.display_name}}'s contribution – Artifacts
+{% endblock %}
+
+{% block content %}
+
+  {% if user %}
+
+    {% if data %}
+      <h2>Statistics by category</h2>
+      <table>
+        <thead>
+          <tr>
+            <th>Category</th>
+            <th>Created artifacts</th>
+            <th>Modified artifacts</th>
+          </tr>
+        </thead>
+        <tbody> 
+          {% for cat, row in data.items() %}
+            <tr>
+              <td>{% if cat %}{{cat.fullname}}{% else %}All categories{% endif %}</td>
+              <td>
+                {% for details in row %}
+                  {% if details.messagetype %} {{details.messagetype}}:
+                  {% else %}Total:{% endif %} {{details.created}}<br/>
+                {% endfor %}
+              </td>
+              <td>
+                {% for details in row %}
+                  {% if details.messagetype %} {{details.messagetype}}:
+                  {% else %}Total:{% endif %} {{details.modified}}<br/>
+                {% endfor %}
+              </td>
+            </tr>
+          {% endfor %}
+        </tbody>
+      </table>
+    {% endif %}
+    <div class="grid-20"><a href="/userstats/{{user.username}}">Go back to general statistics</a></div>
+  {% endif %}
+
+{% endblock %}

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/25f7657c/ForgeUserStats/forgeuserstats/templates/.svn/text-base/commits.html.svn-base
----------------------------------------------------------------------
diff --git a/ForgeUserStats/forgeuserstats/templates/.svn/text-base/commits.html.svn-base b/ForgeUserStats/forgeuserstats/templates/.svn/text-base/commits.html.svn-base
new file mode 100644
index 0000000..c574c9f
--- /dev/null
+++ b/ForgeUserStats/forgeuserstats/templates/.svn/text-base/commits.html.svn-base
@@ -0,0 +1,37 @@
+{% set hide_left_bar = True %}
+{% extends g.theme.master %}
+
+{% block title %}User stats{% endblock %}
+
+{% block header %}
+    Statistics about {{user.display_name}}'s contribution – Code contribution
+{% endblock %}
+
+{% block content %}
+
+  {% if user %}
+
+    {% if data %}
+      <h2>Statistics by category</h2>
+      <table>
+        <thead>
+          <tr>
+            <th>Category</th>
+            <th>Number of commits</th>
+            <th>Lines of code</th>
+          </tr>
+        </thead>
+        <tbody> 
+          {% for cat, el in data.items() %}
+            <tr>
+              <td>{% if cat %}{{cat.fullname}}{% else %}All categories{% endif %}</td>
+              <td>{{el.number}}</td>
+              <td>{{el.lines}}</td>
+            {% endfor %}
+          </tr>
+        </tbody>
+      </table>
+    {% endif %}
+    <div class="grid-20"><a href="/userstats/{{user.username}}">Go back to general statistics</a></div>
+  {% endif %}
+{% endblock %}

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/25f7657c/ForgeUserStats/forgeuserstats/templates/.svn/text-base/index.html.svn-base
----------------------------------------------------------------------
diff --git a/ForgeUserStats/forgeuserstats/templates/.svn/text-base/index.html.svn-base b/ForgeUserStats/forgeuserstats/templates/.svn/text-base/index.html.svn-base
new file mode 100644
index 0000000..b53e596
--- /dev/null
+++ b/ForgeUserStats/forgeuserstats/templates/.svn/text-base/index.html.svn-base
@@ -0,0 +1,341 @@
+{% set hide_left_bar = True %}
+{% extends g.theme.master %}
+
+{% block title %}User stats{% endblock %}
+
+{% block header %}
+    Statistics about {{user.display_name}}'s contribution
+    {% if category %}
+        in projects of category {{category.fullname}}
+    {% endif %}
+{% endblock %}
+
+{% block content %}
+  {% if user %}
+
+    <h2>General statistics</h2>
+    <table>
+      <thead>
+        <tr>
+          <th>Parameter</th>
+          <th>Value</th>
+        </tr>
+      </thead>
+      <tbody> 
+        <tr>
+          <td>Registration date</td>
+          <td>
+            {{registration_date.strftime("%d %b %Y, %H:%M:%S (UTC)")}}, 
+            {{days}} day{% if days != 1 %}s{% endif %} ago</td>
+        </tr>
+        {% if last_login %}
+          <tr>
+            <td>Last login</td>
+            <td>
+              {{last_login.strftime("%d %b %Y, %H:%M:%S (UTC)")}},
+              {{last_login_days}} day{% if last_login_days != 1 %}s{% endif %} ago</td>
+            </td>
+          </tr>
+        {% endif %}
+      </tbody>
+    </table>
+
+    <h2>Contribution statistics</h2>
+
+    <table>
+      <thead>
+        <tr>
+          <th>Parameter</th>
+          <th>Total value</th>
+          <th>Average per-month value</th>
+          <th>Last 30 days</th>
+          {% if days >= 30 %}
+            <th>Trend</th>
+          {% endif %}
+        </tr>
+      </thead>
+      <tbody>
+        {% if not category %}
+          <tr>
+            <td>Logins</td>
+            <td>{{totlogins}}</td>
+            <td>{{permonthlogins}}</td>
+            <td>{{lastmonth_logins}}</td>
+            {% if days >= 30 %}
+              <td>
+                {% if lastmonth_logins > permonthlogins %}
+                  Up
+                {% elif lastmonth_logins == permonthlogins %}
+                  =
+                {% else %}
+                  Down
+                {%endif%}
+              </td>
+            {% endif %}
+          </tr>
+        {% endif %}
+        <tr>
+          <td><a href="/userstats/{{user.username}}/metric/commits/">Commits number</a></td>
+          <td>{{totcommits.number}}</td>
+          <td>{{permonthcommits.number}}</td>
+          <td>{{lastmonthcommits.number}}</td>
+          {% if days >= 30 %}
+            <td>
+              {% if permonthcommits.number > permonthcommits.number %}
+                Up
+              {% elif permonthcommits.number == permonthcommits.number %}
+                =
+              {% else %}
+                Down
+              {%endif%}
+            </td>
+          {% endif %}
+        </tr>
+        <tr>
+          <td><a href="/userstats/{{user.username}}/metric/commits/">Added/modified LOCs</a></td>
+          <td>{{totcommits.lines}}</td>
+          <td>{{permonthcommits.lines}}</td>
+          <td>{{lastmonthcommits.lines}}</td>
+          {% if days >= 30 %}
+            <td>
+              {% if permonthcommits.lines > permonthcommits.lines %}
+                Up
+              {% elif permonthcommits.lines == permonthcommits.lines %}
+                =
+              {% else %}
+                Down
+              {%endif%}
+            </td>
+          {% endif %}
+        </tr>
+        <tr>
+          <td><a href="/userstats/{{user.username}}/metric/artifacts/">Total number of created artifacts</a></td>
+          <td>{{totartifacts.created}}</td>
+          <td>{{permonthartifacts.created}}</td>
+          <td>{{lastmonthartifacts.created}}</td>
+          {% if days >= 30 %}
+            <td>
+              {% if lastmonthartifacts.created > permonthartifacts.created %}
+                Up
+              {% elif lastmonthartifacts.created == permonthartifacts.created %}
+                =
+              {% else %}
+                Down
+              {%endif%}
+            </td>
+          {% endif %}
+        </tr>
+        <tr>
+          <td><a href="/userstats/{{user.username}}/metric/commits/">Total number of edited artifacts</a></td>
+          <td>{{totartifacts.modified}}</td>
+          <td>{{permonthartifacts.modified}}</td>
+          <td>{{lastmonthartifacts.modified}}</td>
+          {% if days >= 30 %}
+            <td>
+              {% if lastmonthartifacts.modified > permonthartifacts.modified %}
+                Up
+              {% elif lastmonthartifacts.modified == permonthartifacts.modified %}
+                =
+              {% else %}
+                Down
+              {%endif%}
+            </td>
+          {% endif %}
+        </tr>
+        
+        {% for key, value in artifacts_by_type.items() %}
+          <tr>
+            <td><a href="/userstats/{{user.username}}/metric/artifacts/">Created {{key}} artifacts</a></td>
+            <td>{{value.created}}</td>
+            <td>{{value.pmcreated}}</td>
+            <td>
+              {% if lastmonth_artifacts_by_type.get(key) %}
+                 {{lastmonth_artifacts_by_type[key].created}}
+              {% else %}
+                 0
+              {% endif %}
+            </td>
+            {% if days >= 30 %}
+              <td>
+                {% if lastmonth_artifacts_by_type.get(key) %}
+                  {% if lastmonth_artifacts_by_type[key].created > value.pmcreated %}
+                    Up
+                  {% elif lastmonth_artifacts_by_type[key].created == value.pmcreated %}
+                    =
+                  {% else %}
+                    Down
+                  {%endif%}
+                {%else%} Down {%endif%}
+              </td>
+            {% endif %}
+          </tr>
+          <tr>
+            <td><a href="/userstats/{{user.username}}/metric/artifacts/">Edited {{key}} artifacts</a></td>
+            <td>{{value.modified}}</td>
+            <td>{{value.pmmodified}}</td>
+            <td>
+              {% if lastmonth_artifacts_by_type.get(key) %}
+                 {{lastmonth_artifacts_by_type[key].modified}}
+              {% else %}
+                 0
+              {% endif %}
+            </td>
+            {% if days >= 30 %}
+              <td>
+                {% if lastmonth_artifacts_by_type.get(key) %}
+                  {% if lastmonth_artifacts_by_type[key].modified > value.pmmodified %}
+                    Up
+                  {% elif lastmonth_artifacts_by_type[key].modified == value.pmmodified %}
+                    =
+                  {% else %}
+                    Down
+                  {%endif%}
+                {%else%} Down {%endif%}
+              </td>
+            {% endif %}
+          </tr>
+        {% endfor %}
+
+        <tr>
+          <td><a href="/userstats/{{user.username}}/metric/tickets/">Assigned tickets</a></td>
+          <td>{{tottickets.assigned}}</td>
+          <td>{{permonthtickets.assigned}}</td>
+          <td>{{lastmonthtickets.assigned}}</td>
+          {% if days >= 30 %}
+            <td>
+              {% if lastmonthtickets.assigned > permonthtickets.assigned %}
+                Up
+              {% elif lastmonthtickets.assigned == permonthtickets.assigned %}
+                =
+              {% else %}
+                Down
+              {%endif%}
+            </td>
+          {% endif %}
+        </tr>
+        <tr>
+          <td><a href="/userstats/{{user.username}}/metric/tickets/">Revoked tickets</a></td>
+          <td>{{tottickets.revoked}}</td>
+          <td>{{permonthtickets.revoked}}</td>
+          <td>{{lastmonthtickets.revoked}}</td>
+          {% if days >= 30 %}
+            <td>
+              {% if lastmonthtickets.revoked > permonthtickets.revoked %}
+                Up
+              {% elif lastmonthtickets.revoked == permonthtickets.revoked %}
+                =
+              {% else %}
+                Down
+              {%endif%}
+            </td>
+          {% endif %}
+        </tr>
+        <tr>
+          <td><a href="/userstats/{{user.username}}/metric/tickets/">Solved tickets</a></td>
+          <td>{{tottickets.solved}}</td>
+          <td>{{permonthtickets.solved}}</td>
+          <td>{{lastmonthtickets.solved}}</td>
+          {% if days >= 30 %}
+            <td>
+              {% if lastmonthtickets.solved > permonthtickets.solved %}
+                Up
+              {% elif lastmonthtickets.solved == permonthtickets.solved %}
+                =
+              {% else %}
+                Down
+              {%endif%}
+            </td>
+          {% endif %}
+        </tr>
+        <tr>
+          <td><a href="/userstats/{{user.username}}/metric/tickets/">Average tickets solving time</a></td>
+          <td>
+            {% if tottickets.averagesolvingtime %}
+              {{tottickets.averagesolvingtime.days}} days, 
+              {{tottickets.averagesolvingtime.hours}} hours,
+              {{tottickets.averagesolvingtime.minutes}} min
+            {% else %}n/a{% endif %}
+          </td>
+          <td>n/a</td>
+          <td>
+            {% if lastmonthtickets.averagesolvingtime %}
+              {{lastmonthtickets.averagesolvingtime.days}} days, 
+              {{lastmonthtickets.averagesolvingtime.hours}} hours,
+              {{lastmonthtickets.averagesolvingtime.minutes}} min
+            {% else %}n/a{% endif %}
+          </td>
+          {% if days >= 30 %}
+            <td>
+              {% if lastmonthtickets.averagesolvingtime > tottickets.averagesolvingtime %}
+                Up
+              {% elif lastmonthtickets.averagesolvingtime == tottickets.averagesolvingtime %}
+                =
+              {% else %}
+                Down
+              {%endif%}
+            </td>
+          {% endif %}
+        </tr>
+      </tbody>
+    </table>
+
+    {% if categories %}
+        <h2>Prefered categories</h2>
+        <table>
+          <thead>
+            <tr>
+              <th>Category name</th>
+              <th>Number of projects</th>
+            </tr>
+          </thead>
+          <tbody>
+            {% for cat, count in categories %}
+              <tr>
+                <td><a href="/userstats/{{user.username}}/category/{{cat.fullname}}">{{cat.fullname}}</a></td>
+                <td>{{count}}</td>
+              </tr>
+            {% endfor %}
+          </tbody>
+        </table>
+    {% endif %}
+    {% if category %}
+        <div class="grid-20"><a href="/userstats/{{user.username}}">Go back to general statistics</a></div>
+    {% else %}
+      <h2>Overall evaluation</h2>
+      <table>
+        <thead>
+          <tr>
+            <th>Field</th>
+            <th>Evaluation</th>
+          </tr>
+        </thead>
+        <tbody>
+          <tr>
+            <td>Code contribution</td>
+            <td>
+               {% for i in range(codestars) %}★{% endfor %}
+               {% for i in range(5 - codestars) %}☆{% endfor %}
+            </td>
+          </tr>
+          <tr>
+            <td>Contribution to discussions on the forge</td>
+            <td>
+               {% for i in range(discussionstars) %}★{% endfor %}
+               {% for i in range(5 - discussionstars) %}☆{% endfor %}
+            </td>
+          </tr>
+          <tr>
+            <td>Contribution to issues solving</td>
+            <td>
+              {% for i in range(ticketsstars) %}★{% endfor %}
+              {% for i in range(5 - ticketsstars) %}☆{% endfor %}
+            </td>
+          </tr>
+        </tbody>
+      </table>
+    {% endif %}
+  {% else %}
+    Invalid user!
+  {% endif %}
+
+{% endblock %}

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/25f7657c/ForgeUserStats/forgeuserstats/templates/.svn/text-base/tickets.html.svn-base
----------------------------------------------------------------------
diff --git a/ForgeUserStats/forgeuserstats/templates/.svn/text-base/tickets.html.svn-base b/ForgeUserStats/forgeuserstats/templates/.svn/text-base/tickets.html.svn-base
new file mode 100644
index 0000000..148cfa8
--- /dev/null
+++ b/ForgeUserStats/forgeuserstats/templates/.svn/text-base/tickets.html.svn-base
@@ -0,0 +1,47 @@
+{% set hide_left_bar = True %}
+{% extends g.theme.master %}
+
+{% block title %}User stats{% endblock %}
+
+{% block header %}
+    Statistics about {{user.display_name}}'s contribution – Tickets
+{% endblock %}
+
+{% block content %}
+
+  {% if user %}
+
+    {% if data %}
+      <h2>Statistics by category</h2>
+      <table>
+        <thead>
+          <tr>
+            <th>Category</th>
+            <th>Assigned tickets</th>
+            <th>Solved tickets</th>
+            <th>Revoked tickets</th>
+            <th>Average solving time</th>
+          </tr>
+        </thead>
+        <tbody> 
+          {% for cat, el in data.items() %}
+            <tr>
+              <td>{% if cat %}{{cat.fullname}}{% else %}All categories{% endif %}</td>
+              <td>{{el.assigned}}</td>
+              <td>{{el.solved}}</td>
+              <td>{{el.revoked}}</td>
+              <td>
+                {% if el.averagesolvingtime %}
+                  {{el.averagesolvingtime.days}} days, 
+                  {{el.averagesolvingtime.hours}} hours,
+                  {{el.averagesolvingtime.minutes}} min
+                {% else %}n/a{% endif %}
+              </td>
+            {% endfor %}
+          </tr>
+        </tbody>
+      </table>
+    {% endif %}
+    <div class="grid-20"><a href="/userstats/{{user.username}}">Go back to general statistics</a></div>
+  {% endif %}
+{% endblock %}

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/25f7657c/ForgeUserStats/forgeuserstats/templates/artifacts.html
----------------------------------------------------------------------
diff --git a/ForgeUserStats/forgeuserstats/templates/artifacts.html b/ForgeUserStats/forgeuserstats/templates/artifacts.html
new file mode 100644
index 0000000..9492628
--- /dev/null
+++ b/ForgeUserStats/forgeuserstats/templates/artifacts.html
@@ -0,0 +1,52 @@
+{% set hide_left_bar = True %}
+{% extends g.theme.master %}
+
+{% block title %}User stats{% endblock %}
+
+{% block header %}
+    Statistics about {{user.display_name}}'s contribution – Artifacts
+{% endblock %}
+
+{% block content %}
+
+  {% if user %}
+    <div class="grid-20">
+      <ul><li><a href="/userstats/{{user.username}}">Go back to general statistics</a></li></ul>
+    </div>
+
+    {% if data %}
+    <div class="grid-20">
+      <h2>Statistics by category</h2>
+      <table>
+        <thead>
+          <tr>
+            <th>Category</th>
+            <th>Created artifacts</th>
+            <th>Modified artifacts</th>
+          </tr>
+        </thead>
+        <tbody> 
+          {% for cat, row in data.items() %}
+            <tr>
+              <td>{% if cat %}{{cat.fullname}}{% else %}All categories{% endif %}</td>
+              <td>
+                {% for details in row %}
+                  {% if details.messagetype %} {{details.messagetype}}:
+                  {% else %}Total:{% endif %} {{details.created}}<br/>
+                {% endfor %}
+              </td>
+              <td>
+                {% for details in row %}
+                  {% if details.messagetype %} {{details.messagetype}}:
+                  {% else %}Total:{% endif %} {{details.modified}}<br/>
+                {% endfor %}
+              </td>
+            </tr>
+          {% endfor %}
+        </tbody>
+      </table>
+    </div>
+    {% endif %}
+  {% endif %}
+
+{% endblock %}

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/25f7657c/ForgeUserStats/forgeuserstats/templates/commits.html
----------------------------------------------------------------------
diff --git a/ForgeUserStats/forgeuserstats/templates/commits.html b/ForgeUserStats/forgeuserstats/templates/commits.html
new file mode 100644
index 0000000..2bca003
--- /dev/null
+++ b/ForgeUserStats/forgeuserstats/templates/commits.html
@@ -0,0 +1,42 @@
+{% set hide_left_bar = True %}
+{% extends g.theme.master %}
+
+{% block title %}User stats{% endblock %}
+
+{% block header %}
+    Statistics about {{user.display_name}}'s contribution – Code contribution
+{% endblock %}
+
+{% block content %}
+
+  {% if user %}
+    <div class="grid-20">
+      <ul><li><a href="/userstats/{{user.username}}">Go back to general statistics</a></li></ul>
+    </div>
+
+    {% if data %}
+    <div class="grid-20">
+      <h2>Statistics by category</h2>
+      <table>
+        <thead>
+          <tr>
+            <th>Category</th>
+            <th>Number of commits</th>
+            <th>Lines of code</th>
+          </tr>
+        </thead>
+        <tbody> 
+          {% for cat, el in data.items() %}
+            <tr>
+              <td>{% if cat %}{{cat.fullname}}{% else %}All categories{% endif %}</td>
+              <td>{{el.number}}</td>
+              <td>{{el.lines}}</td>
+            {% endfor %}
+          </tr>
+        </tbody>
+      </table>
+    </div>
+    {% endif %}
+    <div class="grid-20"><a href="/userstats/{{user.username}}">Go back to general statistics</a></div>
+  {% endif %}
+{% endblock %}

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/25f7657c/ForgeUserStats/forgeuserstats/templates/index.html
----------------------------------------------------------------------
diff --git a/ForgeUserStats/forgeuserstats/templates/index.html b/ForgeUserStats/forgeuserstats/templates/index.html
new file mode 100644
index 0000000..502cb25
--- /dev/null
+++ b/ForgeUserStats/forgeuserstats/templates/index.html
@@ -0,0 +1,423 @@
+{% set hide_left_bar = True %}
+{% extends g.theme.master %}
+
+{% block title %}User stats{% endblock %}
+
+{% block header %}
+    Statistics about {{user.display_name}}'s contribution
+    {% if category %}
+        in projects of category {{category.fullname}}
+    {% endif %}
+{% endblock %}
+
+{% block content %}
+  {% if user %}
+
+    <h2>General statistics</h2>
+    <table>
+      <thead>
+        <tr>
+          <th>Parameter</th>
+          <th>Date</th>
+          <th>Time interval</th>
+        </tr>
+      </thead>
+      <tbody> 
+        <tr>
+          <td>Registration date</td>
+          <td>{{registration_date.strftime("%d %b %Y, %H:%M:%S (UTC)")}}</td> 
+           <td>{{days}} day{% if days != 1 %}s{% endif %} ago</td>
+        </tr>
+        {% if last_login %}
+          <tr>
+            <td>Last login</td>
+            <td>{{last_login.strftime("%d %b %Y, %H:%M:%S (UTC)")}}</td>
+            <td>{{last_login_days}} day{% if last_login_days != 1 %}s{% endif %} ago</td>
+          </tr>
+        {% endif %}
+      </tbody>
+    </table>
+
+    <h2>Contribution statistics</h2>
+
+    <table>
+      <thead>
+        <tr>
+          <th>Parameter</th>
+          <th>Total value</th>
+          <th>Average per-month value</th>
+          <th>Last 30 days</th>
+          {% if days >= 30 %}
+            <th>Trend</th>
+          {% endif %}
+        </tr>
+      </thead>
+      <tbody>
+        {% if not category %}
+          <tr>
+            <td>Logins</td>
+            <td>{{totlogins}}</td>
+            <td>{{permonthlogins}}</td>
+            <td>{{lastmonth_logins}}</td>
+            {% if days >= 30 %}
+              <td style="text-align:center;">
+                {% if lastmonth_logins > permonthlogins %}
+                  <img src="{{g.forge_static('images/up.png')}}"/>
+                {% elif lastmonth_logins == permonthlogins %}
+                  <img src="{{g.forge_static('images/equal.png')}}"/>
+                {% else %}
+                  <img src="{{g.forge_static('images/down.png')}}"/>
+                {%endif%}
+              </td>
+            {% endif %}
+          </tr>
+        {% endif %}
+        <tr>
+          <td>
+            {% if totcommits.number > 0 %}
+              <a href="/userstats/{{user.username}}/metric/commits/">Commits number</a>
+            {% else %}
+              Commits number
+            {% endif %}
+          </td>
+          <td>{{totcommits.number}}</td>
+          <td>{{permonthcommits.number}}</td>
+          <td>{{lastmonthcommits.number}}</td>
+          {% if days >= 30 %}
+            <td style="text-align:center;">
+              {% if permonthcommits.number > permonthcommits.number %}
+                  <img src="{{g.forge_static('images/up.png')}}"/>
+              {% elif permonthcommits.number == permonthcommits.number %}
+                <img src="{{g.forge_static('images/equal.png')}}"/>
+              {% else %}
+                <img src="{{g.forge_static('images/down.png')}}"/>
+              {%endif%}
+            </td>
+          {% endif %}
+        </tr>
+        <tr>
+          <td>
+            {% if totcommits.lines > 0 %}
+              <a href="/userstats/{{user.username}}/metric/commits/">Added/modified LOCs</a>
+            {% else %}
+              Added/modified LOCs
+            {% endif %}
+          </td>
+          <td>{{totcommits.lines}}</td>
+          <td>{{permonthcommits.lines}}</td>
+          <td>{{lastmonthcommits.lines}}</td>
+          {% if days >= 30 %}
+            <td style="text-align:center;">
+              {% if permonthcommits.lines > permonthcommits.lines %}
+                  <img src="{{g.forge_static('images/up.png')}}"/>
+              {% elif permonthcommits.lines == permonthcommits.lines %}
+                <img src="{{g.forge_static('images/equal.png')}}"/>
+              {% else %}
+                <img src="{{g.forge_static('images/down.png')}}"/>
+              {%endif%}
+            </td>
+          {% endif %}
+        </tr>
+        <tr>
+          <td>
+            {% if totartifacts.created > 0 %}
+              <a href="/userstats/{{user.username}}/metric/artifacts/">Total number of created artifacts</a>
+            {% else %}
+              Total number of created artifacts
+            {% endif %}
+          </td>
+          <td>{{totartifacts.created}}</td>
+          <td>{{permonthartifacts.created}}</td>
+          <td>{{lastmonthartifacts.created}}</td>
+          {% if days >= 30 %}
+            <td style="text-align:center;">
+              {% if lastmonthartifacts.created > permonthartifacts.created %}
+                <img src="{{g.forge_static('images/up.png')}}"/>
+              {% elif lastmonthartifacts.created == permonthartifacts.created %}
+                <img src="{{g.forge_static('images/equal.png')}}"/>
+              {% else %}
+                <img src="{{g.forge_static('images/down.png')}}"/>
+              {%endif%}
+            </td>
+          {% endif %}
+        </tr>
+        <tr>
+          <td>
+            {% if totartifacts.modified > 0 %}
+              <a href="/userstats/{{user.username}}/metric/artifacts/">Total number of edited artifacts</a>
+            {% else %}
+              Total number of edited artifacts
+            {% endif %}
+          </td>
+          <td>{{totartifacts.modified}}</td>
+          <td>{{permonthartifacts.modified}}</td>
+          <td>{{lastmonthartifacts.modified}}</td>
+          {% if days >= 30 %}
+            <td style="text-align:center;">
+              {% if lastmonthartifacts.modified > permonthartifacts.modified %}
+                <img src="{{g.forge_static('images/up.png')}}"/>
+              {% elif lastmonthartifacts.modified == permonthartifacts.modified %}
+                <img src="{{g.forge_static('images/equal.png')}}"/>
+              {% else %}
+                <img src="{{g.forge_static('images/down.png')}}"/>
+              {%endif%}
+            </td>
+          {% endif %}
+        </tr>
+        
+        {% for key, value in artifacts_by_type.items() %}
+          <tr>
+            <td>
+              {% if value.created > 0 %}
+                <a href="/userstats/{{user.username}}/metric/artifacts/">Created {{key}} artifacts</a>
+              {% else %}
+                Created {{key}} artifacts
+              {% endif %}
+            </td>
+            <td>{{value.created}}</td>
+            <td>{{value.pmcreated}}</td>
+            <td>
+              {% if lastmonth_artifacts_by_type.get(key) %}
+                 {{lastmonth_artifacts_by_type[key].created}}
+              {% else %}
+                 0
+              {% endif %}
+            </td>
+            {% if days >= 30 %}
+              <td style="text-align:center;">
+                {% if lastmonth_artifacts_by_type.get(key) %}
+                  {% if lastmonth_artifacts_by_type[key].created > value.pmcreated %}
+                    <img src="{{g.forge_static('images/up.png')}}"/>
+                  {% elif lastmonth_artifacts_by_type[key].created == value.pmcreated %}
+                    <img src="{{g.forge_static('images/equal.png')}}"/>
+                  {% else %}
+                    <img src="{{g.forge_static('images/down.png')}}"/>
+                  {%endif%}
+                {%else%} Down {%endif%}
+              </td>
+            {% endif %}
+          </tr>
+          <tr>
+            <td>
+              {% if value.modified > 0 %}
+                <a href="/userstats/{{user.username}}/metric/artifacts/">Edited {{key}} artifacts</a>
+              {% else %}
+                Edited {{key}} artifacts
+              {% endif %}
+            </td>
+            <td>{{value.modified}}</td>
+            <td>{{value.pmmodified}}</td>
+            <td>
+              {% if lastmonth_artifacts_by_type.get(key) %}
+                 {{lastmonth_artifacts_by_type[key].modified}}
+              {% else %}
+                 0
+              {% endif %}
+            </td>
+            {% if days >= 30 %}
+              <td style="text-align:center;">
+                {% if lastmonth_artifacts_by_type.get(key) %}
+                  {% if lastmonth_artifacts_by_type[key].modified > value.pmmodified %}
+                    <img src="{{g.forge_static('images/up.png')}}"/>
+                  {% elif lastmonth_artifacts_by_type[key].modified == value.pmmodified %}
+                    <img src="{{g.forge_static('images/equal.png')}}"/>
+                  {% else %}
+                    <img src="{{g.forge_static('images/down.png')}}"/>
+                  {%endif%}
+                {%else%} Down {%endif%}
+              </td>
+            {% endif %}
+          </tr>
+        {% endfor %}
+
+        <tr>
+          <td>
+            {% if tottickets.assigned > 0 %}
+              <a href="/userstats/{{user.username}}/metric/tickets/">Assigned tickets</a>
+            {% else %}
+              Assigned tickets
+            {% endif %}
+          </td>
+          <td>{{tottickets.assigned}}</td>
+          <td>{{permonthtickets.assigned}}</td>
+          <td>{{lastmonthtickets.assigned}}</td>
+          {% if days >= 30 %}
+            <td style="text-align:center;">
+              {% if lastmonthtickets.assigned > permonthtickets.assigned %}
+                <img src="{{g.forge_static('images/up.png')}}"/>
+              {% elif lastmonthtickets.assigned == permonthtickets.assigned %}
+                <img src="{{g.forge_static('images/equal.png')}}"/>
+              {% else %}
+                <img src="{{g.forge_static('images/down.png')}}"/>
+              {%endif%}
+            </td>
+          {% endif %}
+        </tr>
+        <tr>
+          <td>
+            {% if tottickets.revoked > 0 %}
+              <a href="/userstats/{{user.username}}/metric/tickets/">Revoked tickets</a>
+            {% else %}
+              Revoked tickets
+            {% endif %}
+          </td>
+          <td>{{tottickets.revoked}}</td>
+          <td>{{permonthtickets.revoked}}</td>
+          <td>{{lastmonthtickets.revoked}}</td>
+          {% if days >= 30 %}
+            <td style="text-align:center;">
+              {% if lastmonthtickets.revoked > permonthtickets.revoked %}
+                <img src="{{g.forge_static('images/up.png')}}"/>
+              {% elif lastmonthtickets.revoked == permonthtickets.revoked %}
+                <img src="{{g.forge_static('images/equal.png')}}"/>
+              {% else %}
+                <img src="{{g.forge_static('images/down.png')}}"/>
+              {%endif%}
+            </td>
+          {% endif %}
+        </tr>
+        <tr>
+          <td>
+            {% if tottickets.solved > 0 %}
+              <a href="/userstats/{{user.username}}/metric/tickets/">Solved tickets</a>
+            {% else %}
+              Solved tickets
+            {% endif %}
+          </td>
+          <td>{{tottickets.solved}}</td>
+          <td>{{permonthtickets.solved}}</td>
+          <td>{{lastmonthtickets.solved}}</td>
+          {% if days >= 30 %}
+            <td style="text-align:center;">
+              {% if lastmonthtickets.solved > permonthtickets.solved %}
+                <img src="{{g.forge_static('images/up.png')}}"/>
+              {% elif lastmonthtickets.solved == permonthtickets.solved %}
+                <img src="{{g.forge_static('images/equal.png')}}"/>
+              {% else %}
+                <img src="{{g.forge_static('images/down.png')}}"/>
+              {%endif%}
+            </td>
+          {% endif %}
+        </tr>
+        <tr>
+          <td>
+            {% if tottickets.averagesolvingtime > 0 %}
+              <a href="/userstats/{{user.username}}/metric/tickets/">Average tickets solving time</a>
+            {% else %}
+              Average tickets solving time
+            {% endif %}
+          </td>
+          <td>
+            {% if tottickets.averagesolvingtime %}
+              {{tottickets.averagesolvingtime.days}} days, 
+              {{tottickets.averagesolvingtime.hours}} hours,
+              {{tottickets.averagesolvingtime.minutes}} min
+            {% else %}n/a{% endif %}
+          </td>
+          <td>n/a</td>
+          <td>
+            {% if lastmonthtickets.averagesolvingtime %}
+              {{lastmonthtickets.averagesolvingtime.days}} days, 
+              {{lastmonthtickets.averagesolvingtime.hours}} hours,
+              {{lastmonthtickets.averagesolvingtime.minutes}} min
+            {% else %}n/a{% endif %}
+          </td>
+          {% if days >= 30 %}
+            <td style="text-align:center;">
+              {% if lastmonthtickets.averagesolvingtime > tottickets.averagesolvingtime %}
+                <img src="{{g.forge_static('images/up.png')}}"/>
+              {% elif lastmonthtickets.averagesolvingtime == tottickets.averagesolvingtime %}
+                <img src="{{g.forge_static('images/equal.png')}}"/>
+              {% else %}
+                <img src="{{g.forge_static('images/down.png')}}"/>
+              {%endif%}
+            </td>
+          {% endif %}
+        </tr>
+      </tbody>
+    </table>
+
+    {% if categories %}
+        <h2>Prefered categories</h2>
+        <p>
+          The following table shows the number projects tagged as belonging to each single category in which this user is involved.
+        </p>
+        <table>
+          <thead>
+            <tr>
+              <th>Category name</th>
+              <th>Number of projects</th>
+            </tr>
+          </thead>
+          <tbody>
+            {% for cat, count in categories %}
+              <tr>
+                <td><a href="/userstats/{{user.username}}/category/{{cat.fullname}}">{{cat.fullname}}</a></td>
+                <td>{{count}}</td>
+              </tr>
+            {% endfor %}
+          </tbody>
+        </table>
+         
+        {% if categories|length > 1 %}
+          <p>
+            The same data listed in the previous table is graphically presented by the following histogram.
+          </p>
+          <p>
+            <img src="/userstats/{{user.username}}/categories_graph"/>
+          </p>
+        {% else %}
+          The following table shows the number projects tagged as belonging to each single category in which this user is involved.
+        {% endif %}
+    {% endif %}
+    {% if category %}
+        <div class="grid-20"><a href="/userstats/{{user.username}}">Go back to general statistics</a></div>
+    {% else %}
+      <h2>Overview</h2>
+      <table>
+        <thead>
+          <tr>
+            <th>Field</th>
+            <th>Value</th>
+            <th>Average per-user value</th>
+            <th>Maximum per-user value</th>
+            <th>Rank bar</th>
+          </tr>
+        </thead>
+        <tbody>
+          <tr>
+            <td>Code</td>
+            <td>{{codecontribution}} LOC{% if codecontribution != 1 %}s{% endif %}/month</td>
+            <td>{{averagecodecontrib}} LOC{% if averagecodecontrib != 1 %}s{% endif %}/month</td>
+            <td>{{maxcodecontrib}} LOC{% if maxcodecontrib != 1 %}s{% endif %}/month</td>
+            <td><img src="/userstats/{{user.username}}/code_ranking_bar"/> {{codepercentage}} %</td>
+          </tr>
+          <tr>
+            <td>Discussion</td>
+            <td>{{discussioncontribution}} contr./month</td>
+            <td>{{averagedisccontrib}} contr./month</td>
+            <td>{{maxdisccontrib}} contr./month</td>
+            <td><img src="/userstats/{{user.username}}/discussion_ranking_bar"/> {{discussionpercentage}} %</td>
+          </tr>
+          <tr>
+            <td>Solved issues</td>
+            <td>{{ticketcontribution}} %</td>
+            <td>{{averageticketcontrib}} %</td>
+            <td>{{maxticketcontrib}} %</td>
+            <td><img src="/userstats/{{user.username}}/tickets_ranking_bar"/> {{ticketspercentage}} %</td>
+          </tr>
+        </tbody>
+      </table>
+      <h3>Note</h3>
+      <p>
+         The above table compares the average monthly contribution of this user with the average monthly contributions of the
+         other users of the forge. The progressbar and the percentage refer to the user's position in an overall ranking of the
+         users of this forge. For example, a value of 100% in the field "Code" is associated to the user who has the highest
+         average number of committed LOCs per month. Of course, this doesn't consider the quality of the contributions.
+      </p>
+    {% endif %}
+  {% else %}
+    Invalid user!
+  {% endif %}
+
+{% endblock %}

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/25f7657c/ForgeUserStats/forgeuserstats/templates/tickets.html
----------------------------------------------------------------------
diff --git a/ForgeUserStats/forgeuserstats/templates/tickets.html b/ForgeUserStats/forgeuserstats/templates/tickets.html
new file mode 100644
index 0000000..9bf411b
--- /dev/null
+++ b/ForgeUserStats/forgeuserstats/templates/tickets.html
@@ -0,0 +1,52 @@
+{% set hide_left_bar = True %}
+{% extends g.theme.master %}
+
+{% block title %}User stats{% endblock %}
+
+{% block header %}
+    Statistics about {{user.display_name}}'s contribution – Tickets
+{% endblock %}
+
+{% block content %}
+
+  {% if user %}
+    <div class="grid-20">
+      <ul><li><a href="/userstats/{{user.username}}">Go back to general statistics</a></li></ul>
+    </div>
+
+    {% if data %}
+    <div class="grid-20">
+      <h2>Statistics by category</h2>
+      <table>
+        <thead>
+          <tr>
+            <th>Category</th>
+            <th>Assigned tickets</th>
+            <th>Solved tickets</th>
+            <th>Revoked tickets</th>
+            <th>Average solving time</th>
+          </tr>
+        </thead>
+        <tbody> 
+          {% for cat, el in data.items() %}
+            <tr>
+              <td>{% if cat %}{{cat.fullname}}{% else %}All categories{% endif %}</td>
+              <td>{{el.assigned}}</td>
+              <td>{{el.solved}}</td>
+              <td>{{el.revoked}}</td>
+              <td>
+                {% if el.averagesolvingtime %}
+                  {{el.averagesolvingtime.days}} days, 
+                  {{el.averagesolvingtime.hours}} hours,
+                  {{el.averagesolvingtime.minutes}} min
+                {% else %}n/a{% endif %}
+              </td>
+            {% endfor %}
+          </tr>
+        </tbody>
+      </table>
+    </div>
+    {% endif %}
+    <div class="grid-20"><a href="/userstats/{{user.username}}">Go back to general statistics</a></div>
+  {% endif %}
+{% endblock %}

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/25f7657c/ForgeUserStats/forgeuserstats/version.py
----------------------------------------------------------------------
diff --git a/ForgeUserStats/forgeuserstats/version.py b/ForgeUserStats/forgeuserstats/version.py
new file mode 100644
index 0000000..6514373
--- /dev/null
+++ b/ForgeUserStats/forgeuserstats/version.py
@@ -0,0 +1,2 @@
+__version_info__ = (0, 0)
+__version__ = '.'.join(map(str, __version_info__))

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/25f7657c/ForgeUserStats/setup.py
----------------------------------------------------------------------
diff --git a/ForgeUserStats/setup.py b/ForgeUserStats/setup.py
new file mode 100644
index 0000000..dc2f07b
--- /dev/null
+++ b/ForgeUserStats/setup.py
@@ -0,0 +1,29 @@
+from setuptools import setup, find_packages
+import sys, os
+
+from forgeuserstats.version import __version__
+
+setup(name='ForgeUserStats',
+      version=__version__,
+      description="",
+      long_description="""\
+""",
+      classifiers=[], # Get strings from http://pypi.python.org/pypi?%3Aaction=list_classifiers
+      keywords='',
+      author='',
+      author_email='',
+      url='',
+      license='',
+      packages=find_packages(exclude=['ez_setup', 'examples', 'tests']),
+      include_package_data=True,
+      zip_safe=False,
+      install_requires=[
+          # -*- Extra requirements: -*-
+          'allura',
+      ],
+      entry_points="""
+      # -*- Entry points: -*-
+      [allura.stats]
+      userstats=forgeuserstats.main:ForgeUserStatsApp
+      """,
+      )

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/25f7657c/requirements-common.txt
----------------------------------------------------------------------
diff --git a/requirements-common.txt b/requirements-common.txt
index 9621aa8..9ca2a92 100644
--- a/requirements-common.txt
+++ b/requirements-common.txt
@@ -47,6 +47,8 @@ TurboGears2==2.1.5
 WebOb==1.0.8
 # part of the stdlib, but with a version number.  see http://guide.python-distribute.org/pip.html#listing-installed-packages
 wsgiref==0.1.2
+numpy==1.6.1
+matplotlib==1.1.1rc
 
 # tg2 deps (not used directly)
 Babel==0.9.6