changeset 326:f34eba406e57

More model refinement + update migration script
author Sylvain Beucler <beuc@beuc.net>
date Sat, 21 Aug 2010 15:32:09 +0200
parents c193bb0a8819
children cdce64340e6c
files doc/scripts/tracker_defsgen.py migrate_old_savane.sql savane/tracker/admin.py savane/tracker/defs.py savane/tracker/models.py
diffstat 5 files changed, 262 insertions(+), 216 deletions(-) [+]
line wrap: on
line diff
--- a/doc/scripts/tracker_defsgen.py
+++ b/doc/scripts/tracker_defsgen.py
@@ -52,6 +52,13 @@
 for row in c.fetchall():
     process_field_row(row)
 
+
+# Doc:
+#SHOW_ON_ADD_CHOICES = (('0', _('no')),
+#                       ('1', _('show to logged in users')),
+#                       ('2', _('show to anonymous users')),
+#                       ('3', _('show to both logged in and anonymous users')),)
+
 tfields = ['name','bug_field_id','group_id','use_it','show_on_add',
            'show_on_add_members','place','custom_label',
            'custom_description','custom_display_size',
@@ -61,6 +68,8 @@
   FROM bugs_field_usage JOIN bugs_field USING (bug_field_id) WHERE group_id=100""")
 def process_field_usage_row(row):
     name = row[0]
+    if name == 'place':
+        name = 'rank'
     for i,val in enumerate(row):
         if i <= 2:
             continue
@@ -72,6 +81,19 @@
                 :
             # overlays, duplicates of bugs_field in this context
             continue
+        elif tfields[i] == 'show_on_add':
+            if val == 0:
+                defs[name] += "        'show_on_add_anonymous': 0,\n"
+                defs[name] += "        'show_on_add_connected': 0,\n"
+            elif val == 1:
+                defs[name] += "        'show_on_add_anonymous': 0,\n"
+                defs[name] += "        'show_on_add_connected': 1,\n"
+            elif val == 2:
+                defs[name] += "        'show_on_add_anonymous': 1,\n"
+                defs[name] += "        'show_on_add_connected': 0,\n"
+            elif val == 3:
+                defs[name] += "        'show_on_add_anonymous': 1,\n"
+                defs[name] += "        'show_on_add_connected': 1,\n"
         else:
             defs[name] += "        " \
                 + "'"+tfields[i]+"'" \
--- a/migrate_old_savane.sql
+++ b/migrate_old_savane.sql
@@ -494,7 +494,7 @@
 INSERT INTO tracker_item
     (tracker_id, public_bugs_id, group_id, status_id, severity, privacy,
     discussion_lock,
-    vote, spamscore, ip, category_id, submitted_by_id, assigned_to,
+    vote, spamscore, ip, category_id, submitted_by_id, assigned_to_id,
     date, summary, details, close_date, bug_group_id, resolution_id,
     category_version_id, platform_version_id, reproducibility_id,
     size_id, fix_release_id, plan_release_id, hours, component_version,
@@ -533,48 +533,15 @@
     FROM_UNIXTIME(IF(custom_df5<0,0,custom_df5))
   FROM savane_old.bugs;
 -- Specify "default" differently
-UPDATE tracker_item SET assigned_to=NULL WHERE submitted_by=100;
-UPDATE tracker_item SET submitted_by=NULL WHERE submitted_by=100;
-
--- We're merging all the *_field tables, so we need to assign new ids.
--- (Not needed if we merge the tracker fields definitions, because
--- they are mostly identical (cf. models.py).)
-CREATE TEMPORARY TABLE conv_field_ids (
-  new INT auto_increment PRIMARY KEY,
-  tracker_id VARCHAR(7), old INT,
-  INDEX(tracker_id), INDEX(old));
-INSERT INTO conv_field_ids (tracker_id, old)
-        SELECT 'bugs',    bug_field_id FROM savane_old.bugs_field
-  UNION SELECT 'patch',   bug_field_id FROM savane_old.patch_field
-  UNION SELECT 'support', bug_field_id FROM savane_old.patch_field
-  UNION SELECT 'task',    bug_field_id FROM savane_old.patch_field;
-
--- id <- conv_field_ids.new  (duplicates in savane_old.*_field tables)
--- name <- field_name
--- tracker_id <- 'bugs'
-TRUNCATE tracker_field;
-INSERT INTO tracker_field
-    (id, tracker_id, name, display_type, display_size, label,
-     description, scope, required, empty_ok, keep_history, special, custom)
-  SELECT
-      conv_field_ids.new, 'bugs', field_name, display_type, display_size, label,
-      description, scope, required, empty_ok, keep_history, special, custom
-    FROM savane_old.bugs_field JOIN conv_field_ids
-      ON (bug_field_id = old AND tracker_id = 'bugs');
-INSERT INTO tracker_field
-    (id, tracker_id, name, display_type, display_size, label,
-     description, scope, required, empty_ok, keep_history, special, custom)
-  SELECT
-      conv_field_ids.new, 'patch', field_name, display_type, display_size, label,
-      description, scope, required, empty_ok, keep_history, special, custom
-    FROM savane_old.patch_field JOIN conv_field_ids
-      ON (bug_field_id = old AND tracker_id = 'patch');
+UPDATE tracker_item SET assigned_to_id=NULL WHERE assigned_to_id=100;
+UPDATE tracker_item SET submitted_by_id=NULL WHERE submitted_by_id=100;
 
 -- Get rid of duplicates (old mysql/php/savane bug?)
 -- It only affected group_id=100, maybe the installation was done
 -- twice or something.
 -- Give priority to the last one.
 -- Need to create a real table - a temporary one has issues with being "reopened" in joins
+DROP TABLE IF EXISTS temp_bugs_field_usage;
 CREATE TABLE temp_bugs_field_usage AS SELECT * FROM savane_old.bugs_field_usage;
 ALTER TABLE temp_bugs_field_usage ADD (id INT auto_increment PRIMARY KEY);
 DELETE FROM temp_bugs_field_usage
@@ -587,20 +554,23 @@
     );
 -- id <- <auto>
 -- field_id <- bug_field_id
-TRUNCATE tracker_fieldusage;
-INSERT INTO tracker_fieldusage
-    (field_id, group_id, use_it, show_on_add, show_on_add_members, place,
-     custom_label, custom_description, custom_display_size, custom_empty_ok,
-     custom_keep_history, transition_default_auth)
+-- Don't import default values, they are now defined statically in
+-- tracker.defs.
+TRUNCATE tracker_fieldoverlay;
+INSERT INTO tracker_fieldoverlay
+    (group_id, field_name, use_it, show_on_add_anonymous, show_on_add_connected, show_on_add_members, rank,
+     label, description, display_size, empty_ok,
+     keep_history, transition_default_auth)
   SELECT
-      conv_field_ids.new, group_id, use_it, show_on_add, show_on_add_members, place,
+      group_id, field_name, use_it, IF(show_on_add<2,0,1), IF(show_on_add%2=0,0,1), show_on_add_members, place,
       custom_label, custom_description, custom_display_size, custom_empty_ok,
       IFNULL(custom_keep_history, 0), transition_default_auth
-   FROM temp_bugs_field_usage JOIN conv_field_ids
-      ON (bug_field_id = old AND tracker_id = 'bugs');
+    FROM temp_bugs_field_usage JOIN savane_old.bugs_field
+        USING (bug_field_id)
+      WHERE group_id != 100;
 DROP TABLE temp_bugs_field_usage;
 -- Specify "default" differently
-UPDATE tracker_fieldusage SET group_id=NULL WHERE group_id=100;
+-- UPDATE tracker_fieldoverlay SET group_id=NULL WHERE group_id=100;
 
 -- Get rid of duplicates (old mysql/php/savane bug?)
 -- Apparently this affects 'None' values.
@@ -613,17 +583,17 @@
         WHERE A.bug_fv_id > B.bug_fv_id
           AND A.bug_field_id = B.bug_field_id AND A.group_id = B.group_id AND A.value_id = B.value_id
       ) AS temp
-    );
+  );
 -- id <- <auto>
 -- field_id <- bug_field_id
 TRUNCATE tracker_fieldvalue;
 INSERT INTO tracker_fieldvalue
-    (field_id, group_id, value_id, `value`, description,
+    (group_id, field_name, value_id, `value`, description,
      order_id, status, email_ad, send_all_flag)
   SELECT
-     conv_field_ids.new, group_id, value_id, `value`, description,
+     group_id, field_name, value_id, `value`, savane_old.bugs_field_value.description,
      order_id, status, email_ad, send_all_flag
-   FROM savane_old.bugs_field_value JOIN conv_field_ids
-      ON (bug_field_id = old AND tracker_id = 'bugs');
+   FROM savane_old.bugs_field_value JOIN savane_old.bugs_field
+      USING (bug_field_id);
 -- Specify "default" differently
 UPDATE tracker_fieldvalue SET group_id=NULL WHERE group_id=100;
--- a/savane/tracker/admin.py
+++ b/savane/tracker/admin.py
@@ -24,26 +24,13 @@
 #class TrackerAdmin(admin.ModelAdmin):
 #    list_display  = ('name',)
 
-class FieldUsageInline(admin.TabularInline):
-    model = FieldUsage
-    raw_id_fields = ('group',)
-class FieldAdmin(admin.ModelAdmin):
-    search_fields = ('name', 'label', 'description', )
-    ordering = ('tracker', 'name', )
-    list_display  = ('id', 'tracker', 'scope', 'name', 'label', 'display_type', 'display_size',
-                     'required', 'empty_ok', 'keep_history', 'special', 'custom', )
-    list_display_links = ('id', 'name', 'label')
-    list_filter = ('tracker', 'display_type', 'scope',
-                   'required', 'empty_ok', 'keep_history', 'special', 'custom', )
-    inlines = ( FieldUsageInline, )
-
-class FieldUsageAdmin(admin.ModelAdmin):
-    search_fields = ('group', 'custom_label', 'custom_description', )
-    ordering = ('group', 'field',)
-    list_display  = ('id', 'group', 'field', 'use_it', 'place', )
+class FieldOverlayAdmin(admin.ModelAdmin):
+    search_fields = ('group', 'label', 'description', )
+    ordering = ('group', 'field_name',)
+    list_display  = ('id', 'group', 'field_name', 'use_it', 'rank', )
     list_display_links = ('id',)
-    list_filter = ('use_it', 'show_on_add', 'show_on_add_members', 'custom_empty_ok', 'custom_keep_history',)
+    list_filter = ('use_it', 'show_on_add_anonymous', 'show_on_add_connected', 'show_on_add_members',
+                   'empty_ok', 'keep_history',)
     raw_id_fields = ('group',)
 
-admin.site.register(Field, FieldAdmin)
-admin.site.register(FieldUsage, FieldUsageAdmin)
+admin.site.register(FieldOverlay, FieldOverlayAdmin)
--- a/savane/tracker/defs.py
+++ b/savane/tracker/defs.py
@@ -16,6 +16,53 @@
 # You should have received a copy of the GNU Affero General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
+"""
+The Field definition cannot be changed, so it's been made static
+instead of stored in the database.
+
+Here's the previous model definition.  See also FieldUsage, which is
+still used for non-default (i.e. override) values.
+
+    class Meta:
+        unique_together = (('tracker', 'name'),)
+        verbose_name = _("field")
+        verbose_name_plural = _("fields")
+
+    DISPLAY_TYPE_CHOICES = (('DF', _('date field')),
+                            ('SB', _('select box')),
+                            ('TA', _('text area')),
+                            ('TF', _('text field')),)
+    SCOPE_CHOICES = (('S', _('system')), # user cannot modify related FieldValue's (TF)
+                     ('P', _('project')),)  # user can modify related FieldValue's (TF)
+
+    tracker = models.ForeignKey('Tracker')
+    name = models.CharField(max_length=255, db_index=True)
+    display_type = models.CharField(max_length=255, choices=DISPLAY_TYPE_CHOICES)
+    display_size = models.CharField(max_length=255)
+      # DF: unused
+      # SB: unused
+      # TA: cols/rows
+      # TF: visible_length/max_length
+    label  = models.CharField(max_length=255)
+    description = models.TextField()
+
+    # Field values can be changed (if TF)
+    scope = models.CharField(max_length=1, choices=SCOPE_CHOICES)
+    # Field cannot be hidden (but can be made optional)
+    required = models.BooleanField(help_text=_("field cannot be disabled in configuration"))
+    # Default value (fields can always override this except for 'summary' and 'details', cf. 'special')
+    empty_ok = models.CharField(max_length=1, choices=EMPTY_OK_CHOICES,
+                                default='0')
+    # Default value
+    keep_history = models.BooleanField()
+    # Field cannot be made optional (displayed unless 'bug_id' and 'group_id')
+    # Also, field are not displayed (filled by the system) - except for 'summary', 'comment_type' and 'details'
+    # (consequently, they cannot be customized in any way, except for 'summary' and 'details' where you can only customize the display size)
+    special = models.BooleanField()
+    # Field may change label and description
+    custom = models.BooleanField(help_text=_("let the user change the label and description"))
+"""
+
 from django.utils.translation import ugettext, ugettext_lazy as _
 
 fields = {}
@@ -34,7 +81,8 @@
         'special': 1,
         'custom': 0,
         'use_it': 1,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 10,
         'transition_default_auth': 'A',
@@ -52,7 +100,8 @@
         'special': 1,
         'custom': 0,
         'use_it': 1,
-        'show_on_add': 1,
+        'show_on_add_connected': 1,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 1,
         'place': 30,
         'transition_default_auth': 'A',
@@ -70,7 +119,8 @@
         'special': 1,
         'custom': 0,
         'use_it': 1,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 20,
         'transition_default_auth': 'A',
@@ -88,7 +138,8 @@
         'special': 1,
         'custom': 0,
         'use_it': 1,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 40,
         'transition_default_auth': 'A',
@@ -106,7 +157,8 @@
         'special': 1,
         'custom': 0,
         'use_it': 1,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 50,
         'transition_default_auth': 'A',
@@ -124,7 +176,8 @@
         'special': 0,
         'custom': 0,
         'use_it': 1,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 600,
         'transition_default_auth': 'A',
@@ -142,7 +195,8 @@
         'special': 0,
         'custom': 0,
         'use_it': 1,
-        'show_on_add': 1,
+        'show_on_add_connected': 1,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 1,
         'place': 200,
         'transition_default_auth': 'A',
@@ -160,7 +214,8 @@
         'special': 0,
         'custom': 0,
         'use_it': 1,
-        'show_on_add': 1,
+        'show_on_add_connected': 1,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 1,
         'place': 100,
         'transition_default_auth': 'A',
@@ -178,7 +233,8 @@
         'special': 0,
         'custom': 0,
         'use_it': 1,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 1,
         'place': 500,
         'transition_default_auth': 'A',
@@ -196,7 +252,8 @@
         'special': 1,
         'custom': 0,
         'use_it': 1,
-        'show_on_add': 1,
+        'show_on_add_connected': 1,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 1,
         'place': 700000,
         'transition_default_auth': 'A',
@@ -214,7 +271,8 @@
         'special': 1,
         'custom': 0,
         'use_it': 1,
-        'show_on_add': 1,
+        'show_on_add_connected': 1,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 1,
         'place': 700001,
         'transition_default_auth': 'A',
@@ -232,7 +290,8 @@
         'special': 0,
         'custom': 0,
         'use_it': 0,
-        'show_on_add': 1,
+        'show_on_add_connected': 1,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 1,
         'place': 300,
         'transition_default_auth': 'A',
@@ -250,7 +309,8 @@
         'special': 0,
         'custom': 0,
         'use_it': 1,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 1,
         'place': 400,
         'transition_default_auth': 'A',
@@ -268,7 +328,8 @@
         'special': 0,
         'custom': 0,
         'use_it': 1,
-        'show_on_add': 1,
+        'show_on_add_connected': 1,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 1,
         'place': 402,
         'transition_default_auth': 'A',
@@ -286,7 +347,8 @@
         'special': 1,
         'custom': 0,
         'use_it': 1,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 405,
         'transition_default_auth': 'A',
@@ -304,7 +366,8 @@
         'special': 0,
         'custom': 0,
         'use_it': 0,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 1000,
         'transition_default_auth': 'A',
@@ -322,7 +385,8 @@
         'special': 0,
         'custom': 0,
         'use_it': 0,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 1100,
         'transition_default_auth': 'A',
@@ -340,7 +404,8 @@
         'special': 0,
         'custom': 0,
         'use_it': 0,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 1200,
         'transition_default_auth': 'A',
@@ -358,7 +423,8 @@
         'special': 0,
         'custom': 0,
         'use_it': 0,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 1300,
         'transition_default_auth': 'A',
@@ -376,7 +442,8 @@
         'special': 0,
         'custom': 0,
         'use_it': 0,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 1400,
         'transition_default_auth': 'A',
@@ -394,7 +461,8 @@
         'special': 1,
         'custom': 0,
         'use_it': 1,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 1500,
         'transition_default_auth': 'A',
@@ -412,7 +480,8 @@
         'special': 0,
         'custom': 0,
         'use_it': 0,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 1700,
         'transition_default_auth': 'A',
@@ -430,7 +499,8 @@
         'special': 0,
         'custom': 0,
         'use_it': 0,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 1600,
         'transition_default_auth': 'A',
@@ -448,7 +518,8 @@
         'special': 0,
         'custom': 0,
         'use_it': 0,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 1800,
         'transition_default_auth': 'A',
@@ -466,7 +537,8 @@
         'special': 0,
         'custom': 0,
         'use_it': 0,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 1900,
         'transition_default_auth': 'A',
@@ -484,7 +556,8 @@
         'special': 0,
         'custom': 0,
         'use_it': 0,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 2000,
         'transition_default_auth': 'A',
@@ -502,7 +575,8 @@
         'special': 0,
         'custom': 0,
         'use_it': 1,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 1,
         'place': 200,
         'transition_default_auth': 'A',
@@ -520,7 +594,8 @@
         'special': 0,
         'custom': 0,
         'use_it': 0,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 3000,
         'transition_default_auth': 'A',
@@ -538,7 +613,8 @@
         'special': 0,
         'custom': 0,
         'use_it': 0,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 800,
         'transition_default_auth': 'A',
@@ -556,7 +632,8 @@
         'special': 0,
         'custom': 0,
         'use_it': 0,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 800,
         'transition_default_auth': 'A',
@@ -574,7 +651,8 @@
         'special': 0,
         'custom': 0,
         'use_it': 0,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 550,
         'transition_default_auth': 'A',
@@ -592,7 +670,8 @@
         'special': 0,
         'custom': 0,
         'use_it': 1,
-        'show_on_add': 2,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 1,
         'show_on_add_members': 0,
         'place': 560,
         'transition_default_auth': 'A',
@@ -610,7 +689,8 @@
         'special': 0,
         'custom': 0,
         'use_it': 0,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 570,
         'transition_default_auth': 'A',
@@ -628,7 +708,8 @@
         'special': 0,
         'custom': 0,
         'use_it': 0,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 500,
         'transition_default_auth': 'A',
@@ -646,7 +727,8 @@
         'special': 0,
         'custom': 1,
         'use_it': 0,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 30000,
         'transition_default_auth': 'A',
@@ -664,7 +746,8 @@
         'special': 0,
         'custom': 1,
         'use_it': 0,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 30100,
         'transition_default_auth': 'A',
@@ -682,7 +765,8 @@
         'special': 0,
         'custom': 1,
         'use_it': 0,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 30200,
         'transition_default_auth': 'A',
@@ -700,7 +784,8 @@
         'special': 0,
         'custom': 1,
         'use_it': 0,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 30300,
         'transition_default_auth': 'A',
@@ -718,7 +803,8 @@
         'special': 0,
         'custom': 1,
         'use_it': 0,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 30400,
         'transition_default_auth': 'A',
@@ -736,7 +822,8 @@
         'special': 0,
         'custom': 1,
         'use_it': 0,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 30500,
         'transition_default_auth': 'A',
@@ -754,7 +841,8 @@
         'special': 0,
         'custom': 1,
         'use_it': 0,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 30600,
         'transition_default_auth': 'A',
@@ -772,7 +860,8 @@
         'special': 0,
         'custom': 1,
         'use_it': 0,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 30700,
         'transition_default_auth': 'A',
@@ -790,7 +879,8 @@
         'special': 0,
         'custom': 1,
         'use_it': 0,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 30800,
         'transition_default_auth': 'A',
@@ -808,7 +898,8 @@
         'special': 0,
         'custom': 1,
         'use_it': 0,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 30900,
         'transition_default_auth': 'A',
@@ -826,7 +917,8 @@
         'special': 0,
         'custom': 1,
         'use_it': 0,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 40000,
         'transition_default_auth': 'A',
@@ -844,7 +936,8 @@
         'special': 0,
         'custom': 1,
         'use_it': 0,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 40100,
         'transition_default_auth': 'A',
@@ -862,7 +955,8 @@
         'special': 0,
         'custom': 1,
         'use_it': 0,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 40200,
         'transition_default_auth': 'A',
@@ -880,7 +974,8 @@
         'special': 0,
         'custom': 1,
         'use_it': 0,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 40300,
         'transition_default_auth': 'A',
@@ -898,7 +993,8 @@
         'special': 0,
         'custom': 1,
         'use_it': 0,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 40400,
         'transition_default_auth': 'A',
@@ -916,7 +1012,8 @@
         'special': 0,
         'custom': 1,
         'use_it': 0,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 40500,
         'transition_default_auth': 'A',
@@ -934,7 +1031,8 @@
         'special': 0,
         'custom': 1,
         'use_it': 0,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 40600,
         'transition_default_auth': 'A',
@@ -952,7 +1050,8 @@
         'special': 0,
         'custom': 1,
         'use_it': 0,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 40700,
         'transition_default_auth': 'A',
@@ -970,7 +1069,8 @@
         'special': 0,
         'custom': 1,
         'use_it': 0,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 40800,
         'transition_default_auth': 'A',
@@ -988,7 +1088,8 @@
         'special': 0,
         'custom': 1,
         'use_it': 0,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 40900,
         'transition_default_auth': 'A',
@@ -1006,7 +1107,8 @@
         'special': 0,
         'custom': 1,
         'use_it': 0,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 50000,
         'transition_default_auth': 'A',
@@ -1024,7 +1126,8 @@
         'special': 0,
         'custom': 1,
         'use_it': 0,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 50100,
         'transition_default_auth': 'A',
@@ -1042,7 +1145,8 @@
         'special': 0,
         'custom': 1,
         'use_it': 0,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 50200,
         'transition_default_auth': 'A',
@@ -1060,7 +1164,8 @@
         'special': 0,
         'custom': 1,
         'use_it': 0,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 50300,
         'transition_default_auth': 'A',
@@ -1078,7 +1183,8 @@
         'special': 0,
         'custom': 1,
         'use_it': 0,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 50400,
         'transition_default_auth': 'A',
@@ -1096,7 +1202,8 @@
         'special': 0,
         'custom': 1,
         'use_it': 0,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 50500,
         'transition_default_auth': 'A',
@@ -1114,7 +1221,8 @@
         'special': 0,
         'custom': 1,
         'use_it': 0,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 50600,
         'transition_default_auth': 'A',
@@ -1132,7 +1240,8 @@
         'special': 0,
         'custom': 1,
         'use_it': 0,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 50700,
         'transition_default_auth': 'A',
@@ -1150,7 +1259,8 @@
         'special': 0,
         'custom': 1,
         'use_it': 0,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 50800,
         'transition_default_auth': 'A',
@@ -1168,7 +1278,8 @@
         'special': 0,
         'custom': 1,
         'use_it': 0,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 50900,
         'transition_default_auth': 'A',
@@ -1186,7 +1297,8 @@
         'special': 0,
         'custom': 1,
         'use_it': 0,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 60000,
         'transition_default_auth': 'A',
@@ -1204,7 +1316,8 @@
         'special': 0,
         'custom': 1,
         'use_it': 0,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 60100,
         'transition_default_auth': 'A',
@@ -1222,7 +1335,8 @@
         'special': 0,
         'custom': 1,
         'use_it': 0,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 60200,
         'transition_default_auth': 'A',
@@ -1240,7 +1354,8 @@
         'special': 0,
         'custom': 1,
         'use_it': 0,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 60300,
         'transition_default_auth': 'A',
@@ -1258,7 +1373,8 @@
         'special': 0,
         'custom': 1,
         'use_it': 0,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 60400,
         'transition_default_auth': 'A',
@@ -1276,7 +1392,8 @@
         'special': 0,
         'custom': 0,
         'use_it': 1,
-        'show_on_add': 0,
+        'show_on_add_connected': 0,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 0,
         'place': 800,
         'transition_default_auth': 'A',
@@ -1294,7 +1411,8 @@
         'special': 0,
         'custom': 0,
         'use_it': 1,
-        'show_on_add': 1,
+        'show_on_add_connected': 1,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 1,
         'place': 56,
         'transition_default_auth': 'A',
@@ -1312,7 +1430,8 @@
         'special': 0,
         'custom': 0,
         'use_it': 1,
-        'show_on_add': 1,
+        'show_on_add_connected': 1,
+        'show_on_add_anonymous': 0,
         'show_on_add_members': 1,
         'place': 55,
         'transition_default_auth': 'A',
--- a/savane/tracker/models.py
+++ b/savane/tracker/models.py
@@ -137,89 +137,37 @@
 
 #class SquadPermission(models.Model): pass
 
-
-class Field(models.Model):
-    """
-    """
-    class Meta:
-        unique_together = (('tracker', 'name'),)
-        verbose_name = _("field")
-        verbose_name_plural = _("fields")
-
-    DISPLAY_TYPE_CHOICES = (('DF', _('date field')),
-                            ('SB', _('select box')),
-                            ('TA', _('text area')),
-                            ('TF', _('text field')),)
-    SCOPE_CHOICES = (('S', _('system')), # user cannot modify related FieldValue's (TF)
-                     ('P', _('project')),)  # user can modify related FieldValue's (TF)
-    EMPTY_OK_CHOICES = (('0', _('mandatory only if it was presented to the original submitter')),
-                        ('1', _('optional (empty values are accepted)')),
-                        ('3', _('mandatory')),)
-
-    tracker = models.ForeignKey('Tracker')
-    name = models.CharField(max_length=255, db_index=True)
-    display_type = models.CharField(max_length=255, choices=DISPLAY_TYPE_CHOICES)
-    display_size = models.CharField(max_length=255)
-      # DF: unused
-      # SB: unused
-      # TA: cols/rows
-      # TF: visible_length/max_length
-    label  = models.CharField(max_length=255)
-    description = models.TextField()
-
-    # Field values can be changed (if TF)
-    scope = models.CharField(max_length=1, choices=SCOPE_CHOICES)
-    # Field cannot be hidden (but can be made optional)
-    required = models.BooleanField(help_text=_("field cannot be disabled in configuration"))
-    # Default value (fields can always override this except for 'summary' and 'details', cf. 'special')
-    empty_ok = models.CharField(max_length=1, choices=EMPTY_OK_CHOICES,
-                                default='0')
-    # Default value
-    keep_history = models.BooleanField()
-    # Field cannot be made optional (displayed unless 'bug_id' and 'group_id')
-    # Also, field are not displayed (filled by the system) - except for 'summary', 'comment_type' and 'details'
-    # (consequently, they cannot be customized in any way, except for 'summary' and 'details' where you can only customize the display size)
-    special = models.BooleanField()
-    # Field may change label and description
-    custom = models.BooleanField(help_text=_("let the user change the label and description"))
-
-    def __unicode__(self):
-        return "%s.%s" % (self.tracker_id, self.name)
-
 class FieldOverlay(models.Model):
     """
     Per-group tracker item definition override
     """
     class Meta:
-        unique_together = (('field', 'group'),)
+        unique_together = (('group', 'field_name'),)
         verbose_name = _("field usage")
         verbose_name_plural = _("field usages")
 
+    EMPTY_OK_CHOICES = (('0', _('mandatory only if it was presented to the original submitter')),
+                        ('1', _('optional (empty values are accepted)')),
+                        ('3', _('mandatory')),)
     TRANSITION_DEFAULT_AUTH_CHOICES = (('', _('undefined')),
                                        ('A', _('allowed')),
                                        ('F', _('forbidden')),)
-    SHOW_ON_ADD_CHOICES = (('0', _('no')),
-                           ('1', _('show to logged in users')),
-                           ('2', _('show to anonymous users')),
-                           ('3', _('show to both logged in and anonymous users')),)
-    field = models.ForeignKey('Field')
-    group = models.ForeignKey(auth_models.Group, blank=True, null=True, help_text=_("NULL == default"))
+    group = models.ForeignKey(auth_models.Group)
+    field_name = models.CharField(max_length=32)
 
     # If not Field.required:
     use_it = models.BooleanField(_("used"))
-    show_on_add = models.CharField(max_length=1, choices=SHOW_ON_ADD_CHOICES,
-                                   default='0', blank=True, null=True)
-      # new:
-      # show_on_add_logged_in = models.BooleanField("show to logged in users")
-      # show_on_add_anonymous = models.BooleanField("show to anonymous users")
-    show_on_add_members = models.BooleanField(_("show to project members"))
+    # When posting a new item:
+    show_on_add_anonymous = models.NullBooleanField(_("show to anonymous users"), blank=True, null=True)
+    show_on_add_connected = models.NullBooleanField(_("show to connected users"), blank=True, null=True)
+    show_on_add_members   = models.NullBooleanField(_("show to project members"), blank=True, null=True)
 
     # Can always be changed (expect for special 'summary' and 'details')
-    custom_empty_ok = models.CharField(max_length=1, choices=Field.EMPTY_OK_CHOICES,
+    empty_ok = models.CharField(max_length=1, choices=EMPTY_OK_CHOICES,
                                        default='0', blank=True, null=True)
 
     # Can always be changed
-    place = models.IntegerField(help_text=_("display rank")) # new:rank
+    rank = models.IntegerField(help_text=_("display rank"))
 
     # Specific to SB
     # Can always be changed
@@ -227,29 +175,29 @@
 
     # Specific to TA and TF
     # Works for both custom and non-custom fields
-    custom_display_size = models.CharField(max_length=255, blank=True, null=True)
+    display_size = models.CharField(max_length=255, blank=True, null=True)
       # The default value is in Field.display_size
       #   rather than FieldUsage(group_id=100).custom_display_size
     # If !Field.special
-    custom_keep_history = models.BooleanField(_("keep field value changes in history"))
+    keep_history = models.BooleanField(_("keep field value changes in history"))
 
     # If Field.custom
     # Specific (bad!) fields for custom fields (if Field.custom is True):
-    custom_label = models.CharField(max_length=255, blank=True, null=True)
-    custom_description = models.CharField(max_length=255, blank=True, null=True)
+    label = models.CharField(max_length=255, blank=True, null=True)
+    description = models.CharField(max_length=255, blank=True, null=True)
 
 class FieldValue(models.Model):
     """
     Per-group tracker select box values override
     """
     class Meta:
-        unique_together = (('field', 'group', 'value_id'),)
+        unique_together = (('group', 'field_name', 'value_id'),)
 
     STATUS_CHOICES = (('A', _('active')),
                       ('H', _('hidden')), # mask previously-active or system fields
                       ('P', _('permanent')),) # status cannot be modified, always visible
-    field = models.ForeignKey('Field')
-    group = models.ForeignKey(auth_models.Group, blank=True, null=True, help_text=_("NULL == default"))
+    group = models.ForeignKey(auth_models.Group)
+    field_name = models.CharField(max_length=32)
     value_id = models.IntegerField(db_index=True) # group_specific value identifier
       # It's not a duplicate of 'id', as it's the value referenced by
       # Item fields, and the configuration of that value can be
@@ -299,7 +247,7 @@
     group = models.ForeignKey(auth_models.Group)
     spamscore = models.IntegerField(default=0)
     ip = models.IPAddressField(blank=True, null=True)
-    submitted_by = models.ForeignKey(auth_models.User, blank=True, null=True)
+    submitted_by = models.ForeignKey(auth_models.User, blank=True, null=True, related_name='items_submitted')
     date = models.DateTimeField(default=datetime.date.today)
     close_date = models.DateTimeField(blank=True, null=True)
 
@@ -329,7 +277,7 @@
     discussion_lock = models.IntegerField(default=0)
     vote = models.IntegerField(default=0)
     category_id = models.IntegerField(default=100)
-    assigned_to = models.IntegerField(blank=True, null=True)
+    assigned_to = models.ForeignKey(auth_models.User, related_name='items_assigned', blank=True, null=True)
 
     # - other fields
     status_id = models.IntegerField(default=100, verbose_name=_("open/closed"))