├── store ├── __init__.py ├── migrations │ ├── __init__.py │ ├── __pycache__ │ │ ├── __init__.cpython-35.pyc │ │ ├── 0001_initial.cpython-35.pyc │ │ └── 0002_auto_20181127_1233.cpython-35.pyc │ ├── 0002_auto_20181127_1233.py │ └── 0001_initial.py ├── tests.py ├── urls.py ├── apps.py ├── __pycache__ │ ├── admin.cpython-35.pyc │ ├── apis.cpython-35.pyc │ ├── forms.cpython-35.pyc │ ├── tasks.cpython-35.pyc │ ├── views.cpython-35.pyc │ ├── __init__.cpython-35.pyc │ ├── consts.cpython-35.pyc │ ├── models.cpython-35.pyc │ └── serializers.cpython-35.pyc ├── consts.py ├── admin.py ├── templates │ ├── store │ │ ├── signin.html │ │ ├── store_signup.html │ │ ├── create_task.html │ │ ├── store_accunt.html │ │ ├── base_signup.html │ │ ├── base.html │ │ └── tasks.html │ ├── deliver │ │ ├── signin.html │ │ ├── delivery_boy_signup.html │ │ ├── store_signup.html │ │ ├── store_accunt.html │ │ ├── delivery_boy_account.html │ │ ├── base_signup.html │ │ ├── base.html │ │ └── tasks.html │ ├── base.html │ ├── base_signup.html │ ├── custom_404_view.html │ └── celery.html ├── serializers.py ├── consumers.py ├── tasks.py ├── forms.py ├── models.py ├── apis.py └── views.py ├── runtime.txt ├── Procfile ├── db.sqlite3 ├── static ├── images │ ├── res.jpg │ ├── exam.jpg │ ├── Screenshot from 2018-11-27 17-24-59.png │ ├── Screenshot from 2018-11-27 17-25-19.png │ ├── Screenshot from 2018-11-27 17-25-38.png │ ├── Screenshot from 2018-11-27 17-26-27.png │ ├── Screenshot from 2018-11-27 17-26-48.png │ └── Screenshot from 2018-11-27 17-49-34.png ├── font │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.ttf │ ├── glyphicons-halflings-regular.woff │ └── glyphicons-halflings-regular.woff2 ├── fonts │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.ttf │ ├── glyphicons-halflings-regular.woff │ └── glyphicons-halflings-regular.woff2 ├── js │ ├── npm.js │ ├── index.js │ ├── reconnecting-websocket.min.js │ ├── validate.js │ └── bootstrap.min.js └── css │ ├── style.css │ ├── bootstrap-theme.min.css.map │ ├── bootstrap-theme.min.css │ └── bootstrap-theme.css ├── delivery ├── __pycache__ │ ├── asgi.cpython-35.pyc │ ├── urls.cpython-35.pyc │ ├── wsgi.cpython-35.pyc │ ├── celery.cpython-35.pyc │ ├── routing.cpython-35.pyc │ ├── __init__.cpython-35.pyc │ └── settings.cpython-35.pyc ├── __init__.py ├── routing.py ├── celery.py ├── asgi.py ├── wsgi.py ├── urls.py ├── settings.py.save └── settings.py ├── req.txt ├── requirements.txt ├── templates ├── store │ ├── task_details.html │ ├── signin.html │ ├── signup.html │ ├── store_account.html │ ├── base_signup.html │ ├── task.html │ └── base.html ├── deliver │ ├── signin.html │ ├── delivery_boy_signup.html │ ├── delivery_boy_account.html │ ├── base_signup.html │ ├── base.html │ └── tasks.html ├── registration │ ├── login.html │ ├── signup.html │ ├── store_accunt.html │ ├── base_signup.html │ ├── base.html │ └── task.html ├── base.html └── base_signup.html ├── manage.py └── README.md /store/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /runtime.txt: -------------------------------------------------------------------------------- 1 | python-3.6.7 2 | -------------------------------------------------------------------------------- /store/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: gunicorn delivery.wsgi --log-file- 2 | -------------------------------------------------------------------------------- /db.sqlite3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs1278/delivery/HEAD/db.sqlite3 -------------------------------------------------------------------------------- /store/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /static/images/res.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs1278/delivery/HEAD/static/images/res.jpg -------------------------------------------------------------------------------- /static/images/exam.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs1278/delivery/HEAD/static/images/exam.jpg -------------------------------------------------------------------------------- /store/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import url, inlcude 2 | from rest_framework import routers 3 | 4 | -------------------------------------------------------------------------------- /store/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class StoreConfig(AppConfig): 5 | name = 'store' 6 | -------------------------------------------------------------------------------- /store/__pycache__/admin.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs1278/delivery/HEAD/store/__pycache__/admin.cpython-35.pyc -------------------------------------------------------------------------------- /store/__pycache__/apis.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs1278/delivery/HEAD/store/__pycache__/apis.cpython-35.pyc -------------------------------------------------------------------------------- /store/__pycache__/forms.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs1278/delivery/HEAD/store/__pycache__/forms.cpython-35.pyc -------------------------------------------------------------------------------- /store/__pycache__/tasks.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs1278/delivery/HEAD/store/__pycache__/tasks.cpython-35.pyc -------------------------------------------------------------------------------- /store/__pycache__/views.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs1278/delivery/HEAD/store/__pycache__/views.cpython-35.pyc -------------------------------------------------------------------------------- /delivery/__pycache__/asgi.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs1278/delivery/HEAD/delivery/__pycache__/asgi.cpython-35.pyc -------------------------------------------------------------------------------- /delivery/__pycache__/urls.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs1278/delivery/HEAD/delivery/__pycache__/urls.cpython-35.pyc -------------------------------------------------------------------------------- /delivery/__pycache__/wsgi.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs1278/delivery/HEAD/delivery/__pycache__/wsgi.cpython-35.pyc -------------------------------------------------------------------------------- /store/__pycache__/__init__.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs1278/delivery/HEAD/store/__pycache__/__init__.cpython-35.pyc -------------------------------------------------------------------------------- /store/__pycache__/consts.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs1278/delivery/HEAD/store/__pycache__/consts.cpython-35.pyc -------------------------------------------------------------------------------- /store/__pycache__/models.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs1278/delivery/HEAD/store/__pycache__/models.cpython-35.pyc -------------------------------------------------------------------------------- /delivery/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | from .celery import app as celery_app 3 | 4 | __all__ = ['celery_app'] -------------------------------------------------------------------------------- /delivery/__pycache__/celery.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs1278/delivery/HEAD/delivery/__pycache__/celery.cpython-35.pyc -------------------------------------------------------------------------------- /delivery/__pycache__/routing.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs1278/delivery/HEAD/delivery/__pycache__/routing.cpython-35.pyc -------------------------------------------------------------------------------- /delivery/__pycache__/__init__.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs1278/delivery/HEAD/delivery/__pycache__/__init__.cpython-35.pyc -------------------------------------------------------------------------------- /delivery/__pycache__/settings.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs1278/delivery/HEAD/delivery/__pycache__/settings.cpython-35.pyc -------------------------------------------------------------------------------- /static/font/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs1278/delivery/HEAD/static/font/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /static/font/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs1278/delivery/HEAD/static/font/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /static/font/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs1278/delivery/HEAD/static/font/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /static/font/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs1278/delivery/HEAD/static/font/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /static/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs1278/delivery/HEAD/static/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /static/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs1278/delivery/HEAD/static/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /static/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs1278/delivery/HEAD/static/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /store/__pycache__/serializers.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs1278/delivery/HEAD/store/__pycache__/serializers.cpython-35.pyc -------------------------------------------------------------------------------- /static/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs1278/delivery/HEAD/static/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /store/consts.py: -------------------------------------------------------------------------------- 1 | validation_messages = { 2 | "DUPLICATE_STORE": "Duplicate store found", 3 | "DUPLICATE_NUMBER": "Duplicate Number found", 4 | } -------------------------------------------------------------------------------- /static/images/Screenshot from 2018-11-27 17-24-59.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs1278/delivery/HEAD/static/images/Screenshot from 2018-11-27 17-24-59.png -------------------------------------------------------------------------------- /static/images/Screenshot from 2018-11-27 17-25-19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs1278/delivery/HEAD/static/images/Screenshot from 2018-11-27 17-25-19.png -------------------------------------------------------------------------------- /static/images/Screenshot from 2018-11-27 17-25-38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs1278/delivery/HEAD/static/images/Screenshot from 2018-11-27 17-25-38.png -------------------------------------------------------------------------------- /static/images/Screenshot from 2018-11-27 17-26-27.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs1278/delivery/HEAD/static/images/Screenshot from 2018-11-27 17-26-27.png -------------------------------------------------------------------------------- /static/images/Screenshot from 2018-11-27 17-26-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs1278/delivery/HEAD/static/images/Screenshot from 2018-11-27 17-26-48.png -------------------------------------------------------------------------------- /static/images/Screenshot from 2018-11-27 17-49-34.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs1278/delivery/HEAD/static/images/Screenshot from 2018-11-27 17-49-34.png -------------------------------------------------------------------------------- /store/migrations/__pycache__/__init__.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs1278/delivery/HEAD/store/migrations/__pycache__/__init__.cpython-35.pyc -------------------------------------------------------------------------------- /store/migrations/__pycache__/0001_initial.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs1278/delivery/HEAD/store/migrations/__pycache__/0001_initial.cpython-35.pyc -------------------------------------------------------------------------------- /store/migrations/__pycache__/0002_auto_20181127_1233.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bs1278/delivery/HEAD/store/migrations/__pycache__/0002_auto_20181127_1233.cpython-35.pyc -------------------------------------------------------------------------------- /req.txt: -------------------------------------------------------------------------------- 1 | Django 2 | gunicorn==19.6.0 3 | whitenoise==3.2.1 4 | dj-database-url==0.4.1 5 | djangorestframework 6 | django-rest-framework-social-oauth2==1.0.4 7 | django-bootstrap3==7.0.1 8 | celery==3.1.23 9 | 10 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Django 2 | gunicorn==19.6.0 3 | whitenoise==3.2.1 4 | dj-database-url==0.4.1 5 | djangorestframework 6 | django-rest-framework-social-oauth2==1.0.4 7 | django-bootstrap3==7.0.1 8 | celery==3.1.23 9 | 10 | -------------------------------------------------------------------------------- /store/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from store.models import Store, Task,DeliveryBoy 3 | # Register your models here. 4 | 5 | 6 | admin.site.register(Store) 7 | admin.site.register(Task) 8 | admin.site.register(DeliveryBoy) -------------------------------------------------------------------------------- /delivery/routing.py: -------------------------------------------------------------------------------- 1 | from channels import route 2 | from store import consumers 3 | 4 | ASGI_APPLICATION = "delivery.asgi.application" 5 | 6 | channel_routing = [ 7 | # websocket channels to store consumers 8 | 9 | route("websocket.connect", consumers.ws_connect), 10 | route("websocket.receive", consumers.ws_receive), 11 | ] -------------------------------------------------------------------------------- /delivery/celery.py: -------------------------------------------------------------------------------- 1 | import os 2 | from celery import Celery 3 | from django.conf import settings 4 | 5 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'delivery.settings') 6 | 7 | app = Celery('delivery') 8 | app.config_from_object('django.conf:settings') 9 | app.autodiscover_tasks(lambda: settings.INSTALLED_APPS) 10 | 11 | @app.task(bind=True) 12 | def debug_task(self): 13 | print('Request: {!r}'.format(self.request)) -------------------------------------------------------------------------------- /templates/store/task_details.html: -------------------------------------------------------------------------------- 1 | {% extends 'store/base.html' %} 2 | {% load bootstrap3 %} 3 | 4 | {% block page %} 5 |
6 |
7 |
8 |

9 | TASK DETAILS 10 |

11 |
12 |
13 | 14 |
15 |
16 |
17 | {% endblock%} 18 | -------------------------------------------------------------------------------- /delivery/asgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | Author: Bala 3 | DEscription:ASGI entrypoint file for default channel layer. 4 | Points to the channel layer configured as "default" so you can point 5 | ASGI applications at "liveblog.asgi:channel_layer" as their channel layer. 6 | """ 7 | 8 | 9 | import os 10 | from channels.asgi import get_channel_layer 11 | 12 | os.environ.setdefault("DJANGO_SETTING_MODULE", "delivery.settings") 13 | channel_layer = get_channel_layer() 14 | 15 | -------------------------------------------------------------------------------- /templates/store/signin.html: -------------------------------------------------------------------------------- 1 | {% extends 'base_signup.html' %} 2 | {% load bootstrap3 %} 3 | 4 | {% block title %}Sign In{% endblock %} 5 | {% block heading %}Store - Sign In{% endblock %} 6 | 7 | {% block content %} 8 |
9 | {% csrf_token %} 10 | {% bootstrap_form form %} 11 | 12 |
13 | 14 | Become a Store 15 | {% endblock %} 16 | -------------------------------------------------------------------------------- /store/templates/store/signin.html: -------------------------------------------------------------------------------- 1 | {% extends 'base_signup.html' %} 2 | {% load bootstrap3 %} 3 | 4 | {% block title %}Sign In{% endblock %} 5 | {% block heading %}Store - Sign In{% endblock %} 6 | 7 | {% block content %} 8 |
9 | {% csrf_token %} 10 | {% bootstrap_form form %} 11 | 12 |
13 | 14 | Become a Store 15 | {% endblock %} 16 | -------------------------------------------------------------------------------- /templates/deliver/signin.html: -------------------------------------------------------------------------------- 1 | {% extends 'base_signup.html' %} 2 | {% load bootstrap3 %} 3 | 4 | {% block title %}Sign In{% endblock %} 5 | {% block heading %}Delivery Boy - Sign In{% endblock %} 6 | 7 | {% block content %} 8 |
9 | {% csrf_token %} 10 | {% bootstrap_form form %} 11 | 12 |
13 | 14 | Become a Delivery Boy 15 | {% endblock %} 16 | -------------------------------------------------------------------------------- /templates/registration/login.html: -------------------------------------------------------------------------------- 1 | {% extends 'base_signup.html' %} 2 | {% load bootstrap3 %} 3 | 4 | {% block title %}Sign In{% endblock %} 5 | {% block heading %}Delivery- Sign In{% endblock %} 6 | 7 | {% block content %} 8 |
9 | {% csrf_token %} 10 | {% bootstrap_form form %} 11 | 12 |
13 | 14 | 15 | {% endblock %} 16 | -------------------------------------------------------------------------------- /store/templates/deliver/signin.html: -------------------------------------------------------------------------------- 1 | {% extends 'base_signup.html' %} 2 | {% load bootstrap3 %} 3 | 4 | {% block title %}Sign In{% endblock %} 5 | {% block heading %}Delivery Boy - Sign In{% endblock %} 6 | 7 | {% block content %} 8 |
9 | {% csrf_token %} 10 | {% bootstrap_form form %} 11 | 12 |
13 | 14 | Become a Delivery Boy 15 | {% endblock %} 16 | -------------------------------------------------------------------------------- /static/js/npm.js: -------------------------------------------------------------------------------- 1 | // This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment. 2 | require('../../js/transition.js') 3 | require('../../js/alert.js') 4 | require('../../js/button.js') 5 | require('../../js/carousel.js') 6 | require('../../js/collapse.js') 7 | require('../../js/dropdown.js') 8 | require('../../js/modal.js') 9 | require('../../js/tooltip.js') 10 | require('../../js/popover.js') 11 | require('../../js/scrollspy.js') 12 | require('../../js/tab.js') 13 | require('../../js/affix.js') -------------------------------------------------------------------------------- /delivery/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for delivery 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.11/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | # from whitenoise.django import DjangoWhiteNoise 14 | 15 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "delivery.settings") 16 | 17 | application = get_wsgi_application() 18 | #application = DjangoWhiteNoise(application) 19 | -------------------------------------------------------------------------------- /templates/deliver/delivery_boy_signup.html: -------------------------------------------------------------------------------- 1 | {% extends 'base_signup.html' %} 2 | {% load bootstrap3 %} 3 | 4 | {% block title %}Sign In{% endblock %} 5 | {% block heading %}Delivery Boy - Sign In{% endblock %} 6 | 7 | {% block content %} 8 |
9 | {% csrf_token %} 10 | {% bootstrap_form user_form %} 11 | {% bootstrap_form delivery_boy_form %} 12 | 13 |
14 | Already have an account? 15 | {% endblock %} 16 | -------------------------------------------------------------------------------- /store/templates/deliver/delivery_boy_signup.html: -------------------------------------------------------------------------------- 1 | {% extends 'base_signup.html' %} 2 | {% load bootstrap3 %} 3 | 4 | {% block title %}Sign In{% endblock %} 5 | {% block heading %}Delivery Boy - Sign In{% endblock %} 6 | 7 | {% block content %} 8 |
9 | {% csrf_token %} 10 | {% bootstrap_form user_form %} 11 | {% bootstrap_form delivery_boy_form %} 12 | 13 |
14 | Already have an account? 15 | {% endblock %} 16 | -------------------------------------------------------------------------------- /templates/store/signup.html: -------------------------------------------------------------------------------- 1 | {% extends 'base_signup.html' %} 2 | {% load bootstrap3 %} 3 | 4 | {% block title %}Sign In{% endblock %} 5 | {% block heading %}Store - Sign In{% endblock %} 6 | 7 | {% block content %} 8 |
9 | {% csrf_token %} 10 | {% bootstrap_form user_form %} 11 | {% bootstrap_form store_form %} 12 | 13 | {{ restaurant_form }} 14 | 15 |
16 | 17 | Already have an account? 18 | {% endblock %} 19 | -------------------------------------------------------------------------------- /templates/registration/signup.html: -------------------------------------------------------------------------------- 1 | {% extends 'base_signup.html' %} 2 | {% load bootstrap3 %} 3 | 4 | {% block title %}Sign In{% endblock %} 5 | {% block heading %}Store - Sign In{% endblock %} 6 | 7 | {% block content %} 8 |
9 | {% csrf_token %} 10 | {% bootstrap_form user_form %} 11 | {% bootstrap_form store_form %} 12 | 13 | {{ restaurant_form }} 14 | 15 |
16 | 17 | Already have an account? 18 | {% endblock %} 19 | -------------------------------------------------------------------------------- /store/templates/store/store_signup.html: -------------------------------------------------------------------------------- 1 | {% extends 'base_signup.html' %} 2 | {% load bootstrap3 %} 3 | 4 | {% block title %}Sign In{% endblock %} 5 | {% block heading %}Store - Sign In{% endblock %} 6 | 7 | {% block content %} 8 |
9 | {% csrf_token %} 10 | {% bootstrap_form user_form %} 11 | {% bootstrap_form store_form %} 12 | 13 | {{ restaurant_form }} 14 | 15 |
16 | 17 | Already have an account? 18 | {% endblock %} 19 | -------------------------------------------------------------------------------- /store/templates/deliver/store_signup.html: -------------------------------------------------------------------------------- 1 | {% extends 'base_signup.html' %} 2 | {% load bootstrap3 %} 3 | 4 | {% block title %}Sign In{% endblock %} 5 | {% block heading %}Delivery Boy - Sign In{% endblock %} 6 | 7 | {% block content %} 8 |
9 | {% csrf_token %} 10 | {% bootstrap_form user_form %} 11 | {% bootstrap_form delivery_boy_form %} 12 | 13 | {{ delivery_boy_form }} 14 | 15 |
16 | 17 | Already have an account? 18 | {% endblock %} 19 | -------------------------------------------------------------------------------- /store/templates/store/create_task.html: -------------------------------------------------------------------------------- 1 | {% extends 'store/base.html' %} 2 | {% load bootstrap3 %} 3 | 4 | {% block page %} 5 |
6 |
7 |
8 |

9 | Account 10 |

11 |
12 |
13 |
14 | {% csrf_token %} 15 | {% bootstrap_form task_form %} 16 | 17 | 18 |
19 |
20 |
21 |
22 | {% endblock%} 23 | -------------------------------------------------------------------------------- /templates/store/store_account.html: -------------------------------------------------------------------------------- 1 | {% extends 'store/base.html' %} 2 | {% load bootstrap3 %} 3 | 4 | {% block page %} 5 |
6 |
7 |
8 |

9 | Account 10 |

11 |
12 |
13 |
14 | {% csrf_token %} 15 | {% bootstrap_form user_form %} 16 | {% bootstrap_form store_form %} 17 | 18 | 19 |
20 |
21 |
22 |
23 | {% endblock%} 24 | -------------------------------------------------------------------------------- /store/templates/store/store_accunt.html: -------------------------------------------------------------------------------- 1 | {% extends 'store/base.html' %} 2 | {% load bootstrap3 %} 3 | 4 | {% block page %} 5 |
6 |
7 |
8 |

9 | Account 10 |

11 |
12 |
13 |
14 | {% csrf_token %} 15 | {% bootstrap_form user_form %} 16 | {% bootstrap_form store_form %} 17 | 18 | 19 |
20 |
21 |
22 |
23 | {% endblock%} 24 | -------------------------------------------------------------------------------- /templates/registration/store_accunt.html: -------------------------------------------------------------------------------- 1 | {% extends 'store/base.html' %} 2 | {% load bootstrap3 %} 3 | 4 | {% block page %} 5 |
6 |
7 |
8 |

9 | Account 10 |

11 |
12 |
13 |
14 | {% csrf_token %} 15 | {% bootstrap_form user_form %} 16 | {% bootstrap_form store_form %} 17 | 18 | 19 |
20 |
21 |
22 |
23 | {% endblock%} 24 | -------------------------------------------------------------------------------- /store/templates/deliver/store_accunt.html: -------------------------------------------------------------------------------- 1 | {% extends 'store/base.html' %} 2 | {% load bootstrap3 %} 3 | 4 | {% block page %} 5 |
6 |
7 |
8 |

9 | Account 10 |

11 |
12 |
13 |
14 | {% csrf_token %} 15 | {% bootstrap_form user_form %} 16 | {% bootstrap_form delivery_boy_form %} 17 | 18 | 19 |
20 |
21 |
22 |
23 | {% endblock%} 24 | -------------------------------------------------------------------------------- /templates/deliver/delivery_boy_account.html: -------------------------------------------------------------------------------- 1 | {% extends 'deliver/base.html' %} 2 | {% load bootstrap3 %} 3 | 4 | {% block page %} 5 |
6 |
7 |
8 |

9 | Account 10 |

11 |
12 |
13 |
14 | {% csrf_token %} 15 | {% bootstrap_form user_form %} 16 | {% bootstrap_form delivery_boy_form %} 17 | 18 | 19 |
20 |
21 |
22 |
23 | {% endblock%} 24 | -------------------------------------------------------------------------------- /store/templates/deliver/delivery_boy_account.html: -------------------------------------------------------------------------------- 1 | {% extends 'deliver/base.html' %} 2 | {% load bootstrap3 %} 3 | 4 | {% block page %} 5 |
6 |
7 |
8 |

9 | Account 10 |

11 |
12 |
13 |
14 | {% csrf_token %} 15 | {% bootstrap_form user_form %} 16 | {% bootstrap_form delivery_boy_form %} 17 | 18 | 19 |
20 |
21 |
22 |
23 | {% endblock%} 24 | -------------------------------------------------------------------------------- /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", "delivery.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 | -------------------------------------------------------------------------------- /store/migrations/0002_auto_20181127_1233.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.0 on 2018-11-27 07:03 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('store', '0001_initial'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterModelOptions( 14 | name='task', 15 | options={'ordering': ('created_at',), 'verbose_name': 'Delivery Task', 'verbose_name_plural': 'Delivery Tasks'}, 16 | ), 17 | migrations.AddField( 18 | model_name='task', 19 | name='celery_id', 20 | field=models.CharField(blank=True, max_length=200, null=True), 21 | ), 22 | migrations.AddField( 23 | model_name='task', 24 | name='completed_at', 25 | field=models.DateTimeField(blank=True, null=True), 26 | ), 27 | ] 28 | -------------------------------------------------------------------------------- /templates/base.html: -------------------------------------------------------------------------------- 1 | {% load staticfiles %} 2 | {% load static %} 3 | 4 | 5 | 6 | 7 | {% block title %}{% endblock %} 8 | 9 | 10 | 11 | 12 | 13 | {% block extra_style %}{% endblock %} 14 | {% block script %}{% endblock %} 15 | 16 | 17 |
18 |
19 | 22 |
23 | {% block page %}{% endblock %} 24 |
25 |
26 |
27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /store/serializers.py: -------------------------------------------------------------------------------- 1 | from rest_framework import serializers 2 | from store.models import Store, Task,DeliveryBoy 3 | 4 | 5 | 6 | class StoreSerializer(serializers.ModelSerializer): 7 | 8 | class Meta: 9 | model = Store 10 | fields = ("id", "store_name", "contact_number") 11 | 12 | 13 | class TaskStoreSerializer(serializers.ModelSerializer): 14 | class Meta: 15 | model = Store 16 | fields = ("id", "store_name", "contact_number") 17 | 18 | 19 | class TaskDeliverBoySerializer(serializers.ModelSerializer): 20 | name = serializers.ReadOnlyField(source="user.get_full_name") 21 | 22 | class Meta: 23 | model = DeliveryBoy 24 | fields = ("id", "name", "number") 25 | 26 | class TaskSerializer(serializers.ModelSerializer): 27 | 28 | delivery_boy = TaskDeliverBoySerializer() 29 | store = TaskStoreSerializer() 30 | status = serializers.ReadOnlyField(source="get_status_display") 31 | 32 | class Meta: 33 | model = Task 34 | fields = ("id", "title", "store", "delivery_boy", "status", "preiority") 35 | 36 | -------------------------------------------------------------------------------- /static/js/index.js: -------------------------------------------------------------------------------- 1 | $(function() { 2 | $('.material-card > .mc-btn-action').click(function () { 3 | var card = $(this).parent('.material-card'); 4 | var icon = $(this).children('i'); 5 | icon.addClass('fa-spin-fast'); 6 | 7 | if (card.hasClass('mc-active')) { 8 | card.removeClass('mc-active'); 9 | 10 | window.setTimeout(function() { 11 | icon 12 | .removeClass('fa-arrow-left') 13 | .removeClass('fa-spin-fast') 14 | .addClass('fa-bars'); 15 | 16 | }, 800); 17 | } else { 18 | card.addClass('mc-active'); 19 | 20 | window.setTimeout(function() { 21 | icon 22 | .removeClass('fa-bars') 23 | .removeClass('fa-spin-fast') 24 | .addClass('fa-arrow-left'); 25 | 26 | }, 800); 27 | } 28 | }); 29 | }); -------------------------------------------------------------------------------- /store/templates/base.html: -------------------------------------------------------------------------------- 1 | {% load staticfiles %} 2 | {% load static %} 3 | 4 | 5 | 6 | 7 | {% block title %}{% endblock %} 8 | 9 | 10 | 11 | 12 | 13 | 16 | {% block extra_style %}{% endblock %} 17 | {% block script %}{% endblock %} 18 | 19 | 20 |
21 |
22 | 25 |
26 | {% block page %}{% endblock %} 27 |
28 |
29 |
30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /templates/base_signup.html: -------------------------------------------------------------------------------- 1 | {% load staticfiles %} 2 | 3 | 4 | 5 | 6 | {% block title %}{% endblock %} 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |

{% block heading %}{% endblock %}

26 |
27 | {% block content %}{% endblock %} 28 |
29 |
30 |
31 |
32 |
33 |
34 | 35 | -------------------------------------------------------------------------------- /store/templates/base_signup.html: -------------------------------------------------------------------------------- 1 | {% load staticfiles %} 2 | 3 | 4 | 5 | 6 | {% block title %}{% endblock %} 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |

{% block heading %}{% endblock %}

26 |
27 | {% block content %}{% endblock %} 28 |
29 |
30 |
31 |
32 |
33 |
34 | 35 | -------------------------------------------------------------------------------- /templates/store/base_signup.html: -------------------------------------------------------------------------------- 1 | {% load staticfiles %} 2 | 3 | 4 | 5 | 6 | {% block title %}{% endblock %} 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |

{% block heading %}{% endblock %}

26 |
27 | {% block content %}{% endblock %} 28 |
29 |
30 |
31 |
32 |
33 |
34 | 35 | 36 | -------------------------------------------------------------------------------- /templates/deliver/base_signup.html: -------------------------------------------------------------------------------- 1 | {% load staticfiles %} 2 | 3 | 4 | 5 | 6 | {% block title %}{% endblock %} 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |

{% block heading %}{% endblock %}

26 |
27 | {% block content %}{% endblock %} 28 |
29 |
30 |
31 |
32 |
33 |
34 | 35 | 36 | -------------------------------------------------------------------------------- /store/templates/deliver/base_signup.html: -------------------------------------------------------------------------------- 1 | {% load staticfiles %} 2 | 3 | 4 | 5 | 6 | {% block title %}{% endblock %} 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |

{% block heading %}{% endblock %}

26 |
27 | {% block content %}{% endblock %} 28 |
29 |
30 |
31 |
32 |
33 |
34 | 35 | 36 | -------------------------------------------------------------------------------- /store/templates/store/base_signup.html: -------------------------------------------------------------------------------- 1 | {% load staticfiles %} 2 | 3 | 4 | 5 | 6 | {% block title %}{% endblock %} 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |

{% block heading %}{% endblock %}

26 |
27 | {% block content %}{% endblock %} 28 |
29 |
30 |
31 |
32 |
33 |
34 | 35 | 36 | -------------------------------------------------------------------------------- /templates/registration/base_signup.html: -------------------------------------------------------------------------------- 1 | {% load staticfiles %} 2 | 3 | 4 | 5 | 6 | {% block title %}{% endblock %} 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |

{% block heading %}{% endblock %}

26 |
27 | {% block content %}{% endblock %} 28 |
29 |
30 |
31 |
32 |
33 |
34 | 35 | 36 | -------------------------------------------------------------------------------- /store/templates/store/base.html: -------------------------------------------------------------------------------- 1 | o{% extends 'base.html' %} 2 | {% block title %} Store {% endblock %} 3 | {% block script %} 4 | 25 | {% endblock %} 26 | 27 | {% block sidebar %} 28 | {% url 'store_tasks' as store_task_url %} 29 | {% url 'store_account' as store_account_url %} 30 |
31 |

Welcome, {{request.user.store.store_name}}

32 |

{{reqest.user.get_full_name }}

33 |
34 |
35 | 36 | Tasks 37 | 38 | 39 | Account 41 |
42 |
43 | Logout 45 |
46 | {% endblock %} -------------------------------------------------------------------------------- /templates/registration/base.html: -------------------------------------------------------------------------------- 1 | o{% extends 'base.html' %} 2 | {% block title %} Store {% endblock %} 3 | {% block script %} 4 | 25 | {% endblock %} 26 | 27 | {% block sidebar %} 28 | {% url 'store_task' as store_task_url %} 29 | {% url 'store_account' as store_account_url %} 30 |
31 |

Welcome, {{request.user.store.store_name}}

32 |

{{reqest.user.get_full_name }}

33 |
34 |
35 | Dashboard 36 | Tasks 37 | 38 | Profile 39 | Account 41 |
42 |
43 | Logout 45 |
46 | {% endblock %} -------------------------------------------------------------------------------- /store/consumers.py: -------------------------------------------------------------------------------- 1 | import json 2 | import logging 3 | from channels import Channel 4 | from channels.sessions import channel_session 5 | from delivery.celery import app 6 | from store.models import Task 7 | from store.tasks import deliver_task_accept_notification_ 8 | 9 | log = logging.getLogger(__name__) 10 | 11 | 12 | @channel_session 13 | def ws_connect(message): 14 | message.reply_channel.send({ 15 | "text": json.dumps({ 16 | "action": "reply_channel", 17 | "reply_channel": message.reply_channel.name, 18 | }) 19 | }) 20 | 21 | 22 | @channel_session 23 | def ws_receive(message): 24 | try: 25 | data = json.loads(message['text']) 26 | except ValueError: 27 | log.debug("websocket message is not json text=%s", message['text']) 28 | return 29 | 30 | if data: 31 | reply_channel = models.reply_channel.name 32 | if data['action'] == 'push_task_accepted_notification': 33 | push_task_accepted_notification(data, reply_channel) 34 | if data['action'] == '' 35 | 36 | 37 | def push_task_accepted_notification(data, reply_channel): 38 | log.debug("Task Name:%s", data['task_title']) 39 | # save model to our data base 40 | task = Task( 41 | title=data['task_title'], 42 | status=Task.READY, 43 | store = data['task_store'], 44 | preiority=data['task_preiority'], 45 | ) 46 | task.save() 47 | # fireup celery task 48 | accept_task = deliver_task_accept_notification_.delay(task.id, reply_channel) 49 | # store celery task id for future ref 50 | task.celery_id = accept_task.id 51 | task.save() 52 | 53 | # info client about task 54 | Channel(reply_channel).send({ 55 | "text": json.dumps({ 56 | "action": "started", 57 | "task_id": task.id, 58 | "task_name": task.title, 59 | "task_status": task.status, 60 | 61 | }) 62 | }) -------------------------------------------------------------------------------- /templates/store/task.html: -------------------------------------------------------------------------------- 1 | {% extends 'store/base.html' %} 2 | 3 | {% block page %} 4 | 5 |
6 |
7 |

Tasks

8 |
9 |
10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | {% for order in orders %} 25 | 26 | 27 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | {% endfor %} 40 | 41 | 42 |
IdTitlePreiorityStatusDelivery BoyCreatedAccepted
{{ order.id }} 28 | {% for od in order.order_details.all %} 29 | {{ od.meal.name }} {{ od.meal.price }} 30 | x {{ od.quantity }} = ${{ od.sub_total }} 31 | {% endfor %} 32 | {{ order.customer }}{{ order.driver }}{{ order.total }}{{ order.get_status_display }}
43 |
44 |
45 | 46 | {% endblock %} 47 | -------------------------------------------------------------------------------- /store/templates/deliver/base.html: -------------------------------------------------------------------------------- 1 | o{% extends 'base.html' %} 2 | {% block title %} Deliver{% endblock %} 3 | {% block script %} 4 | 27 | {% endblock %} 28 | 29 | {% block sidebar %} 30 | {% url 'delivery_boy_tasks' as delivery_boy_tasks_url %} 31 | {% url 'delivery_boy_account' as delivery_boy_url %} 32 |
33 |

Welcome, {{request.user.delivery_boy.first_name}}

34 |

{{reqest.user.get_full_name }}

35 |
36 |
37 |
38 | 39 | Tasks 40 | 41 | 42 | Account 44 |
45 |
46 | Logout 48 |
49 | {% endblock %} -------------------------------------------------------------------------------- /templates/store/base.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | {% block title %} Store {% endblock %} 3 | {% block script %} 4 | 25 | {% endblock %} 26 | 27 | {% block sidebar %} 28 | {% url 'store_tasks' as store_task_url %} 29 | {% url 'store_account' as store_account_url %} 30 | {% url 'create_task' as create_task_url %} 31 |
32 |

Welcome, {{request.user.store.store_name}}

33 |

{{reqest.user.get_full_name }}

34 |
35 |
36 |
37 | 38 | Tasks 39 | New Task 40 | 41 | 42 | Account 44 |
45 |
46 | Logout 48 |
49 | {% endblock %} -------------------------------------------------------------------------------- /templates/deliver/base.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | {% block title %} Deliver {% endblock %} 3 | {% block script %} 4 | 10 | 34 | {% endblock %} 35 | {% block sidebar %} 36 | {% url 'deliver_tasks' as deliver_tasks_url %} 37 | {% url 'delivery_boy_account' as delivery_boy_url %} 38 | 39 |
40 |

Welcome, {{request.user.delivery_boy}}

41 |
42 |

{{reqest.user.get_full_name }}

43 |
44 |
45 | 46 | Tasks 47 | 48 | Account 50 |
51 |
52 | Logout 54 |
55 | {% endblock %} -------------------------------------------------------------------------------- /store/templates/custom_404_view.html: -------------------------------------------------------------------------------- 1 | 2 | 72 |
73 |

404

74 |
75 | 76 | 77 |
78 | -------------------------------------------------------------------------------- /templates/registration/task.html: -------------------------------------------------------------------------------- 1 | {% extends 'store/base.html' %} 2 | 3 | {% block page %} 4 | 5 |
6 |
7 |

Tasks

8 |
9 |
10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | {% for order in orders %} 25 | 26 | 27 | 33 | 34 | 35 | 36 | 37 | 46 | 47 | {% endfor %} 48 | 49 | 50 |
IdOrder DetailsCustomerDriverTotalStatusAction
{{ order.id }} 28 | {% for od in order.order_details.all %} 29 | {{ od.meal.name }} {{ od.meal.price }} 30 | x {{ od.quantity }} = ${{ od.sub_total }} 31 | {% endfor %} 32 | {{ order.customer }}{{ order.driver }}{{ order.total }}{{ order.get_status_display }} 38 | {% if order.status == 1 %} 39 |
40 | {% csrf_token %} 41 | 42 | 43 |
44 | {% endif %} 45 |
51 |
52 |
53 | 54 | {% endblock %} 55 | -------------------------------------------------------------------------------- /store/templates/deliver/tasks.html: -------------------------------------------------------------------------------- 1 | {% extends 'store/base.html' %} 2 | 3 | {% block page %} 4 | 5 |
6 |
7 |

Tasks

8 |
9 |
10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | {% for task in tasks %} 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | {% if task.status %} 34 | {% if task.status == 'READY' %} 35 | 36 | {% else %}{% endif %} 37 | {% if task.status == 'COMPLETED' %} 38 | 39 | {% else %}{% endif %} 40 | {% if task.status == 'REJECTED' %} 41 | 42 | {% else %}{% endif %} 43 | {% if task.status == 'ACCEPTED' %} 44 | 45 | {% else %}{% endif %} 46 | {% endif %} 47 | 48 | 49 | {% endfor %} 50 | 51 | 52 |
IdTitlePreiorityDelivery BoyCreated AtAccepted AtStatusAct
{{ task.id }}{{ task.title }}{{ task.preiority }}{{ task.delivery_boy }}{{ task.created_at }}{{ task.accepted_at }}{{ task.status }}{{ task.status }}{{ task.status }}{{ task.status }}Modify
53 |
54 |
55 | 56 | {% endblock %} 57 | -------------------------------------------------------------------------------- /static/css/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding-top: 50px; 3 | background-color: #EDF2F5; 4 | overflow: auto; 5 | } 6 | 7 | .bg-blue { 8 | background-color: #3F3F63; 9 | } 10 | 11 | .bg-gray { 12 | background-color: #88A1B2; 13 | } 14 | 15 | .text-white { 16 | color: white; 17 | } 18 | 19 | .btn-pink { 20 | color: white; 21 | background-color: #EE5462; 22 | } 23 | 24 | .btn-pink:hover, 25 | .btn-pink:focus { 26 | color: white; 27 | background-color: #DA4F5D; 28 | } 29 | 30 | /* SIDE BAR */ 31 | .sidebar { 32 | height: 100vh; 33 | position: fixed; 34 | top: 0; 35 | left: 0; 36 | padding: 0; 37 | background-color: red; /* For browsers that do not support gradients */ 38 | background-image: linear-gradient(#b92b27,#1565C0); /* Standard syntax (must be last) */ 39 | overflow: auto; 40 | } 41 | 42 | /* SIDE BAR - HEADER */ 43 | .sidebar > div:first-child { 44 | padding: 30px 10px; 45 | font-weight: bold; 46 | font-size: 15px; 47 | 48 | } 49 | 50 | .sidebar > div:first-child > h4 { 51 | color: #e0deeb; 52 | } 53 | 54 | .sidebar > div:first-child > h5 { 55 | color: #b6b4c1; 56 | } 57 | 58 | /* SIDE BAR - LIST */ 59 | .sidebar .list-group { 60 | padding: 0; 61 | 62 | } 63 | 64 | .sidebar .list-group > span { 65 | color: #b6b4c1; 66 | display: block; 67 | margin-top: 20px; 68 | padding: 20px 30px; 69 | font-size: 16px; 70 | font-weight: 300; 71 | } 72 | 73 | .sidebar .list-group .list-group-item, 74 | .sidebar .list-group .list-group-item:focus { 75 | 76 | color: #b6b4c1; 77 | border: 0; 78 | padding-left: 60px; 79 | padding-right: 30px; 80 | } 81 | 82 | .sidebar .list-group .list-group-item.active, 83 | .sidebar .list-group .list-group-item:hover { 84 | background-color: #383957; 85 | color: #e0deeb; 86 | } 87 | 88 | .sidebar .list-group .list-group-item:first-child { 89 | border-top-left-radius: 0; 90 | border-top-right-radius: 0; 91 | } 92 | 93 | .sidebar .list-group .list-group-item .badge, 94 | .sidebar .list-group .list-group-item.active .badge { 95 | background-color: #EE5462; 96 | color: #e0deeb; 97 | } 98 | 99 | /* SIDE BAR - LOGOUT */ 100 | .sidebar > div:last-child { 101 | padding: 30px; 102 | } 103 | 104 | .sidebar > div:last-child .btn { 105 | width: 100%; 106 | } 107 | 108 | /* CONTENT */ 109 | .content { 110 | padding: 0 40px; 111 | } 112 | 113 | .content .panel { 114 | border: none; 115 | } 116 | 117 | .table > thead > tr > th, 118 | .table > thead > tr > td { 119 | vertical-align: middle; 120 | } 121 | 122 | .table, 123 | .table > thead > tr > th { 124 | border-color: #88A1B2; 125 | } 126 | 127 | 128 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #### Delivery is Simple Delivery management Application. 2 | #### Store manager can create task for delivery boys. 3 | #### Store manager can cancel task which not yet accpeted by delivery boy. 4 | #### Store manager can view all tasks list and thier status on dashboard. 5 | 6 | #### Deliver boy can Accept New Tasks from store. 7 | #### Deliver boy can reject his/her task once accepted. 8 | #### Deliver boy can view all his Past accepted tasks and completed tasks on dashboard. 9 | #### Deliver boy can only accpet three tasks in his account if he accept more he/she needs to perform action on old tasks. 10 | 11 | 12 | 13 | 14 | 15 | #### Setting up 16 | 17 | 18 | Fork the project to your personal account and get a local copy on your machine. 19 | Change into the project folder. 20 | 21 | 22 | Setup Virtual Environment for Delivery app 23 | ```sh 24 | $ pyvenv venv (creates new virtualenv for project) 25 | $ source venv/bin/activate (activate virtualenv assumeing using ubuntu) 26 | $ pip install -r requirements.txt (install dependencies) 27 | ``` 28 | 29 | Make sure to create migrations, create tables in db, and create a superuser to have an admin dashboard. 30 | 31 | ```sh 32 | $ python manage.py makemigrations (creates migration files based on your models) 33 | $ python manage.py migrate (creates the tables in your db based on the migration files) 34 | $ python manage.py createsuperuser (creates a superuser for your application in the db) 35 | $ python manage.py runserver (run server) 36 | ``` 37 | ##### for storemanager 38 | ##### username : omega 39 | ##### password :ASDFGhjkl1@ 40 | 41 | 42 | ##### for deliver boy 43 | ##### username : deliverboy-1 44 | ##### password : ASDFGhjkl1@ 45 | 46 | Now you should be able to view your app to view your admin dashboard use 47 | http://127.0.0.1:8000/admin/. 48 | 49 | ```sh 50 | http://localhost:8000/store/signin/ (for signup) 51 | http://localhost:8000/store/tasks/ (store manager dashboard) 52 | http://localhost:8000/deliver/tasks/ (deliverboy dashboard) 53 | note: diliver boy and store manager are deifferent type accounts 54 | ``` 55 | 56 | Delivery 57 | Delivery 58 | Delivery 59 | Delivery 60 | Delivery 61 | -------------------------------------------------------------------------------- /store/tasks.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | import time 3 | import json 4 | import logging 5 | from django.http import JsonResponse 6 | from django.http.response import HttpResponse 7 | from django.views.decorators.csrf import csrf_exempt 8 | from django.db import transaction 9 | from django.contrib.auth.models import User 10 | from channels import Channel 11 | from celery import shared_task 12 | from celery.utils.log import get_task_logger 13 | from store.models import Store, Task, DeliveryBoy 14 | from store.serializers import TaskSerializer 15 | from delivery.celery import app 16 | 17 | 18 | log = logging.getLogger(__name__) 19 | logger = get_task_logger(__name__) 20 | 21 | 22 | @app.task 23 | def deliver_task_accept_notification(task_id, reply_channel): 24 | task = Task.objects.get(pk=task_id) 25 | log.debug("Running Task_name=%s", task.title) 26 | task.status = Task.ACCEPTED 27 | task.save() 28 | 29 | # send status update back to browser client 30 | 31 | if reply_channel is not None: 32 | Channel(replay_channel).send({ 33 | "text": json.dumps({ 34 | "action": "deliver_task_accept_notification", 35 | "task_id": task_id, 36 | "task_name": task.title, 37 | "task_status": task.status, 38 | "task_preiority": task.preiority, 39 | "task_store": task.store, 40 | }) 41 | }) 42 | 43 | 44 | @app.task 45 | def store_manager_created_new_task(task_id, reply_channel): 46 | task = Task.objects.get(pk=task_id) 47 | log.debug("Running Task Name=%s", task.title) 48 | if reply_channel is not None: 49 | Channel(reply_channel).send({ 50 | "text": json.dumps({ 51 | "action": "task_created", 52 | "task_id": task_id, 53 | "task_title": task.title, 54 | "task_status": task.status, 55 | "task_preiority": task.preiority, 56 | "task_store": task.store 57 | }) 58 | }) 59 | 60 | 61 | @app.task 62 | def deliver_task_reject_notification(task_id, reply_channel): 63 | task = Task.objects.get(pk=task_id) 64 | log.debug("Running Task Name=%s", task.title) 65 | if reply_channel is not None: 66 | Channel(reply_channel).send({ 67 | "text": json.dumps({ 68 | "action": "accepted", 69 | "task_id": task_id, 70 | "task_name": task.title, 71 | "task_status": task.status, 72 | "task_preiority": task.preiority, 73 | "task_store": task.store, 74 | }) 75 | }) 76 | 77 | 78 | @app.task 79 | def deliver_task_completed_notification(task_id, reply_channel): 80 | task = Task.objects.get(pk=task_id) 81 | log.debug("Running Task Name=%s", task.title) 82 | if reply_channel is not None: 83 | Channel(reply_channel).send({ 84 | "text": json.dumps({ 85 | "action": "accepted", 86 | "task_id": task_id, 87 | "task_name": task.title, 88 | "task_status": task.status, 89 | "task_preiority": task.preiority, 90 | "task_store": task.store, 91 | }) 92 | }) -------------------------------------------------------------------------------- /store/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.1.3 on 2018-11-26 13:29 2 | 3 | from django.conf import settings 4 | from django.db import migrations, models 5 | import django.db.models.deletion 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | initial = True 11 | 12 | dependencies = [ 13 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 14 | ] 15 | 16 | operations = [ 17 | migrations.CreateModel( 18 | name='DeliveryBoy', 19 | fields=[ 20 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 21 | ('number', models.CharField(max_length=12, unique=True)), 22 | ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='delivery_boy', to=settings.AUTH_USER_MODEL)), 23 | ], 24 | options={ 25 | 'verbose_name': 'Delivery Boy', 26 | 'verbose_name_plural': 'Delivery Boys', 27 | }, 28 | ), 29 | migrations.CreateModel( 30 | name='Store', 31 | fields=[ 32 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 33 | ('store_name', models.CharField(max_length=150)), 34 | ('contact_number', models.CharField(max_length=12)), 35 | ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='store', to=settings.AUTH_USER_MODEL)), 36 | ], 37 | options={ 38 | 'verbose_name': 'Store Manager', 39 | 'verbose_name_plural': 'Store Managers', 40 | }, 41 | ), 42 | migrations.CreateModel( 43 | name='Task', 44 | fields=[ 45 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 46 | ('title', models.CharField(max_length=100)), 47 | ('preiority', models.CharField(choices=[('HIGH', 'High'), ('MEDIUM', 'Medium'), ('LOW', 'Low')], max_length=6)), 48 | ('status', models.CharField(choices=[('READY', 'Ready'), ('ACCEPTED', 'Accepted'), ('COMPLETED', 'Completed'), ('REJECTED', 'Rejected'), ('CANCELD', 'Canceld')], max_length=10)), 49 | ('created_at', models.DateTimeField(auto_now=True)), 50 | ('accepted_at', models.DateTimeField(blank=True, null=True)), 51 | ('edited_at', models.DateTimeField(auto_now_add=True)), 52 | ('delivery_boy', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='store.DeliveryBoy')), 53 | ('store', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='store.Store')), 54 | ], 55 | options={ 56 | 'verbose_name': 'Delivery Task', 57 | 'verbose_name_plural': 'Delivery Tasks', 58 | }, 59 | ), 60 | ] 61 | -------------------------------------------------------------------------------- /static/js/reconnecting-websocket.min.js: -------------------------------------------------------------------------------- 1 | !function(a,b){"function"==typeof define&&define.amd?define([],b):"undefined"!=typeof module&&module.exports?module.exports=b():a.ReconnectingWebSocket=b()}(this,function(){function a(b,c,d){function l(a,b){var c=document.createEvent("CustomEvent");return c.initCustomEvent(a,!1,!1,b),c}var e={debug:!1,automaticOpen:!0,reconnectInterval:1e3,maxReconnectInterval:3e4,reconnectDecay:1.5,timeoutInterval:2e3};d||(d={});for(var f in e)this[f]="undefined"!=typeof d[f]?d[f]:e[f];this.url=b,this.reconnectAttempts=0,this.readyState=WebSocket.CONNECTING,this.protocol=null;var h,g=this,i=!1,j=!1,k=document.createElement("div");k.addEventListener("open",function(a){g.onopen(a)}),k.addEventListener("close",function(a){g.onclose(a)}),k.addEventListener("connecting",function(a){g.onconnecting(a)}),k.addEventListener("message",function(a){g.onmessage(a)}),k.addEventListener("error",function(a){g.onerror(a)}),this.addEventListener=k.addEventListener.bind(k),this.removeEventListener=k.removeEventListener.bind(k),this.dispatchEvent=k.dispatchEvent.bind(k),this.open=function(b){h=new WebSocket(g.url,c||[]),b||k.dispatchEvent(l("connecting")),(g.debug||a.debugAll)&&console.debug("ReconnectingWebSocket","attempt-connect",g.url);var d=h,e=setTimeout(function(){(g.debug||a.debugAll)&&console.debug("ReconnectingWebSocket","connection-timeout",g.url),j=!0,d.close(),j=!1},g.timeoutInterval);h.onopen=function(){clearTimeout(e),(g.debug||a.debugAll)&&console.debug("ReconnectingWebSocket","onopen",g.url),g.protocol=h.protocol,g.readyState=WebSocket.OPEN,g.reconnectAttempts=0;var d=l("open");d.isReconnect=b,b=!1,k.dispatchEvent(d)},h.onclose=function(c){if(clearTimeout(e),h=null,i)g.readyState=WebSocket.CLOSED,k.dispatchEvent(l("close"));else{g.readyState=WebSocket.CONNECTING;var d=l("connecting");d.code=c.code,d.reason=c.reason,d.wasClean=c.wasClean,k.dispatchEvent(d),b||j||((g.debug||a.debugAll)&&console.debug("ReconnectingWebSocket","onclose",g.url),k.dispatchEvent(l("close")));var e=g.reconnectInterval*Math.pow(g.reconnectDecay,g.reconnectAttempts);setTimeout(function(){g.reconnectAttempts++,g.open(!0)},e>g.maxReconnectInterval?g.maxReconnectInterval:e)}},h.onmessage=function(b){(g.debug||a.debugAll)&&console.debug("ReconnectingWebSocket","onmessage",g.url,b.data);var c=l("message");c.data=b.data,k.dispatchEvent(c)},h.onerror=function(b){(g.debug||a.debugAll)&&console.debug("ReconnectingWebSocket","onerror",g.url,b),k.dispatchEvent(l("error"))}},1==this.automaticOpen&&this.open(!1),this.send=function(b){if(h)return(g.debug||a.debugAll)&&console.debug("ReconnectingWebSocket","send",g.url,b),h.send(b);throw"INVALID_STATE_ERR : Pausing to reconnect websocket"},this.close=function(a,b){"undefined"==typeof a&&(a=1e3),i=!0,h&&h.close(a,b)},this.refresh=function(){h&&h.close()}}return a.prototype.onopen=function(){},a.prototype.onclose=function(){},a.prototype.onconnecting=function(){},a.prototype.onmessage=function(){},a.prototype.onerror=function(){},a.debugAll=!1,a.CONNECTING=WebSocket.CONNECTING,a.OPEN=WebSocket.OPEN,a.CLOSING=WebSocket.CLOSING,a.CLOSED=WebSocket.CLOSED,a}); 2 | -------------------------------------------------------------------------------- /delivery/urls.py: -------------------------------------------------------------------------------- 1 | """delivery URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/1.11/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, handler404 17 | from django.contrib import admin 18 | from django.conf import settings 19 | from django.conf.urls.static import static 20 | from django.contrib.auth import views as auth_views 21 | from django.contrib.auth import views as deliver_views 22 | from store import views, apis 23 | 24 | 25 | 26 | urlpatterns = [ 27 | url(r'^admin/', admin.site.urls), 28 | # url(r'^celery/', views.celery_task_checker, name='celery_task_checker'), 29 | 30 | url(r'^api_auth_token/', views.get_auth_token), 31 | 32 | url(r'^store/signin/', auth_views.LoginView.as_view(),{'template_name':'store/signin.html'}, name="store-signin" ), 33 | url(r'^store/signout', auth_views.LogoutView.as_view(),{'next_page': '/store/signin'}, name="store-signout"), 34 | url(r'^store/signup', views.store_signup, name="store-signup"), 35 | url(r'^store/$', views.store_home, name='store_home'), 36 | 37 | url(r'^store/accounts/$', views.store_account, name='store_account'), 38 | url(r'^store/tasks/$', views.store_tasks, name="store_tasks"), 39 | url(r'^store/tasks/details/(?P\d+)/', views.TaskDetails.as_view(), name="task_details"), 40 | url(r'^store/create_task/$', views.create_task, name="create_task"), 41 | url(r'^api/store/cancel_task/$', apis.store_manager_cancel_task), 42 | 43 | url(r'^api/store/task/notification/(?P.+)/$', apis.store_task_notification), 44 | 45 | 46 | url(r'^deliver/signin/', deliver_views.LoginView.as_view(),{'template_name':'deliver/signin.html'}, name="delivery_boy-signin" ), 47 | url(r'^deliver/signout', auth_views.LogoutView.as_view(),{'next_page': '/deliver/signin'}, name="delivery_boy-signout"), 48 | url(r'^deliver/signup', views.delivery_boy_signup, name="delivery_boy-signup"), 49 | url(r'^deliver/$', views.delivery_boy_home, name='delivery_boy_home'), 50 | 51 | url(r'^deliver/accounts/$', views.delivery_boy_account, name='delivery_boy_account'), 52 | url(r'^deliver/tasks/$', views.deliver_tasks, name="deliver_tasks"), 53 | #APIs for Deliver boy 54 | 55 | 56 | url(r'^api/deliver/task/ready/$', apis.delivery_boy_ready_new_tasks), 57 | url(r'^api/deliver/task/accept/$', apis.delivery_boy_accept_task), 58 | url(r'^api/deliver/task/latest/$', apis.delivery_boy_get_latest_task), 59 | url(r'^api/deliver/task/complete/$', apis.delivery_boy_complete_task), 60 | url(r'^api/deliver/task/reject/$', apis.delivery_boy_reject_task), 61 | url(r'^api/deliver/task/completed_tasks/$', apis.get_deliver_boy_completed_tasks), 62 | url(r'^$',views.home,name="home"), 63 | 64 | ]+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) 65 | 66 | 67 | handler404 = 'views.views.handler404' 68 | handler500 = 'views.views.handler500' -------------------------------------------------------------------------------- /delivery/settings.py.save: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for delivery project. 3 | 4 | Generated by 'django-admin startproject' using Django 1.11. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.11/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/1.11/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.11/howto/deployment/checklist/ 21 | 22 | # SECURITY WARNING: keep the secret key used in production secret! 23 | SECRET_KEY = '_%w)@*4jt$7lh76v4m+rm@z577zwt+t$6&ilh5ojtj-75svw((' 24 | 25 | # SECURITY WARNING: don't run with debug turned on in production! 26 | DEBUG = True 27 | 28 | ALLOWED_HOSTS = ['*', n] 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 | 42 | MIDDLEWARE = [ 43 | 'django.middleware.security.SecurityMiddleware', 44 | 'django.contrib.sessions.middleware.SessionMiddleware', 45 | 'django.middleware.common.CommonMiddleware', 46 | 'django.middleware.csrf.CsrfViewMiddleware', 47 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 48 | 'django.contrib.messages.middleware.MessageMiddleware', 49 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 50 | ] 51 | 52 | ROOT_URLCONF = 'delivery.urls' 53 | 54 | TEMPLATES = [ 55 | { 56 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 57 | 'DIRS': [], 58 | 'APP_DIRS': True, 59 | 'OPTIONS': { 60 | 'context_processors': [ 61 | 'django.template.context_processors.debug', 62 | 'django.template.context_processors.request', 63 | 'django.contrib.auth.context_processors.auth', 64 | 'django.contrib.messages.context_processors.messages', 65 | ], 66 | }, 67 | }, 68 | ] 69 | 70 | WSGI_APPLICATION = 'delivery.wsgi.application' 71 | 72 | 73 | # Database 74 | # https://docs.djangoproject.com/en/1.11/ref/settings/#databases 75 | 76 | DATABASES = { 77 | 'default': { 78 | 'ENGINE': 'django.db.backends.sqlite3', 79 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 80 | } 81 | } 82 | 83 | 84 | # Password validation 85 | # https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators 86 | 87 | AUTH_PASSWORD_VALIDATORS = [ 88 | { 89 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 90 | }, 91 | { 92 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 93 | }, 94 | { 95 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 96 | }, 97 | { 98 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 99 | }, 100 | ] 101 | 102 | 103 | # Internationalization 104 | # https://docs.djangoproject.com/en/1.11/topics/i18n/ 105 | 106 | LANGUAGE_CODE = 'en-us' 107 | 108 | TIME_ZONE = 'UTC' 109 | 110 | USE_I18N = True 111 | 112 | USE_L10N = True 113 | 114 | USE_TZ = True 115 | 116 | 117 | # Static files (CSS, JavaScript, Images) 118 | # https://docs.djangoproject.com/en/1.11/howto/static-files/ 119 | 120 | STATIC_URL = '/static/' 121 | -------------------------------------------------------------------------------- /store/templates/celery.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | {% load staticfiles %} 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | {% block title %}{% endblock %} 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 |
31 |
32 |
33 |

Task Runner

34 |
35 | 36 | 37 |
38 |
39 |
40 |

Task Status

41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 |
Task IDTask NameTask Status
53 |
54 |
55 | 56 |
57 |
58 | 59 | 60 | 61 | 109 | 110 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /store/templates/store/tasks.html: -------------------------------------------------------------------------------- 1 | {% extends 'store/base.html' %} 2 | 3 | {% block page %} 4 | 5 |
6 |
7 |

Tasks

8 |
9 |
10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | {% for task in tasks %} 25 | 26 | 27 | 28 | 29 | 30 | {% if task.status %} 31 | {% if task.status == 'READY' %} 32 | 33 | {% else %}{% endif %} 34 | {% if task.status == 'COMPLETED' %} 35 | 36 | {% else %}{% endif %} 37 | {% if task.status == 'REJECTED' %} 38 | 39 | {% else %}{% endif %} 40 | {% if task.status == 'CANCELD' %} 41 | 42 | {% else %}{% endif %} 43 | {% if task.status == 'ACCEPTED' %} 44 | 45 | {% else %}{% endif %} 46 | {% endif %} 47 | 49 | 51 | 52 | 53 | {% endfor %} 54 | 55 | 56 |
IdTitlePreiorityDelivery BoyStatusActionDetails
{{ task.id }}{{ task.title }}{{ task.preiority }}{{ task.delivery_boy }}{{ task.status }}{{ task.status }}{{ task.status }}{{ task.status }}{{ task.status }} 48 | 50 |
57 | 58 |
59 |
60 | 61 |
62 |
63 | 64 | 83 | 84 | 118 | {% endblock %} 119 | -------------------------------------------------------------------------------- /store/forms.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | from django.utils.translation import ugettext as _ 3 | from django.core.validators import ValidationError 4 | from django.contrib.auth.models import User 5 | from store.models import Task, Store, DeliveryBoy 6 | 7 | 8 | 9 | class UserForm(forms.ModelForm): 10 | """ 11 | Simple Django authentication User form for signup 12 | """ 13 | 14 | email = forms.EmailField(max_length=150, required=True) 15 | password = forms.CharField(widget=forms.PasswordInput()) 16 | 17 | class Meta: 18 | model = User 19 | fields = ("username", "password", "first_name", "last_name", "email") 20 | 21 | def __init__(self, *args, **kwargs): 22 | super(UserForm, self).__init__(*args, **kwargs) 23 | self.fields['username'].widget.attrs.update({'class': 'form-control'}) 24 | self.fields['password'].widget.attrs.update({'class': 'form-control'}) 25 | self.fields['first_name'].widget.attrs.update({'class': 'form-control'}) 26 | self.fields['last_name'].widget.attrs.update({'class': 'form-control'}) 27 | self.fields['email'].widget.attrs.update({'class': 'form-control'}) 28 | 29 | 30 | class UserEditForm(forms.ModelForm): 31 | """ 32 | user edit form for profile section 33 | """ 34 | email = forms.EmailField(max_length=150, required=True) 35 | 36 | class Meta: 37 | model = User 38 | fields = ("first_name", "last_name", "email") 39 | 40 | def __init__(self, *args, **kwargs): 41 | super(UserEditForm, self).__init__(*args, **kwargs) 42 | self.fields['first_name'].widget.attrs.update({'class': 'form-control'}) 43 | self.fields['last_name'].widget.attrs.update({'class': 'form-control'}) 44 | self.fields['email'].widget.attrs.update({'class': 'form-control'}) 45 | 46 | 47 | class StoreForm(forms.ModelForm): 48 | """ 49 | store form for store managers 50 | """ 51 | validation_messages = { 52 | "duplicate_store": "Store Name Already exists" , 53 | "dupicate_number": "Number Already exists with Store" 54 | } 55 | 56 | class Meta: 57 | model = Store 58 | fields = ('store_name', 'contact_number') 59 | 60 | labels = { 61 | 'store_name': "Enter Store Name", 62 | 'contact_number': "Enter Contact Number" 63 | } 64 | 65 | def __init__(self, *args, **kwargs): 66 | super(StoreForm, self).__init__(*args, **kwargs) 67 | self.fields['store_name'].widget.attrs.update({'class': 'form-control'}) 68 | self.fields['contact_number'].widget.attrs.update({'class': 'form-control'}) 69 | 70 | def clean_store_name(self): 71 | sn_instance = self.cleaned_data.get("store_name") 72 | validate = self.__class__._meta.model._default_manager.filter(store_name=sn_instance).exists() 73 | if validate: 74 | raise ValidationError(self.validation_messages.get("duplicate_store")) 75 | 76 | def clean_contact_number(self): 77 | cn_instance = self.cleaned_data.get("contact_number") 78 | validate = self.__class__._meta.model._default_manager.filter(contact_number=cn_instance).exists() 79 | if validate: 80 | raise ValidationError(self.validation_messages.get("dupicate_number")) 81 | 82 | 83 | class DeliveryBoyForm(forms.ModelForm): 84 | """ 85 | Delivery boy signup form 86 | """ 87 | validation_messages = { 88 | "dupicate_number": "Number Already exists with Store" 89 | } 90 | 91 | class Meta: 92 | model = DeliveryBoy 93 | fields = ('number',) 94 | 95 | labels = { 96 | 'number': "Enter Contact Number" 97 | } 98 | 99 | 100 | def clean_contact_number(self): 101 | cn_instance = self.cleaned_data.get("number") 102 | validate = self.__class__._meta.model._default_manager.filter(number=cn_instance).exists() 103 | if validate: 104 | raise ValidationError(self.validation_messages.get("dupicate_number")) 105 | 106 | 107 | class TaskForm(forms.ModelForm): 108 | """ 109 | task creation form store managers 110 | """ 111 | validation_messages = { 112 | "Title_Error": "Please Enter Some Other Title" 113 | } 114 | 115 | class Meta: 116 | model = Task 117 | fields = ('title', 'preiority', 'status') 118 | 119 | labels = { 120 | "title" : "Enter Title", 121 | "preiority" : "Select Task Preiority", 122 | "status": "Add Task Intial Status" 123 | } 124 | 125 | def __init__(self, *args, **kwargs): 126 | super(TaskForm, self).__init__(*args, **kwargs) 127 | self.fields['title'].widget.attrs.update({'class': 'form-control'}) 128 | self.fields['preiority'].widget.attrs.update({'class': 'form-control'}) 129 | self.fields['status'].widget.attrs.update({'class': 'form-control'}) 130 | 131 | def clean_title(self): 132 | title_instance = self.cleaned_data.get("title") 133 | validate = Task.objects.filter(title=title_instance, status=Task.ACCEPTED).exists() 134 | if validate: 135 | raise ValidationError(validation_messages["Title_Error"]) 136 | return title_instance 137 | 138 | -------------------------------------------------------------------------------- /store/models.py: -------------------------------------------------------------------------------- 1 | """ 2 | Author : Bala 3 | Description : StoreManager and DeliveryTask models lives in this file 4 | Note : 5 | """ 6 | 7 | import datetime 8 | import logging 9 | import traceback 10 | from django.db import models 11 | from django.db.models import Q 12 | from django.utils.translation import ugettext as _ 13 | from django.utils import timezone 14 | from django.contrib.auth.models import User 15 | from django.conf import settings 16 | from django.dispatch import receiver 17 | from django.urls import reverse 18 | from django.core.validators import ValidationError 19 | from django.db.models.signals import post_save 20 | from rest_framework.authtoken.models import Token 21 | from store.consts import validation_messages 22 | # Create your models here. 23 | 24 | @receiver(post_save, sender=settings.AUTH_USER_MODEL) 25 | def create_auth_token(sender, instance=None, created=False, **kwargs): 26 | if created: 27 | Token.objects.create(user=instance) 28 | 29 | 30 | class Store(models.Model): 31 | """ 32 | store manager model 33 | """ 34 | user = models.OneToOneField(User, 35 | on_delete=models.CASCADE, 36 | related_name='store') 37 | store_name = models.CharField(max_length=150) 38 | contact_number = models.CharField(max_length=12) 39 | 40 | def __str__(self): 41 | return self.store_name 42 | 43 | def __repr__(self): 44 | return self.store_name 45 | 46 | 47 | 48 | def validate_unique(self, *args, **kwargs): 49 | """ 50 | validates store_name and contact number as a unique 51 | """ 52 | super(Store, self).validate_unique(*args, **kwargs) 53 | sn_qs = self.__class__._default_manager.filter( 54 | store_name=self.store_name).exists() 55 | cn_qs = self.__class__._default_manager.filter( 56 | contact_number=self.contact_number).exists() 57 | if sn_qs: 58 | raise ValidationError(validation_messages.get("DUPLICATE_STORE")) 59 | if cn_qs: 60 | raise ValidationError(validation_messages.get("DUPLICATE_NUMBER")) 61 | 62 | def clean(self, *args, **kwargs): 63 | if self.store_name: 64 | self.store_name=self.store_name.lower() 65 | 66 | def save(self, *args, **kwargs): 67 | super(Store, self).save(*args, **kwargs) 68 | 69 | class Meta: 70 | verbose_name = _("Store Manager") 71 | verbose_name_plural = _("Store Managers") 72 | 73 | 74 | class DeliveryBoy(models.Model): 75 | """ 76 | delivery boy model 77 | """ 78 | user = models.OneToOneField(User, 79 | on_delete=models.CASCADE, 80 | related_name='delivery_boy') 81 | number = models.CharField(max_length=12, unique=True) 82 | 83 | def __str__(self): 84 | return self.user.get_full_name() 85 | 86 | def __repr__(self): 87 | return self.user.get_full_name() 88 | 89 | def validate_unique(self, *args, **kwargs): 90 | super(DeliveryBoy, self).validate_unique(*args, **kwargs) 91 | #qs = self.__class__._default_manger.filter(number=self.number).exists() 92 | qs = DeliveryBoy.objects.filter(number=self.number).exists() 93 | if qs: 94 | raise ValidationError(validation_messages.get("DUPLICATE_NUMBER")) 95 | 96 | class Meta: 97 | verbose_name = _("Delivery Boy") 98 | verbose_name_plural = _("Delivery Boys") 99 | 100 | 101 | class Task(models.Model): 102 | """ 103 | task model 104 | """ 105 | HIGH = 'HIGH' 106 | MEDIUM = 'MEDIUM' 107 | LOW = 'LOW' 108 | 109 | ACCEPTED = 'ACCEPTED' 110 | COMPLETED = 'COMPLETED' 111 | REJECTED = 'REJECTED' 112 | READY = 'READY' 113 | CANCELD = 'CANCELD' 114 | PREIORITY_CHOICES = ( 115 | (HIGH, 'High'), 116 | (MEDIUM, 'Medium'), 117 | (LOW, 'Low'), 118 | ) 119 | 120 | STATUS_CHOICES = ( 121 | (READY, 'Ready'), 122 | (ACCEPTED, 'Accepted'), 123 | (COMPLETED, 'Completed'), 124 | (REJECTED, 'Rejected'), 125 | (CANCELD, 'Canceld') 126 | ) 127 | 128 | title = models.CharField(max_length=100) 129 | store = models.ForeignKey(Store, on_delete=models.CASCADE) 130 | delivery_boy = models.ForeignKey(DeliveryBoy, 131 | on_delete=models.CASCADE, 132 | blank=True, null=True) 133 | preiority = models.CharField(max_length=6, choices=PREIORITY_CHOICES) 134 | status = models.CharField(max_length=10, choices=STATUS_CHOICES) 135 | created_at = models.DateTimeField( auto_now=True) 136 | accepted_at = models.DateTimeField(blank=True, null=True) 137 | completed_at = models.DateTimeField(blank=True, null=True) 138 | edited_at = models.DateTimeField(auto_now_add=True) 139 | celery_id = models.CharField(max_length=200, null=True, blank=True) 140 | 141 | def __str__(self): 142 | return self.title 143 | 144 | def __repr__(self): 145 | return self.title 146 | 147 | def get_absolute_url(self): 148 | return reverse('task_details', args=[str(self.id)]) 149 | 150 | class Meta: 151 | verbose_name = _("Delivery Task") 152 | verbose_name_plural = _("Delivery Tasks") 153 | ordering = ('created_at',) 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /delivery/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for delivery project. 3 | 4 | Generated by 'django-admin startproject' using Django 1.11. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.11/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/1.11/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.11/howto/deployment/checklist/ 21 | 22 | # SECURITY WARNING: keep the secret key used in production secret! 23 | SECRET_KEY = '_%w)@*4jt$7lh76v4m+rm@z577zwt+t$6&ilh5ojtj-75svw((' 24 | 25 | # SECURITY WARNING: don't run with debug turned on in production! 26 | DEBUG = True 27 | 28 | ALLOWED_HOSTS = ['192.168.0.108', 'localhost'] 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 | # 'channels', 41 | 'rest_framework', 42 | 'store', 43 | 44 | 'oauth2_provider', 45 | 'rest_framework_social_oauth2', 46 | 'rest_framework.authtoken', 47 | 'bootstrap3' 48 | ] 49 | 50 | MIDDLEWARE = [ 51 | 'django.middleware.security.SecurityMiddleware', 52 | 'django.contrib.sessions.middleware.SessionMiddleware', 53 | 'django.middleware.common.CommonMiddleware', 54 | 'django.middleware.csrf.CsrfViewMiddleware', 55 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 56 | 'django.contrib.messages.middleware.MessageMiddleware', 57 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 58 | ] 59 | REST_FRAMEWORK = { 60 | 'DEFAULT_PERMISSION_CLASSES': ( 61 | 'rest_framework.permissions.IsAuthenticated', 62 | ), 63 | 'DEFAULT_AUTHENTICATION_CLASSES': ( 64 | 'rest_framework.authentication.TokenAuthentication', 65 | ) 66 | } 67 | 68 | 69 | ROOT_URLCONF = 'delivery.urls' 70 | 71 | TEMPLATES = [ 72 | { 73 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 74 | 'DIRS': [os.path.join(BASE_DIR, 'templates')], 75 | 'APP_DIRS': True, 76 | 'OPTIONS': { 77 | 'context_processors': [ 78 | 'django.template.context_processors.debug', 79 | 'django.template.context_processors.request', 80 | 'django.contrib.auth.context_processors.auth', 81 | 'django.contrib.messages.context_processors.messages', 82 | ], 83 | }, 84 | }, 85 | ] 86 | 87 | WSGI_APPLICATION = 'delivery.wsgi.application' 88 | 89 | 90 | # Database 91 | # https://docs.djangoproject.com/en/1.11/ref/settings/#databases 92 | 93 | DATABASES = { 94 | 'default': { 95 | 'ENGINE': 'django.db.backends.sqlite3', 96 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 97 | } 98 | } 99 | 100 | 101 | # Password validation 102 | # https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators 103 | 104 | AUTH_PASSWORD_VALIDATORS = [ 105 | { 106 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 107 | }, 108 | { 109 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 110 | }, 111 | { 112 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 113 | }, 114 | { 115 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 116 | }, 117 | ] 118 | 119 | 120 | # Internationalization 121 | # https://docs.djangoproject.com/en/1.11/topics/i18n/ 122 | 123 | LANGUAGE_CODE = 'en-us' 124 | 125 | TIME_ZONE = 'Asia/Kolkata' 126 | 127 | USE_I18N = True 128 | 129 | USE_L10N = True 130 | 131 | USE_TZ = True 132 | 133 | 134 | # Static files (CSS, JavaScript, Images) 135 | # https://docs.djangoproject.com/en/1.11/howto/static-files/ 136 | 137 | STATIC_URL = '/static/' 138 | STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') 139 | STATICFILES_DIRS = [ 140 | os.path.join(BASE_DIR, "static") 141 | ] 142 | LOGIN_REDIRECT_URL = '/' 143 | 144 | MEDIA_ROOT = os.path.join(BASE_DIR, 'media') 145 | MEDIA_URL = '/media/' 146 | 147 | 148 | 149 | # BROKER_URL = 'amqp://localhost' 150 | # CELERY_RESULT_BACKEND = 'amqp://localhost' 151 | BROKER_URL = 'c' 152 | CELERY_ACCEPT_CONTENT = ['json'] 153 | CELERY_TASK_SERIALIZER = 'json' 154 | CELERY_RESULT_SERIALIZER = 'json' 155 | CELERY_TIMEZONE = 'Asia/Kolkata' 156 | 157 | 158 | 159 | # Channels settings 160 | CHANNEL_LAYERS = { 161 | "default": { 162 | "BACKEND": "asgi_redis.RedisChannelLayer", # use redis backend 163 | "CONFIG": { 164 | "hosts": [os.environ.get('REDIS_URL', 'redis://localhost:6379')], # set redis address 165 | }, 166 | "ROUTING": "example.routing.channel_routing", # load routing from our routing.py file 167 | }, 168 | } 169 | 170 | ASGI_APPLICATION = "delivery.routing.application" 171 | # STATICFILES_STORAGE = 'whitenoise.django.GzipManifestStaticFilesStorage' 172 | -------------------------------------------------------------------------------- /static/css/bootstrap-theme.min.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["less/theme.less","less/mixins/vendor-prefixes.less","less/mixins/gradients.less","less/mixins/reset-filter.less"],"names":[],"mappings":";;;;AAmBA,YAAA,aAAA,UAAA,aAAA,aAAA,aAME,YAAA,EAAA,KAAA,EAAA,eC2CA,mBAAA,MAAA,EAAA,IAAA,EAAA,sBAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,MAAA,EAAA,IAAA,EAAA,sBAAA,EAAA,IAAA,IAAA,iBDvCR,mBAAA,mBAAA,oBAAA,oBAAA,iBAAA,iBAAA,oBAAA,oBAAA,oBAAA,oBAAA,oBAAA,oBCsCA,mBAAA,MAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,MAAA,EAAA,IAAA,IAAA,iBDlCR,qBAAA,sBAAA,sBAAA,uBAAA,mBAAA,oBAAA,sBAAA,uBAAA,sBAAA,uBAAA,sBAAA,uBAAA,+BAAA,gCAAA,6BAAA,gCAAA,gCAAA,gCCiCA,mBAAA,KACQ,WAAA,KDlDV,mBAAA,oBAAA,iBAAA,oBAAA,oBAAA,oBAuBI,YAAA,KAyCF,YAAA,YAEE,iBAAA,KAKJ,aErEI,YAAA,EAAA,IAAA,EAAA,KACA,iBAAA,iDACA,iBAAA,4CAAA,iBAAA,qEAEA,iBAAA,+CCnBF,OAAA,+GH4CA,OAAA,0DACA,kBAAA,SAuC2C,aAAA,QAA2B,aAAA,KArCtE,mBAAA,mBAEE,iBAAA,QACA,oBAAA,EAAA,MAGF,oBAAA,oBAEE,iBAAA,QACA,aAAA,QAMA,sBAAA,6BAAA,4BAAA,6BAAA,4BAAA,4BAAA,uBAAA,8BAAA,6BAAA,8BAAA,6BAAA,6BAAA,gCAAA,uCAAA,sCAAA,uCAAA,sCAAA,sCAME,iBAAA,QACA,iBAAA,KAgBN,aEtEI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDAEA,OAAA,+GCnBF,OAAA,0DH4CA,kBAAA,SACA,aAAA,QAEA,mBAAA,mBAEE,iBAAA,QACA,oBAAA,EAAA,MAGF,oBAAA,oBAEE,iBAAA,QACA,aAAA,QAMA,sBAAA,6BAAA,4BAAA,6BAAA,4BAAA,4BAAA,uBAAA,8BAAA,6BAAA,8BAAA,6BAAA,6BAAA,gCAAA,uCAAA,sCAAA,uCAAA,sCAAA,sCAME,iBAAA,QACA,iBAAA,KAiBN,aEvEI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDAEA,OAAA,+GCnBF,OAAA,0DH4CA,kBAAA,SACA,aAAA,QAEA,mBAAA,mBAEE,iBAAA,QACA,oBAAA,EAAA,MAGF,oBAAA,oBAEE,iBAAA,QACA,aAAA,QAMA,sBAAA,6BAAA,4BAAA,6BAAA,4BAAA,4BAAA,uBAAA,8BAAA,6BAAA,8BAAA,6BAAA,6BAAA,gCAAA,uCAAA,sCAAA,uCAAA,sCAAA,sCAME,iBAAA,QACA,iBAAA,KAkBN,UExEI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDAEA,OAAA,+GCnBF,OAAA,0DH4CA,kBAAA,SACA,aAAA,QAEA,gBAAA,gBAEE,iBAAA,QACA,oBAAA,EAAA,MAGF,iBAAA,iBAEE,iBAAA,QACA,aAAA,QAMA,mBAAA,0BAAA,yBAAA,0BAAA,yBAAA,yBAAA,oBAAA,2BAAA,0BAAA,2BAAA,0BAAA,0BAAA,6BAAA,oCAAA,mCAAA,oCAAA,mCAAA,mCAME,iBAAA,QACA,iBAAA,KAmBN,aEzEI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDAEA,OAAA,+GCnBF,OAAA,0DH4CA,kBAAA,SACA,aAAA,QAEA,mBAAA,mBAEE,iBAAA,QACA,oBAAA,EAAA,MAGF,oBAAA,oBAEE,iBAAA,QACA,aAAA,QAMA,sBAAA,6BAAA,4BAAA,6BAAA,4BAAA,4BAAA,uBAAA,8BAAA,6BAAA,8BAAA,6BAAA,6BAAA,gCAAA,uCAAA,sCAAA,uCAAA,sCAAA,sCAME,iBAAA,QACA,iBAAA,KAoBN,YE1EI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDAEA,OAAA,+GCnBF,OAAA,0DH4CA,kBAAA,SACA,aAAA,QAEA,kBAAA,kBAEE,iBAAA,QACA,oBAAA,EAAA,MAGF,mBAAA,mBAEE,iBAAA,QACA,aAAA,QAMA,qBAAA,4BAAA,2BAAA,4BAAA,2BAAA,2BAAA,sBAAA,6BAAA,4BAAA,6BAAA,4BAAA,4BAAA,+BAAA,sCAAA,qCAAA,sCAAA,qCAAA,qCAME,iBAAA,QACA,iBAAA,KA2BN,eAAA,WClCE,mBAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,EAAA,IAAA,IAAA,iBD2CV,0BAAA,0BE3FI,iBAAA,QACA,iBAAA,oDACA,iBAAA,+CAAA,iBAAA,wEACA,iBAAA,kDACA,OAAA,+GF0FF,kBAAA,SAEF,yBAAA,+BAAA,+BEhGI,iBAAA,QACA,iBAAA,oDACA,iBAAA,+CAAA,iBAAA,wEACA,iBAAA,kDACA,OAAA,+GFgGF,kBAAA,SASF,gBE7GI,iBAAA,iDACA,iBAAA,4CACA,iBAAA,qEAAA,iBAAA,+CACA,OAAA,+GACA,OAAA,0DCnBF,kBAAA,SH+HA,cAAA,ICjEA,mBAAA,MAAA,EAAA,IAAA,EAAA,sBAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,MAAA,EAAA,IAAA,EAAA,sBAAA,EAAA,IAAA,IAAA,iBD6DV,sCAAA,oCE7GI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SD2CF,mBAAA,MAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,MAAA,EAAA,IAAA,IAAA,iBD0EV,cAAA,iBAEE,YAAA,EAAA,IAAA,EAAA,sBAIF,gBEhII,iBAAA,iDACA,iBAAA,4CACA,iBAAA,qEAAA,iBAAA,+CACA,OAAA,+GACA,OAAA,0DCnBF,kBAAA,SHkJA,cAAA,IAHF,sCAAA,oCEhII,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SD2CF,mBAAA,MAAA,EAAA,IAAA,IAAA,gBACQ,WAAA,MAAA,EAAA,IAAA,IAAA,gBDgFV,8BAAA,iCAYI,YAAA,EAAA,KAAA,EAAA,gBAKJ,qBAAA,kBAAA,mBAGE,cAAA,EAqBF,yBAfI,mDAAA,yDAAA,yDAGE,MAAA,KE7JF,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,UFqKJ,OACE,YAAA,EAAA,IAAA,EAAA,qBC3HA,mBAAA,MAAA,EAAA,IAAA,EAAA,sBAAA,EAAA,IAAA,IAAA,gBACQ,WAAA,MAAA,EAAA,IAAA,EAAA,sBAAA,EAAA,IAAA,IAAA,gBDsIV,eEtLI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF8KF,aAAA,QAKF,YEvLI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF8KF,aAAA,QAMF,eExLI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF8KF,aAAA,QAOF,cEzLI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF8KF,aAAA,QAeF,UEjMI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFuMJ,cE3MI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFwMJ,sBE5MI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFyMJ,mBE7MI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF0MJ,sBE9MI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF2MJ,qBE/MI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF+MJ,sBElLI,iBAAA,yKACA,iBAAA,oKACA,iBAAA,iKFyLJ,YACE,cAAA,IC9KA,mBAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,EAAA,IAAA,IAAA,iBDgLV,wBAAA,8BAAA,8BAGE,YAAA,EAAA,KAAA,EAAA,QEnOE,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFiOF,aAAA,QALF,+BAAA,qCAAA,qCAQI,YAAA,KAUJ,OCnME,mBAAA,EAAA,IAAA,IAAA,gBACQ,WAAA,EAAA,IAAA,IAAA,gBD4MV,8BE5PI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFyPJ,8BE7PI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF0PJ,8BE9PI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF2PJ,2BE/PI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF4PJ,8BEhQI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF6PJ,6BEjQI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFoQJ,MExQI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFsQF,aAAA,QC3NA,mBAAA,MAAA,EAAA,IAAA,IAAA,gBAAA,EAAA,IAAA,EAAA,qBACQ,WAAA,MAAA,EAAA,IAAA,IAAA,gBAAA,EAAA,IAAA,EAAA"} -------------------------------------------------------------------------------- /templates/deliver/tasks.html: -------------------------------------------------------------------------------- 1 | {% extends 'deliver/base.html' %} 2 | 3 | {% block page %} 4 | 5 |
6 |
7 |

New Tasks

8 |
9 |
10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | {% for task in tasks %} 24 | 25 | 26 | 27 | 28 | 29 | 30 | 32 | 33 | 34 | {% endfor %} 35 | 36 | 37 |
IdTitleStorePreiorityActionStatus
{{ task.id }}{{ task.title }}{{ task.store }}{{ task.preiority}}{{task.status}}
38 |
39 |
40 | 41 |
42 |
43 |

Accepted Tasks

44 |
45 |
46 |
47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | {% for task in accepted_tasks %} 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | {% endfor %} 69 | 70 | 71 |
IdTitleStoreRejectCompletedStatus
{{ task.id }}{{ task.title }}{{ task.store }}{{task.status}}
72 |
73 |
74 | 75 |
76 |
77 |

Completed Tasks

78 |
79 |
80 |
81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | {% for task in completed_tasks %} 92 | 93 | 94 | 95 | 96 | 97 | 98 | {% endfor %} 99 | 100 | 101 |
IdTitleStoreCompleted
{{ task.id }}{{ task.title }}{{ task.store }}{{task.status}}
102 |
103 |
104 | 157 | {% endblock %} 158 | -------------------------------------------------------------------------------- /store/apis.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | import datetime 4 | from django.utils import timezone 5 | from django.http import JsonResponse 6 | from django.views.decorators.csrf import csrf_exempt 7 | from django.db import transaction 8 | from oauth2_provider.models import AccessToken 9 | from rest_framework import status 10 | from store.models import Task, Store, DeliveryBoy 11 | from store.serializers import (StoreSerializer, 12 | TaskStoreSerializer, 13 | TaskDeliverBoySerializer, 14 | TaskSerializer) 15 | # from store.tasks import (deliver_task_accept_notification, 16 | # deliver_task_reject_notification, 17 | # deliver_task_completed_notification, 18 | # store_created_new_task_notification) 19 | 20 | 21 | ############### 22 | # store # 23 | ############### 24 | 25 | def store_task_notification(request, last_request_time): 26 | notification = Task.objects.get(created_at__gt=last_request_time, status=Task.READY) 27 | return JsonResponse({"notification": notification}) 28 | 29 | def store_manager_cancel_task(request): 30 | """ 31 | end point for store manager can cancel task which is no longer accepted 32 | """ 33 | with transaction.atomic(): 34 | # using atomic transations may be store manager and deliver boy 35 | # performs certain action at same time 36 | try: 37 | task_id = request.GET.get('task_id', None) 38 | task_instance = Task.objects.get(id=task_id, 39 | store=request.user.store, 40 | delivery_boy=None, 41 | status=Task.READY) 42 | task_instance.status = Task.CANCELD 43 | task_instance.save() 44 | success_data = { 45 | 'result': 'OK' 46 | } 47 | return JsonResponse(success_data, 48 | status=status.HTTP_200_OK) 49 | except ValueError: 50 | return JsonResponse( 51 | {"status": "failed", 52 | "error":"task accepted by delivery boy"}) 53 | 54 | def get_store_manager_all_tasks(request): 55 | """ 56 | end point for store manager to retrive all tasks 57 | """ 58 | tasks = TaskSerializer( 59 | Task.objects.filter(store=request.user.store).order_by("-id"), 60 | many=True 61 | ).data 62 | return JsonResponse({"tasks" : tasks}) 63 | 64 | 65 | 66 | def delivery_boy_accept_task(request): 67 | """ 68 | end point for deliver boy can accpet task 69 | """ 70 | task_id = request.GET.get('task_id', None) 71 | if Task.objects.filter(delivery_boy=request.user.delivery_boy, status=Task.ACCEPTED).count() >= 3: 72 | return JsonResponse({"status": "failed", "error": "reaced maximum limit"}) 73 | 74 | with transaction.atomic(): 75 | # using atomic transactions to avoid race conditions 76 | # may two users can access same resource at a time to avoid that 77 | try: 78 | task_instance = Task.objects.get(id=task_id, delivery_boy=None) 79 | task_instance.status = Task.ACCEPTED 80 | task_instance.delivery_boy = request.user.delivery_boy 81 | task_instance.accepted_at = datetime.datetime.now() 82 | task_instance.save() 83 | success_data = { 84 | "result": "success" 85 | } 86 | # delivery_boy_accept_task.delay(task_instance.id) 87 | return JsonResponse(success_data, status=status.HTTP_201_CREATED) 88 | 89 | except Task.DoesNotExist: 90 | return JsonResponse({"status": "failed", "error":"task accepted by another delivery boy"}) 91 | 92 | 93 | def delivery_boy_reject_task(request): 94 | """ 95 | endpoint for deliver boy for rejecting task 96 | """ 97 | task_id = request.GET.get('task_id', None) 98 | d_boy = request.user.delivery_boy 99 | task = Task.objects.get(id=task_id, 100 | delivery_boy=d_boy, 101 | status=Task.ACCEPTED) 102 | task.status = Task.READY 103 | task.delivery_boy = None 104 | task_id = task.id 105 | task.save() 106 | # delivery_boy_reject_task.delay(task_id) 107 | return JsonResponse({"status": "success"}, status=status.HTTP_200_OK) 108 | 109 | 110 | def delivery_boy_complete_task(request): 111 | """ 112 | end point for deliver boy for completed task 113 | """ 114 | task_id = request.GET.get('task_id', None) 115 | d_boy = request.user.delivery_boy 116 | task = Task.objects.get(id=task_id, delivery_boy=d_boy) 117 | task.status = Task.COMPLETED 118 | task_id = task.id 119 | task.save() 120 | # deliver_task_completed_notification.delay(task_id) 121 | return JsonResponse({"status": "success"}, status=status.HTTP_200_OK) 122 | 123 | 124 | def get_deliver_boy_completed_tasks(request): 125 | access_token = AccessToken.objects.get( 126 | token = request.GET.get("access_token"), 127 | expires__gt = timezone.now()) 128 | d_boy = access_token.user.delivery_boy 129 | tasks = TaskSerializer( 130 | Task.objects.filter(status=Task.COMPLETED, delivery_boy=d_boy).order_by("-id"), 131 | many=True 132 | ).data 133 | return JsonResponse({"tasks" : tasks}) 134 | 135 | 136 | def delivery_boy_ready_new_tasks(request): 137 | tasks = TaskSerializer( 138 | Task.objects.filter(status=Task.READY, delivery_boy=None).order_by("-id"), 139 | many=True 140 | ).data 141 | return JsonResponse({"tasks" : tasks}) 142 | 143 | 144 | def delivery_boy_get_latest_task(request): 145 | access_token = AccessToken.objects.get(token=request.GET.get("access_token"), expires__gt=timezone.now()) 146 | d_boy = access_token.user.delivery_boy 147 | tasks = TaskSerializer(Task.objects.get.filter(delivery_boy=d_boy).order_by("-created_at").last()).data 148 | return JsonResponse({"task": task}) 149 | 150 | 151 | 152 | ####################### 153 | # token end points # 154 | ####################### 155 | 156 | @csrf_exempt 157 | def delivery_boy_accept_task_token(request): 158 | if request.method == 'POST': 159 | access_token = AccessToken.objects.get(token=request.POST.get("access_token"), expires__gt=timezone.now()) 160 | d_boy = access_token.user.delivery_boy 161 | 162 | if Task.objects.filter(delivery_boy=d_boy).exclude(status=Task.ACCEPTED): 163 | return JsonResponse({"status": "failed", "error": "You can accept one task at a time"}) 164 | 165 | with transaction.atomic(): 166 | try: 167 | task = Task.objects.select_for_update().get( 168 | id=request.POST["task_id"], 169 | delivery_boy=None) 170 | task.delivery_boy = d_boy 171 | task.status = Task.ACCEPTED 172 | # implement push notification here store manager 173 | task.save() 174 | return JsonResponse({"status": "success"}) 175 | 176 | except Task.DoesNotExist: 177 | return JsonResponse({"status": "failed", "error":"task accepted by another delivery boy"}) 178 | 179 | 180 | def delivery_boy_complete_task_token(request): 181 | access_token = AccessToken.objects.get(token=request.POST.get("access_token"), expires__gt=timezone.now()) 182 | d_boy = access_token.user.delivery_boy 183 | task = Task.objects.get(id=request.POST["task_id"], delivery_boy=d_boy) 184 | task.status = Task.COMPLETED 185 | # implement push notification here store manager 186 | task.save() 187 | return JsonResponse({"status": "success"}) 188 | 189 | 190 | def delivery_boy_reject_task_token(request): 191 | access_token = AccessToken.objects.get(token=request.POST.get("access_token"), expires__gt=timezone.now()) 192 | d_boy = access_token.user.delivery_boy 193 | task = Task.objects.get(id=request.POST["task_id"], delivery_boy=d_boy, status=Task.ACCEPTED) 194 | task.status = Task.READY 195 | # implement push notification here store manager 196 | task.save() 197 | return JsonResponse({"status": "success"}) -------------------------------------------------------------------------------- /store/views.py: -------------------------------------------------------------------------------- 1 | """ 2 | Author : Bala 3 | Description : Store Manager views lives in this file 4 | 5 | """ 6 | import datetime 7 | from django.shortcuts import render, redirect 8 | from django.contrib.auth.decorators import login_required 9 | from django.contrib.auth import authenticate, login, logout 10 | from django.contrib.auth.models import User 11 | from django.http.response import HttpResponse 12 | from django.core.validators import ValidationError 13 | from django.http import HttpResponseRedirect 14 | from django.urls import reverse 15 | from django.db.models import Q 16 | from django.shortcuts import render_to_response 17 | from django.template import RequestContext 18 | from django.contrib import messages 19 | from django.http import JsonResponse 20 | from django.shortcuts import render 21 | from django.contrib.auth.decorators import user_passes_test 22 | from rest_framework import viewsets 23 | from django.views.generic import TemplateView,CreateView,DetailView 24 | from store.models import Store, Task 25 | from store.forms import (UserForm, 26 | UserEditForm, 27 | StoreForm, 28 | TaskForm, 29 | DeliveryBoyForm) 30 | # from store.tasks import store_created_new_task_notification 31 | # Create your views here. 32 | 33 | 34 | def celery_task_checker(request): 35 | return render(request, 'celery.html') 36 | 37 | 38 | def home(request): 39 | try: 40 | if request.user.store: 41 | return redirect(store_home) 42 | except Exception as e: 43 | 44 | # elif request.user.delivery_boy: 45 | return redirect(delivery_boy_home) 46 | 47 | def get_auth_token(request): 48 | return redirect(store_home) 49 | 50 | 51 | @login_required(login_url='/store/signin') 52 | def store_home(request): 53 | return redirect(store_tasks) 54 | 55 | 56 | def store_signup(request): 57 | user_form = UserForm() 58 | store_form = StoreForm() 59 | 60 | if request.method == "POST": 61 | user_form = UserForm(request.POST) 62 | store_form = StoreForm(request.POST) 63 | 64 | if user_form.is_valid() and store_form.is_valid(): 65 | new_user_instance = User.objects.create_user(**user_form.cleaned_data) 66 | new_store_instance = store_form.save(commit=False) 67 | new_store_instance.user = new_user_instance 68 | new_store_instance.save() 69 | 70 | login(request, authenticate( 71 | username=user_form.cleaned_data["username"], 72 | password=user_form.cleaned_data["password"] 73 | )) 74 | return redirect(store_home) 75 | return render(request, "store/store_signup.html", 76 | {"user_form": user_form, "store_form":store_form}) 77 | 78 | 79 | @login_required(login_url='/store/signin/') 80 | def store_account(request): 81 | user_form = UserEditForm(instance=request.user) 82 | store_form = StoreForm(instance=request.user.store) 83 | 84 | if request.method == "POST": 85 | user_form = UserEditForm(request.POST, instance=request.user) 86 | store_form = StoreForm(request.POST, instance=request.user.store) 87 | if user_form.is_valid() and store_form.is_valid(): 88 | user_form.save() 89 | store_form.save() 90 | return render(request, 'store/store_account.html', 91 | {'user_form':user_form, 'store_form':store_form}) 92 | 93 | 94 | 95 | @login_required(login_url='/store/signin/') 96 | def create_task(request): 97 | task_form = TaskForm() 98 | if request.method == "POST": 99 | task_form = TaskForm(request.POST) 100 | if task_form.is_valid(): 101 | #task_instance = Task.objects.create(**task_form.cleaned_data) 102 | task_instance = task_form.save(commit=False) 103 | task_instance.store = request.user.store 104 | task_instance.status = Task.READY 105 | task_instance.save() 106 | messages.success(request, 'New Task Created') 107 | # store_created_new_task_notification.delay(task_instance.id) 108 | return redirect(store_home) 109 | 110 | return render(request, 'store/create_task.html', {'task_form': task_form}) 111 | 112 | 113 | @login_required(login_url="/store/signin") 114 | def store_tasks(request): 115 | print("user") 116 | print(request.user.store) 117 | if request.method == "POST": 118 | pass 119 | #tasks = Task.objects.filter(store=request.user.store).order_by("-id") 120 | tasks = Task.objects.filter(store=request.user.store).order_by("-id") 121 | return render(request, "store/tasks.html", {"tasks":tasks}) 122 | 123 | 124 | @login_required(login_url="/store/signin") 125 | def store_task(request, id): 126 | task = Task.objects.get(id=id, store=request.user.store) 127 | return render(request, "store/task.html", {"task": task}) 128 | 129 | 130 | def delivery_boy_signup(request): 131 | user_form = UserForm() 132 | delivery_boy_form = DeliveryBoyForm() 133 | 134 | if request.method == "POST": 135 | user_form = UserForm(request.POST) 136 | delivery_boy_form = DeliveryBoyForm(request.POST) 137 | 138 | if user_form.is_valid() and delivery_boy_form.is_valid(): 139 | new_user_instance = User.objects.create_user(**user_form.cleaned_data) 140 | delivery_boy_instance = delivery_boy_form.save(commit=False) 141 | delivery_boy_instance.user = new_user_instance 142 | delivery_boy_instance.save() 143 | 144 | login(request, authenticate( 145 | username=user_form.cleaned_data['username'], 146 | password=user_form.cleaned_data['password'] 147 | )) 148 | return redirect(delivery_boy_home) 149 | return render(request, "deliver/delivery_boy_signup.html", 150 | {"user_form": user_form, "delivery_boy_form": delivery_boy_form}) 151 | 152 | 153 | 154 | @login_required(login_url='/deliever/signin') 155 | def delivery_boy_home(request): 156 | return redirect(deliver_tasks) 157 | 158 | 159 | @login_required(login_url='/deliver/signin') 160 | def delivery_boy_account(request): 161 | user_form = UserEditForm(instance=request.user) 162 | delivery_boy_form = DeliveryBoyForm( 163 | instance=request.user.delivery_boy) 164 | 165 | if request.method == "POST": 166 | user_form = UserEditForm( 167 | request.POST, instance=request.user) 168 | delivery_boy_form = DeliveryBoyForm( 169 | request.POST, instance=request.user.delivery_boy) 170 | if user_form.is_valid() and delivery_boy_form.is_valid(): 171 | user_form.save() 172 | delivery_boy_form.save() 173 | return render(request, 'deliver/delivery_boy_account.html', 174 | {'user_form':user_form, 'delivery_boy_form':delivery_boy_form}) 175 | 176 | 177 | @login_required(login_url="/deliever/signin") 178 | def deliver_tasks(request): 179 | tasks = Task.objects.filter(delivery_boy=None).exclude( 180 | Q(status=Task.CANCELD) | Q(status=Task.COMPLETED)).order_by('-created_at') 181 | accepted_tasks = Task.objects.filter( 182 | status=Task.ACCEPTED, delivery_boy=request.user.delivery_boy).order_by('-created_at') 183 | completed_tasks = Task.objects.filter( 184 | status=Task.COMPLETED, delivery_boy=request.user.delivery_boy).order_by('-created_at') 185 | return render(request, "deliver/tasks.html", 186 | {"tasks": tasks, 187 | "accepted_tasks": accepted_tasks, 188 | "completed_tasks": completed_tasks}) 189 | 190 | class TaskDetails(DetailView): 191 | template_name = 'store/task_details.html' 192 | model = Task 193 | context_object_name = 'task' 194 | 195 | def handler404(request, *args, **argv): 196 | response = render_to_response('custom_404_view.html', {}, 197 | context_instance=RequestContext(request)) 198 | response.status_code = 404 199 | return response 200 | 201 | def handler500(request, *args, **argv): 202 | response = render_to_response('custom_404_view.html', {}, 203 | context_instance=RequestContext(request)) 204 | response.status_code = 500 205 | return response 206 | -------------------------------------------------------------------------------- /static/js/validate.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function(){ 2 | $("#register_form").submit(function(e){ 3 | e.preventDefault(); 4 | $("#name-warning").hide(); 5 | $("#email-warning").hide(); 6 | $("#password-warning").hide(); 7 | if(document.forms["register_form"]["name"].value == '') 8 | { 9 | $("#name-warning").show(); 10 | return; 11 | } 12 | if(document.forms["register_form"]["email"].value=='') 13 | { 14 | $("#email-warning").show(); 15 | return; 16 | } 17 | if(document.forms["register_form"]["password"].value=='') 18 | { 19 | $("#password-warning").show(); 20 | return; 21 | } 22 | $.post("/quiz/create/", 23 | { 24 | name : document.forms["register_form"]["name"].value, 25 | email : document.forms["register_form"]["email"].value, 26 | password : document.forms["register_form"]["password"].value, 27 | csrfmiddlewaretoken :document.forms["register_form"]["csrfmiddlewaretoken"].value 28 | }, 29 | function(data,status) 30 | { 31 | if (status == "success") 32 | { 33 | $("#modal1").modal('hide'); 34 | $("#register-success").show(); 35 | } 36 | } 37 | ); 38 | }) ; 39 | $("#login_form").submit(function(e){ 40 | // alert("hello"); 41 | e.preventDefault(); 42 | $.post("/quiz/validate_login/", 43 | { 44 | username : document.forms["login_form"]["username"].value, 45 | password : document.forms["login_form"]["password"].value, 46 | csrfmiddlewaretoken : document.forms["login_form"]["csrfmiddlewaretoken"].value 47 | }, 48 | function(data,status) 49 | { 50 | window.location.href="/quiz/test"; 51 | } 52 | ); 53 | }); 54 | $(".add_exam").click(function(){ 55 | $(".glyphicon-plus").toggle(); 56 | $(".glyphicon-arrow-down").toggle(); 57 | $("#show-exam-form").slideToggle(); 58 | }); 59 | function add_questions(exam_id,i) 60 | { 61 | $("#exam_list").hide(); 62 | $("#add_questions").show(); 63 | $("#num-question-btn").click(function(){ 64 | $("#add_questions").hide(); 65 | $("#read-questions").show(); 66 | count = $("#question-no").val(); 67 | //alert(count); 68 | console.log("quesion"); 69 | console.log(document.forms["question-form"]["question"].value); 70 | console.log(document.forms["question-form"]["answer"].value); 71 | $("#question-form").submit(function (e) { 72 | e.preventDefault(); 73 | 74 | $("#icon-span").attr("class","glyphicon glyphicon-ok"); 75 | $.post("/quiz/add_question/", 76 | { 77 | question : document.forms["question-form"]["question"].value, 78 | option1 : document.forms["question-form"]["option1"].value, 79 | option2 : document.forms["question-form"]["option2"].value, 80 | option3 : document.forms["question-form"]["option3"].value, 81 | option4 : document.forms["question-form"]["option4"].value, 82 | answer : document.forms["question-form"]["answer"].value, 83 | exam : exam_id, 84 | csrfmiddlewaretoken : document.forms["question-form"]["csrfmiddlewaretoken"].value 85 | }, 86 | function(data,success) 87 | { 88 | document.forms["question-form"]["question"].value = ""; 89 | document.forms["question-form"]["option1"].value = ""; 90 | document.forms["question-form"]["option2"].value = ""; 91 | document.forms["question-form"]["option3"].value = ""; 92 | document.forms["question-form"]["option4"].value = ""; 93 | document.forms["question-form"]["answer"].value = ""; 94 | $("#icon-span").attr("class","glyphicon glyphicon-forward"); 95 | } 96 | ); 97 | i++; 98 | if(i>=count) { 99 | $("#read-questions").hide(); 100 | window.location.reload(); 101 | } 102 | }); 103 | }); 104 | } 105 | $("#exam-form").submit(function(e){ 106 | // alert("helo"); 107 | e.preventDefault(); 108 | $.post("/quiz/add_exam/", 109 | { 110 | exam_name : document.forms["exam-form"]["exam_name"].value, 111 | user : document.forms["exam-form"]["user"].value, 112 | csrfmiddlewaretoken :document.forms["exam-form"]["csrfmiddlewaretoken"].value 113 | }, 114 | function(data,status) 115 | { 116 | //alert(data); 117 | $("#exam_list").append(template(document.forms["exam-form"]["user"].value,document.forms["exam-form"]["exam_name"].value)); 118 | $(".add_exam").click(); 119 | document.forms["exam-form"]["exam_name"].value = ""; 120 | add_questions(data,0); 121 | } 122 | ); 123 | }); 124 | function show_result(count,total) 125 | { 126 | $("#count").text(count); 127 | $("#total").text(total); 128 | $("#score").slideDown(); 129 | 130 | } 131 | $(".exit-btn").click(function(){ 132 | window.location.reload(); 133 | }); 134 | function test(data,count) 135 | { 136 | j = 1; 137 | $(".select-option").click(function(){ 138 | $(".glyphicon-ok").attr("class","glyphicon glyphicon-unchecked col-sm-offset-1"); 139 | $(this).find(".glyphicon").attr("class","glyphicon glyphicon-ok col-sm-offset-1"); 140 | $("#option-answer").val($(this).find(".option").text()); 141 | }); 142 | $("#verify").click(function(){ 143 | $(".before").hide(); 144 | $(".after").show(); 145 | if($("#option-answer").val() == data[j-1].answer) 146 | { 147 | $(".after-ok").show(); 148 | } 149 | else{ 150 | $(".after-not-ok").show(); 151 | } 152 | }); 153 | $("#after").click(function(){ 154 | if($("#option-answer").val() == data[j-1].answer) 155 | count++; 156 | if(j >= data.length) 157 | { 158 | $(".after").hide(); 159 | $(".after-ok").hide(); 160 | $(".after-not-ok").hide(); 161 | $(".glyphicon-ok").attr("class","glyphicon glyphicon-unchecked col-sm-offset-1"); 162 | $ (".before").show(); 163 | $("#question-display").hide(); 164 | 165 | exam = data[0]['exam'] 166 | $.ajax({ 167 | url: '/save_result/', 168 | data: { 169 | 'result': count, 170 | 'exam': exam 171 | }, 172 | dataType: 'json', 173 | success: function (data) { 174 | if (data.is_taken) { 175 | alert("Your test is already completed this result won't be consider."); 176 | } 177 | } 178 | }); 179 | 180 | show_result(count,data.length); 181 | return; 182 | } 183 | $(".question-place").html(data[j].question); 184 | $(".option1-place").html(data[j].option1); 185 | $(".option2-place").html(data[j].option2); 186 | $(".option3-place").html(data[j].option3); 187 | $(".option4-place").html(data[j].option4); 188 | $(".after").hide(); 189 | $(".after-ok").hide(); 190 | $(".after-not-ok").hide(); 191 | $(".glyphicon-ok").attr("class","glyphicon glyphicon-unchecked col-sm-offset-1"); 192 | $(".before").show(); 193 | j++; 194 | }); 195 | } 196 | $("#exam_list").on('click','.exam-panel',function(){ 197 | $("#exam_list").hide(); 198 | exam_id = $(this).find(".exam_template").attr('id'); 199 | $.get("/quiz/api/question/",function(data,status){ 200 | var i; 201 | //alert("hello"); 202 | data2 = []; 203 | for(i=0;ili>a:focus,.dropdown-menu>li>a:hover{background-color:#e8e8e8;background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{background-color:#2e6da4;background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}.navbar-default{background-image:-webkit-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-o-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#f8f8f8));background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075)}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.open>a{background-image:-webkit-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-o-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dbdbdb),to(#e2e2e2));background-image:linear-gradient(to bottom,#dbdbdb 0,#e2e2e2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.075);box-shadow:inset 0 3px 9px rgba(0,0,0,.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,.25)}.navbar-inverse{background-image:-webkit-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-o-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#3c3c3c),to(#222));background-image:linear-gradient(to bottom,#3c3c3c 0,#222 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-radius:4px}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.open>a{background-image:-webkit-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-o-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#080808),to(#0f0f0f));background-image:linear-gradient(to bottom,#080808 0,#0f0f0f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.25);box-shadow:inset 0 3px 9px rgba(0,0,0,.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,.25)}.navbar-fixed-bottom,.navbar-fixed-top,.navbar-static-top{border-radius:0}@media (max-width:767px){.navbar .navbar-nav .open .dropdown-menu>.active>a,.navbar .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}}.alert{text-shadow:0 1px 0 rgba(255,255,255,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05)}.alert-success{background-image:-webkit-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#c8e5bc));background-image:linear-gradient(to bottom,#dff0d8 0,#c8e5bc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);background-repeat:repeat-x;border-color:#b2dba1}.alert-info{background-image:-webkit-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#b9def0));background-image:linear-gradient(to bottom,#d9edf7 0,#b9def0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);background-repeat:repeat-x;border-color:#9acfea}.alert-warning{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#f8efc0));background-image:linear-gradient(to bottom,#fcf8e3 0,#f8efc0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);background-repeat:repeat-x;border-color:#f5e79e}.alert-danger{background-image:-webkit-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-o-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#e7c3c3));background-image:linear-gradient(to bottom,#f2dede 0,#e7c3c3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);background-repeat:repeat-x;border-color:#dca7a7}.progress{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#ebebeb),to(#f5f5f5));background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x}.progress-bar{background-image:-webkit-linear-gradient(top,#337ab7 0,#286090 100%);background-image:-o-linear-gradient(top,#337ab7 0,#286090 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#286090));background-image:linear-gradient(to bottom,#337ab7 0,#286090 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0);background-repeat:repeat-x}.progress-bar-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#449d44));background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);background-repeat:repeat-x}.progress-bar-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#31b0d5));background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);background-repeat:repeat-x}.progress-bar-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#ec971f));background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);background-repeat:repeat-x}.progress-bar-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c9302c));background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);background-repeat:repeat-x}.progress-bar-striped{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{text-shadow:0 -1px 0 #286090;background-image:-webkit-linear-gradient(top,#337ab7 0,#2b669a 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2b669a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2b669a));background-image:linear-gradient(to bottom,#337ab7 0,#2b669a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);background-repeat:repeat-x;border-color:#2b669a}.list-group-item.active .badge,.list-group-item.active:focus .badge,.list-group-item.active:hover .badge{text-shadow:none}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.05);box-shadow:0 1px 2px rgba(0,0,0,.05)}.panel-default>.panel-heading{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.panel-primary>.panel-heading{background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}.panel-success>.panel-heading{background-image:-webkit-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#d0e9c6));background-image:linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);background-repeat:repeat-x}.panel-info>.panel-heading{background-image:-webkit-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#c4e3f3));background-image:linear-gradient(to bottom,#d9edf7 0,#c4e3f3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);background-repeat:repeat-x}.panel-warning>.panel-heading{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#faf2cc));background-image:linear-gradient(to bottom,#fcf8e3 0,#faf2cc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);background-repeat:repeat-x}.panel-danger>.panel-heading{background-image:-webkit-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-o-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#ebcccc));background-image:linear-gradient(to bottom,#f2dede 0,#ebcccc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);background-repeat:repeat-x}.well{background-image:-webkit-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#e8e8e8),to(#f5f5f5));background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x;border-color:#dcdcdc;-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1)} 6 | /*# sourceMappingURL=bootstrap-theme.min.css.map */ -------------------------------------------------------------------------------- /static/css/bootstrap-theme.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.3.6 (http://getbootstrap.com) 3 | * Copyright 2011-2015 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */ 6 | .btn-default, 7 | .btn-primary, 8 | .btn-success, 9 | .btn-info, 10 | .btn-warning, 11 | .btn-danger { 12 | text-shadow: 0 -1px 0 rgba(0, 0, 0, .2); 13 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075); 14 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075); 15 | } 16 | .btn-default:active, 17 | .btn-primary:active, 18 | .btn-success:active, 19 | .btn-info:active, 20 | .btn-warning:active, 21 | .btn-danger:active, 22 | .btn-default.active, 23 | .btn-primary.active, 24 | .btn-success.active, 25 | .btn-info.active, 26 | .btn-warning.active, 27 | .btn-danger.active { 28 | -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); 29 | box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); 30 | } 31 | .btn-default.disabled, 32 | .btn-primary.disabled, 33 | .btn-success.disabled, 34 | .btn-info.disabled, 35 | .btn-warning.disabled, 36 | .btn-danger.disabled, 37 | .btn-default[disabled], 38 | .btn-primary[disabled], 39 | .btn-success[disabled], 40 | .btn-info[disabled], 41 | .btn-warning[disabled], 42 | .btn-danger[disabled], 43 | fieldset[disabled] .btn-default, 44 | fieldset[disabled] .btn-primary, 45 | fieldset[disabled] .btn-success, 46 | fieldset[disabled] .btn-info, 47 | fieldset[disabled] .btn-warning, 48 | fieldset[disabled] .btn-danger { 49 | -webkit-box-shadow: none; 50 | box-shadow: none; 51 | } 52 | .btn-default .badge, 53 | .btn-primary .badge, 54 | .btn-success .badge, 55 | .btn-info .badge, 56 | .btn-warning .badge, 57 | .btn-danger .badge { 58 | text-shadow: none; 59 | } 60 | .btn:active, 61 | .btn.active { 62 | background-image: none; 63 | } 64 | .btn-default { 65 | text-shadow: 0 1px 0 #fff; 66 | background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%); 67 | background-image: -o-linear-gradient(top, #fff 0%, #e0e0e0 100%); 68 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#e0e0e0)); 69 | background-image: linear-gradient(to bottom, #fff 0%, #e0e0e0 100%); 70 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0); 71 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 72 | background-repeat: repeat-x; 73 | border-color: #dbdbdb; 74 | border-color: #ccc; 75 | } 76 | .btn-default:hover, 77 | .btn-default:focus { 78 | background-color: #e0e0e0; 79 | background-position: 0 -15px; 80 | } 81 | .btn-default:active, 82 | .btn-default.active { 83 | background-color: #e0e0e0; 84 | border-color: #dbdbdb; 85 | } 86 | .btn-default.disabled, 87 | .btn-default[disabled], 88 | fieldset[disabled] .btn-default, 89 | .btn-default.disabled:hover, 90 | .btn-default[disabled]:hover, 91 | fieldset[disabled] .btn-default:hover, 92 | .btn-default.disabled:focus, 93 | .btn-default[disabled]:focus, 94 | fieldset[disabled] .btn-default:focus, 95 | .btn-default.disabled.focus, 96 | .btn-default[disabled].focus, 97 | fieldset[disabled] .btn-default.focus, 98 | .btn-default.disabled:active, 99 | .btn-default[disabled]:active, 100 | fieldset[disabled] .btn-default:active, 101 | .btn-default.disabled.active, 102 | .btn-default[disabled].active, 103 | fieldset[disabled] .btn-default.active { 104 | background-color: #e0e0e0; 105 | background-image: none; 106 | } 107 | .btn-primary { 108 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #265a88 100%); 109 | background-image: -o-linear-gradient(top, #337ab7 0%, #265a88 100%); 110 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#265a88)); 111 | background-image: linear-gradient(to bottom, #337ab7 0%, #265a88 100%); 112 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0); 113 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 114 | background-repeat: repeat-x; 115 | border-color: #245580; 116 | } 117 | .btn-primary:hover, 118 | .btn-primary:focus { 119 | background-color: #265a88; 120 | background-position: 0 -15px; 121 | } 122 | .btn-primary:active, 123 | .btn-primary.active { 124 | background-color: #265a88; 125 | border-color: #245580; 126 | } 127 | .btn-primary.disabled, 128 | .btn-primary[disabled], 129 | fieldset[disabled] .btn-primary, 130 | .btn-primary.disabled:hover, 131 | .btn-primary[disabled]:hover, 132 | fieldset[disabled] .btn-primary:hover, 133 | .btn-primary.disabled:focus, 134 | .btn-primary[disabled]:focus, 135 | fieldset[disabled] .btn-primary:focus, 136 | .btn-primary.disabled.focus, 137 | .btn-primary[disabled].focus, 138 | fieldset[disabled] .btn-primary.focus, 139 | .btn-primary.disabled:active, 140 | .btn-primary[disabled]:active, 141 | fieldset[disabled] .btn-primary:active, 142 | .btn-primary.disabled.active, 143 | .btn-primary[disabled].active, 144 | fieldset[disabled] .btn-primary.active { 145 | background-color: #265a88; 146 | background-image: none; 147 | } 148 | .btn-success { 149 | background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%); 150 | background-image: -o-linear-gradient(top, #5cb85c 0%, #419641 100%); 151 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#419641)); 152 | background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%); 153 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0); 154 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 155 | background-repeat: repeat-x; 156 | border-color: #3e8f3e; 157 | } 158 | .btn-success:hover, 159 | .btn-success:focus { 160 | background-color: #419641; 161 | background-position: 0 -15px; 162 | } 163 | .btn-success:active, 164 | .btn-success.active { 165 | background-color: #419641; 166 | border-color: #3e8f3e; 167 | } 168 | .btn-success.disabled, 169 | .btn-success[disabled], 170 | fieldset[disabled] .btn-success, 171 | .btn-success.disabled:hover, 172 | .btn-success[disabled]:hover, 173 | fieldset[disabled] .btn-success:hover, 174 | .btn-success.disabled:focus, 175 | .btn-success[disabled]:focus, 176 | fieldset[disabled] .btn-success:focus, 177 | .btn-success.disabled.focus, 178 | .btn-success[disabled].focus, 179 | fieldset[disabled] .btn-success.focus, 180 | .btn-success.disabled:active, 181 | .btn-success[disabled]:active, 182 | fieldset[disabled] .btn-success:active, 183 | .btn-success.disabled.active, 184 | .btn-success[disabled].active, 185 | fieldset[disabled] .btn-success.active { 186 | background-color: #419641; 187 | background-image: none; 188 | } 189 | .btn-info { 190 | background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%); 191 | background-image: -o-linear-gradient(top, #5bc0de 0%, #2aabd2 100%); 192 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#2aabd2)); 193 | background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%); 194 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0); 195 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 196 | background-repeat: repeat-x; 197 | border-color: #28a4c9; 198 | } 199 | .btn-info:hover, 200 | .btn-info:focus { 201 | background-color: #2aabd2; 202 | background-position: 0 -15px; 203 | } 204 | .btn-info:active, 205 | .btn-info.active { 206 | background-color: #2aabd2; 207 | border-color: #28a4c9; 208 | } 209 | .btn-info.disabled, 210 | .btn-info[disabled], 211 | fieldset[disabled] .btn-info, 212 | .btn-info.disabled:hover, 213 | .btn-info[disabled]:hover, 214 | fieldset[disabled] .btn-info:hover, 215 | .btn-info.disabled:focus, 216 | .btn-info[disabled]:focus, 217 | fieldset[disabled] .btn-info:focus, 218 | .btn-info.disabled.focus, 219 | .btn-info[disabled].focus, 220 | fieldset[disabled] .btn-info.focus, 221 | .btn-info.disabled:active, 222 | .btn-info[disabled]:active, 223 | fieldset[disabled] .btn-info:active, 224 | .btn-info.disabled.active, 225 | .btn-info[disabled].active, 226 | fieldset[disabled] .btn-info.active { 227 | background-color: #2aabd2; 228 | background-image: none; 229 | } 230 | .btn-warning { 231 | background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%); 232 | background-image: -o-linear-gradient(top, #f0ad4e 0%, #eb9316 100%); 233 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#eb9316)); 234 | background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%); 235 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0); 236 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 237 | background-repeat: repeat-x; 238 | border-color: #e38d13; 239 | } 240 | .btn-warning:hover, 241 | .btn-warning:focus { 242 | background-color: #eb9316; 243 | background-position: 0 -15px; 244 | } 245 | .btn-warning:active, 246 | .btn-warning.active { 247 | background-color: #eb9316; 248 | border-color: #e38d13; 249 | } 250 | .btn-warning.disabled, 251 | .btn-warning[disabled], 252 | fieldset[disabled] .btn-warning, 253 | .btn-warning.disabled:hover, 254 | .btn-warning[disabled]:hover, 255 | fieldset[disabled] .btn-warning:hover, 256 | .btn-warning.disabled:focus, 257 | .btn-warning[disabled]:focus, 258 | fieldset[disabled] .btn-warning:focus, 259 | .btn-warning.disabled.focus, 260 | .btn-warning[disabled].focus, 261 | fieldset[disabled] .btn-warning.focus, 262 | .btn-warning.disabled:active, 263 | .btn-warning[disabled]:active, 264 | fieldset[disabled] .btn-warning:active, 265 | .btn-warning.disabled.active, 266 | .btn-warning[disabled].active, 267 | fieldset[disabled] .btn-warning.active { 268 | background-color: #eb9316; 269 | background-image: none; 270 | } 271 | .btn-danger { 272 | background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%); 273 | background-image: -o-linear-gradient(top, #d9534f 0%, #c12e2a 100%); 274 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c12e2a)); 275 | background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%); 276 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0); 277 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 278 | background-repeat: repeat-x; 279 | border-color: #b92c28; 280 | } 281 | .btn-danger:hover, 282 | .btn-danger:focus { 283 | background-color: #c12e2a; 284 | background-position: 0 -15px; 285 | } 286 | .btn-danger:active, 287 | .btn-danger.active { 288 | background-color: #c12e2a; 289 | border-color: #b92c28; 290 | } 291 | .btn-danger.disabled, 292 | .btn-danger[disabled], 293 | fieldset[disabled] .btn-danger, 294 | .btn-danger.disabled:hover, 295 | .btn-danger[disabled]:hover, 296 | fieldset[disabled] .btn-danger:hover, 297 | .btn-danger.disabled:focus, 298 | .btn-danger[disabled]:focus, 299 | fieldset[disabled] .btn-danger:focus, 300 | .btn-danger.disabled.focus, 301 | .btn-danger[disabled].focus, 302 | fieldset[disabled] .btn-danger.focus, 303 | .btn-danger.disabled:active, 304 | .btn-danger[disabled]:active, 305 | fieldset[disabled] .btn-danger:active, 306 | .btn-danger.disabled.active, 307 | .btn-danger[disabled].active, 308 | fieldset[disabled] .btn-danger.active { 309 | background-color: #c12e2a; 310 | background-image: none; 311 | } 312 | .thumbnail, 313 | .img-thumbnail { 314 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 315 | box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 316 | } 317 | .dropdown-menu > li > a:hover, 318 | .dropdown-menu > li > a:focus { 319 | background-color: #e8e8e8; 320 | background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 321 | background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 322 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8)); 323 | background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); 324 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); 325 | background-repeat: repeat-x; 326 | } 327 | .dropdown-menu > .active > a, 328 | .dropdown-menu > .active > a:hover, 329 | .dropdown-menu > .active > a:focus { 330 | background-color: #2e6da4; 331 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 332 | background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 333 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4)); 334 | background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%); 335 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0); 336 | background-repeat: repeat-x; 337 | } 338 | .navbar-default { 339 | background-image: -webkit-linear-gradient(top, #fff 0%, #f8f8f8 100%); 340 | background-image: -o-linear-gradient(top, #fff 0%, #f8f8f8 100%); 341 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#f8f8f8)); 342 | background-image: linear-gradient(to bottom, #fff 0%, #f8f8f8 100%); 343 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0); 344 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 345 | background-repeat: repeat-x; 346 | border-radius: 4px; 347 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075); 348 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075); 349 | } 350 | .navbar-default .navbar-nav > .open > a, 351 | .navbar-default .navbar-nav > .active > a { 352 | background-image: -webkit-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%); 353 | background-image: -o-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%); 354 | background-image: -webkit-gradient(linear, left top, left bottom, from(#dbdbdb), to(#e2e2e2)); 355 | background-image: linear-gradient(to bottom, #dbdbdb 0%, #e2e2e2 100%); 356 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0); 357 | background-repeat: repeat-x; 358 | -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075); 359 | box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075); 360 | } 361 | .navbar-brand, 362 | .navbar-nav > li > a { 363 | text-shadow: 0 1px 0 rgba(255, 255, 255, .25); 364 | } 365 | .navbar-inverse { 366 | background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222 100%); 367 | background-image: -o-linear-gradient(top, #3c3c3c 0%, #222 100%); 368 | background-image: -webkit-gradient(linear, left top, left bottom, from(#3c3c3c), to(#222)); 369 | background-image: linear-gradient(to bottom, #3c3c3c 0%, #222 100%); 370 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0); 371 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 372 | background-repeat: repeat-x; 373 | border-radius: 4px; 374 | } 375 | .navbar-inverse .navbar-nav > .open > a, 376 | .navbar-inverse .navbar-nav > .active > a { 377 | background-image: -webkit-linear-gradient(top, #080808 0%, #0f0f0f 100%); 378 | background-image: -o-linear-gradient(top, #080808 0%, #0f0f0f 100%); 379 | background-image: -webkit-gradient(linear, left top, left bottom, from(#080808), to(#0f0f0f)); 380 | background-image: linear-gradient(to bottom, #080808 0%, #0f0f0f 100%); 381 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0); 382 | background-repeat: repeat-x; 383 | -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25); 384 | box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25); 385 | } 386 | .navbar-inverse .navbar-brand, 387 | .navbar-inverse .navbar-nav > li > a { 388 | text-shadow: 0 -1px 0 rgba(0, 0, 0, .25); 389 | } 390 | .navbar-static-top, 391 | .navbar-fixed-top, 392 | .navbar-fixed-bottom { 393 | border-radius: 0; 394 | } 395 | @media (max-width: 767px) { 396 | .navbar .navbar-nav .open .dropdown-menu > .active > a, 397 | .navbar .navbar-nav .open .dropdown-menu > .active > a:hover, 398 | .navbar .navbar-nav .open .dropdown-menu > .active > a:focus { 399 | color: #fff; 400 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 401 | background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 402 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4)); 403 | background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%); 404 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0); 405 | background-repeat: repeat-x; 406 | } 407 | } 408 | .alert { 409 | text-shadow: 0 1px 0 rgba(255, 255, 255, .2); 410 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05); 411 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05); 412 | } 413 | .alert-success { 414 | background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%); 415 | background-image: -o-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%); 416 | background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#c8e5bc)); 417 | background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%); 418 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0); 419 | background-repeat: repeat-x; 420 | border-color: #b2dba1; 421 | } 422 | .alert-info { 423 | background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%); 424 | background-image: -o-linear-gradient(top, #d9edf7 0%, #b9def0 100%); 425 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#b9def0)); 426 | background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%); 427 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0); 428 | background-repeat: repeat-x; 429 | border-color: #9acfea; 430 | } 431 | .alert-warning { 432 | background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%); 433 | background-image: -o-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%); 434 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#f8efc0)); 435 | background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%); 436 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0); 437 | background-repeat: repeat-x; 438 | border-color: #f5e79e; 439 | } 440 | .alert-danger { 441 | background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%); 442 | background-image: -o-linear-gradient(top, #f2dede 0%, #e7c3c3 100%); 443 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#e7c3c3)); 444 | background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%); 445 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0); 446 | background-repeat: repeat-x; 447 | border-color: #dca7a7; 448 | } 449 | .progress { 450 | background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%); 451 | background-image: -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%); 452 | background-image: -webkit-gradient(linear, left top, left bottom, from(#ebebeb), to(#f5f5f5)); 453 | background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%); 454 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0); 455 | background-repeat: repeat-x; 456 | } 457 | .progress-bar { 458 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #286090 100%); 459 | background-image: -o-linear-gradient(top, #337ab7 0%, #286090 100%); 460 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#286090)); 461 | background-image: linear-gradient(to bottom, #337ab7 0%, #286090 100%); 462 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0); 463 | background-repeat: repeat-x; 464 | } 465 | .progress-bar-success { 466 | background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%); 467 | background-image: -o-linear-gradient(top, #5cb85c 0%, #449d44 100%); 468 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#449d44)); 469 | background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%); 470 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0); 471 | background-repeat: repeat-x; 472 | } 473 | .progress-bar-info { 474 | background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%); 475 | background-image: -o-linear-gradient(top, #5bc0de 0%, #31b0d5 100%); 476 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#31b0d5)); 477 | background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%); 478 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0); 479 | background-repeat: repeat-x; 480 | } 481 | .progress-bar-warning { 482 | background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%); 483 | background-image: -o-linear-gradient(top, #f0ad4e 0%, #ec971f 100%); 484 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#ec971f)); 485 | background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%); 486 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0); 487 | background-repeat: repeat-x; 488 | } 489 | .progress-bar-danger { 490 | background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%); 491 | background-image: -o-linear-gradient(top, #d9534f 0%, #c9302c 100%); 492 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c9302c)); 493 | background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%); 494 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0); 495 | background-repeat: repeat-x; 496 | } 497 | .progress-bar-striped { 498 | background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); 499 | background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); 500 | background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); 501 | } 502 | .list-group { 503 | border-radius: 4px; 504 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 505 | box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 506 | } 507 | .list-group-item.active, 508 | .list-group-item.active:hover, 509 | .list-group-item.active:focus { 510 | text-shadow: 0 -1px 0 #286090; 511 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #2b669a 100%); 512 | background-image: -o-linear-gradient(top, #337ab7 0%, #2b669a 100%); 513 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2b669a)); 514 | background-image: linear-gradient(to bottom, #337ab7 0%, #2b669a 100%); 515 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0); 516 | background-repeat: repeat-x; 517 | border-color: #2b669a; 518 | } 519 | .list-group-item.active .badge, 520 | .list-group-item.active:hover .badge, 521 | .list-group-item.active:focus .badge { 522 | text-shadow: none; 523 | } 524 | .panel { 525 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .05); 526 | box-shadow: 0 1px 2px rgba(0, 0, 0, .05); 527 | } 528 | .panel-default > .panel-heading { 529 | background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 530 | background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 531 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8)); 532 | background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); 533 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); 534 | background-repeat: repeat-x; 535 | } 536 | .panel-primary > .panel-heading { 537 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 538 | background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 539 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4)); 540 | background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%); 541 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0); 542 | background-repeat: repeat-x; 543 | } 544 | .panel-success > .panel-heading { 545 | background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%); 546 | background-image: -o-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%); 547 | background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#d0e9c6)); 548 | background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%); 549 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0); 550 | background-repeat: repeat-x; 551 | } 552 | .panel-info > .panel-heading { 553 | background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%); 554 | background-image: -o-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%); 555 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#c4e3f3)); 556 | background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%); 557 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0); 558 | background-repeat: repeat-x; 559 | } 560 | .panel-warning > .panel-heading { 561 | background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%); 562 | background-image: -o-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%); 563 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#faf2cc)); 564 | background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%); 565 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0); 566 | background-repeat: repeat-x; 567 | } 568 | .panel-danger > .panel-heading { 569 | background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%); 570 | background-image: -o-linear-gradient(top, #f2dede 0%, #ebcccc 100%); 571 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#ebcccc)); 572 | background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%); 573 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0); 574 | background-repeat: repeat-x; 575 | } 576 | .well { 577 | background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%); 578 | background-image: -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%); 579 | background-image: -webkit-gradient(linear, left top, left bottom, from(#e8e8e8), to(#f5f5f5)); 580 | background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%); 581 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0); 582 | background-repeat: repeat-x; 583 | border-color: #dcdcdc; 584 | -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1); 585 | box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1); 586 | } 587 | /*# sourceMappingURL=bootstrap-theme.css.map */ 588 | -------------------------------------------------------------------------------- /static/js/bootstrap.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.3.7 (http://getbootstrap.com) 3 | * Copyright 2011-2016 Twitter, Inc. 4 | * Licensed under the MIT license 5 | */ 6 | if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1||b[0]>3)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher, but lower than version 4")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){if(a(b.target).is(this))return b.handleObj.handler.apply(this,arguments)}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.7",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a("#"===f?[]:f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.7",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c).prop(c,!0)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c).prop(c,!1))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")?(c.prop("checked")&&(a=!1),b.find(".active").removeClass("active"),this.$element.addClass("active")):"checkbox"==c.prop("type")&&(c.prop("checked")!==this.$element.hasClass("active")&&(a=!1),this.$element.toggleClass("active")),c.prop("checked",this.$element.hasClass("active")),a&&c.trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active")),this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target).closest(".btn");b.call(d,"toggle"),a(c.target).is('input[type="radio"], input[type="checkbox"]')||(c.preventDefault(),d.is("input,button")?d.trigger("focus"):d.find("input:visible,button:visible").first().trigger("focus"))}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(b.type))})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=null,this.sliding=null,this.interval=null,this.$active=null,this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.7",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){if(!/input|textarea/i.test(a.target.tagName)){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()}},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.getItemForDirection=function(a,b){var c=this.getItemIndex(b),d="prev"==a&&0===c||"next"==a&&c==this.$items.length-1;if(d&&!this.options.wrap)return b;var e="prev"==a?-1:1,f=(c+e)%this.$items.length;return this.$items.eq(f)},c.prototype.to=function(a){var b=this,c=this.getItemIndex(this.$active=this.$element.find(".item.active"));if(!(a>this.$items.length-1||a<0))return this.sliding?this.$element.one("slid.bs.carousel",function(){b.to(a)}):c==a?this.pause().cycle():this.slide(a>c?"next":"prev",this.$items.eq(a))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){if(!this.sliding)return this.slide("next")},c.prototype.prev=function(){if(!this.sliding)return this.slide("prev")},c.prototype.slide=function(b,d){var e=this.$element.find(".item.active"),f=d||this.getItemForDirection(b,e),g=this.interval,h="next"==b?"left":"right",i=this;if(f.hasClass("active"))return this.sliding=!1;var j=f[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:h});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,g&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(f)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:h});return a.support.transition&&this.$element.hasClass("slide")?(f.addClass(b),f[0].offsetWidth,e.addClass(h),f.addClass(h),e.one("bsTransitionEnd",function(){f.removeClass([b,h].join(" ")).addClass("active"),e.removeClass(["active",h].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(e.removeClass("active"),f.addClass("active"),this.sliding=!1,this.$element.trigger(m)),g&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this};var e=function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}};a(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){var c,d=b.attr("data-target")||(c=b.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"");return a(d)}function c(b){return this.each(function(){var c=a(this),e=c.data("bs.collapse"),f=a.extend({},d.DEFAULTS,c.data(),"object"==typeof b&&b);!e&&f.toggle&&/show|hide/.test(b)&&(f.toggle=!1),e||c.data("bs.collapse",e=new d(this,f)),"string"==typeof b&&e[b]()})}var d=function(b,c){this.$element=a(b),this.options=a.extend({},d.DEFAULTS,c),this.$trigger=a('[data-toggle="collapse"][href="#'+b.id+'"],[data-toggle="collapse"][data-target="#'+b.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};d.VERSION="3.3.7",d.TRANSITION_DURATION=350,d.DEFAULTS={toggle:!0},d.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},d.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b,e=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(e&&e.length&&(b=e.data("bs.collapse"),b&&b.transitioning))){var f=a.Event("show.bs.collapse");if(this.$element.trigger(f),!f.isDefaultPrevented()){e&&e.length&&(c.call(e,"hide"),b||e.data("bs.collapse",null));var g=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var h=function(){this.$element.removeClass("collapsing").addClass("collapse in")[g](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return h.call(this);var i=a.camelCase(["scroll",g].join("-"));this.$element.one("bsTransitionEnd",a.proxy(h,this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i])}}}},d.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var e=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(e,this)).emulateTransitionEnd(d.TRANSITION_DURATION):e.call(this)}}},d.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},d.prototype.getParent=function(){return a(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(c,d){var e=a(d);this.addAriaAndCollapsedClass(b(e),e)},this)).end()},d.prototype.addAriaAndCollapsedClass=function(a,b){var c=a.hasClass("in");a.attr("aria-expanded",c),b.toggleClass("collapsed",!c).attr("aria-expanded",c)};var e=a.fn.collapse;a.fn.collapse=c,a.fn.collapse.Constructor=d,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(d){var e=a(this);e.attr("data-target")||d.preventDefault();var f=b(e),g=f.data("bs.collapse"),h=g?"toggle":e.data();c.call(f,h)})}(jQuery),+function(a){"use strict";function b(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function c(c){c&&3===c.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=b(d),f={relatedTarget:this};e.hasClass("open")&&(c&&"click"==c.type&&/input|textarea/i.test(c.target.tagName)&&a.contains(e[0],c.target)||(e.trigger(c=a.Event("hide.bs.dropdown",f)),c.isDefaultPrevented()||(d.attr("aria-expanded","false"),e.removeClass("open").trigger(a.Event("hidden.bs.dropdown",f)))))}))}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.3.7",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=b(e),g=f.hasClass("open");if(c(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a(document.createElement("div")).addClass("dropdown-backdrop").insertAfter(a(this)).on("click",c);var h={relatedTarget:this};if(f.trigger(d=a.Event("show.bs.dropdown",h)),d.isDefaultPrevented())return;e.trigger("focus").attr("aria-expanded","true"),f.toggleClass("open").trigger(a.Event("shown.bs.dropdown",h))}return!1}},g.prototype.keydown=function(c){if(/(38|40|27|32)/.test(c.which)&&!/input|textarea/i.test(c.target.tagName)){var d=a(this);if(c.preventDefault(),c.stopPropagation(),!d.is(".disabled, :disabled")){var e=b(d),g=e.hasClass("open");if(!g&&27!=c.which||g&&27==c.which)return 27==c.which&&e.find(f).trigger("focus"),d.trigger("click");var h=" li:not(.disabled):visible a",i=e.find(".dropdown-menu"+h);if(i.length){var j=i.index(c.target);38==c.which&&j>0&&j--,40==c.which&&jdocument.documentElement.clientHeight;this.$element.css({paddingLeft:!this.bodyIsOverflowing&&a?this.scrollbarWidth:"",paddingRight:this.bodyIsOverflowing&&!a?this.scrollbarWidth:""})},c.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:"",paddingRight:""})},c.prototype.checkScrollbar=function(){var a=window.innerWidth;if(!a){var b=document.documentElement.getBoundingClientRect();a=b.right-Math.abs(b.left)}this.bodyIsOverflowing=document.body.clientWidth
',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},c.prototype.init=function(b,c,d){if(this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.$viewport=this.options.viewport&&a(a.isFunction(this.options.viewport)?this.options.viewport.call(this,this.$element):this.options.viewport.selector||this.options.viewport),this.inState={click:!1,hover:!1,focus:!1},this.$element[0]instanceof document.constructor&&!this.options.selector)throw new Error("`selector` option must be specified when initializing "+this.type+" on the window.document object!");for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focusin",i="hover"==g?"mouseleave":"focusout";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},c.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},c.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusin"==b.type?"focus":"hover"]=!0),c.tip().hasClass("in")||"in"==c.hoverState?void(c.hoverState="in"):(clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?void(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show)):c.show())},c.prototype.isInStateTrue=function(){for(var a in this.inState)if(this.inState[a])return!0;return!1},c.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);if(c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusout"==b.type?"focus":"hover"]=!1),!c.isInStateTrue())return clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?void(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide)):c.hide()},c.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(b);var d=a.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(b.isDefaultPrevented()||!d)return;var e=this,f=this.tip(),g=this.getUID(this.type);this.setContent(),f.attr("id",g),this.$element.attr("aria-describedby",g),this.options.animation&&f.addClass("fade");var h="function"==typeof this.options.placement?this.options.placement.call(this,f[0],this.$element[0]):this.options.placement,i=/\s?auto?\s?/i,j=i.test(h);j&&(h=h.replace(i,"")||"top"),f.detach().css({top:0,left:0,display:"block"}).addClass(h).data("bs."+this.type,this),this.options.container?f.appendTo(this.options.container):f.insertAfter(this.$element),this.$element.trigger("inserted.bs."+this.type);var k=this.getPosition(),l=f[0].offsetWidth,m=f[0].offsetHeight;if(j){var n=h,o=this.getPosition(this.$viewport);h="bottom"==h&&k.bottom+m>o.bottom?"top":"top"==h&&k.top-mo.width?"left":"left"==h&&k.left-lg.top+g.height&&(e.top=g.top+g.height-i)}else{var j=b.left-f,k=b.left+f+c;jg.right&&(e.left=g.left+g.width-k)}return e},c.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},c.prototype.getUID=function(a){do a+=~~(1e6*Math.random());while(document.getElementById(a));return a},c.prototype.tip=function(){if(!this.$tip&&(this.$tip=a(this.options.template),1!=this.$tip.length))throw new Error(this.type+" `template` option must consist of exactly 1 top-level element!");return this.$tip},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},c.prototype.enable=function(){this.enabled=!0},c.prototype.disable=function(){this.enabled=!1},c.prototype.toggleEnabled=function(){this.enabled=!this.enabled},c.prototype.toggle=function(b){var c=this;b&&(c=a(b.currentTarget).data("bs."+this.type),c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c))),b?(c.inState.click=!c.inState.click,c.isInStateTrue()?c.enter(c):c.leave(c)):c.tip().hasClass("in")?c.leave(c):c.enter(c)},c.prototype.destroy=function(){var a=this;clearTimeout(this.timeout),this.hide(function(){a.$element.off("."+a.type).removeData("bs."+a.type),a.$tip&&a.$tip.detach(),a.$tip=null,a.$arrow=null,a.$viewport=null,a.$element=null})};var d=a.fn.tooltip;a.fn.tooltip=b,a.fn.tooltip.Constructor=c,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=d,this}}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof b&&b;!e&&/destroy|hide/.test(b)||(e||d.data("bs.popover",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");c.VERSION="3.3.7",c.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:''}),c.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),c.prototype.constructor=c,c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content").children().detach().end()[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},c.prototype.hasContent=function(){return this.getTitle()||this.getContent()},c.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")};var d=a.fn.popover;a.fn.popover=b,a.fn.popover.Constructor=c,a.fn.popover.noConflict=function(){return a.fn.popover=d,this}}(jQuery),+function(a){"use strict";function b(c,d){this.$body=a(document.body),this.$scrollElement=a(a(c).is(document.body)?window:c),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",a.proxy(this.process,this)),this.refresh(),this.process()}function c(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})}b.VERSION="3.3.7",b.DEFAULTS={offset:10},b.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},b.prototype.refresh=function(){var b=this,c="offset",d=0;this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight(),a.isWindow(this.$scrollElement[0])||(c="position",d=this.$scrollElement.scrollTop()),this.$body.find(this.selector).map(function(){var b=a(this),e=b.data("target")||b.attr("href"),f=/^#./.test(e)&&a(e);return f&&f.length&&f.is(":visible")&&[[f[c]().top+d,e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){b.offsets.push(this[0]),b.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.getScrollHeight(),d=this.options.offset+c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(this.scrollHeight!=c&&this.refresh(),b>=d)return g!=(a=f[f.length-1])&&this.activate(a);if(g&&b=e[a]&&(void 0===e[a+1]||b .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),b.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),h?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu").length&&b.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),e&&e()}var g=d.find("> .active"),h=e&&a.support.transition&&(g.length&&g.hasClass("fade")||!!d.find("> .fade").length);g.length&&h?g.one("bsTransitionEnd",f).emulateTransitionEnd(c.TRANSITION_DURATION):f(),g.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this};var e=function(c){c.preventDefault(),b.call(a(this),"show")};a(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',e).on("click.bs.tab.data-api",'[data-toggle="pill"]',e)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.3.7",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getState=function(a,b,c,d){var e=this.$target.scrollTop(),f=this.$element.offset(),g=this.$target.height();if(null!=c&&"top"==this.affixed)return e=a-d&&"bottom"},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=this.$element.height(),d=this.options.offset,e=d.top,f=d.bottom,g=Math.max(a(document).height(),a(document.body).height());"object"!=typeof d&&(f=e=d),"function"==typeof e&&(e=d.top(this.$element)),"function"==typeof f&&(f=d.bottom(this.$element));var h=this.getState(g,b,e,f);if(this.affixed!=h){null!=this.unpin&&this.$element.css("top","");var i="affix"+(h?"-"+h:""),j=a.Event(i+".bs.affix");if(this.$element.trigger(j),j.isDefaultPrevented())return;this.affixed=h,this.unpin="bottom"==h?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(i).trigger(i.replace("affix","affixed")+".bs.affix")}"bottom"==h&&this.$element.offset({top:g-b-f})}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},null!=d.offsetBottom&&(d.offset.bottom=d.offsetBottom),null!=d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery); --------------------------------------------------------------------------------