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/02/25 22:56:17 UTC
[26/50] [abbrv] [5453] adding support for user stats
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/d686cc00/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/d686cc00/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/d686cc00/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/d686cc00/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/d686cc00/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/d686cc00/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/d686cc00/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/d686cc00/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/d686cc00/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/d686cc00/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/d686cc00/requirements-common.txt
----------------------------------------------------------------------
diff --git a/requirements-common.txt b/requirements-common.txt
index 9663e48..3628e5d 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