Example #1
0
class TranslatedModel(UncachedModelBase):
    name = TranslatedField()
    description = TranslatedField()
    default_locale = models.CharField(max_length=10)
    no_locale = TranslatedField(require_locale=False)

    objects = UncachedManagerBase()
Example #2
0
class FileUpload(ModelBase):
    """Created when a file is uploaded for validation/submission."""
    uuid = models.UUIDField(default=uuid.uuid4, editable=False)
    path = models.CharField(max_length=255, default='')
    name = models.CharField(max_length=255,
                            default='',
                            help_text="The user's original filename")
    hash = models.CharField(max_length=255, default='')
    user = models.ForeignKey('users.UserProfile', null=True)
    valid = models.BooleanField(default=False)
    validation = models.TextField(null=True)
    automated_signing = models.BooleanField(default=False)
    compat_with_app = models.PositiveIntegerField(
        choices=amo.APPS_CHOICES, db_column="compat_with_app_id", null=True)
    compat_with_appver = models.ForeignKey(
        AppVersion, null=True, related_name='uploads_compat_for_appver')
    # Not all FileUploads will have a version and addon but it will be set
    # if the file was uploaded using the new API.
    version = models.CharField(max_length=255, null=True)
    addon = models.ForeignKey('addons.Addon', null=True)

    objects = UncachedManagerBase()

    class Meta(ModelBase.Meta):
        db_table = 'file_uploads'

    def __unicode__(self):
        return unicode(self.uuid.hex)

    def save(self, *args, **kw):
        if self.validation:
            if self.load_validation()['errors'] == 0:
                self.valid = True
        super(FileUpload, self).save(*args, **kw)

    def add_file(self, chunks, filename, size):
        if not self.uuid:
            self.uuid = self._meta.get_field('uuid')._create_uuid()

        filename = force_bytes(u'{0}_{1}'.format(self.uuid.hex, filename))
        loc = os.path.join(user_media_path('addons'), 'temp', uuid.uuid4().hex)
        base, ext = os.path.splitext(force_bytes(filename))
        is_crx = False

        # Change a ZIP to an XPI, to maintain backward compatibility
        # with older versions of Firefox and to keep the rest of the XPI code
        # path as consistent as possible for ZIP uploads.
        # See: https://github.com/mozilla/addons-server/pull/2785
        if ext == '.zip':
            ext = '.xpi'

        # If the extension is a CRX, we need to do some actual work to it
        # before we just convert it to an XPI. We strip the header from the
        # CRX, then it's good; see more about the CRX file format here:
        # https://developer.chrome.com/extensions/crx
        if ext == '.crx':
            ext = '.xpi'
            is_crx = True

        if ext in EXTENSIONS:
            loc += ext

        log.info('UPLOAD: %r (%s bytes) to %r' % (filename, size, loc))
        if is_crx:
            hash = write_crx_as_xpi(chunks, storage, loc)
        else:
            hash = hashlib.sha256()
            with storage.open(loc, 'wb') as file_destination:
                for chunk in chunks:
                    hash.update(chunk)
                    file_destination.write(chunk)
        self.path = loc
        self.name = filename
        self.hash = 'sha256:%s' % hash.hexdigest()
        self.save()

    @classmethod
    def from_post(cls, chunks, filename, size, **params):
        upload = FileUpload(**params)
        upload.add_file(chunks, filename, size)
        return upload

    @property
    def processed(self):
        return bool(self.valid or self.validation)

    @property
    def validation_timeout(self):
        if self.processed:
            validation = self.load_validation()
            messages = validation['messages']
            timeout_id = [
                'validator', 'unexpected_exception', 'validation_timeout'
            ]
            return any(msg['id'] == timeout_id for msg in messages)
        else:
            return False

    @property
    def processed_validation(self):
        """Return processed validation results as expected by the frontend."""
        if self.validation:
            # Import loop.
            from olympia.devhub.utils import process_validation

            validation = self.load_validation()
            is_compatibility = self.compat_with_app is not None

            return process_validation(validation, is_compatibility, self.hash)

    @property
    def passed_all_validations(self):
        return self.processed and self.valid

    @property
    def passed_auto_validation(self):
        return self.load_validation()['passed_auto_validation']

    def load_validation(self):
        return json.loads(self.validation)

    @property
    def pretty_name(self):
        parts = self.name.split('_', 1)
        if len(parts) > 1:
            return parts[1]
        return self.name
Example #3
0
class FileUpload(ModelBase):
    """Created when a file is uploaded for validation/submission."""
    uuid = UUIDField(auto=True)
    path = models.CharField(max_length=255, default='')
    name = models.CharField(max_length=255,
                            default='',
                            help_text="The user's original filename")
    hash = models.CharField(max_length=255, default='')
    user = models.ForeignKey('users.UserProfile', null=True)
    valid = models.BooleanField(default=False)
    validation = models.TextField(null=True)
    automated_signing = models.BooleanField(default=False)
    compat_with_app = models.PositiveIntegerField(
        choices=amo.APPS_CHOICES, db_column="compat_with_app_id", null=True)
    compat_with_appver = models.ForeignKey(
        AppVersion, null=True, related_name='uploads_compat_for_appver')
    # Not all FileUploads will have a version and addon but it will be set
    # if the file was uploaded using the new API.
    version = models.CharField(max_length=255, null=True)
    addon = models.ForeignKey('addons.Addon', null=True)

    objects = UncachedManagerBase()

    class Meta(ModelBase.Meta):
        db_table = 'file_uploads'

    def __unicode__(self):
        return self.uuid

    def save(self, *args, **kw):
        if self.validation:
            if self.load_validation()['errors'] == 0:
                self.valid = True
        super(FileUpload, self).save(*args, **kw)

    def add_file(self, chunks, filename, size):
        if not self.uuid:
            self.uuid = self._meta.get_field('uuid')._create_uuid().hex
        filename = smart_str(u'{0}_{1}'.format(self.uuid, filename))
        loc = os.path.join(user_media_path('addons'), 'temp', uuid.uuid4().hex)
        base, ext = os.path.splitext(smart_path(filename))
        if ext in EXTENSIONS:
            loc += ext
        log.info('UPLOAD: %r (%s bytes) to %r' % (filename, size, loc))
        hash = hashlib.sha256()
        with storage.open(loc, 'wb') as fd:
            for chunk in chunks:
                hash.update(chunk)
                fd.write(chunk)
        self.path = loc
        self.name = filename
        self.hash = 'sha256:%s' % hash.hexdigest()
        self.save()

    @classmethod
    def from_post(cls, chunks, filename, size, **params):
        upload = FileUpload(**params)
        upload.add_file(chunks, filename, size)
        return upload

    @property
    def processed(self):
        return bool(self.valid or self.validation)

    @property
    def validation_timeout(self):
        if self.processed:
            validation = self.load_validation()
            messages = validation['messages']
            timeout_id = [
                'validator', 'unexpected_exception', 'validation_timeout'
            ]
            return any(msg['id'] == timeout_id for msg in messages)
        else:
            return False

    @property
    def processed_validation(self):
        """Return processed validation results as expected by the frontend."""
        if self.validation:
            # Import loop.
            from olympia.devhub.utils import process_validation

            validation = self.load_validation()
            is_compatibility = self.compat_with_app is not None

            return process_validation(validation, is_compatibility, self.hash)

    @property
    def passed_all_validations(self):
        return self.processed and self.valid

    @property
    def passed_auto_validation(self):
        return self.load_validation()['passed_auto_validation']

    def load_validation(self):
        return json.loads(self.validation)