├── .gitignore ├── LICENSE-MIT ├── README.md ├── bootstrap-fileprogress.jquery.json ├── bower.json ├── src └── bootstrap-uploadprogress.js └── test ├── README.md ├── db.sqlite3 ├── manage.py ├── project ├── __init__.py ├── progress │ ├── __init__.py │ ├── admin.py │ ├── apps.py │ ├── forms.py │ ├── migrations │ │ ├── 0001_initial.py │ │ └── __init__.py │ ├── models.py │ ├── templates │ │ ├── base.html │ │ ├── package_form.html │ │ ├── package_form_modal.html │ │ └── package_list.html │ ├── tests.py │ ├── urls.py │ └── views.py ├── settings.py ├── urls.py └── wsgi.py └── requirements.txt /.gitignore: -------------------------------------------------------------------------------- 1 | test/components 2 | test/upload 3 | *.pyc 4 | db.sqlite3 5 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Jakob Aarøe Dam 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Bootstrap UploadProgress 2 | 3 | Bootstrap UploadProgress is a simple plugin that adds an upload progress bar to forms that upload files. This improves 4 | on most browsers that lack any progress indication of uploads. 5 | 6 | ## Getting Started, Documentation and Examples 7 | https://aarhusworks.com/2015/05/27/bootstrap-uploadprogress.html 8 | 9 | ## Bug tracker 10 | 11 | Have a bug or a feature request? [Please open a new issue](https://github.com/jakobadam/bootstrap-uploadprogress/issues). 12 | 13 | ## Copyright and license 14 | 15 | Bootstrap UploadProgress is an open source project, sponsored by [Aarhusworks](http://aarhusworks.com), and released under terms of the MIT Licence. 16 | -------------------------------------------------------------------------------- /bootstrap-fileprogress.jquery.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bootstrap-uploadprogress", 3 | "title": "Bootstrap progressbar on input file", 4 | "version": "v1.0.0", 5 | "description": "jQuery Uploadprogress for Bootstrap - Progressbar for forms with file inputs", 6 | "keywords": ["jquery", "file", "upload", "boostrap", "multiple", "input"], 7 | "homepage": "http://aarhusworks.com/bootstrap-uploadprogress/", 8 | "demo": "", 9 | "bugs": "https://github.com/jakobadam/bootstrap-uploadprogress/issues", 10 | "author": { 11 | "name": "Jakob Aarøe Dam", 12 | "url": "https://github.com/jakobadam" 13 | }, 14 | "maintainers": [ 15 | { 16 | "name": "Jakob Aarøe Dam", 17 | "url": "https://github.com/jakobadam" 18 | } 19 | ], 20 | "repository": { 21 | "type": "git", 22 | "url": "https://github.com/jakobadam/bootstrap-uploadprogress" 23 | }, 24 | "licenses": [ 25 | { 26 | "type": "MIT", 27 | "url": "http://www.opensource.org/licenses/MIT" 28 | } 29 | ], 30 | "devDependencies": { 31 | "jquery": ">=1.5" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bootstrap-uploadprogress", 3 | "version": "1.0.0", 4 | "homepage": "https://github.com/jakobadam/bootstrap-uploadprogress", 5 | "authors": [ 6 | "Jakob Aarøe Dam" 7 | ], 8 | "description": "Bootstrap Uploadprogress is a simple plugin to get an upload progressbar.", 9 | "main": "src/bootstrap-uploadprogress.js", 10 | "keywords": [ 11 | "bootstrap", 12 | "fileupload", 13 | "uploadprogress" 14 | ], 15 | "license": "MIT", 16 | "ignore": [ 17 | "**/.*", 18 | "node_modules", 19 | "bower_components", 20 | "test", 21 | "tests" 22 | ], 23 | "dependencies": { 24 | "jquery": ">=1.6" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/bootstrap-uploadprogress.js: -------------------------------------------------------------------------------- 1 | /* 2 | * bootstrap-uploadprogress 3 | * github: https://github.com/jakobadam/bootstrap-uploadprogress 4 | * 5 | * Copyright (c) 2015 Jakob Aarøe Dam 6 | * Version 1.0.0 7 | * Licensed under the MIT license. 8 | */ 9 | (function($){ 10 | "use strict"; 11 | 12 | $.support.xhrFileUpload = !!(window.FileReader && window.ProgressEvent); 13 | $.support.xhrFormData = !!window.FormData; 14 | 15 | if(!$.support.xhrFileUpload || !$.support.xhrFormData){ 16 | // skip decorating form 17 | return; 18 | } 19 | 20 | var template = ''; 42 | 43 | var Uploadprogress = function(element, options){ 44 | this.options = options; 45 | this.$element = $(element); 46 | }; 47 | 48 | Uploadprogress.prototype = { 49 | 50 | constructor: function() { 51 | this.$form = this.$element; 52 | this.$form.on('submit', $.proxy(this.submit, this)); 53 | this.$modal = $(this.options.template); 54 | this.$modal_message = this.$modal.find('.modal-message'); 55 | this.$modal_title = this.$modal.find('.modal-title'); 56 | this.$modal_footer = this.$modal.find('.modal-footer'); 57 | this.$modal_bar = this.$modal.find('.progress-bar'); 58 | 59 | this.$modal.on('hidden.bs.modal', $.proxy(this.reset, this)); 60 | }, 61 | 62 | reset: function(){ 63 | this.$modal_title = this.$modal_title.text('Uploading'); 64 | this.$modal_footer.hide(); 65 | this.$modal_bar.addClass('progress-bar-success'); 66 | this.$modal_bar.removeClass('progress-bar-danger'); 67 | if(this.xhr){ 68 | this.xhr.abort(); 69 | } 70 | }, 71 | 72 | submit: function(e) { 73 | e.preventDefault(); 74 | 75 | this.$modal.modal({ 76 | backdrop: 'static', 77 | keyboard: false 78 | }); 79 | 80 | // We need the native XMLHttpRequest for the progress event 81 | var xhr = new XMLHttpRequest(); 82 | this.xhr = xhr; 83 | 84 | xhr.addEventListener('load', $.proxy(this.success, this, xhr)); 85 | xhr.addEventListener('error', $.proxy(this.error, this, xhr)); 86 | //xhr.addEventListener('abort', function(){}); 87 | 88 | xhr.upload.addEventListener('progress', $.proxy(this.progress, this)); 89 | 90 | var form = this.$form; 91 | 92 | xhr.open(form.attr('method'), window.location.href); 93 | xhr.setRequestHeader('X-REQUESTED-WITH', 'XMLHttpRequest'); 94 | 95 | var data = new FormData(form.get(0)); 96 | xhr.send(data); 97 | }, 98 | 99 | success: function(xhr) { 100 | if(xhr.status == 0 || xhr.status >= 400){ 101 | // HTTP 500 ends up here!?! 102 | return this.error(xhr); 103 | } 104 | this.set_progress(100); 105 | var url; 106 | var content_type = xhr.getResponseHeader('Content-Type'); 107 | 108 | // make it possible to return the redirect URL in 109 | // a JSON response 110 | if(content_type.indexOf('application/json') !== -1){ 111 | var response = $.parseJSON(xhr.responseText); 112 | url = response.location; 113 | } 114 | else{ 115 | url = this.options.redirect_url; 116 | } 117 | window.location.href = url; 118 | }, 119 | 120 | // handle form error 121 | // we replace the form with the returned one 122 | error: function(xhr){ 123 | this.$modal_title.text('Upload failed'); 124 | 125 | this.$modal_bar.removeClass('progress-bar-success'); 126 | this.$modal_bar.addClass('progress-bar-danger'); 127 | this.$modal_footer.show(); 128 | 129 | var content_type = xhr.getResponseHeader('Content-Type'); 130 | 131 | // Replace the contents of the form, with the returned html 132 | if(xhr.status === 422){ 133 | var new_html = $.parseHTML(xhr.responseText); 134 | this.replace_form(new_html); 135 | this.$modal.modal('hide'); 136 | } 137 | // Write the error response to the document. 138 | else{ 139 | var response_text = xhr.responseText; 140 | if(content_type.indexOf('text/plain') !== -1){ 141 | response_text = '
' + response_text + '
'; 142 | } 143 | document.write(xhr.responseText); 144 | } 145 | }, 146 | 147 | set_progress: function(percent){ 148 | this.$modal_bar.attr('aria-valuenow', percent); 149 | this.$modal_bar.text(percent + '%'); 150 | this.$modal_bar.css('width', percent + '%'); 151 | }, 152 | 153 | progress: function(/*ProgressEvent*/e){ 154 | var percent = Math.round((e.loaded / e.total) * 100); 155 | this.set_progress(percent); 156 | }, 157 | 158 | // replace_form replaces the contents of the current form 159 | // with the form in the html argument. 160 | // We use the id of the current form to find the new form in the html 161 | replace_form: function(html){ 162 | var new_form; 163 | var form_id = this.$form.attr('id'); 164 | if(form_id !== undefined){ 165 | new_form = $(html).find('#' + form_id); 166 | } 167 | else{ 168 | new_form = $(html).find('form'); 169 | } 170 | 171 | // add the filestyle again 172 | new_form.find(':file').filestyle({buttonBefore: true}); 173 | this.$form.html(new_form.children()); 174 | } 175 | }; 176 | 177 | $.fn.uploadprogress = function(options, value){ 178 | return this.each(function(){ 179 | var _options = $.extend({}, $.fn.uploadprogress.defaults, options); 180 | var file_progress = new Uploadprogress(this, _options); 181 | file_progress.constructor(); 182 | }); 183 | }; 184 | 185 | $.fn.uploadprogress.defaults = { 186 | template: template 187 | //redirect_url: ... 188 | 189 | // need to customize stuff? Add here, and change code accordingly. 190 | }; 191 | 192 | })(window.jQuery); 193 | -------------------------------------------------------------------------------- /test/README.md: -------------------------------------------------------------------------------- 1 | # Bootstrap UploadProgress test using Django 2 | 3 | This is a test of bootstrap-uploadprogress using Django. It uses 4 | uploading of software packages -- which are usually large files -- to 5 | demonstrate the functionality. 6 | 7 | ## Getting started 8 | 9 | Install Django and friends 10 | ``` 11 | $ pip install -r requirements.txt 12 | ``` 13 | 14 | Install Javascript prerequisites 15 | ``` 16 | $ ./manange.py bower install 17 | ``` 18 | 19 | Run development server 20 | ``` 21 | $ ./manage.py runserver 22 | ``` 23 | 24 | ## Test 25 | 26 | Point browser to http://localhost:8000 27 | 28 | ``` 29 | $ firefox localhost:8080 30 | ``` 31 | 32 | Go and upload something big. 33 | -------------------------------------------------------------------------------- /test/db.sqlite3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jakobadam/bootstrap-uploadprogress/76aa8344bd914950053788879443a1d2cec5a9f9/test/db.sqlite3 -------------------------------------------------------------------------------- /test/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project.settings") 7 | try: 8 | from django.core.management import execute_from_command_line 9 | except ImportError: 10 | # The above import may fail for some other reason. Ensure that the 11 | # issue is really that Django is missing to avoid masking other 12 | # exceptions on Python 2. 13 | try: 14 | import django 15 | except ImportError: 16 | raise ImportError( 17 | "Couldn't import Django. Are you sure it's installed and " 18 | "available on your PYTHONPATH environment variable? Did you " 19 | "forget to activate a virtual environment?" 20 | ) 21 | raise 22 | execute_from_command_line(sys.argv) 23 | -------------------------------------------------------------------------------- /test/project/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jakobadam/bootstrap-uploadprogress/76aa8344bd914950053788879443a1d2cec5a9f9/test/project/__init__.py -------------------------------------------------------------------------------- /test/project/progress/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jakobadam/bootstrap-uploadprogress/76aa8344bd914950053788879443a1d2cec5a9f9/test/project/progress/__init__.py -------------------------------------------------------------------------------- /test/project/progress/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /test/project/progress/apps.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | 3 | from django.apps import AppConfig 4 | 5 | 6 | class ProgressConfig(AppConfig): 7 | name = 'progress' 8 | -------------------------------------------------------------------------------- /test/project/progress/forms.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | 3 | from models import Package 4 | 5 | def _get_widget(placeholder): 6 | return forms.TextInput(attrs={'placeholder':placeholder}) 7 | 8 | class PackageForm(forms.ModelForm): 9 | 10 | class Meta: 11 | exclude = [] 12 | model = Package 13 | widgets = { 14 | 'name': _get_widget('Enter package name') 15 | } 16 | 17 | 18 | -------------------------------------------------------------------------------- /test/project/progress/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.1 on 2016-09-13 16:02 3 | from __future__ import unicode_literals 4 | 5 | import django.core.validators 6 | from django.db import migrations, models 7 | import re 8 | 9 | 10 | class Migration(migrations.Migration): 11 | 12 | initial = True 13 | 14 | dependencies = [ 15 | ] 16 | 17 | operations = [ 18 | migrations.CreateModel( 19 | name='Package', 20 | fields=[ 21 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 22 | ('name', models.CharField(db_index=True, max_length=512, validators=[django.core.validators.RegexValidator(re.compile(b'^[-a-zA-Z0-9_() .]+$'), b'Use ASCII characters only')], verbose_name=b'Software name')), 23 | ('file', models.FileField(upload_to=b'', verbose_name=b'File')), 24 | ], 25 | options={ 26 | 'ordering': ('name',), 27 | }, 28 | ), 29 | ] 30 | -------------------------------------------------------------------------------- /test/project/progress/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jakobadam/bootstrap-uploadprogress/76aa8344bd914950053788879443a1d2cec5a9f9/test/project/progress/migrations/__init__.py -------------------------------------------------------------------------------- /test/project/progress/models.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | from django.db import models 4 | from django.core.validators import RegexValidator 5 | 6 | RE_PACKAGE_NAME = re.compile(r'^[-a-zA-Z0-9_() .]+$') 7 | 8 | class Package(models.Model): 9 | 10 | class Meta: 11 | ordering = ('name',) 12 | 13 | name = models.CharField( 14 | db_index=True, 15 | max_length=512, 16 | verbose_name='Software name', 17 | validators=[RegexValidator(RE_PACKAGE_NAME, 'Use ASCII characters only')] 18 | ) 19 | 20 | file = models.FileField( 21 | verbose_name='File' 22 | ) 23 | -------------------------------------------------------------------------------- /test/project/progress/templates/base.html: -------------------------------------------------------------------------------- 1 | {% load static %} 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | {% block page_title%}{% endblock %} | {% block site_title%}{% endblock %} 10 | 11 | 12 | 13 | 14 | 15 | 16 | 20 | 21 | 22 | {% block base_head %}{% endblock %} 23 | {% block head %}{% endblock %} 24 | 25 | 26 | 27 |
28 | 29 |
30 | {% for message in messages %} 31 |
35 | {{ message | safe }} 36 |
37 | {% endfor %} 38 |
39 | 40 |
41 | {% block body %}{% endblock %} 42 |
43 |
44 | 45 | 46 | 47 | {% block scripts %}{% endblock %} 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /test/project/progress/templates/package_form.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% load static %} 4 | {% load crispy_forms_tags %} 5 | 6 | {% block page_title%}Upload Software Package{% endblock %} 7 | 8 | {% block body %} 9 |
10 | 11 |

{% if object.id %}Update {{object}}{% else %}Upload Package{% endif %}

12 | 13 |
14 |
15 | {% csrf_token %} 16 | 17 | {{form|crispy}} 18 | 19 | 23 | 24 |
25 |
26 | 27 | Cancel 28 |
29 | {% endblock%} 30 | 31 | {% block scripts %} 32 | 33 | 34 | 35 | 41 | {% endblock %} 42 | -------------------------------------------------------------------------------- /test/project/progress/templates/package_form_modal.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% load static %} 4 | {% load crispy_forms_tags %} 5 | 6 | {% block page_title%}Upload Software Package{% endblock %} 7 | 8 | {% block body %} 9 |
10 | 11 |

{% if object.id %}Update {{object}}{% else %}Upload Package{% endif %}

12 | 13 |

Example: form inside modal

14 | 15 | 16 | 17 | 53 | 54 |
55 | 56 | 57 | {% endblock%} 58 | 59 | {% block scripts %} 60 | 61 | 62 | 63 | 77 | {% endblock %} 78 | -------------------------------------------------------------------------------- /test/project/progress/templates/package_list.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | {% load static %} 3 | 4 | {% block page_title%}Packages{% endblock %} 5 | 6 | {% block body %} 7 |
8 | 9 |

Packages

10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | {% for package in packages %} 22 | 23 | 24 | 25 | 36 | 37 | {% endfor %} 38 | 39 | 40 |
NameSizeActions
{{package.name}}{{package.file.size|filesizeformat}} 26 |
29 | {% csrf_token %} 30 | 31 | 34 |
35 |
41 | 42 |
43 | 44 |
45 | upload package 46 |
47 | 48 |
49 | 50 | {% endblock %} 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /test/project/progress/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /test/project/progress/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import url 2 | 3 | from . import views 4 | 5 | urlpatterns = [ 6 | # Examples: 7 | # url(r'^$', 'testprogress.views.home', name='home'), 8 | # url(r'^blog/', include('blog.urls')), 9 | 10 | url(r'^$', views.package_list, name='package_list'), 11 | url(r'^add/$', views.package_add, name='package_add'), 12 | url(r'^edit/(?P\d+)/$', views.package_edit, name='package_edit'), 13 | url(r'^delete/(?P\d+)/$', views.package_delete, name='package_delete'), 14 | ] 15 | -------------------------------------------------------------------------------- /test/project/progress/views.py: -------------------------------------------------------------------------------- 1 | from django import shortcuts 2 | from django import http 3 | 4 | from django.core.urlresolvers import reverse 5 | from django.views.decorators.http import require_http_methods 6 | from django.contrib import messages 7 | 8 | from .models import Package 9 | from .forms import PackageForm 10 | 11 | def package_list(request): 12 | return shortcuts.render(request, 'package_list.html', { 13 | 'packages': Package.objects.all() 14 | }) 15 | 16 | def package_add(request, instance=None): 17 | status = 200 18 | if request.method == 'POST': 19 | form = PackageForm(request.POST, request.FILES, instance=instance) 20 | 21 | if form.is_valid(): 22 | instance = form.save() 23 | messages.success(request, u'{} uploaded'.format(instance)) 24 | return http.HttpResponseRedirect(reverse('package_list')) 25 | else: 26 | status = 422 27 | else: 28 | form = PackageForm(instance=instance) 29 | 30 | return shortcuts.render(request, 'package_form.html', { 31 | 'form':form 32 | }, status=status) 33 | 34 | def package_edit(request, pk): 35 | package = shortcuts.get_object_or_404(Package, pk=pk) 36 | return package_add(request, instance=package) 37 | 38 | @require_http_methods(['POST']) 39 | def package_delete(request, pk): 40 | package = shortcuts.get_object_or_404(Package, pk=pk) 41 | package.delete() 42 | messages.info(request, 'Deleted {}'.format(package)) 43 | return http.HttpResponseRedirect(reverse('package_list')) 44 | 45 | -------------------------------------------------------------------------------- /test/project/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for progress project. 3 | 4 | Generated by 'django-admin startproject' using Django 1.10.1. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.10/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/1.10/ref/settings/ 11 | """ 12 | 13 | import os 14 | 15 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 16 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 17 | 18 | 19 | # Quick-start development settings - unsuitable for production 20 | # See https://docs.djangoproject.com/en/1.10/howto/deployment/checklist/ 21 | 22 | # SECURITY WARNING: keep the secret key used in production secret! 23 | SECRET_KEY = '!#s%vt0m5z801g5#i^^ov(y#y*j&&h04(zg^o(817i-o4t=bk6' 24 | 25 | # SECURITY WARNING: don't run with debug turned on in production! 26 | DEBUG = True 27 | 28 | ALLOWED_HOSTS = [] 29 | 30 | 31 | # Application definition 32 | 33 | INSTALLED_APPS = [ 34 | 'django.contrib.admin', 35 | 'django.contrib.auth', 36 | 'django.contrib.contenttypes', 37 | 'django.contrib.sessions', 38 | 'django.contrib.messages', 39 | 'django.contrib.staticfiles', 40 | 41 | 'crispy_forms', 42 | 'djangobower', 43 | 44 | 'project.progress' 45 | 46 | ] 47 | 48 | 49 | MIDDLEWARE_CLASSES = [ 50 | 'django.middleware.security.SecurityMiddleware', 51 | 'django.contrib.sessions.middleware.SessionMiddleware', 52 | 'django.middleware.common.CommonMiddleware', 53 | 'django.middleware.csrf.CsrfViewMiddleware', 54 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 55 | 'django.contrib.messages.middleware.MessageMiddleware', 56 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 57 | ] 58 | 59 | MIDDLEWARE = [ 60 | 'django.contrib.sessions.middleware.SessionMiddleware', 61 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 62 | 'django.contrib.messages.middleware.MessageMiddleware', 63 | ] 64 | 65 | ROOT_URLCONF = 'project.urls' 66 | 67 | TEMPLATES = [ 68 | { 69 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 70 | 'DIRS': [], 71 | 'APP_DIRS': True, 72 | 'OPTIONS': { 73 | 'context_processors': [ 74 | 'django.template.context_processors.debug', 75 | 'django.template.context_processors.request', 76 | 'django.contrib.auth.context_processors.auth', 77 | 'django.contrib.messages.context_processors.messages', 78 | ], 79 | }, 80 | }, 81 | ] 82 | 83 | WSGI_APPLICATION = 'project.wsgi.application' 84 | 85 | 86 | # Database 87 | # https://docs.djangoproject.com/en/1.10/ref/settings/#databases 88 | 89 | DATABASES = { 90 | 'default': { 91 | 'ENGINE': 'django.db.backends.sqlite3', 92 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 93 | } 94 | } 95 | 96 | 97 | # Password validation 98 | # https://docs.djangoproject.com/en/1.10/ref/settings/#auth-password-validators 99 | 100 | AUTH_PASSWORD_VALIDATORS = [ 101 | { 102 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 103 | }, 104 | { 105 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 106 | }, 107 | { 108 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 109 | }, 110 | { 111 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 112 | }, 113 | ] 114 | 115 | 116 | # Internationalization 117 | # https://docs.djangoproject.com/en/1.10/topics/i18n/ 118 | 119 | LANGUAGE_CODE = 'en-us' 120 | 121 | TIME_ZONE = 'UTC' 122 | 123 | USE_I18N = True 124 | 125 | USE_L10N = True 126 | 127 | USE_TZ = True 128 | 129 | 130 | # Static files (CSS, JavaScript, Images) 131 | # https://docs.djangoproject.com/en/1.10/howto/static-files/ 132 | 133 | STATIC_URL = '/static/' 134 | 135 | CRISPY_TEMPLATE_PACK = 'bootstrap3' 136 | BOWER_INSTALLED_APPS = ( 137 | 'bootstrap#3.3', 138 | 'html5shiv', 139 | 'respond', 140 | 'bootstrap-filestyle', 141 | # 'bootstrap-uploadprogress' # Use this in production. 142 | ) 143 | # For bootstrap-uploadprogress.js 144 | STATICFILES_DIRS = ( 145 | "../..", 146 | ) 147 | 148 | BOWER_COMPONENTS_ROOT = os.path.join(BASE_DIR, 'components') 149 | MEDIA_ROOT = os.path.join(BASE_DIR, 'upload') 150 | 151 | STATICFILES_FINDERS = ( 152 | 'django.contrib.staticfiles.finders.FileSystemFinder', 153 | 'django.contrib.staticfiles.finders.AppDirectoriesFinder', 154 | 'djangobower.finders.BowerFinder', 155 | ) 156 | -------------------------------------------------------------------------------- /test/project/urls.py: -------------------------------------------------------------------------------- 1 | """progress URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/1.10/topics/http/urls/ 5 | Examples: 6 | Function views 7 | 1. Add an import: from my_app import views 8 | 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') 9 | Class-based views 10 | 1. Add an import: from other_app.views import Home 11 | 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.conf.urls import url, include 14 | 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) 15 | """ 16 | from django.conf.urls import url, include 17 | from django.contrib import admin 18 | 19 | urlpatterns = [ 20 | url(r'^admin/', admin.site.urls), 21 | url(r'', include('project.progress.urls')) 22 | ] 23 | -------------------------------------------------------------------------------- /test/project/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for progress project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.10/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project.settings") 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /test/requirements.txt: -------------------------------------------------------------------------------- 1 | Django==2.2.8 2 | django-bower 3 | django-crispy-forms 4 | six 5 | --------------------------------------------------------------------------------