Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
28 changed files
with
1,475 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
*.py[cdo] | ||
*~ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
Copyright (c) 2012, Cuker Interactive | ||
All rights reserved. | ||
|
||
Redistribution and use in source and binary forms, with or without | ||
modification, are permitted provided that the following conditions are met: | ||
* Redistributions of source code must retain the above copyright | ||
notice, this list of conditions and the following disclaimer. | ||
* Redistributions in binary form must reproduce the above copyright | ||
notice, this list of conditions and the following disclaimer in the | ||
documentation and/or other materials provided with the distribution. | ||
* Neither the name of the author nor the names of other contributors | ||
may be used to endorse or promote products derived from this software | ||
without specific prior written permission. | ||
|
||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | ||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY | ||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
recursive-include directupload/templates * |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
from django.db import models | ||
from django.contrib.admin import ModelAdmin | ||
|
||
from widgets import UploadifyClearableFileInput | ||
|
||
class UploadifyAdminMixin(object): | ||
def formfield_for_dbfield(self, db_field, **kwargs): | ||
if isinstance(db_field, models.FileField): | ||
return self.formfield_for_file_field(db_field, kwargs.pop('request', None), **kwargs) | ||
return ModelAdmin.formfield_for_dbfield(self, db_field, **kwargs) | ||
|
||
def formfield_for_file_field(self, db_field, request=None, **kwargs): | ||
""" | ||
Get a form Field that is prepared for uploadify | ||
""" | ||
kwargs['widget'] = UploadifyClearableFileInput(db_field=db_field) | ||
return db_field.formfield(**kwargs) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
from django.conf import settings | ||
|
||
UPLOADIFY_BACKEND = getattr(settings, 'UPLOADIFY_BACKEND', 'directupload.backends.djangoview.DjangoViewBackend') | ||
#UPLOADIFY_BACKEND = getattr(settings, 'UPLOADIFY_BACKEND', 'directupload.backends.s3.S3UploadifyBackend') | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
try: | ||
import importlib | ||
except ImportError: | ||
from django.utils import importlib | ||
|
||
def get_uploadify_backend(): | ||
from directupload.app_settings import UPLOADIFY_BACKEND | ||
module_name, class_name = UPLOADIFY_BACKEND.rsplit('.', 1) | ||
module = importlib.import_module(module_name) | ||
return getattr(module, class_name) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
from django.conf import settings | ||
from django.core.exceptions import ImproperlyConfigured | ||
from django.core.urlresolvers import reverse | ||
|
||
from django.utils import simplejson as json | ||
|
||
from common import UPLOADIFY_OPTIONS, UPLOADIFY_METHODS, DEFAULT_CANCELIMG, DEFAULT_UPLOADER, BUTTON_TEXT | ||
|
||
class BaseUploadifyBackend(object): | ||
def __init__(self, request, uploadify_options={}, post_data={}): | ||
self.request = request | ||
self.options = getattr(settings, 'UPLOADIFY_DEFAULT_OPTIONS', {}) | ||
self.options.update(uploadify_options) | ||
|
||
if any(True for key in self.options if key not in UPLOADIFY_OPTIONS + UPLOADIFY_METHODS): | ||
raise ImproperlyConfigured("Attempted to initialize with unrecognized option '%s'." % key) | ||
|
||
_set_default_if_none(self.options, 'cancelImage', DEFAULT_CANCELIMG) | ||
_set_default_if_none(self.options, 'swf', DEFAULT_UPLOADER) | ||
_set_default_if_none(self.options, 'uploader', self.get_uploader()) | ||
_set_default_if_none(self.options, 'buttonText', BUTTON_TEXT) | ||
_set_default_if_none(self.options, 'checkExisting', self.get_check_existing()) | ||
_set_default_if_none(self.options, 'determineName', self.get_determine_name()) | ||
|
||
self.post_data = post_data | ||
self.build_post_data() | ||
|
||
def get_check_existing(self): | ||
return False | ||
|
||
def get_determine_name(self): | ||
return reverse('uploadify-determine-name') | ||
|
||
def get_uploader(self): | ||
pass | ||
|
||
def build_post_data(self): | ||
pass | ||
|
||
def update_post_params(self, params): | ||
pass | ||
|
||
def get_options_json(self): | ||
self.options['postData'] = self.post_data | ||
subs = [] | ||
for key in self.options: | ||
if key in UPLOADIFY_METHODS: | ||
subs.append(('"%%%s%%"' % key, self.options[key])) | ||
self.options[key] = "%%%s%%" % key | ||
|
||
out = json.dumps(self.options) | ||
|
||
for search, replace in subs: | ||
out = out.replace(search, replace) | ||
|
||
return out | ||
|
||
def _set_default_if_none(dict, key, default=None): | ||
if key not in dict: | ||
dict[key] = default | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
from django.conf import settings | ||
|
||
UPLOADIFY_OPTIONS = ('auto', 'buttonImg', 'buttonText', 'cancelImg', 'checkScript', 'displayData', 'expressInstall', 'fileDataName', 'fileDesc', 'fileExt', 'folder', 'height', 'hideButton', 'method', 'multi', 'queueID', 'queueSizeLimit', 'removeCompleted', 'rollover', 'script','scriptAccess', 'scriptData', 'simUploadLimit', 'sizeLimit', 'uploader', 'width', 'wmode') | ||
|
||
UPLOADIFY_METHODS = ('onAllComplete', 'onCancel', 'onCheck', 'onClearQueue', 'onComplete', 'onError', 'onInit', 'onOpen', 'onProgress', 'onQueueFull', 'onSelect', 'onSelectOnce', 'onSWFReady') | ||
|
||
BUTTON_TEXT = 'Select File' | ||
|
||
# Defaults for required Uploadify options | ||
DEFAULT_CANCELIMG = settings.STATIC_URL + "uploadify/uploadify-cancel.png" | ||
DEFAULT_UPLOADER = settings.STATIC_URL + "uploadify/uploadify.swf" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
from base import BaseUploadifyBackend | ||
|
||
import datetime | ||
from urllib import urlencode | ||
|
||
from django.middleware.csrf import get_token | ||
from django.core.urlresolvers import reverse | ||
|
||
from utils import Signer | ||
signer = Signer() | ||
|
||
def sign(value): | ||
return signer.sign(value) | ||
|
||
def unsign(value): | ||
return signer.unsign(value) | ||
|
||
class DjangoViewBackend(BaseUploadifyBackend): | ||
"""Uploadify for using the builtin django view""" | ||
|
||
def get_uploader(self): | ||
return reverse('uploadify-upload-file') | ||
|
||
def build_post_data(self): | ||
data = {'upload_to': self.options['folder'], | ||
'request_time': datetime.datetime.now().isoformat(), | ||
'_request_id': 'foo',} #TODO salt} | ||
signed_data = sign(urlencode(data)) | ||
self.post_data['payload'] = signed_data | ||
self.post_data['csrfmiddlewaretoken'] = get_token(self.request) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
from django.conf import settings | ||
from django.core.exceptions import ImproperlyConfigured | ||
from urllib import quote_plus | ||
from datetime import datetime | ||
from datetime import timedelta | ||
import base64 | ||
import hmac | ||
import hashlib | ||
import os | ||
|
||
from base import BaseUploadifyBackend, _set_default_if_none, json | ||
|
||
# AWS Options | ||
ACCESS_KEY_ID = getattr(settings, 'AWS_ACCESS_KEY_ID', None) | ||
SECRET_ACCESS_KEY = getattr(settings, 'AWS_SECRET_ACCESS_KEY', None) | ||
BUCKET_NAME = getattr(settings, 'AWS_BUCKET_NAME', None) | ||
SECURE_URLS = getattr(settings, 'AWS_S3_SECURE_URLS', False) | ||
BUCKET_URL = getattr(settings, 'AWS_BUCKET_URL', ('https://' if SECURE_URLS else 'http://') + BUCKET_NAME + '.s3.amazonaws.com') | ||
DEFAULT_ACL = getattr(settings, 'AWS_DEFAULT_ACL', 'public-read') | ||
DEFAULT_KEY_PATTERN = getattr(settings, 'AWS_DEFAULT_KEY_PATTERN', '${targetname}') | ||
DEFAULT_FORM_TIME = getattr(settings, 'AWS_DEFAULT_FORM_LIFETIME', 36000) # 10 HOURS | ||
|
||
|
||
class S3UploadifyBackend(BaseUploadifyBackend): | ||
"""Uploadify for Amazon S3""" | ||
|
||
def __init__(self, request, uploadify_options={}, post_data={}, conditions={}): | ||
self.conditions = conditions | ||
super(S3UploadifyBackend, self).__init__(request, uploadify_options, post_data) | ||
|
||
def get_uploader(self): | ||
return BUCKET_URL | ||
|
||
def build_post_data(self): | ||
self.options['fileObjName'] = 'file' #S3 requires this be the field name | ||
|
||
if 'folder' in self.options: | ||
key = os.path.join(self.options['folder'], DEFAULT_KEY_PATTERN) | ||
else: | ||
key = DEFAULT_KEY_PATTERN | ||
#_set_default_if_none(self.post_data, 'key', key) #this is set by update_post_params | ||
_set_default_if_none(self.post_data, 'acl', DEFAULT_ACL) | ||
|
||
try: | ||
_set_default_if_none(self.post_data, 'bucket', BUCKET_NAME) | ||
except ValueError: | ||
raise ImproperlyConfigured("Bucket name is a required property.") | ||
|
||
try: | ||
_set_default_if_none(self.post_data, 'AWSAccessKeyId', ACCESS_KEY_ID) | ||
except ValueError: | ||
raise ImproperlyConfigured("AWS Access Key ID is a required property.") | ||
|
||
self.conditions = self.build_conditions() | ||
|
||
if not SECRET_ACCESS_KEY: | ||
raise ImproperlyConfigured("AWS Secret Access Key is a required property.") | ||
|
||
expiration_time = datetime.utcnow() + timedelta(seconds=DEFAULT_FORM_TIME) | ||
self.policy_string = self.build_post_policy(expiration_time) | ||
self.policy = base64.b64encode(self.policy_string) | ||
|
||
self.signature = base64.encodestring(hmac.new(SECRET_ACCESS_KEY, self.policy, hashlib.sha1).digest()).strip() | ||
|
||
self.post_data['policy'] = self.policy | ||
self.post_data['signature'] = self.signature | ||
|
||
def build_conditions(self): | ||
conditions = list() | ||
|
||
#make s3 happy with uploadify | ||
#conditions.append(['starts-with', '$folder', '']) #no longer passed by uploadify | ||
conditions.append(['starts-with', '$filename', '']) | ||
conditions.append(['starts-with', '$targetname', '']) #variable introduced by this package | ||
conditions.append(['starts-with', '$targetpath', self.options['folder']]) | ||
#conditions.append({'success_action_status': '200'}) | ||
|
||
#real conditions | ||
conditions.append(['starts-with', '$key', self.options['folder']]) | ||
conditions.append({'bucket': self.post_data['bucket']}) | ||
conditions.append({'acl': self.post_data['acl']}) | ||
return conditions | ||
|
||
def build_post_policy(self, expiration_time): | ||
policy = {'expiration': expiration_time.strftime("%Y-%m-%dT%H:%M:%SZ"), | ||
'conditions': self.conditions,} | ||
return json.dumps(policy) | ||
|
||
def update_post_params(self, params): | ||
#instruct s3 that our key is the targetpath | ||
params['key'] = params['targetpath'] | ||
|
||
def _uri_encode(str): | ||
try: | ||
# The Uploadify flash component apparently decodes the scriptData once, so we need to encode twice here. | ||
return quote_plus(quote_plus(str, safe='~'), safe='~') | ||
except: | ||
raise ValueError | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
from django.conf import settings | ||
from django.utils.crypto import constant_time_compare, salted_hmac | ||
|
||
import base64 | ||
|
||
def b64_encode(s): | ||
return base64.urlsafe_b64encode(s).strip('=') | ||
|
||
def b64_decode(s): | ||
pad = '=' * (-len(s) % 4) | ||
return base64.urlsafe_b64decode(s + pad) | ||
|
||
def base64_hmac(salt, value, key): | ||
return b64_encode(salted_hmac(salt, value, key).digest()) | ||
|
||
class LegacySigner(object): | ||
''' | ||
Limited functionality signer | ||
''' | ||
def __init__(self, key=None, sep=':', salt=None): | ||
self.sep = sep | ||
self.key = key or settings.SECRET_KEY | ||
self.salt = salt or ('%s.%s' % | ||
(self.__class__.__module__, self.__class__.__name__)) | ||
|
||
def signature(self, value): | ||
return base64_hmac(self.salt + 'signer', value, self.key) | ||
|
||
def sign(self, value): | ||
return '%s%s%s' % (value, self.sep, self.signature(value)) | ||
|
||
def unsign(self, signed_value): | ||
if not self.sep in signed_value: | ||
raise ValueError('No "%s" found in value' % self.sep) | ||
value, sig = signed_value.rsplit(self.sep, 1) | ||
if constant_time_compare(sig, self.signature(value)): | ||
return value | ||
raise ValueError('Signature "%s" does not match' % sig) | ||
|
||
try: | ||
from django.core.signing import Signer | ||
except ImportError: | ||
Signer = LegacySigner | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
from django.db import models | ||
|
||
from widgets import UploadifyClearableFileInput | ||
|
||
def patch_admin(): | ||
from django.contrib.admin.options import FORMFIELD_FOR_DBFIELD_DEFAULTS | ||
FORMFIELD_FOR_DBFIELD_DEFAULTS[models.ImageField] = {'widget': UploadifyClearableFileInput} | ||
FORMFIELD_FOR_DBFIELD_DEFAULTS[models.FileField] = {'widget': UploadifyClearableFileInput} | ||
|
||
patch_admin() | ||
|
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.