
import os
import json
import uuid
from zipfile import ZipFile, BadZipfile

import autoslug
import tagging
from django.contrib import auth
from django.db import models

# Create your models here.

class Extension(models.Model):
    name = models.CharField(max_length=200)
    uuid = models.TextField()
    slug = autoslug.AutoSlugField(populate_from="name", unique=True)
    creator = models.ForeignKey(auth.models.User)
    description = models.TextField()
    url = models.URLField()
    created = models.DateTimeField(auto_now_add=True)
    is_published = models.BooleanField(default=False)

    def get_version(self, version):
        if version in (None, 'latest'):
            return self.extensionversion_set.order_by('-version')[0]

        return self.extensionversion_set.get(version=int(version))

tagging.register(Extension)

class InvalidExtensionData(Exception):
    pass

class ExtensionVersion(models.Model):
    extension = models.ForeignKey(Extension)
    version = models.IntegerField(default=0)
    extra_json_fields = models.TextField()

    def make_filename(self, filename):
        return os.path.join(self.extension.uuid, str(self.version),
                            self.extension.slug + ".shell-extension.zip")

    source = models.FileField(upload_to=make_filename)

    def make_metadata_json(self):
        """
        Return generated contents of metadata.json
        """
        data = json.loads(self.extra_json_fields)
        data['_generated']  = "Generated by SweetTooth, do not edit"
        data['name']        = self.extension.name
        data['description'] = self.extension.description
        data['url']         = self.extension.url
        data['uuid']        = self.extension.uuid
        data['version']     = self.version
        return json.dumps(data, sort_keys=True, indent=2)

    def replace_metadata_json(self):
        """
        In the uploaded extension zipfile, edit metadata.json
        to reflect the new contents.
        """
        zipfile = ZipFile(self.source.storage.path(self.source.name), "a")
        zipfile.writestr("metadata.json", self.make_metadata_json())
        zipfile.close()

    @classmethod
    def from_metadata_json(cls, metadata, extension=None):
        """
        Given the contents of a metadata.json file, create an extension
        and version with its data and return them.
        """

        if extension is None:
            extension = Extension()
            extension.name = metadata.get('name', "")
            extension.description = metadata.get('description', "")
            extension.url = metadata.get('url', "")
            extension.uuid = metadata.get('uuid', str(uuid.uuid1()))

        version = ExtensionVersion(extension=extension)
        version.extra_json_fields = json.dumps(metadata)
        return extension, version

    @classmethod
    def from_zipfile(cls, uploaded_file, extension=None):
        """
        Given a file, create an extension and version, populated
        with the data from the metadata.json and return them.
        """
        try:
            zipfile = ZipFile(uploaded_file, 'r')
        except BadZipfile:
            raise InvalidExtensionData("Invalid zip file")

        try:
            metadata = json.load(zipfile.open('metadata.json', 'r'))
        except KeyError:
            # no metadata.json in archive, use web editor
            metadata = {}
        except ValueError:
            # invalid JSON file, raise error
            raise InvalidExtensionData("Invalid JSON data")

        extension, version = cls.from_metadata_json(metadata, extension)
        zipfile.close()
        return extension, version

    def save(self, **kw):
        # autoincrement version
        if self.version == 0:
            versions = type(self).objects.filter(extension=self.extension)
            versions = versions.order_by('-version')
            try:
                self.version_number = versions[0]
            except IndexError:
                # New extension, no versions yes
                self.version_number = 1

        super(ExtensionVersion, self).save(**kw)

@@ -2801,16 +2801,302 @@
 etadata)
+%0A%0A        # get version number%0A        ver_ids = extension.extensionversion_set.order_by('-version')%0A        try:%0A            ver_id = ver_ids%5B0%5D.version + 1%0A        except IndexError:%0A            # New extension, no versions yet%0A            ver_id = 1%0A%0A        version.version = ver_id
 %0A       
@@ -3958,458 +3958,4 @@
 ion%0A
-%0A    def save(self, **kw):%0A        # autoincrement version%0A        if self.version == 0:%0A            versions = type(self).objects.filter(extension=self.extension)%0A            versions = versions.order_by('-version')%0A            try:%0A                self.version_number = versions%5B0%5D%0A            except IndexError:%0A                # New extension, no versions yes%0A                self.version_number = 1%0A%0A        super(ExtensionVersion, self).save(**kw)%0A

Remove auto-incrementing approach in favor of explicit approach.