[damned-lies] Add stats for uploaded (merged) files
- From: Claude Paroz <claudep src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [damned-lies] Add stats for uploaded (merged) files
- Date: Sat, 6 Aug 2011 16:57:30 +0000 (UTC)
commit 9bb95310a60187b55a2a8d38e76e9d289e72999d
Author: Claude Paroz <claude 2xlibre net>
Date: Sat Aug 6 18:55:19 2011 +0200
Add stats for uploaded (merged) files
people/tests/__init__.py | 1 -
stats/models.py | 13 ++
stats/templatetags/stats_extras.py | 8 +
stats/tests/__init__.py | 3 +
teams/tests.py | 2 +-
templates/vertimus/vertimus_detail.html | 5 +-
vertimus/migrations/0002_add_merged_file.py | 184 ++++++++++++++++++++++
vertimus/migrations/0003_populate_merged_file.py | 181 +++++++++++++++++++++
vertimus/models.py | 58 +++----
vertimus/tests/__init__.py | 36 +++--
vertimus/views.py | 9 +-
11 files changed, 443 insertions(+), 57 deletions(-)
---
diff --git a/people/tests/__init__.py b/people/tests/__init__.py
index b11b560..797a4d8 100644
--- a/people/tests/__init__.py
+++ b/people/tests/__init__.py
@@ -93,6 +93,5 @@ class PeopleTestCase(TestCase):
# Test only p5 should be deleted
self.assertEqual(Person.objects.all().count(), 5)
Person.clean_obsolete_accounts()
- import pdb; pdb.set_trace()
self.assertEqual(Person.objects.all().count(), 4)
self.assertEqual(set(Person.objects.all()), set([p1, p2, p3, p4]))
diff --git a/stats/models.py b/stats/models.py
index 77656f0..9838d9f 100644
--- a/stats/models.py
+++ b/stats/models.py
@@ -1205,6 +1205,12 @@ class PoFile(models.Model):
def __unicode__(self):
return "%s (%s/%s/%s)" % (self.path, self.translated, self.fuzzy, self.untranslated)
+ def url(self):
+ return utils.url_join(settings.MEDIA_URL, settings.UPLOAD_DIR, os.path.basename(self.path))
+
+ def filename(self):
+ return os.path.basename(self.path)
+
def pot_size(self):
return self.translated + self.fuzzy + self.untranslated
@@ -1230,6 +1236,13 @@ class PoFile(models.Model):
else:
return int(100*self.untranslated/self.pot_size())
+ def update_stats(self):
+ stats = utils.po_file_stats(self.path, msgfmt_checks=False)
+ self.translated = stats['translated']
+ self.fuzzy = stats['fuzzy']
+ self.untranslated = stats['untranslated']
+ self.save()
+
class Statistics(models.Model):
branch = models.ForeignKey(Branch)
diff --git a/stats/templatetags/stats_extras.py b/stats/templatetags/stats_extras.py
index 1612a02..07fad51 100644
--- a/stats/templatetags/stats_extras.py
+++ b/stats/templatetags/stats_extras.py
@@ -45,6 +45,14 @@ def num_stats(stat, scope='full'):
'fuzzy': stat.fuzzy(scope),
'untranslated': stat.untranslated(scope),
}
+ elif isinstance(stat, PoFile):
+ stats = {
+ 'translated': stat.translated,
+ 'fuzzy': stat.fuzzy,
+ 'untranslated': stat.untranslated,
+ }
+ if scope != 'short':
+ stats['prc'] = stat.tr_percentage()
else:
stats = stat
if 'prc' in stats:
diff --git a/stats/tests/__init__.py b/stats/tests/__init__.py
index 7a74096..abefe5d 100644
--- a/stats/tests/__init__.py
+++ b/stats/tests/__init__.py
@@ -37,9 +37,12 @@ def test_scratchdir(test_func):
""" Decorator to temporarily use the scratchdir inside the test directory """
def decorator(self):
old_SCRATCHDIR = settings.SCRATCHDIR
+ old_POTDIR = settings.POTDIR
settings.SCRATCHDIR = os.path.dirname(os.path.abspath(__file__))
+ settings.POTDIR = os.path.join(settings.SCRATCHDIR, "POT")
test_func(self)
settings.SCRATCHDIR = old_SCRATCHDIR
+ settings.POTDIR = old_POTDIR
return decorator
diff --git a/teams/tests.py b/teams/tests.py
index 21d029d..da4ce2e 100644
--- a/teams/tests.py
+++ b/teams/tests.py
@@ -203,7 +203,7 @@ class RoleTest(TeamsAndRolesTests):
self.assertTrue(self.role.is_active)
self.assertTrue(self.role2.is_active)
self.assertTrue(self.role_limit_date.is_active)
- self.assertTrue(self.role_inactive.is_active)
+ self.assertTrue(self.role_inactive.is_active)
Role.inactivate_unused_roles()
diff --git a/templates/vertimus/vertimus_detail.html b/templates/vertimus/vertimus_detail.html
index 025176d..c315e79 100644
--- a/templates/vertimus/vertimus_detail.html
+++ b/templates/vertimus/vertimus_detail.html
@@ -154,9 +154,8 @@ $(document).ready(function() {
{% if action.has_po_file %}
{% if action.merged_file.url %}
<a href="{{ action.merged_file.url }}">
- <img src="{{ MEDIA_URL }}img/download.png"/> {{ action.merged_file.filename }}
- </a>
- <br/>
+ <img src="{{ MEDIA_URL }}img/download.png"/> {{ action.merged_file.filename }}</a>
+ {{ action.merged_file|num_stats:'short' }}<br/>
{% endif %}
<div class="right_actions">{% trans "diff with:" %}
{% for f in files %}
diff --git a/vertimus/migrations/0002_add_merged_file.py b/vertimus/migrations/0002_add_merged_file.py
new file mode 100644
index 0000000..97fa059
--- /dev/null
+++ b/vertimus/migrations/0002_add_merged_file.py
@@ -0,0 +1,184 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Adding field 'ActionArchived.merged_file'
+ db.add_column('action_archived', 'merged_file', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['stats.PoFile'], unique=True, null=True), keep_default=False)
+
+ # Adding field 'Action.merged_file'
+ db.add_column('action', 'merged_file', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['stats.PoFile'], unique=True, null=True), keep_default=False)
+
+
+ def backwards(self, orm):
+
+ # Deleting field 'ActionArchived.merged_file'
+ db.delete_column('action_archived', 'merged_file_id')
+
+ # Deleting field 'Action.merged_file'
+ db.delete_column('action', 'merged_file_id')
+
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'languages.language': {
+ 'Meta': {'ordering': "('name',)", 'object_name': 'Language', 'db_table': "'language'"},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'locale': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '15'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '50'}),
+ 'plurals': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}),
+ 'team': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['teams.Team']", 'null': 'True', 'blank': 'True'})
+ },
+ 'people.person': {
+ 'Meta': {'ordering': "('username',)", 'object_name': 'Person', 'db_table': "'person'", '_ormbases': ['auth.User']},
+ 'activation_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'bugzilla_account': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'image': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'irc_nick': ('django.db.models.fields.SlugField', [], {'db_index': 'True', 'max_length': '20', 'null': 'True', 'blank': 'True'}),
+ 'svn_account': ('django.db.models.fields.SlugField', [], {'db_index': 'True', 'max_length': '20', 'null': 'True', 'blank': 'True'}),
+ 'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}),
+ 'webpage_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'})
+ },
+ 'stats.branch': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('name', 'module'),)", 'object_name': 'Branch', 'db_table': "'branch'"},
+ 'file_hashes': ('common.fields.DictionaryField', [], {'default': "''", 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'module': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['stats.Module']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'vcs_subpath': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'weight': ('django.db.models.fields.IntegerField', [], {'default': '0'})
+ },
+ 'stats.domain': {
+ 'Meta': {'ordering': "('-dtype', 'name')", 'object_name': 'Domain', 'db_table': "'domain'"},
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'directory': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'dtype': ('django.db.models.fields.CharField', [], {'default': "'ui'", 'max_length': '5'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'linguas_location': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'module': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['stats.Module']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'pot_method': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'red_filter': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'stats.module': {
+ 'Meta': {'ordering': "('name',)", 'object_name': 'Module', 'db_table': "'module'"},
+ 'bugs_base': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'bugs_component': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'bugs_product': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'ext_platform': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'homepage': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'maintainers': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'maintains_modules'", 'blank': 'True', 'db_table': "'module_maintainer'", 'to': "orm['people.Person']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'vcs_root': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+ 'vcs_type': ('django.db.models.fields.CharField', [], {'max_length': '5'}),
+ 'vcs_web': ('django.db.models.fields.URLField', [], {'max_length': '200'})
+ },
+ 'stats.pofile': {
+ 'Meta': {'object_name': 'PoFile', 'db_table': "'pofile'"},
+ 'figures': ('common.fields.JSONField', [], {'null': 'True', 'blank': 'True'}),
+ 'fuzzy': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'translated': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'untranslated': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'})
+ },
+ 'teams.role': {
+ 'Meta': {'unique_together': "(('team', 'person'),)", 'object_name': 'Role', 'db_table': "'role'"},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['people.Person']"}),
+ 'role': ('django.db.models.fields.CharField', [], {'default': "'translator'", 'max_length': '15'}),
+ 'team': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['teams.Team']"})
+ },
+ 'teams.team': {
+ 'Meta': {'ordering': "('description',)", 'object_name': 'Team', 'db_table': "'team'"},
+ 'description': ('django.db.models.fields.TextField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mailing_list': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'mailing_list_subscribe': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'members': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'teams'", 'symmetrical': 'False', 'through': "orm['teams.Role']", 'to': "orm['people.Person']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '80'}),
+ 'presentation': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'use_workflow': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'webpage_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'})
+ },
+ 'vertimus.action': {
+ 'Meta': {'object_name': 'Action', 'db_table': "'action'"},
+ 'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'created': ('django.db.models.fields.DateTimeField', [], {}),
+ 'file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'merged_file': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['stats.PoFile']", 'unique': 'True', 'null': 'True'}),
+ 'name': ('django.db.models.fields.SlugField', [], {'max_length': '8', 'db_index': 'True'}),
+ 'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['people.Person']"}),
+ 'state_db': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['vertimus.State']"})
+ },
+ 'vertimus.actionarchived': {
+ 'Meta': {'object_name': 'ActionArchived', 'db_table': "'action_archived'"},
+ 'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'created': ('django.db.models.fields.DateTimeField', [], {}),
+ 'file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'merged_file': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['stats.PoFile']", 'unique': 'True', 'null': 'True'}),
+ 'name': ('django.db.models.fields.SlugField', [], {'max_length': '8', 'db_index': 'True'}),
+ 'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['people.Person']"}),
+ 'sequence': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
+ 'state_db': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['vertimus.State']"})
+ },
+ 'vertimus.state': {
+ 'Meta': {'unique_together': "(('branch', 'domain', 'language'),)", 'object_name': 'State', 'db_table': "'state'"},
+ 'branch': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['stats.Branch']"}),
+ 'domain': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['stats.Domain']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'language': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['languages.Language']"}),
+ 'name': ('django.db.models.fields.SlugField', [], {'default': "'None'", 'max_length': '20', 'db_index': 'True'}),
+ 'person': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['people.Person']", 'null': 'True'}),
+ 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'auto_now_add': 'True', 'blank': 'True'})
+ }
+ }
+
+ complete_apps = ['vertimus']
diff --git a/vertimus/migrations/0003_populate_merged_file.py b/vertimus/migrations/0003_populate_merged_file.py
new file mode 100644
index 0000000..7af9905
--- /dev/null
+++ b/vertimus/migrations/0003_populate_merged_file.py
@@ -0,0 +1,181 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import DataMigration
+from django.db import models
+
+from vertimus.models import Action
+from stats.models import PoFile
+
+class Migration(DataMigration):
+
+ def forwards(self, orm):
+ "Write your forwards methods here."
+ for action in Action.objects.all():
+ if action.has_po_file() and not action.merged_file:
+ merged_path = "%s.merged.po" % action.file.path[:-3]
+ action.merged_file = PoFile.objects.create(path=merged_path)
+ action.save()
+
+ def backwards(self, orm):
+ "Write your backwards methods here."
+ pass
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'languages.language': {
+ 'Meta': {'ordering': "('name',)", 'object_name': 'Language', 'db_table': "'language'"},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'locale': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '15'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '50'}),
+ 'plurals': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}),
+ 'team': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['teams.Team']", 'null': 'True', 'blank': 'True'})
+ },
+ 'people.person': {
+ 'Meta': {'ordering': "('username',)", 'object_name': 'Person', 'db_table': "'person'", '_ormbases': ['auth.User']},
+ 'activation_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'bugzilla_account': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'image': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'irc_nick': ('django.db.models.fields.SlugField', [], {'db_index': 'True', 'max_length': '20', 'null': 'True', 'blank': 'True'}),
+ 'svn_account': ('django.db.models.fields.SlugField', [], {'db_index': 'True', 'max_length': '20', 'null': 'True', 'blank': 'True'}),
+ 'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}),
+ 'webpage_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'})
+ },
+ 'stats.branch': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('name', 'module'),)", 'object_name': 'Branch', 'db_table': "'branch'"},
+ 'file_hashes': ('common.fields.DictionaryField', [], {'default': "''", 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'module': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['stats.Module']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'vcs_subpath': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'weight': ('django.db.models.fields.IntegerField', [], {'default': '0'})
+ },
+ 'stats.domain': {
+ 'Meta': {'ordering': "('-dtype', 'name')", 'object_name': 'Domain', 'db_table': "'domain'"},
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'directory': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'dtype': ('django.db.models.fields.CharField', [], {'default': "'ui'", 'max_length': '5'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'linguas_location': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'module': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['stats.Module']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'pot_method': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'red_filter': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'stats.module': {
+ 'Meta': {'ordering': "('name',)", 'object_name': 'Module', 'db_table': "'module'"},
+ 'bugs_base': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'bugs_component': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'bugs_product': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'ext_platform': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'homepage': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'maintainers': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'maintains_modules'", 'blank': 'True', 'db_table': "'module_maintainer'", 'to': "orm['people.Person']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'vcs_root': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+ 'vcs_type': ('django.db.models.fields.CharField', [], {'max_length': '5'}),
+ 'vcs_web': ('django.db.models.fields.URLField', [], {'max_length': '200'})
+ },
+ 'stats.pofile': {
+ 'Meta': {'object_name': 'PoFile', 'db_table': "'pofile'"},
+ 'figures': ('common.fields.JSONField', [], {'null': 'True', 'blank': 'True'}),
+ 'fuzzy': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'translated': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'untranslated': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'})
+ },
+ 'teams.role': {
+ 'Meta': {'unique_together': "(('team', 'person'),)", 'object_name': 'Role', 'db_table': "'role'"},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['people.Person']"}),
+ 'role': ('django.db.models.fields.CharField', [], {'default': "'translator'", 'max_length': '15'}),
+ 'team': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['teams.Team']"})
+ },
+ 'teams.team': {
+ 'Meta': {'ordering': "('description',)", 'object_name': 'Team', 'db_table': "'team'"},
+ 'description': ('django.db.models.fields.TextField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mailing_list': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'mailing_list_subscribe': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'members': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'teams'", 'symmetrical': 'False', 'through': "orm['teams.Role']", 'to': "orm['people.Person']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '80'}),
+ 'presentation': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'use_workflow': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'webpage_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'})
+ },
+ 'vertimus.action': {
+ 'Meta': {'object_name': 'Action', 'db_table': "'action'"},
+ 'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'created': ('django.db.models.fields.DateTimeField', [], {}),
+ 'file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'merged_file': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['stats.PoFile']", 'unique': 'True', 'null': 'True'}),
+ 'name': ('django.db.models.fields.SlugField', [], {'max_length': '8', 'db_index': 'True'}),
+ 'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['people.Person']"}),
+ 'state_db': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['vertimus.State']"})
+ },
+ 'vertimus.actionarchived': {
+ 'Meta': {'object_name': 'ActionArchived', 'db_table': "'action_archived'"},
+ 'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'created': ('django.db.models.fields.DateTimeField', [], {}),
+ 'file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'merged_file': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['stats.PoFile']", 'unique': 'True', 'null': 'True'}),
+ 'name': ('django.db.models.fields.SlugField', [], {'max_length': '8', 'db_index': 'True'}),
+ 'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['people.Person']"}),
+ 'sequence': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
+ 'state_db': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['vertimus.State']"})
+ },
+ 'vertimus.state': {
+ 'Meta': {'unique_together': "(('branch', 'domain', 'language'),)", 'object_name': 'State', 'db_table': "'state'"},
+ 'branch': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['stats.Branch']"}),
+ 'domain': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['stats.Domain']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'language': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['languages.Language']"}),
+ 'name': ('django.db.models.fields.SlugField', [], {'default': "'None'", 'max_length': '20', 'db_index': 'True'}),
+ 'person': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['people.Person']", 'null': 'True'}),
+ 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'auto_now_add': 'True', 'blank': 'True'})
+ }
+ }
+
+ complete_apps = ['vertimus']
diff --git a/vertimus/models.py b/vertimus/models.py
index 7fb6bf0..06214a2 100644
--- a/vertimus/models.py
+++ b/vertimus/models.py
@@ -28,7 +28,7 @@ from django.contrib.sites.models import Site
from django.core import mail, urlresolvers
from django.db import models
from django.db.models import Max
-from django.db.models.signals import post_save, post_delete
+from django.db.models.signals import post_save, pre_delete
from django.utils.translation import get_language, activate, ugettext, ugettext_lazy as _
from stats.models import Branch, Domain, Statistics, PoFile
@@ -315,7 +315,7 @@ class ActionAbstract(models.Model):
comment = models.TextField(blank=True, null=True)
file = models.FileField(upload_to=generate_upload_filename, blank=True, null=True)
#up_file = models.OneToOneField(PoFile, null=True, related_name='action_p')
- #merged_file = models.OneToOneField(PoFile, null=True, related_name='action_m')
+ merged_file = models.OneToOneField(PoFile, null=True) #, related_name='action_m')
# A comment or a file is required
arg_is_required = False
@@ -345,17 +345,6 @@ class ActionAbstract(models.Model):
except:
return False
- def merged_file(self):
- """If available, returns the merged file as a dict: {'url':'path':'filename'}"""
- mfile_url = mfile_path = mfile_name = None
- if self.file:
- mfile_url = self.file.url[:-3] + ".merged.po"
- mfile_path = self.file.path[:-3] + ".merged.po"
- mfile_name = os.path.basename(mfile_path)
- if not os.access(mfile_path, os.R_OK):
- mfile_url = mfile_path = mfile_name = None
- return {'url': mfile_url, 'path': mfile_path, 'filename': mfile_name}
-
@classmethod
def get_action_history(cls, state=None, sequence=None):
"""
@@ -436,20 +425,27 @@ class Action(ActionAbstract):
def merge_file_with_pot(self, pot_file):
"""Merge the uploaded translated file with current pot."""
- if self.file:
+ if not self.file:
+ return
+ if not self.merged_file:
merged_path = "%s.merged.po" % self.file.path[:-3]
- command = "msgmerge --previous -o %(out_po)s %(po_file)s %(pot_file)s" % {
- 'out_po': merged_path,
- 'po_file': self.file.path,
- 'pot_file': pot_file
- }
- run_shell_command(command)
- # If uploaded file is reduced, run po_grep *after* merge
- if is_po_reduced(self.file):
- temp_path = "%s.temp.po" % self.file.path[:-3]
- shutil.copy(merged_path, temp_path)
- po_grep(temp_path, merged_path, self.state_db.domain.red_filter)
- os.remove(temp_path)
+ self.merged_file = PoFile.objects.create(path=merged_path)
+ self.save()
+ return # post_save will call merge_file_with_pot again
+ merged_path = self.merged_file.path
+ command = "msgmerge --previous -o %(out_po)s %(po_file)s %(pot_file)s" % {
+ 'out_po': merged_path,
+ 'po_file': self.file.path,
+ 'pot_file': pot_file
+ }
+ run_shell_command(command)
+ # If uploaded file is reduced, run po_grep *after* merge
+ if is_po_reduced(self.file):
+ temp_path = "%s.temp.po" % self.file.path[:-3]
+ shutil.copy(merged_path, temp_path)
+ po_grep(temp_path, merged_path, self.state_db.domain.red_filter)
+ os.remove(temp_path)
+ self.merged_file.update_stats()
def send_mail_new_state(self, state, recipient_list):
# Remove None and empty string items from the list
@@ -757,18 +753,18 @@ post_save.connect(merge_uploaded_file)
def delete_action_files(sender, instance, **kwargs):
"""
- post_delete callback for Action that deletes the file + the merged file from upload
+ pre_delete callback for Action that deletes the file + the merged file from upload
directory.
"""
if not isinstance(instance, ActionAbstract) or not getattr(instance, 'file'):
return
if instance.file.path.endswith('.po'):
- merged_file = instance.file.path[:-3] + ".merged.po"
- if os.access(merged_file, os.W_OK):
- os.remove(merged_file)
+ if instance.merged_file:
+ if os.access(instance.merged_file.path, os.W_OK):
+ os.remove(instance.merged_file.path)
if os.access(instance.file.path, os.W_OK):
os.remove(instance.file.path)
-post_delete.connect(delete_action_files)
+pre_delete.connect(delete_action_files)
def reactivate_role(sender, instance, **kwargs):
# Reactivating the role if needed
diff --git a/vertimus/tests/__init__.py b/vertimus/tests/__init__.py
index 327c645..4b01580 100644
--- a/vertimus/tests/__init__.py
+++ b/vertimus/tests/__init__.py
@@ -30,6 +30,7 @@ from django.utils.datastructures import MultiValueDict
from teams.tests import TeamsAndRolesTests
from stats.models import Module, Branch, Release, Category, Domain, Statistics
+from stats.tests import test_scratchdir
from vertimus.models import *
from vertimus.forms import ActionForm
@@ -38,30 +39,32 @@ class VertimusTest(TeamsAndRolesTests):
def setUp(self):
super(VertimusTest, self).setUp()
- self.m = Module(name='gedit', description='GNOME Editor',
+ self.m = Module.objects.create(name='gedit', description='GNOME Editor',
bugs_base="http://bugzilla.gnome.org/",
bugs_product='gedit', bugs_component='general',
vcs_type='svn', vcs_root="http://svn.gnome.org/svn",
vcs_web="http://svn.gnome.org/viewvc/gedit")
- self.m.save()
Branch.checkout_on_creation = False
self.b = Branch(name='gnome-2-24', module=self.m)
# Block the update of Statistics by the thread
self.b.save(update_statistics=False)
- self.r = Release(name='gnome-2-24', status='official',
+ self.r = Release.objects.create(name='gnome-2-24', status='official',
description='GNOME 2.24 (stable)',
string_frozen=True)
- self.r.save()
- self.c = Category(release=self.r, branch=self.b, name='desktop')
- self.c.save()
+ self.c = Category.objects.create(release=self.r, branch=self.b, name='desktop')
- self.d = Domain(module=self.m, name='po',
+ self.d = Domain.objects.create(module=self.m, name='po',
description='UI translations',
dtype='ui', directory='po')
- self.d.save()
+ pot_stat = Statistics.objects.create(language=None, branch=self.b, domain=self.d)
+ self.files_to_clean = []
+
+ def tearDown(self):
+ for path in self.files_to_clean:
+ os.remove(path)
def test_state_none(self):
state = StateNone(branch=self.b, domain=self.d, language=self.l)
@@ -204,6 +207,7 @@ class VertimusTest(TeamsAndRolesTests):
action.apply_on(state)
self.assertTrue(isinstance(state, StateTranslating))
+ @test_scratchdir
def test_action_ut(self):
# Disabling the role
role = Role.objects.get(person=self.pt, team=self.l.team)
@@ -213,11 +217,14 @@ class VertimusTest(TeamsAndRolesTests):
state = StateTranslating(branch=self.b, domain=self.d, language=self.l, person=self.pt)
state.save()
- test_file = ContentFile('test content')
- test_file.name = 'mytestfile.po'
-
- action = Action.new_by_name('UT', person=self.pt, comment="Done by translator.", file=test_file)
+ test_file = open(os.path.join(os.path.dirname(os.path.abspath(__file__)), "valid_po.po"), 'r')
+
+ action = Action.new_by_name('UT', person=self.pt, comment="Done by translator.", file=File(test_file))
action.apply_on(state)
+ self.assertEqual(action.file.url, '/media/upload/gedit-gnome-2-24-po-fr-%d.po' % state.id)
+ self.assertEqual(action.merged_file.url(), '/media/upload/gedit-gnome-2-24-po-fr-%d.merged.po' % state.id)
+ self.files_to_clean.extend([action.file.path, action.merged_file.path])
+
self.assertTrue(isinstance(state, StateTranslated))
# Mail sent to mailing list
self.assertEquals(len(mail.outbox), 1)
@@ -245,6 +252,7 @@ class VertimusTest(TeamsAndRolesTests):
action = Action.new_by_name('UP', person=self.pr, comment="Done.", file=test_file)
action.apply_on(state)
+ self.files_to_clean.append(action.file.path)
self.assertTrue(isinstance(state, StateProofread))
def test_action_tc(self):
@@ -374,9 +382,6 @@ class VertimusTest(TeamsAndRolesTests):
self.assertEqual(Action.objects.all().count(), 0)
def test_vertimus_view(self):
- pot_stat = Statistics(language=None, branch=self.b, domain=self.d)
- pot_stat.save()
-
url = reverse('vertimus_by_ids', args=[self.b.id, self.d.id, self.l.id])
response = self.client.get(url)
self.assertNotContains(response, '<option value="WC">')
@@ -397,7 +402,6 @@ class VertimusTest(TeamsAndRolesTests):
f = open(os.path.join(os.path.dirname(os.path.abspath(__file__)), "valid_po.po"), 'r')
post_file = MultiValueDict({'file': [File(f)]})
form = ActionForm([('WC', u'Write a comment')], post_content, post_file)
-
self.assert_(form.is_valid())
# Test form without file
diff --git a/vertimus/views.py b/vertimus/views.py
index 590d3ef..e8d5553 100644
--- a/vertimus/views.py
+++ b/vertimus/views.py
@@ -147,7 +147,7 @@ def vertimus_diff(request, action_id_1, action_id_2, level):
action_1 = get_object_or_404(ActionReal, pk=action_id_1)
state = action_1.state_db
- file_path_1 = action_1.merged_file()['path'] or action_1.file.path
+ file_path_1 = action_1.merged_file and action_1.merged_file.path or action_1.file.path
reduced = is_po_reduced(file_path_1)
try:
@@ -160,7 +160,7 @@ def vertimus_diff(request, action_id_1, action_id_2, level):
if action_id_2 not in (None, "0"):
# 1) id_2 specified in URL
action_2 = get_object_or_404(ActionReal, pk=action_id_2)
- file_path_2 = action_2.merged_file()['path'] or action_2.file.path
+ file_path_2 = action_2.merged_file and action_2.merged_file.path or action_2.file.path
descr_2 = _("Uploaded file by %(name)s on %(date)s") % { 'name': action_2.person.name,
'date': action_2.created }
else:
@@ -170,7 +170,7 @@ def vertimus_diff(request, action_id_1, action_id_2, level):
action_2 = action_1.get_previous_action_with_po()
if action_2:
- file_path_2 = action_2.merged_file()['path'] or action_2.file.path
+ file_path_2 = action_2.merged_file and action_2.merged_file.path or action_2.file.path
descr_2 = _("Uploaded file by %(name)s on %(date)s") % { 'name': action_2.person.name,
'date': action_2.created }
else:
@@ -208,5 +208,4 @@ def latest_uploaded_po(request, module_name, branch_name, domain_name, locale_na
file__endswith=".po").order_by('-created')[:1]
if not latest_upload:
raise Http404
- merged_file = latest_upload[0].merged_file()
- return HttpResponseRedirect(merged_file['url'])
+ return HttpResponseRedirect(latest_upload[0].merged_file.url())
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]