Commit 9bb95310 authored by Claude Paroz's avatar Claude Paroz

Add stats for uploaded (merged) files

parent 781064d8
......@@ -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]))
......@@ -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)
......
......@@ -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:
......
......@@ -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
......
......@@ -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()
......
......@@ -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"/>&nbsp;{{ action.merged_file.filename }}
</a>
<br/>
<img src="{{ MEDIA_URL }}img/download.png"/>&nbsp;{{ action.merged_file.filename }}</a>
{{ action.merged_file|num_stats:'short' }}<br/>
{% endif %}
<div class="right_actions">{% trans "diff with:" %}
{% for f in files %}
......
# 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']
# 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']
......@@ -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
......
......@@ -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
......
......@@ -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