Skip to content

Commit ce3784e

Browse files
committed
Major refactoring
- Added python3 support - Added selenium tests - Added py.test tests - Added travis-ci - Added coveralls - Added testapp - Removed jQuery dependency - Removed uploader dependency
1 parent 6b8b7b4 commit ce3784e

26 files changed

+636
-2459
lines changed

.travis.yml

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,35 @@
11
language: python
2+
sudo: false
23
python:
3-
- "2.6"
4-
- "2.7"
5-
- "3.2"
6-
- "3.3"
7-
- "3.4"
4+
- "2.6"
5+
- "2.7"
6+
- "3.3"
7+
- "3.4"
8+
- "pypy"
9+
- "pypy3"
810
env:
9-
- DJANGO=1.5.11
10-
- DJANGO=1.6.8
11-
- DJANGO=1.7.1
11+
global:
12+
- DISPLAY=:99.0
13+
matrix:
14+
- DJANGO="<1.6,>=1.5"
15+
- DJANGO="<1.7,>=1.6"
16+
- DJANGO="<1.8,>=1.7"
17+
- DJANGO="<1.9,>=1.8"
18+
1219
matrix:
13-
exclude:
20+
allow_failures:
21+
- env: DJANGO="<1.6,>=1.5"
22+
- env: DJANGO="<1.7,>=1.6"
1423
- python: "2.6"
15-
env: DJANGO=1.7.1
24+
- python: "3.2"
1625
install:
17-
- pip install Django==$DJANGO --use-mirrors
18-
- pip install pytest pytest-pep8 pytest-flakes django-pytest --use-mirrors
19-
- pip install -r requirements.txt --use-mirrors
26+
- pip install --upgrade pip
27+
- pip install .
28+
- pip install Django$DJANGO
29+
- pip install pytest pytest-pep8 pytest-flakes pytest-django selenium
30+
- pip install coveralls
31+
- sh -e /etc/init.d/xvfb start
2032
script:
21-
- python setup.py test
33+
coverage run --source=s3file runtests.py
34+
after_success:
35+
coveralls

README.md

Lines changed: 121 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,122 @@
1-
django-s3file
2-
=============
1+
# django-s3file
32

4-
A lightweight file upload input for Django and Amazon S3
3+
A lightweight file upload input for Django and Amazon S3.
4+
5+
[![Build Status](https://travis-ci.org/codingjoe/django-s3file.svg?branch=master)](https://travis-ci.org/codingjoe/django-s3file)
6+
[![Test Coverage](https://coveralls.io/repos/codingjoe/django-s3file/badge.png?branch=master)](https://coveralls.io/r/codingjoe/django-s3file)
7+
[![Code health](https://scrutinizer-ci.com/g/codingjoe/django-s3file/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/codingjoe/django-s3file/?branch=master)
8+
9+
10+
## Features
11+
12+
- Pure JavaScript (no jQuery)
13+
- Python 2 and 3 support
14+
- Auto swapping based on your environment
15+
- Pluggable as it returns a simple django file, just like native input
16+
- Easily extensible (authentication, styles)
17+
18+
19+
## Installation
20+
21+
Just install S3file using `pip` or `easy_install`.
22+
```bash
23+
pip install django-s3file
24+
```
25+
Don't forget to add `s3file` to the `INSTALLED_APPS`.
26+
27+
28+
## Usage
29+
30+
### Simple integrations
31+
32+
Include s3file's URLs in your URL root.
33+
34+
**urls.py**
35+
```python
36+
urlpatterns = patterns(
37+
...
38+
url(r'^s3file/', include('s3file.urls')),
39+
)
40+
```
41+
42+
**forms.py**
43+
```python
44+
from s3file.forms import AutoFileInput
45+
46+
class MyModelForm(forms.ModelForm):
47+
48+
class Meta:
49+
model = MyModel
50+
fields = ('my_file_field')
51+
widgets = {
52+
'my_file_field': AutoFileInput
53+
}
54+
```
55+
**Done!** No really, that's all that needs to be done.
56+
57+
58+
### Setting up the CORS policy on your AWS S3 Bucket
59+
60+
```xml
61+
<CORSConfiguration>
62+
<CORSRule>
63+
<AllowedOrigin>*</AllowedOrigin>
64+
<AllowedMethod>PUT</AllowedMethod>
65+
<AllowedMethod>POST</AllowedMethod>
66+
<AllowedMethod>GET</AllowedMethod>
67+
<MaxAgeSeconds>3000</MaxAgeSeconds>
68+
<AllowedHeader>*</AllowedHeader>
69+
</CORSRule>
70+
</CORSConfiguration>
71+
```
72+
73+
74+
### Advanced usage examples
75+
76+
#### Authentication
77+
The signing endpoint supports CSRF by default but does not require a authenticated user.
78+
This and other behavior can be easily added by inheriting from the view.
79+
80+
**views.py**
81+
```python
82+
from s3file.views import S3FileView
83+
from braces.views import LoginRequiredMixin
84+
85+
class MyS3FileView(LoginRequiredMixin, S3FileView):
86+
pass
87+
```
88+
89+
Now don't forget to change the URLs.
90+
91+
**urls.py**
92+
```python
93+
urlpatterns = patterns(
94+
...
95+
url('^s3file/sign',
96+
MyS3FileView.as_view(), name='s3file-sign'),
97+
)
98+
```
99+
100+
## License
101+
102+
The MIT License (MIT)
103+
104+
Copyright (c) 2014 Johannes Hoppe
105+
106+
Permission is hereby granted, free of charge, to any person obtaining a copy
107+
of this software and associated documentation files (the "Software"), to deal
108+
in the Software without restriction, including without limitation the rights
109+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
110+
copies of the Software, and to permit persons to whom the Software is
111+
furnished to do so, subject to the following conditions:
112+
113+
The above copyright notice and this permission notice shall be included in all
114+
copies or substantial portions of the Software.
115+
116+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
117+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
118+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
119+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
120+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
121+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
122+
SOFTWARE.

pytest.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
[pytest]
22
norecursedirs=env vendor
33
addopts = --tb=short --pep8 --flakes -rxs
4+
DJANGO_SETTINGS_MODULE=tests.testapp.settings
45
pep8maxlinelength=99
56
pep8ignore=
67
setup.py ALL

runtests.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3017,10 +3017,11 @@
30173017
mH1szWdxTVmKQB+pisiXvm43FLwGlW0kHFWj8Pfe+/9+GP1/axf19w==
30183018
"""
30193019

3020-
import sys
30213020
import base64
3021+
import sys
30223022
import zlib
30233023

3024+
30243025
class DictImporter(object):
30253026
def __init__(self, sources):
30263027
self.sources = sources

s3file/forms.py

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
11
# -*- coding:utf-8 -*-
2-
from __future__ import (unicode_literals)
2+
from __future__ import unicode_literals
33

44
import logging
55
import os
66

77
from django.conf import settings
8-
98
from django.core.files import File
10-
from django.forms.widgets import ClearableFileInput
119
from django.core.files.storage import default_storage
12-
from django.utils.safestring import mark_safe
1310
from django.core.urlresolvers import reverse_lazy
11+
from django.forms.widgets import ClearableFileInput
12+
from django.utils.encoding import force_text
13+
from django.utils.safestring import mark_safe
1414

15-
16-
logger = logging.getLogger(__name__)
15+
logger = logging.getLogger('s3file')
1716

1817

1918
class S3FileInput(ClearableFileInput):
@@ -23,14 +22,15 @@ class S3FileInput(ClearableFileInput):
2322
needs_multipart_form = False
2423
signing_url = reverse_lazy('s3file-sign')
2524
template = (
26-
'<div class="s3file" data-url="{signing_url}" data-target="{element_id}">\n'
27-
' <a class="link" target="_blank" href="{file_url}">{file_name}</a>\n'
28-
' <a class="remove" href="javascript: void(0)">{remove}</a>\n'
29-
' <input type="hidden" value="{value}" id="{element_id}" name="{name}" />\n'
30-
' <input type="file" class="fileinput" id="s3-{element_id}" />\n'
31-
' <div class="progress progress-striped active">\n'
32-
' <div class="progress-bar"></div>\n'
33-
' </div>\n'
25+
'<div class="s3file" data-policy-url="{policy_url}">'
26+
' <a class="file-link" target="_blank" href="{file_url}">{file_name}</a>'
27+
' <a class="file-remove" href="#remove">Remove</a>'
28+
' <input class="file-url" type="hidden" value="{file_url}"'
29+
' id="{element_id}" name="{name}" />'
30+
' <input class="file-input" type="file" />'
31+
' <div class="progress progress-striped active">'
32+
' <div class="bar"></div>'
33+
' </div>'
3434
'</div>'
3535
)
3636

@@ -51,13 +51,13 @@ def render(self, name, value, attrs=None):
5151
input_value = ''
5252

5353
output = self.template.format(
54-
signing_url=self.signing_url,
54+
policy_url=self.signing_url,
5555
file_url=file_url,
5656
file_name=file_name,
5757
element_id=element_id or '',
5858
name=name,
5959
value=input_value,
60-
remove=unicode(self.clear_checkbox_label)
60+
remove=force_text(self.clear_checkbox_label)
6161
)
6262

6363
return mark_safe(output)
@@ -77,10 +77,8 @@ def value_from_datadict(self, data, files, name):
7777

7878
class Media:
7979
js = (
80-
's3file/js/jquery.iframe-transport.js',
81-
's3file/js/jquery.ui.widget.js',
82-
's3file/js/jquery.fileupload.js',
8380
's3file/js/s3file.js',
81+
8482
)
8583
css = {
8684
'all': (
@@ -90,6 +88,16 @@ class Media:
9088

9189

9290
def AutoFileInput(*args, **kwargs):
91+
"""
92+
A factory method that returns ether an instance of S3FileInput
93+
of ClearableFileInput depending on whether or not the S3 Key is
94+
set in django.config.settings.
95+
:
96+
Settings example:
97+
AWS_SECRET_ACCESS_KEY='asdf'
98+
:
99+
:return: S3FileInput, django.forms.ClearableFileInput
100+
"""
93101
if hasattr(settings, 'AWS_SECRET_ACCESS_KEY') \
94102
and settings.AWS_SECRET_ACCESS_KEY:
95103
return S3FileInput(*args, **kwargs)

0 commit comments

Comments
 (0)