Ejemplo n.º 1
0
class PermissionSet(models.Model):

    profile = models.ForeignKey('pootle_profile.PootleProfile', db_index=True)
    directory = models.ForeignKey(
        'pootle_app.Directory',
        db_index=True,
        related_name='permission_sets',
    )
    positive_permissions = models.ManyToManyField(
        Permission,
        db_index=True,
        related_name='permission_sets_positive',
    )
    # Negative permissions are no longer used, kept around to scheme
    # compatibility with older versions.
    negative_permissions = models.ManyToManyField(
        Permission,
        editable=False,
        related_name='permission_sets_negative',
    )

    objects = RelatedManager()

    class Meta:
        unique_together = ('profile', 'directory')
        app_label = "pootle_app"

    def __unicode__(self):
        return "%s : %s" % (self.profile.user.username,
                            self.directory.pootle_path)

    def to_dict(self):
        permissions_iterator = self.positive_permissions.iterator()
        return dict((perm.codename, perm) for perm in permissions_iterator)

    def save(self, *args, **kwargs):
        super(PermissionSet, self).save(*args, **kwargs)
        # FIXME: can we use `post_save` signals or invalidate caches in
        # model managers, please?
        username = self.profile.user.username
        keys = [
            iri_to_uri('Permissions:%s' % username),
            iri_to_uri('projects:accessible:%s' % username),
        ]
        cache.delete_many(keys)

    def delete(self, *args, **kwargs):
        super(PermissionSet, self).delete(*args, **kwargs)
        # FIXME: can we use `post_delete` signals or invalidate caches in
        # model managers, please?
        username = self.profile.user.username
        keys = [
            iri_to_uri('Permissions:%s' % username),
            iri_to_uri('projects:accessible:%s' % username),
        ]
        cache.delete_many(keys)
Ejemplo n.º 2
0
class Suggestion(models.Model):

    unit = models.IntegerField(null=False, db_index=True)
    translation_project = models.ForeignKey(
        'pootle_translationproject.TranslationProject',
        db_index=True,
    )
    state = models.CharField(
        max_length=16,
        default='pending',
        null=False,
        choices=[
            ('pending', _('Pending')),
            ('accepted', _('Accepted')),
            ('rejected', _('Rejected')),
        ],
        db_index=True,
    )
    suggester = models.ForeignKey(
        'pootle_profile.PootleProfile',
        null=True,
        related_name='suggester',
        db_index=True,
    )
    creation_time = models.DateTimeField(auto_now_add=True, db_index=True)
    reviewer = models.ForeignKey(
        'pootle_profile.PootleProfile',
        null=True,
        related_name='reviewer',
        db_index=True,
    )
    review_time = models.DateTimeField(null=True, db_index=True)

    objects = RelatedManager()

    class Meta:
        app_label = "pootle_app"
Ejemplo n.º 3
0
class Submission(models.Model):

    creation_time = models.DateTimeField(db_index=True)
    translation_project = models.ForeignKey(
        'pootle_translationproject.TranslationProject',
        db_index=True,
    )
    submitter = models.ForeignKey(
        'pootle_profile.PootleProfile',
        null=True,
        db_index=True,
    )
    from_suggestion = models.OneToOneField(
        'pootle_app.Suggestion',
        null=True,
        db_index=True,
    )
    unit = models.ForeignKey(
        'pootle_store.Unit',
        blank=True,
        null=True,
        db_index=True,
    )
    check = models.ForeignKey(
        'pootle_store.QualityCheck',
        blank=True,
        null=True,
        db_index=True,
    )
    # The field that was changed in the unit.
    field = models.IntegerField(null=True, blank=True, db_index=True)

    # How did this submission come about? (one of the constants above).
    type = models.IntegerField(null=True, blank=True, db_index=True)

    # old_value and new_value can store string representations of multistrings
    # in the case where they store values for a unit's source or target. In
    # such cases, the strings might not be usable as is. Use the two helper
    # functions in pootle_store.fields to convert to and from this format.
    old_value = models.TextField(blank=True, default=u"")
    new_value = models.TextField(blank=True, default=u"")

    objects = RelatedManager()
    simple_objects = models.Manager()

    class Meta:
        ordering = ["creation_time"]
        get_latest_by = "creation_time"
        db_table = 'pootle_app_submission'

    def __unicode__(self):
        return u"%s (%s)" % (self.creation_time.strftime("%Y-%m-%d %H:%M"),
                             unicode(self.submitter))

    def as_html(self):
        return self.get_submission_message()

    def get_submission_message(self):
        """Return a message describing the submission.

        The message includes the user (with link to profile and gravatar), a
        message describing the action performed, and when it was performed.
        """

        unit = None
        if self.unit is not None:
            unit = {
                'source': escape(truncatechars(self.unit, 50)),
                'url': self.unit.get_translate_url(),
            }

            if self.check is not None:
                unit['check_name'] = self.check.name
                unit['check_display_name'] = check_names[self.check.name]
                unit['checks_url'] = ('http://docs.translatehouse.org/'
                                      'projects/translate-toolkit/en/latest/'
                                      'commands/pofilter_tests.html')

        if self.from_suggestion:
            displayuser = self.from_suggestion.reviewer
        else:
            # Sadly we may not have submitter information in all the
            # situations yet
            # TODO check if it is true
            if self.submitter:
                displayuser = self.submitter
            else:
                displayuser = User.objects.get_nobody_user().get_profile()

        displayname = displayuser.fullname
        if not displayname:
            displayname = displayuser.user.username

        action_bundle = {
            "profile_url": displayuser.get_absolute_url(),
            "gravatar_url": displayuser.gravatar_url(20),
            "displayname": displayname,
            "username": displayuser.user.username,
            "date": self.creation_time,
            "isoformat_date": self.creation_time.isoformat(),
            "action": "",
        }

        action_bundle["action"] = {
            SubmissionTypes.REVERT:
            _(
                'reverted translation for '
                '<i><a href="%(url)s">%(source)s</a></i>', unit),
            SubmissionTypes.SUGG_ACCEPT:
            _(
                'accepted suggestion for '
                '<i><a href="%(url)s">%(source)s</a></i>', unit),
            SubmissionTypes.UPLOAD:
            _('uploaded a file'),
            SubmissionTypes.MUTE_CHECK:
            _(
                'muted '
                '<a href="%(checks_url)s#%(check_name)s">%(check_display_name)s</a>'
                ' check for <i><a href="%(url)s">%(source)s</a></i>', unit),
            SubmissionTypes.UNMUTE_CHECK:
            _(
                'unmuted '
                '<a href="%(checks_url)s#%(check_name)s">%(check_display_name)s</a>'
                ' check for <i><a href="%(url)s">%(source)s</a></i>', unit),
        }.get(self.type, '')

        #TODO Look how to detect submissions for "sent suggestion", "rejected
        # suggestion"...

        #TODO Fix bug 3011 and replace the following code with the appropiate
        # one in the dictionary above.

        if not action_bundle["action"]:
            try:
                # If the action is unset, maybe the action is one of the
                # following ones.
                action_bundle["action"] = {
                    TRANSLATED:
                    _('translated '
                      '<i><a href="%(url)s">%(source)s</a></i>', unit),
                    FUZZY:
                    _(
                        'pre-translated '
                        '<i><a href="%(url)s">%(source)s</a></i>', unit),
                    UNTRANSLATED:
                    _(
                        'removed translation for '
                        '<i><a href="%(url)s">%(source)s</a></i>', unit),
                }.get(self.unit.state, '')
            except AttributeError:
                return ''

        return mark_safe(
            u'<div class="last-action">'
            '  <a href="%(profile_url)s">'
            '    <img src="%(gravatar_url)s" />'
            '    <span title="%(username)s">%(displayname)s</span>'
            '  </a>'
            '  <span class="action-text">%(action)s</span>'
            '  <time class="extra-item-meta js-relative-date"'
            '    title="%(date)s" datetime="%(isoformat_date)s">&nbsp;'
            '  </time>'
            '</div>' % action_bundle)
Ejemplo n.º 4
0
class Language(models.Model, TreeItem):

    code = models.CharField(
        max_length=50,
        null=False,
        unique=True,
        db_index=True,
        verbose_name=_("Code"),
        help_text=_('ISO 639 language code for the language, possibly '
                    'followed by an underscore (_) and an ISO 3166 country '
                    'code. <a href="http://www.w3.org/International/articles/'
                    'language-tags/">More information</a>'),
    )
    fullname = models.CharField(
        max_length=255,
        null=False,
        verbose_name=_("Full Name"),
    )
    description = MarkupField(
        blank=True,
        help_text=_(
            'A description of this language. This is useful to give '
            'more information or instructions. Allowed markup: %s',
            get_markup_filter_name()),
    )
    specialchars = models.CharField(
        max_length=255,
        blank=True,
        verbose_name=_("Special Characters"),
        help_text=_('Enter any special characters that users might find '
                    'difficult to type'),
    )
    nplurals = models.SmallIntegerField(
        default=0,
        choices=((0, _('Unknown')), (1, 1), (2, 2), (3, 3), (4, 4), (5, 5),
                 (6, 6)),
        verbose_name=_("Number of Plurals"),
        help_text=_('For more information, visit <a href="'
                    'http://docs.translatehouse.org/projects/'
                    'localization-guide/en/latest/l10n/pluralforms.html">our '
                    'page</a> on plural forms.'),
    )
    pluralequation = models.CharField(
        max_length=255,
        blank=True,
        verbose_name=_("Plural Equation"),
        help_text=_('For more information, visit <a href="'
                    'http://docs.translatehouse.org/projects/'
                    'localization-guide/en/latest/l10n/pluralforms.html">our '
                    'page</a> on plural forms.'),
    )
    directory = models.OneToOneField(
        'pootle_app.Directory',
        db_index=True,
        editable=False,
    )

    objects = RelatedManager()
    live = LiveLanguageManager()

    class Meta:
        ordering = ['code']
        db_table = 'pootle_app_language'

    ############################ Properties ###################################

    @property
    def pootle_path(self):
        return '/%s/' % self.code

    @property
    def name(self):
        """Localized fullname for the language."""
        return tr_lang(self.fullname)

    ############################ Methods ######################################

    @property
    def direction(self):
        """Return the language direction."""
        return language_dir(self.code)

    def __unicode__(self):
        return u"%s - %s" % (self.name, self.code)

    def __init__(self, *args, **kwargs):
        super(Language, self).__init__(*args, **kwargs)

    def __repr__(self):
        return u'<%s: %s>' % (self.__class__.__name__, self.fullname)

    def save(self, *args, **kwargs):
        # create corresponding directory object
        from pootle_app.models.directory import Directory
        self.directory = Directory.objects.root.get_or_make_subdir(self.code)

        super(Language, self).save(*args, **kwargs)

        # FIXME: far from ideal, should cache at the manager level instead
        cache.delete(CACHE_KEY)

    def delete(self, *args, **kwargs):
        directory = self.directory
        super(Language, self).delete(*args, **kwargs)
        directory.delete()

        # FIXME: far from ideal, should cache at the manager level instead
        cache.delete(CACHE_KEY)

    def get_absolute_url(self):
        return reverse('pootle-language-overview', args=[self.code])

    def get_translate_url(self, **kwargs):
        return u''.join([
            reverse('pootle-language-translate', args=[self.code]),
            get_editor_filter(**kwargs),
        ])

    ### TreeItem

    def get_children(self):
        return self.translationproject_set.enabled()

    def get_cachekey(self):
        return self.directory.pootle_path

    ### /TreeItem

    def translated_percentage(self):
        total = max(self.get_total_wordcount(), 1)
        translated = self.get_translated_wordcount()
        return int(100.0 * translated / total)
Ejemplo n.º 5
0
class Submission(models.Model):

    creation_time = models.DateTimeField(db_index=True)
    translation_project = models.ForeignKey(
        'pootle_translationproject.TranslationProject',
        db_index=True,
    )
    submitter = models.ForeignKey(
        'pootle_profile.PootleProfile',
        null=True,
        db_index=True,
    )
    from_suggestion = models.OneToOneField(
        'pootle_app.Suggestion',
        null=True,
        db_index=True,
    )
    unit = models.ForeignKey(
        'pootle_store.Unit',
        blank=True,
        null=True,
        db_index=True,
    )
    # The field that was changed in the unit.
    field = models.IntegerField(null=True, blank=True, db_index=True)

    # How did this submission come about? (one of the constants above).
    type = models.IntegerField(null=True, blank=True, db_index=True)

    # old_value and new_value can store string representations of multistrings
    # in the case where they store values for a unit's source or target. In
    # such cases, the strings might not be usable as is. Use the two helper
    # functions in pootle_store.fields to convert to and from this format.
    old_value = models.TextField(blank=True, default=u"")
    new_value = models.TextField(blank=True, default=u"")

    objects = RelatedManager()
    simple_objects = models.Manager()

    class Meta:
        ordering = ["creation_time"]
        get_latest_by = "creation_time"
        db_table = 'pootle_app_submission'

    def __unicode__(self):
        return u"%s (%s)" % (self.creation_time.strftime("%Y-%m-%d %H:%M"),
                             unicode(self.submitter))

    def as_html(self):
        #FIXME: Sadly we may not have submitter information in all the
        # situations yet.
        if self.submitter:
            submitter_info = u'<a href="%(profile_url)s">%(submitter)s</a>' % {
                    'profile_url': self.submitter.get_absolute_url(),
                    'submitter': unicode(self.submitter),
                }
        else:
            submitter_info = _("anonymous user")

        snippet = u'%(time)s (%(submitter_info)s)' % {
                    'time': self.creation_time.strftime("%Y-%m-%d %H:%M"),
                    'submitter_info': submitter_info,
                }

        return mark_safe(snippet)

    def get_submission_message(self):
        """Return a message describing the submission.

        The message includes the user (with link to profile and gravatar), a
        message describing the action performed, and when it was performed.
        """

        action_bundle = {
            "profile_url": self.submitter.get_absolute_url(),
            "gravatar_url": self.submitter.gravatar_url(20),
            "username": self.submitter.user.username,
        }

        unit = {
            'user': ('  <a href="%(profile_url)s">'
                     '    <span>%(username)s</span>'
                     '  </a>') % action_bundle,
        }

        if self.unit is not None:
            unit.update({
                'source': escape(truncatechars(self.unit, 50)),
                'url': self.unit.get_absolute_url(),
            })

        action_bundle.update({
            "date": self.creation_time,
            "isoformat_date": self.creation_time.isoformat(),
            "action": {
                SubmissionTypes.REVERT: _('%(user)s reverted translation for '
                                          'string <i><a href="%(url)s">'
                                          '%(source)s</a></i>', unit),
                SubmissionTypes.SUGG_ACCEPT: _('%(user)s accepted suggestion '
                                               'for string <i><a href="%(url)s">'
                                               '%(source)s</a></i>', unit),
                SubmissionTypes.UPLOAD: _('%(user)s uploaded a file', unit),
            }.get(self.type, ''),
        })

        #TODO Look how to detect submissions for "sent suggestion", "rejected
        # suggestion"...

        #TODO Fix bug 3011 and replace the following code with the appropiate
        # one in the dictionary above.

        if not action_bundle["action"]:
            try:
                # If the action is unset, maybe the action is one of the
                # following ones.
                action_bundle["action"] = {
                    TRANSLATED: _('%(user)s submitted translation for string '
                                  '<i><a href="%(url)s">%(source)s</a></i>',
                                  unit),
                    FUZZY: _('%(user)s submitted "needs work" translation for '
                             'string <i><a href="%(url)s">%(source)s</a></i>',
                             unit),
                    UNTRANSLATED: _('%(user)s removed translation for string '
                                    '<i><a href="%(url)s">%(source)s</a></i>',
                                    unit),
                }.get(self.unit.state, '')
            except AttributeError:
                return ''

        # If it is not possible to provide the action performed, then it is
        # better to not return anything at all.
        if not action_bundle["action"]:
            return ''

        return (u'<div class="last-action">'
            '  <a href="%(profile_url)s">'
            '    <img src="%(gravatar_url)s" />'
            '  </a>'
            '  %(action)s'
            '  <time class="extra-item-meta js-relative-date"'
            '    title="%(date)s" datetime="%(isoformat_date)s">&nbsp;'
            '  </time>'
            '</div>' % action_bundle)