Mercurial > hg > savane-forge
changeset 333:1de0e15f60d6
Get field choices in corner cases: old now-invalid value_id; choices overlays
author | Sylvain Beucler <beuc@beuc.net> |
---|---|
date | Sun, 22 Aug 2010 21:10:41 +0200 |
parents | 7234fcf49cc0 |
children | 70f5630b1e1e |
files | doc/scripts/tracker_gendefs.py savane/tracker/defs.py savane/tracker/models.py |
diffstat | 3 files changed, 142 insertions(+), 88 deletions(-) [+] |
line wrap: on
line diff
--- a/doc/scripts/tracker_gendefs.py +++ b/doc/scripts/tracker_gendefs.py @@ -18,7 +18,10 @@ name = row[1] field_names.append(name) defs[name] = '' - defs[name] += " '"+name+"' : {\n" + if name == 'field_name': + defs[name] += " 'name' : {\n" + else: + defs[name] += " '"+name+"' : {\n" for i,val in enumerate(row): if i <= 0 \ or (complex_defs[name]['display_type'] not in ('TA', 'TF') and tfields[i] == 'display_size'):
--- a/savane/tracker/defs.py +++ b/savane/tracker/defs.py @@ -62,7 +62,7 @@ field_defs = { 'bug_id' : { - 'field_name': 'bug_id', + 'name': 'bug_id', 'display_type': 'TF', 'scope': 'S', 'required': 1, @@ -70,7 +70,7 @@ 'custom': 0, }, 'group_id' : { - 'field_name': 'group_id', + 'name': 'group_id', 'display_type': 'TF', 'scope': 'S', 'required': 1, @@ -78,7 +78,7 @@ 'custom': 0, }, 'submitted_by' : { - 'field_name': 'submitted_by', + 'name': 'submitted_by', 'display_type': 'SB', 'scope': 'S', 'required': 1, @@ -86,7 +86,7 @@ 'custom': 0, }, 'date' : { - 'field_name': 'date', + 'name': 'date', 'display_type': 'DF', 'scope': 'S', 'required': 1, @@ -94,7 +94,7 @@ 'custom': 0, }, 'close_date' : { - 'field_name': 'close_date', + 'name': 'close_date', 'display_type': 'DF', 'scope': 'S', 'required': 1, @@ -102,7 +102,7 @@ 'custom': 0, }, 'status_id' : { - 'field_name': 'status_id', + 'name': 'status_id', 'display_type': 'SB', 'scope': 'S', 'required': 1, @@ -110,7 +110,7 @@ 'custom': 0, }, 'severity' : { - 'field_name': 'severity', + 'name': 'severity', 'display_type': 'SB', 'scope': 'S', 'required': 0, @@ -118,7 +118,7 @@ 'custom': 0, }, 'category_id' : { - 'field_name': 'category_id', + 'name': 'category_id', 'display_type': 'SB', 'scope': 'P', 'required': 0, @@ -126,7 +126,7 @@ 'custom': 0, }, 'assigned_to' : { - 'field_name': 'assigned_to', + 'name': 'assigned_to', 'display_type': 'SB', 'scope': 'S', 'required': 1, @@ -134,7 +134,7 @@ 'custom': 0, }, 'summary' : { - 'field_name': 'summary', + 'name': 'summary', 'display_type': 'TF', 'scope': 'S', 'required': 1, @@ -142,7 +142,7 @@ 'custom': 0, }, 'details' : { - 'field_name': 'details', + 'name': 'details', 'display_type': 'TA', 'scope': 'S', 'required': 1, @@ -150,7 +150,7 @@ 'custom': 0, }, 'bug_group_id' : { - 'field_name': 'bug_group_id', + 'name': 'bug_group_id', 'display_type': 'SB', 'scope': 'P', 'required': 0, @@ -158,7 +158,7 @@ 'custom': 0, }, 'resolution_id' : { - 'field_name': 'resolution_id', + 'name': 'resolution_id', 'display_type': 'SB', 'scope': 'P', 'required': 0, @@ -166,7 +166,7 @@ 'custom': 0, }, 'privacy' : { - 'field_name': 'privacy', + 'name': 'privacy', 'display_type': 'SB', 'scope': 'S', 'required': 0, @@ -174,7 +174,7 @@ 'custom': 0, }, 'vote' : { - 'field_name': 'vote', + 'name': 'vote', 'display_type': 'TF', 'scope': 'S', 'required': 0, @@ -182,7 +182,7 @@ 'custom': 0, }, 'category_version_id' : { - 'field_name': 'category_version_id', + 'name': 'category_version_id', 'display_type': 'SB', 'scope': 'P', 'required': 0, @@ -190,7 +190,7 @@ 'custom': 0, }, 'platform_version_id' : { - 'field_name': 'platform_version_id', + 'name': 'platform_version_id', 'display_type': 'SB', 'scope': 'P', 'required': 0, @@ -198,7 +198,7 @@ 'custom': 0, }, 'reproducibility_id' : { - 'field_name': 'reproducibility_id', + 'name': 'reproducibility_id', 'display_type': 'SB', 'scope': 'S', 'required': 0, @@ -206,7 +206,7 @@ 'custom': 0, }, 'size_id' : { - 'field_name': 'size_id', + 'name': 'size_id', 'display_type': 'SB', 'scope': 'S', 'required': 0, @@ -214,7 +214,7 @@ 'custom': 0, }, 'fix_release_id' : { - 'field_name': 'fix_release_id', + 'name': 'fix_release_id', 'display_type': 'SB', 'scope': 'P', 'required': 0, @@ -222,7 +222,7 @@ 'custom': 0, }, 'comment_type_id' : { - 'field_name': 'comment_type_id', + 'name': 'comment_type_id', 'display_type': 'SB', 'scope': 'P', 'required': 1, @@ -230,7 +230,7 @@ 'custom': 0, }, 'hours' : { - 'field_name': 'hours', + 'name': 'hours', 'display_type': 'TF', 'scope': 'S', 'required': 0, @@ -238,7 +238,7 @@ 'custom': 0, }, 'plan_release_id' : { - 'field_name': 'plan_release_id', + 'name': 'plan_release_id', 'display_type': 'SB', 'scope': 'P', 'required': 0, @@ -246,7 +246,7 @@ 'custom': 0, }, 'component_version' : { - 'field_name': 'component_version', + 'name': 'component_version', 'display_type': 'TF', 'scope': 'S', 'required': 0, @@ -254,7 +254,7 @@ 'custom': 0, }, 'fix_release' : { - 'field_name': 'fix_release', + 'name': 'fix_release', 'display_type': 'TF', 'scope': 'S', 'required': 0, @@ -262,7 +262,7 @@ 'custom': 0, }, 'plan_release' : { - 'field_name': 'plan_release', + 'name': 'plan_release', 'display_type': 'TF', 'scope': 'S', 'required': 0, @@ -270,7 +270,7 @@ 'custom': 0, }, 'priority' : { - 'field_name': 'priority', + 'name': 'priority', 'display_type': 'SB', 'scope': 'S', 'required': 0, @@ -278,7 +278,7 @@ 'custom': 0, }, 'keywords' : { - 'field_name': 'keywords', + 'name': 'keywords', 'display_type': 'TF', 'scope': 'S', 'required': 0, @@ -286,7 +286,7 @@ 'custom': 0, }, 'release_id' : { - 'field_name': 'release_id', + 'name': 'release_id', 'display_type': 'SB', 'scope': 'P', 'required': 0, @@ -294,7 +294,7 @@ 'custom': 0, }, 'release' : { - 'field_name': 'release', + 'name': 'release', 'display_type': 'TF', 'scope': 'S', 'required': 0, @@ -302,7 +302,7 @@ 'custom': 0, }, 'originator_name' : { - 'field_name': 'originator_name', + 'name': 'originator_name', 'display_type': 'TF', 'scope': 'S', 'required': 0, @@ -310,7 +310,7 @@ 'custom': 0, }, 'originator_email' : { - 'field_name': 'originator_email', + 'name': 'originator_email', 'display_type': 'TF', 'scope': 'S', 'required': 0, @@ -318,7 +318,7 @@ 'custom': 0, }, 'originator_phone' : { - 'field_name': 'originator_phone', + 'name': 'originator_phone', 'display_type': 'TF', 'scope': 'S', 'required': 0, @@ -326,7 +326,7 @@ 'custom': 0, }, 'percent_complete' : { - 'field_name': 'percent_complete', + 'name': 'percent_complete', 'display_type': 'SB', 'scope': 'S', 'required': 0, @@ -334,7 +334,7 @@ 'custom': 0, }, 'custom_tf1' : { - 'field_name': 'custom_tf1', + 'name': 'custom_tf1', 'display_type': 'TF', 'scope': 'P', 'required': 0, @@ -342,7 +342,7 @@ 'custom': 1, }, 'custom_tf2' : { - 'field_name': 'custom_tf2', + 'name': 'custom_tf2', 'display_type': 'TF', 'scope': 'P', 'required': 0, @@ -350,7 +350,7 @@ 'custom': 1, }, 'custom_tf3' : { - 'field_name': 'custom_tf3', + 'name': 'custom_tf3', 'display_type': 'TF', 'scope': 'P', 'required': 0, @@ -358,7 +358,7 @@ 'custom': 1, }, 'custom_tf4' : { - 'field_name': 'custom_tf4', + 'name': 'custom_tf4', 'display_type': 'TF', 'scope': 'P', 'required': 0, @@ -366,7 +366,7 @@ 'custom': 1, }, 'custom_tf5' : { - 'field_name': 'custom_tf5', + 'name': 'custom_tf5', 'display_type': 'TF', 'scope': 'P', 'required': 0, @@ -374,7 +374,7 @@ 'custom': 1, }, 'custom_tf6' : { - 'field_name': 'custom_tf6', + 'name': 'custom_tf6', 'display_type': 'TF', 'scope': 'P', 'required': 0, @@ -382,7 +382,7 @@ 'custom': 1, }, 'custom_tf7' : { - 'field_name': 'custom_tf7', + 'name': 'custom_tf7', 'display_type': 'TF', 'scope': 'P', 'required': 0, @@ -390,7 +390,7 @@ 'custom': 1, }, 'custom_tf8' : { - 'field_name': 'custom_tf8', + 'name': 'custom_tf8', 'display_type': 'TF', 'scope': 'P', 'required': 0, @@ -398,7 +398,7 @@ 'custom': 1, }, 'custom_tf9' : { - 'field_name': 'custom_tf9', + 'name': 'custom_tf9', 'display_type': 'TF', 'scope': 'P', 'required': 0, @@ -406,7 +406,7 @@ 'custom': 1, }, 'custom_tf10' : { - 'field_name': 'custom_tf10', + 'name': 'custom_tf10', 'display_type': 'TF', 'scope': 'P', 'required': 0, @@ -414,7 +414,7 @@ 'custom': 1, }, 'custom_ta1' : { - 'field_name': 'custom_ta1', + 'name': 'custom_ta1', 'display_type': 'TA', 'scope': 'P', 'required': 0, @@ -422,7 +422,7 @@ 'custom': 1, }, 'custom_ta2' : { - 'field_name': 'custom_ta2', + 'name': 'custom_ta2', 'display_type': 'TA', 'scope': 'P', 'required': 0, @@ -430,7 +430,7 @@ 'custom': 1, }, 'custom_ta3' : { - 'field_name': 'custom_ta3', + 'name': 'custom_ta3', 'display_type': 'TA', 'scope': 'P', 'required': 0, @@ -438,7 +438,7 @@ 'custom': 1, }, 'custom_ta4' : { - 'field_name': 'custom_ta4', + 'name': 'custom_ta4', 'display_type': 'TA', 'scope': 'P', 'required': 0, @@ -446,7 +446,7 @@ 'custom': 1, }, 'custom_ta5' : { - 'field_name': 'custom_ta5', + 'name': 'custom_ta5', 'display_type': 'TA', 'scope': 'P', 'required': 0, @@ -454,7 +454,7 @@ 'custom': 1, }, 'custom_ta6' : { - 'field_name': 'custom_ta6', + 'name': 'custom_ta6', 'display_type': 'TA', 'scope': 'P', 'required': 0, @@ -462,7 +462,7 @@ 'custom': 1, }, 'custom_ta7' : { - 'field_name': 'custom_ta7', + 'name': 'custom_ta7', 'display_type': 'TA', 'scope': 'P', 'required': 0, @@ -470,7 +470,7 @@ 'custom': 1, }, 'custom_ta8' : { - 'field_name': 'custom_ta8', + 'name': 'custom_ta8', 'display_type': 'TA', 'scope': 'P', 'required': 0, @@ -478,7 +478,7 @@ 'custom': 1, }, 'custom_ta9' : { - 'field_name': 'custom_ta9', + 'name': 'custom_ta9', 'display_type': 'TA', 'scope': 'P', 'required': 0, @@ -486,7 +486,7 @@ 'custom': 1, }, 'custom_ta10' : { - 'field_name': 'custom_ta10', + 'name': 'custom_ta10', 'display_type': 'TA', 'scope': 'P', 'required': 0, @@ -494,7 +494,7 @@ 'custom': 1, }, 'custom_sb1' : { - 'field_name': 'custom_sb1', + 'name': 'custom_sb1', 'display_type': 'SB', 'scope': 'P', 'required': 0, @@ -502,7 +502,7 @@ 'custom': 1, }, 'custom_sb2' : { - 'field_name': 'custom_sb2', + 'name': 'custom_sb2', 'display_type': 'SB', 'scope': 'P', 'required': 0, @@ -510,7 +510,7 @@ 'custom': 1, }, 'custom_sb3' : { - 'field_name': 'custom_sb3', + 'name': 'custom_sb3', 'display_type': 'SB', 'scope': 'P', 'required': 0, @@ -518,7 +518,7 @@ 'custom': 1, }, 'custom_sb4' : { - 'field_name': 'custom_sb4', + 'name': 'custom_sb4', 'display_type': 'SB', 'scope': 'P', 'required': 0, @@ -526,7 +526,7 @@ 'custom': 1, }, 'custom_sb5' : { - 'field_name': 'custom_sb5', + 'name': 'custom_sb5', 'display_type': 'SB', 'scope': 'P', 'required': 0, @@ -534,7 +534,7 @@ 'custom': 1, }, 'custom_sb6' : { - 'field_name': 'custom_sb6', + 'name': 'custom_sb6', 'display_type': 'SB', 'scope': 'P', 'required': 0, @@ -542,7 +542,7 @@ 'custom': 1, }, 'custom_sb7' : { - 'field_name': 'custom_sb7', + 'name': 'custom_sb7', 'display_type': 'SB', 'scope': 'P', 'required': 0, @@ -550,7 +550,7 @@ 'custom': 1, }, 'custom_sb8' : { - 'field_name': 'custom_sb8', + 'name': 'custom_sb8', 'display_type': 'SB', 'scope': 'P', 'required': 0, @@ -558,7 +558,7 @@ 'custom': 1, }, 'custom_sb9' : { - 'field_name': 'custom_sb9', + 'name': 'custom_sb9', 'display_type': 'SB', 'scope': 'P', 'required': 0, @@ -566,7 +566,7 @@ 'custom': 1, }, 'custom_sb10' : { - 'field_name': 'custom_sb10', + 'name': 'custom_sb10', 'display_type': 'SB', 'scope': 'P', 'required': 0, @@ -574,7 +574,7 @@ 'custom': 1, }, 'custom_df1' : { - 'field_name': 'custom_df1', + 'name': 'custom_df1', 'display_type': 'DF', 'scope': 'P', 'required': 0, @@ -582,7 +582,7 @@ 'custom': 1, }, 'custom_df2' : { - 'field_name': 'custom_df2', + 'name': 'custom_df2', 'display_type': 'DF', 'scope': 'P', 'required': 0, @@ -590,7 +590,7 @@ 'custom': 1, }, 'custom_df3' : { - 'field_name': 'custom_df3', + 'name': 'custom_df3', 'display_type': 'DF', 'scope': 'P', 'required': 0, @@ -598,7 +598,7 @@ 'custom': 1, }, 'custom_df4' : { - 'field_name': 'custom_df4', + 'name': 'custom_df4', 'display_type': 'DF', 'scope': 'P', 'required': 0, @@ -606,7 +606,7 @@ 'custom': 1, }, 'custom_df5' : { - 'field_name': 'custom_df5', + 'name': 'custom_df5', 'display_type': 'DF', 'scope': 'P', 'required': 0, @@ -614,7 +614,7 @@ 'custom': 1, }, 'discussion_lock' : { - 'field_name': 'discussion_lock', + 'name': 'discussion_lock', 'display_type': 'SB', 'scope': 'S', 'required': 1, @@ -622,7 +622,7 @@ 'custom': 0, }, 'planned_close_date' : { - 'field_name': 'planned_close_date', + 'name': 'planned_close_date', 'display_type': 'DF', 'scope': 'S', 'required': 0, @@ -630,7 +630,7 @@ 'custom': 0, }, 'planned_starting_date' : { - 'field_name': 'planned_starting_date', + 'name': 'planned_starting_date', 'display_type': 'DF', 'scope': 'S', 'required': 0,
--- a/savane/tracker/models.py +++ b/savane/tracker/models.py @@ -17,6 +17,7 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. from django.db import models +from django.db.models import Q from django.utils.translation import ugettext, ugettext_lazy as _ import django.contrib.auth.models as auth_models from django.utils.safestring import mark_safe @@ -182,7 +183,7 @@ # Can always be changed (expect for special 'summary' and 'details') empty_ok = models.CharField(max_length=1, choices=EMPTY_OK_CHOICES, - default='0', blank=True, null=True) + default='0', blank=True, null=True) # Can always be changed rank = models.IntegerField(help_text=_("display rank")) @@ -233,7 +234,7 @@ STATUS_CHOICES = (('A', _('active')), ('H', _('hidden')), # mask previously-active or system fields ('P', _('permanent')),) # status cannot be modified, always visible - tracker = models.ForeignKey(Tracker) + tracker = models.ForeignKey(Tracker, blank=True, null=True) group = models.ForeignKey(auth_models.Group, blank=True, null=True, help_text=_("NULL == default for all groups")) field = models.CharField(max_length=32) @@ -258,23 +259,56 @@ group_name = self.group.name return "%s.%s: %s (%d)" % (group_name, self.field, self.value, self.value_id) -def field_get_values(tracker_id, group, field): +## +# Field +## + +def field_get_values(tracker_id, group, field_def, cur_item_value_id=None): """ Return all possible values for this select box field """ - if field == 'assigned_to': + name = field_def['name'] + if name == 'submitted_by': + # Not editable + return [] + if name == 'assigned_to': # Hard-coded processing: it's a list of project members - default_values = [{'value_id' : -1, 'value' : _("None")}] - for user in group.user_set.order_by('username'): - default_values.append({'value_id' : user.pk, 'value' : user.username}) + values = [{'value_id' : -1, 'value' : _("None")}] + pks = list(group.user_set.order_by('username').values_list('pk', flat=True)) + # Add the current value if the user was previously part of the + # project and assigned this time + if cur_item_value_id not in pks: + pks.insert(0, cur_item_value_id) + for user in auth_models.User.objects.filter(pk__in=pks): + values.append({'value_id' : user.pk, 'value' : user.username}) else: - #tracker_id=tracker_id, - default_values = list(FieldChoice.objects \ - .filter(group=None, field=field).exclude(status='H') \ + values = list(FieldChoice.objects \ + .filter(tracker=tracker_id, group=None, field=name) \ + .filter(~Q(status='H')|Q(value_id=cur_item_value_id)) \ .values('value_id', 'value', 'rank')) # value overlays - default_values.sort(key=lambda x: x['rank']) - return default_values + overlay_values = list(FieldChoice.objects \ + .filter(tracker=tracker_id, group=group, field=name) \ + .values('value_id', 'value', 'rank', 'status')) + for o in overlay_values: + found = False + i = 0 + for v in values: + if v['value_id'] == o['value_id']: + found = True + if v['status'] == 'H': + del values[i] + i -= 1 + else: + v['value'] = o['value'] + v['rank'] = o['rank'] + break + i += 1 + if not found and o['status'] != 'H' and field_def['scope'] != 'S': + v.append(o) + values.sort(key=lambda x: x['rank']) + + return values # Auto_increment counters # We could make this more generic, but we'd have to implement @@ -468,7 +502,8 @@ overlay.apply_on(fields[name]) for name in fields: if fields[name]['display_type'] == 'SB': - fields[name]['values'] = field_get_values(self.tracker_id, self.group, name) + fields[name]['values'] = field_get_values(self.tracker_id, self.group, + fields[name], self.get_value(name)) return fields def get_form_fields(self, user=None): @@ -478,7 +513,6 @@ fields = self.get_fields().copy() ret = [] for name in fields.keys(): - print fields[name] if (not (fields[name]['required'] or fields[name]['use_it']) or fields[name]['special']): continue @@ -486,12 +520,29 @@ ret.sort(key=lambda x: x[1]['rank']) return ret + def get_value(self, key): + if key == 'comment_type_id': + # not stored in the item, but in the history + # TODO: it actually has nothing do in fields definitions + # (not part of the generic form, not a stored value); move + # it out! + return None + elif key in ('submitted_by', 'assigned_to'): + user = getattr(self, key) + if user is None: + return None + else: + return user.pk + else: + return getattr(self, key) + def get_form(self, user=None): # TODO: privacy + # TODO: privileges form_fields = self.get_form_fields() html = ''; for field_no, (name,field) in enumerate(form_fields): - value = getattr(self, name) + value = self.get_value(name) if field_no % 2 == 0: html += '<tr>'