Mercurial > hg > savane-forge
changeset 341:85fa60bc06d4
Tracker: import and display history (including comments)
author | Sylvain Beucler <beuc@beuc.net> |
---|---|
date | Sat, 28 Aug 2010 12:54:52 +0200 |
parents | bd527a3a0c68 |
children | a13981e03bf4 |
files | migrate_old_savane.sql savane/svmain/templatetags/svmarkup.py savane/tracker/models.py static_media/savane/css/tracker.css templates/tracker/item_form.html |
diffstat | 5 files changed, 191 insertions(+), 29 deletions(-) [+] |
line wrap: on
line diff
--- a/migrate_old_savane.sql +++ b/migrate_old_savane.sql @@ -669,3 +669,30 @@ FROM savane_old.trackers_msgid JOIN tracker_item ON (savane_old.trackers_msgid.item_id = tracker_item.public_bugs_id AND savane_old.trackers_msgid.artifact = tracker_item.tracker_id); + +-- Comments +TRUNCATE tracker_comment; +INSERT INTO tracker_comment + (item_id, message, posted_by_id, date, comment_type, spamscore, ip) + SELECT internal_id, old_value, mod_by, FROM_UNIXTIME(savane_old.bugs_history.date), + type, savane_old.bugs_history.spamscore, savane_old.bugs_history.ip + FROM savane_old.bugs_history JOIN tracker_item + ON (savane_old.bugs_history.bug_id = tracker_item.public_bugs_id) + WHERE field_name='details'; +-- TODO: import 'patch' +-- TODO: import 'support' +-- TODO: import 'task' + +-- Field history +TRUNCATE tracker_itemhistory; +INSERT INTO tracker_itemhistory + (item_id, date, mod_by_id, field, old_value, new_value) + SELECT internal_id, FROM_UNIXTIME(savane_old.bugs_history.date), + mod_by, field_name, old_value, new_value + FROM savane_old.bugs_history JOIN tracker_item + ON (savane_old.bugs_history.bug_id = tracker_item.public_bugs_id) + WHERE field_name <> 'details'; +-- TODO: import 'patch' +-- TODO: import 'support' +-- TODO: import 'task' +
--- a/savane/svmain/templatetags/svmarkup.py +++ b/savane/svmain/templatetags/svmarkup.py @@ -26,3 +26,11 @@ @register.filter def svmarkup_full(text): return mark_safe(markup.full(escape(text))) + +@register.filter +def svmarkup_rich(text): + return mark_safe(markup.rich(escape(text))) + +@register.filter +def svmarkup_basic(text): + return mark_safe(markup.basic(escape(text)))
--- a/savane/tracker/models.py +++ b/savane/tracker/models.py @@ -618,14 +618,34 @@ item = models.ForeignKey('Item') msg_id = models.CharField(max_length=255) +class Comment(models.Model): + """ + Item comments (field='details') + """ + class Meta: + ordering = ('item','date',) + item = models.ForeignKey('Item') + date = models.DateTimeField(default=datetime.date.today) + posted_by = models.ForeignKey(auth_models.User) + message = models.TextField(blank=True, null=True) + comment_type = models.IntegerField(_("comment type"), blank=True, null=True) + # Should be: + # type = models.ForeignKey('FieldChoice', to_field='value_id') + # + constraint(same group or NULL) + constraint(field='comment_type_id') + # The purpose is to add <strong>[$comment_type]</strong> when + # displaying an item comment. + spamscore = models.IntegerField(_("total spamscore for this comment")) + ip = models.IPAddressField(blank=True, null=True) class ItemHistory(models.Model): """ - This stores 2 kinds of values: - - item comments (field='details') - - value changes, for fields that have history tracking enabled + Value changes, for fields that have history tracking enabled """ + class Meta: + ordering = ('item','date','id',) item = models.ForeignKey('Item') + date = models.DateTimeField(default=datetime.date.today) + mod_by = models.ForeignKey(auth_models.User) field = models.CharField(max_length=32) # Should be: field = models.ForeignKey('Field', to_field='name') # + constraint (item.tracker=field.tracker) @@ -633,31 +653,19 @@ # But as it's a history field, adding constraints might be just bad. old_value= models.TextField(blank=True, null=True) new_value= models.TextField() - mod_by = models.ForeignKey(auth_models.User) - date = models.DateTimeField(default=datetime.date.today) - ip = models.IPAddressField(blank=True, null=True) - - # Specific (bad!) field for 'details' - # I guess 'details' could be stored separately. - type = models.IntegerField(_("comment type"), blank=True, null=True) - # Should be: - # type = models.ForeignKey('FieldChoice', to_field='value_id') - # + constraint(same group or 100) + constraint(field='comment_type_id') - # The purpose is to add <strong>[$comment_type]</strong> when - # displaying an item comment. - spamscore = models.IntegerField(_("total spamscore for this comment")) class ItemCc(models.Model): """ Item carbon copies for mail notifications """ item = models.ForeignKey('Item') - email = models.EmailField(max_length=255) + contact = models.CharField(max_length=255) added_by = models.ForeignKey(auth_models.User) comment = models.TextField() date = models.DateTimeField(default=datetime.date.today) #class ItemDependencies: +# TODO: import # => cf. Item.dependencies class ItemFile(models.Model): @@ -673,17 +681,17 @@ filetype = models.TextField() # /!\ `file` longblob NOT NULL - if not savane-cleanup -class ItemSpamScore(models.Model): - """ - Spam reports - - Score is summed in ItemHistory.spamscore. - """ - score = models.IntegerField(default=1) - affected_user = models.ForeignKey(auth_models.User, related_name='itemspamscore_affected_set') - reporter_user = models.ForeignKey(auth_models.User, related_name='itemspamscore_reported_set') - item = models.ForeignKey('Item') - comment_id = models.ForeignKey('ItemHistory', null=True) +#class CommentSpamScore(models.Model): +# """ +# Spam reports +# +# Score is summed in ItemHistory.spamscore. +# """ +# score = models.IntegerField(default=1) +# affected = models.ForeignKey(auth_models.User, related_name='commentspamscore_affected_set') +# reporter = models.ForeignKey(auth_models.User, related_name='commentspamscore_reported_set') +# item = models.ForeignKey('Item') +# comment_id = models.ForeignKey('ItemComment', null=True) # TODO:
--- a/static_media/savane/css/tracker.css +++ b/static_media/savane/css/tracker.css @@ -47,6 +47,30 @@ border-left: thin #b5b5b5 solid; } +table.comments { + width: 98%; + margin-left: 1%; + margin-right: 1%; + margin-bottom: 15px; + vertical-align: top; + border-spacing: 1px; + border: 0; +} +table.comments p { + padding-left:0.2em; + padding-right:0.2em; +} +table.comments td { + vertical-align: top; +} + +table.history td { + text-align: center; +} +table.history td.old_value { + text-align: right; +} + /********************************************************************** * * Priorities
--- a/templates/tracker/item_form.html +++ b/templates/tracker/item_form.html @@ -1,5 +1,6 @@ {% extends "base.html" %} {% load i18n %} +{% load svmarkup %} {% block title %} {{object.group.name}} - {{object.get_tracker_name}}{% trans ": " %} @@ -67,7 +68,7 @@ <p class="preinput">{% trans "Add a new comment" %}{% trans ": " %}<br /> <textarea cols="65" rows="16" name="comment"></textarea> </p> -<p class="preinput">{% trans "Comment type & canned response" %}{% trans ": " %}<br /> +<p class="preinput">{% filter force_escape %}{% trans "Comment type & canned response" %}{% endfilter %}{% trans ": " %}<br /> <select name="comment_type_id"> {% for choice in object.get_field_defs.comment_type_id.choices %} <option value="{{choice.value_id}}">{{choice.value}}</option> @@ -89,6 +90,58 @@ <h2>{% trans "Discussion" %}</h2> +<table class="comments"> +{% for comment in object.comment_set.all reversed %} +<tr class="{% cycle 'boxitem' 'boxitemalt' as rowcolor %}"> + <td> + <a name="comment{{forloop.counter}}" href="#comment{{forloop.count}}" + class="preinput"> + {{comment.date}}, + {% blocktrans with forloop.counter as number %}comment #{{number}}{% endblocktrans %}{% trans ": " %} + </a><br /> + {{ comment.message|svmarkup_rich }} + </td> + <td class="boxitemextra"> + {% if comment.posted_by_id %} + {% if comment.posted_by %} + <a href="{% url savane:svmain:user_detail comment.posted_by.username %}" + >{{comment.posted_by.get_full_name}} + <{{comment.posted_by.username}}></a> + {% else %} + <strong>{% trans "Invalid user ID" %}</strong> + {% endif %} + {% else %} + {% trans "Anonymous" %} + {% endif %} + <!-- TODO: display poster privs --> + </td> +</tr> +{% endfor %} +<tr class="{% cycle rowcolor %}"> + <td> + <a name="comment0" href="#comment0" + class="preinput"> + {{object.date}}, <strong>{% trans "original submission" %}{% trans ": " %}</strong> + </a><br /> + {{ object.details|svmarkup_full }} + </td> + <td class="boxitemextra"> + {% if object.submitted_by_id %} + {% if object.submitted_by %} + <a href="{% url savane:svmain:user_detail object.submitted_by.username %}" + >{{object.submitted_by.get_full_name}} + <{{object.submitted_by.username}}></a> + {% else %} + <strong>{% trans "Invalid user ID" %}</strong> + {% endif %} + {% else %} + {% trans "Anonymous" %} + {% endif %} + <!-- TODO: display poster privs --> + </td> +</tr> +</table> + <h2>{% trans "Attached files" %}</h2> <h2>{% trans "Dependencies" %}</h2> @@ -102,6 +155,48 @@ <h2>{% trans "History" %}</h2> +<p> +{% blocktrans count object.itemhistory_set.count as count %}Follows {{count}} latest change.{% plural %}Follow {{count}} latest changes.{% endblocktrans %} +</p> + +<table class="history smaller box"> +<tr> + <th>Date</th> + <th>Changed by</th> + <th>Updated field</th> + <th>Previous value</th> + <th width="1">=></th> + <th>Replaced By</th> +</tr> +{% for history in object.itemhistory_set.all %} +{% ifchanged history.date history.mod_by %} +<tr class="{% cycle 'boxitem' 'boxitemalt' as rowcolor %}"> + <td>{{history.date}}</td> + <td> + {% if history.mod_by_id %} + {% if history.mod_by %} + <a href="{% url savane:svmain:user_detail history.mod_by.username %}" + >{{history.mod_by.username}}</a> + {% else %} + <strong>{% trans "Invalid user ID" %}</strong> + {% endif %} + {% else %} + {% trans "Anonymous" %} + {% endif %} + </td> +{% else %} +<!-- skip {% cycle rowcolor %} once --> +<tr class="{% cycle rowcolor %}"> + <td></td><td></td> +{% endifchanged %} + <td>{{history.field}}</td><!-- TODO: field definition['label'] --> + <td class="old_value">{{history.old_value}}</td><!-- TODO: if SB, use FieldChoice --> + <td><img width="24" src="{{STATIC_MEDIA_URL}}savane/images/common/arrows1/next.orig.png" border="0" alt="=>" /></td> + <td>{{history.new_value}}</td> +</tr> +{% endfor %} +</table> + {% endblock %} {% comment %} Local Variables: **