# -*- coding: utf-8 -*-

#

# jQuery File Upload Plugin GAE Python Example 2.2.0

# https://github.com/blueimp/jQuery-File-Upload

#

# Copyright 2011, Sebastian Tschan

# https://blueimp.net

#

# Licensed under the MIT license:

# http://www.opensource.org/licenses/MIT

#



from __future__ import with_statement

from google.appengine.api import files, images

from google.appengine.ext import blobstore, deferred

from google.appengine.ext.webapp import blobstore_handlers

import json

import re

import urllib

import webapp2



WEBSITE = 'https://blueimp.github.io/jQuery-File-Upload/'

MIN_FILE_SIZE = 1  # bytes

MAX_FILE_SIZE = 5000000  # bytes

IMAGE_TYPES = re.compile('image/(gif|p?jpeg|(x-)?png)')

ACCEPT_FILE_TYPES = IMAGE_TYPES

THUMBNAIL_MODIFICATOR = '=s80'  # max width / height

EXPIRATION_TIME = 300  # seconds





def cleanup(blob_keys):

    blobstore.delete(blob_keys)





class UploadHandler(webapp2.RequestHandler):



    def initialize(self, request, response):

        super(UploadHandler, self).initialize(request, response)

        self.response.headers['Access-Control-Allow-Origin'] = '*'

        self.response.headers[

            'Access-Control-Allow-Methods'

        ] = 'OPTIONS, HEAD, GET, POST, PUT, DELETE'

        self.response.headers[

            'Access-Control-Allow-Headers'

        ] = 'Content-Type, Content-Range, Content-Disposition'



    def validate(self, file):

        if file['size'] < MIN_FILE_SIZE:

            file['error'] = 'File is too small'

        elif file['size'] > MAX_FILE_SIZE:

            file['error'] = 'File is too big'

        elif not ACCEPT_FILE_TYPES.match(file['type']):

            file['error'] = 'Filetype not allowed'

        else:

            return True

        return False



    def get_file_size(self, file):

        file.seek(0, 2)  # Seek to the end of the file

        size = file.tell()  # Get the position of EOF

        file.seek(0)  # Reset the file position to the beginning

        return size



    def write_blob(self, data, info):

        blob = files.blobstore.create(

            mime_type=info['type'],

            _blobinfo_uploaded_filename=info['name']

        )

        with files.open(blob, 'a') as f:

            f.write(data)

        files.finalize(blob)

        return files.blobstore.get_blob_key(blob)



    def handle_upload(self):

        results = []

        blob_keys = []

        for name, fieldStorage in self.request.POST.items():

            if type(fieldStorage) is unicode:

                continue

            result = {}

            result['name'] = re.sub(

                r'^.*\\',

                '',

                fieldStorage.filename

            )

            result['type'] = fieldStorage.type

            result['size'] = self.get_file_size(fieldStorage.file)

            if self.validate(result):

                blob_key = str(

                    self.write_blob(fieldStorage.value, result)

                )

                blob_keys.append(blob_key)

                result['deleteType'] = 'DELETE'

                result['deleteUrl'] = self.request.host_url +\

                    '/?key=' + urllib.quote(blob_key, '')

                if (IMAGE_TYPES.match(result['type'])):

                    try:

                        result['url'] = images.get_serving_url(

                            blob_key,

                            secure_url=self.request.host_url.startswith(

                                'https'

                            )

                        )

                        result['thumbnailUrl'] = result['url'] +\

                            THUMBNAIL_MODIFICATOR

                    except:  # Could not get an image serving url

                        pass

                if not 'url' in result:

                    result['url'] = self.request.host_url +\

                        '/' + blob_key + '/' + urllib.quote(

                            result['name'].encode('utf-8'), '')

            results.append(result)

        deferred.defer(

            cleanup,

            blob_keys,

            _countdown=EXPIRATION_TIME

        )

        return results



    def options(self):

        pass



    def head(self):

        pass



    def get(self):

        self.redirect(WEBSITE)



    def post(self):

        if (self.request.get('_method') == 'DELETE'):

            return self.delete()

        result = {'files': self.handle_upload()}

        s = json.dumps(result, separators=(',', ':'))

        redirect = self.request.get('redirect')

        if redirect:

            return self.redirect(str(

                redirect.replace('%s', urllib.quote(s, ''), 1)

            ))

        if 'application/json' in self.request.headers.get('Accept'):

            self.response.headers['Content-Type'] = 'application/json'

        self.response.write(s)



    def delete(self):

        key = self.request.get('key') or ''

        blobstore.delete(key)

        s = json.dumps({key: True}, separators=(',', ':'))

        if 'application/json' in self.request.headers.get('Accept'):

            self.response.headers['Content-Type'] = 'application/json'

        self.response.write(s)





class DownloadHandler(blobstore_handlers.BlobstoreDownloadHandler):

    def get(self, key, filename):

        if not blobstore.get(key):

            self.error(404)

        else:

            # Prevent browsers from MIME-sniffing the content-type:

            self.response.headers['X-Content-Type-Options'] = 'nosniff'

            # Cache for the expiration time:

            self.response.headers['Cache-Control'] = 'public,max-age=%d' % EXPIRATION_TIME

            # Send the file forcing a download dialog:

            self.send_blob(key, save_as=filename, content_type='application/octet-stream')



app = webapp2.WSGIApplication(

    [

        ('/', UploadHandler),

        ('/([^/]+)/([^/]+)', DownloadHandler)

    ],

    debug=True

)

