From: Radek Czajka Date: Wed, 20 Mar 2013 15:40:32 +0000 (+0100) Subject: Some reorganizing. X-Git-Url: https://git.mdrn.pl/cas.git/commitdiff_plain/7e61a123a0b4b5f6641cb791f76cda92369dca4b Some reorganizing. --- diff --git a/.gitignore b/.gitignore index f1e760b..999c6ae 100755 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ *.pyc *.sqlite localsettings.py +/media +/static + diff --git a/README.md b/README.md index d63f735..724d3ba 100644 --- a/README.md +++ b/README.md @@ -1,32 +1,29 @@ O projekcie ----------- -CAS to aplikacja WWW służąca do uwierzytelniania (a w przyszłości również autoryzacji) użytkowników -serwisów Fundacji Nowoczesna Polska. Implementuje on protokół CAS w -wersji 1.0. +CAS to aplikacja WWW służąca do uwierzytelniania użytkowników +serwisów Fundacji Nowoczesna Polska. Implementuje ona protokół CAS +w wersjach 1.0 i 2.0. Wymagania --------- -* Django 1.1 -* zuber/django-cas-provider +* Zobacz requirements.txt Instalacja i uruchomienie ------------------------- -1. Ściągnij i zainstaluj pip -2. Przejdź do katalogu aplikacji w konsoli -3. Zainstaluj wymagane biblioteki (patrz sekcja wymagania_) komendą +1. Zainstaluj wymagane biblioteki, np. używając pip: pip install -r requirements.txt -4. Wypełnij bazę danych (Django poprosi o utworzenie pierwszego użytkownika) +2. Wypełnij bazę danych (Django poprosi o utworzenie pierwszego użytkownika) - ./manage.py syncdb + ./manage.py syncdb --migrate 5. Uruchom serwer deweloperski ./manage.py runserver -6. Przy wdrożeniu będziesz musiał najpewniej utworzyć plik `localsettings.py` i wpisać tam -ustawienia używanej bazy danych. Zalecane jest serwowanie aplikacji przez modwsgi na serwerze Apache2. \ No newline at end of file +6. Przy wdrożeniu utwórz plik `localsettings.py` i wpisz tam +ustawienia używanej bazy danych. diff --git a/cas.vhost.template b/cas.vhost.template deleted file mode 100644 index 970c91f..0000000 --- a/cas.vhost.template +++ /dev/null @@ -1,50 +0,0 @@ - - ServerName $DOMAIN - ServerAlias $DOMAIN_ALIASES - - ServerAdmin $ADMIN_EMAIL - - Alias /robots.txt $MEDIA_ROOT/static/robots.txt - Alias /favicon.ico $MEDIA_ROOT/static/favicon.ico - - Alias /media/ $MEDIA_ROOT - - # - # WSGI configuration follows - # - - WSGIDaemonProcess $PROJECT_NAME processes=2 threads=1 user=$WSGI_USER group=$WSGI_USER display-name=%{GROUP} - WSGIProcessGroup $PROJECT_NAME - WSGIScriptAlias / $WSGI_TARGET - - - Order allow,deny - Allow from all - - - - # Insert filter - SetOutputFilter DEFLATE - - # Don't compress images - SetEnvIfNoCase Request_URI \ - \.(?:xsl|xml|json|gif|jpe?g|png)$ no-gzip dont-vary - - - - Order allow,deny - Allow from all - - - # - # Header unset ETag - # FileETag None - # ExpiresActive On - # ExpiresDefault "now plus 1 year" - # - - LogLevel info - ErrorLog /var/log/apache2/$PROJECT_NAME/error.log - CustomLog /var/log/apache2/$PROJECT_NAME/access.log combined - - \ No newline at end of file diff --git a/cas.wsgi.template b/cas.wsgi.template deleted file mode 100644 index d8c87da..0000000 --- a/cas.wsgi.template +++ /dev/null @@ -1,23 +0,0 @@ -#!$PYTHON -import site -site.addsitedir('$PYTHON_SITE') - -import os -from os.path import abspath, dirname, join -import sys - -# Redirect sys.stdout to sys.stderr for bad libraries like geopy that use -# print statements for optional import exceptions. -sys.stdout = sys.stderr - -# Add apps and lib directories to PYTHONPATH -sys.path = [ - '$PROJECT_ROOT/src', - '$PROJECT_ROOT/provider', -] + sys.path - -# Run Django -os.environ['DJANGO_SETTINGS_MODULE'] = '$PROJECT_NAME.settings' - -from django.core.handlers.wsgi import WSGIHandler -application = WSGIHandler() diff --git a/src/accounts/admin.py b/src/accounts/admin.py new file mode 100644 index 0000000..f4af527 --- /dev/null +++ b/src/accounts/admin.py @@ -0,0 +1,4 @@ +from django.contrib import admin +from .models import Service + +admin.site.register(Service) diff --git a/src/accounts/locale/pl_PL/LC_MESSAGES/django.mo b/src/accounts/locale/pl_PL/LC_MESSAGES/django.mo index 59955ae..f568b22 100644 Binary files a/src/accounts/locale/pl_PL/LC_MESSAGES/django.mo and b/src/accounts/locale/pl_PL/LC_MESSAGES/django.mo differ diff --git a/src/accounts/locale/pl_PL/LC_MESSAGES/django.po b/src/accounts/locale/pl_PL/LC_MESSAGES/django.po index 8bb2e63..001893c 100644 --- a/src/accounts/locale/pl_PL/LC_MESSAGES/django.po +++ b/src/accounts/locale/pl_PL/LC_MESSAGES/django.po @@ -3,15 +3,15 @@ # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # -#, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-04-18 10:48+0200\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" +"POT-Creation-Date: 2013-03-20 16:32+0100\n" +"PO-Revision-Date: 2013-03-20 16:35+0100\n" +"Last-Translator: Radek Czajka \n" "Language-Team: LANGUAGE \n" +"Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" @@ -28,22 +28,31 @@ msgstr "Powtórzone hasło" msgid "Passwords do not match!" msgstr "Hasło i powtórzenie się nie zgadzają!" -#: templates/account/profile.html:12 +#: templates/account/profile.html:8 +msgid "Change at Gravatar.com" +msgstr "Zmień na Gravatar.com" + +#: templates/account/profile.html:9 +msgid "Logout" +msgstr "Wyloguj" + +#: templates/account/profile.html:19 msgid "Your profile" msgstr "Twój profil" -#: templates/account/profile.html:16 +#: templates/account/profile.html:24 msgid "Change profile" msgstr "Zmień profil" -#: templates/account/profile.html:20 +#: templates/account/profile.html:28 msgid "Password change" msgstr "Zmiana hasła" -#: templates/account/profile.html:24 +#: templates/account/profile.html:33 msgid "Change password" msgstr "Zmień hasło" -#: templates/account/profile.html:30 -msgid "Availble services" -msgstr "Dostępne usługi" +#: templates/account/profile.html:40 +msgid "Sign in to:" +msgstr "Zaloguj do:" + diff --git a/src/accounts/migrations/0001_initial.py b/src/accounts/migrations/0001_initial.py new file mode 100644 index 0000000..87acc1b --- /dev/null +++ b/src/accounts/migrations/0001_initial.py @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding model 'Service' + db.create_table(u'accounts_service', ( + (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('ordering', self.gf('django.db.models.fields.IntegerField')()), + ('name', self.gf('django.db.models.fields.CharField')(max_length=255)), + ('url', self.gf('django.db.models.fields.URLField')(max_length=200)), + ('image', self.gf('django.db.models.fields.files.ImageField')(max_length=100)), + )) + db.send_create_signal(u'accounts', ['Service']) + + + def backwards(self, orm): + # Deleting model 'Service' + db.delete_table(u'accounts_service') + + + models = { + u'accounts.service': { + 'Meta': {'ordering': "('ordering',)", 'object_name': 'Service'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'ordering': ('django.db.models.fields.IntegerField', [], {}), + 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'}) + } + } + + complete_apps = ['accounts'] \ No newline at end of file diff --git a/src/accounts/migrations/__init__.py b/src/accounts/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/accounts/models.py b/src/accounts/models.py index 71a8362..126fc11 100644 --- a/src/accounts/models.py +++ b/src/accounts/models.py @@ -1,3 +1,11 @@ from django.db import models -# Create your models here. + +class Service(models.Model): + ordering = models.IntegerField() + name = models.CharField(max_length=255) + url = models.URLField() + image = models.ImageField(upload_to='accounts/service/') + + class Meta: + ordering = ('ordering', ) diff --git a/src/accounts/templates/account/profile.html b/src/accounts/templates/account/profile.html index b80eaac..bc576d9 100644 --- a/src/accounts/templates/account/profile.html +++ b/src/accounts/templates/account/profile.html @@ -2,19 +2,21 @@ {% load gravatar i18n %} {% block content %} - +
{% if messages %} -

{% for message in messages %}{{ message }}{% endfor %}

+
+ {% for message in messages %}

{{ message }}

{% endfor %} +
{% endif %} -

{% trans "Your profile" %}

+

{% trans "Your profile" %}

{% csrf_token %} @@ -33,9 +35,14 @@ -
- - - -
+ {% if services %} +
+

{% trans "Sign in to:" %}

+ {% for service in services %} + + {{ service.name }} + + {% endfor %} +
+ {% endif %} {% endblock %} diff --git a/src/accounts/views.py b/src/accounts/views.py index df8365a..a501b97 100644 --- a/src/accounts/views.py +++ b/src/accounts/views.py @@ -6,12 +6,14 @@ from django.shortcuts import render from django.utils.translation import ugettext as __ from django.views.decorators.http import require_POST from accounts.forms import UserBasicForm, UserPasswordForm +from .models import Service @login_required def account_profile(request, basic_form=None, pass_form=None): return render(request, "account/profile.html", { "basic_form": basic_form or UserBasicForm(instance=request.user), "pass_form": pass_form or UserPasswordForm(), + "services": Service.objects.all(), }) diff --git a/src/cas/locale/pl/LC_MESSAGES/django.mo b/src/cas/locale/pl/LC_MESSAGES/django.mo new file mode 100644 index 0000000..e155fa0 Binary files /dev/null and b/src/cas/locale/pl/LC_MESSAGES/django.mo differ diff --git a/src/cas/locale/pl/LC_MESSAGES/django.po b/src/cas/locale/pl/LC_MESSAGES/django.po new file mode 100644 index 0000000..7a56631 --- /dev/null +++ b/src/cas/locale/pl/LC_MESSAGES/django.po @@ -0,0 +1,50 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2013-03-20 16:31+0100\n" +"PO-Revision-Date: 2013-03-20 16:04+0100\n" +"Last-Translator: Radek Czajka \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " +"|| n%100>=20) ? 1 : 2);\n" + +#: templates/cas/login.html:9 +msgid "Login" +msgstr "Zaloguj" + +#: templates/cas/login.html:16 +msgid "Log me in" +msgstr "Zaloguj mnie" + +#: templates/cas/logout.html:5 templates/cas/logout.html.py:12 +msgid "Logged out" +msgstr "Wylogowano" + +#: templates/cas/logout.html:14 +msgid "" +"You have successfully logged out. To ensure that you are logged out of all " +"services, please close your browser." +msgstr "" +"Pomyślnie wylogowano. Zamknij przeglądarkę, aby zapewnić wylogowanie ze " +"wszystkich serwisów." + +#: templates/cas/logout.html:17 +#, python-format +msgid "" +"You can return to service you came from: %(url)s" +msgstr "Możesz wrócić do serwisu: %(url)s." + +#: templates/cas/logout.html:21 +#, python-format +msgid "You can also login again" +msgstr "Możesz też zalogować się ponownie." diff --git a/src/cas/manage.py b/src/cas/manage.py deleted file mode 100755 index 28f7ef8..0000000 --- a/src/cas/manage.py +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env python -from django.core.management import execute_manager - -from os import path -import sys - -PROJECT_ROOT = path.realpath(path.dirname(__file__)) -sys.path = [ - path.abspath(path.join(PROJECT_ROOT, '..')), -] + sys.path - -try: - import settings # Assumed to be in the same directory. -except ImportError: - import traceback - traceback.print_exc(file=sys.stderr) - sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__) - sys.exit(1) - -if __name__ == "__main__": - # Append lib and apps directories to PYTHONPATH - execute_manager(settings) diff --git a/src/cas/media/static/brackets.png b/src/cas/media/static/brackets.png deleted file mode 100644 index c8567c5..0000000 Binary files a/src/cas/media/static/brackets.png and /dev/null differ diff --git a/src/cas/media/static/css/main.css b/src/cas/media/static/css/main.css deleted file mode 100644 index b1f4c1e..0000000 --- a/src/cas/media/static/css/main.css +++ /dev/null @@ -1,139 +0,0 @@ -.enclose { - text-align: center; - min-height: 500px; - background: url(/media/static/brackets.png) no-repeat 50% 0; - margin-top: 1em; -} - -.enclosed { - margin-top: 7em; - display: inline-block; - text-align: left; - max-width: 300px; - background-color: rgb(247, 247, 247); - background-color: rgba(247, 247, 247, .5); -} - -a { - text-decoration: none; -} -a:hover { - text-decoration: underline; -} - - -form p { - margin: 0; -} -form label, form input { - display: block; - width: 100%; -} -#login-form input { - font-size: 1.75em; - margin-bottom: .4em; -} - - - - -html, body { - margin: 0; - padding: 0; - height: 100%; -} -body { - background-color: #F7F7F7; - color: black; - font-family: Lato; -} - -#header-wrap { - background: #191919; - color: #989898; -} -header { - max-width: 960px; - margin: auto; - padding: 1em 0; -} -header img { - margin: 0 20px; - vertical-align: middle; -} -footer, #content_push { - height: 10em; -} -footer { - -} - -#content-wrap { -} - -#content { - max-width: 960px; - margin: auto; -} -#content-inner { -} - - - - - -#details { - margin: 1em; - float: left; - max-width: 75%; - -} - -#details form table th { - text-align: left; -} - -#details form { - margin-bottom: 2em; -} - -#details .message { - border: 2px solid green; - font-size: 2em; - padding: 20px; -} - -#details h2 { - margin-top: 40px; -} - -.user_avatar { - float: left; - margin: 1em; - max-width: 20%; - text-align: center; -} - -.user_avatar img { - box-shadow: 0 0 .2em black; -} - -#services-list { - clear: both; - border-top: 1px solid red; -} - -#services-list a { - -} - -#services-list img { - width: 90px; - height: 50px; - margin: 10px 10px 0 0; -} - - -img.small_logo { - width: 250px; -} diff --git a/src/cas/media/static/platforma.png b/src/cas/media/static/platforma.png deleted file mode 100644 index bb649f2..0000000 Binary files a/src/cas/media/static/platforma.png and /dev/null differ diff --git a/src/cas/media/static/redmine_logo.png b/src/cas/media/static/redmine_logo.png deleted file mode 100644 index bdfabb1..0000000 Binary files a/src/cas/media/static/redmine_logo.png and /dev/null differ diff --git a/src/cas/settings.py b/src/cas/settings.py index 21a4a35..c09aa48 100644 --- a/src/cas/settings.py +++ b/src/cas/settings.py @@ -41,17 +41,19 @@ USE_I18N = True # Absolute path to the directory that holds media. # Example: "/home/media/media.lawrence.com/" -MEDIA_ROOT = PROJECT_ROOT + '/media/' +MEDIA_ROOT = path.join(PROJECT_ROOT, '../../media/') # URL that handles the media served from MEDIA_ROOT. Make sure to use a # trailing slash if there is a path component (optional in other cases). # Examples: "http://media.lawrence.com", "http://example.com/media/" MEDIA_URL = '/media/' -# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a -# trailing slash. -# Examples: "http://foo.com/media/", "/media/". -ADMIN_MEDIA_PREFIX = '/admin-media/' +STATIC_ROOT = path.join(PROJECT_ROOT, '../../static/') +STATIC_URL = '/static/' + +STATICFILES_DIRS = [ + path.join(PROJECT_ROOT, 'static'), +] ROOT_URLCONF = 'cas.urls' @@ -59,6 +61,10 @@ TEMPLATE_DIRS = ( PROJECT_ROOT + '/templates', ) +LOCALE_PATHS = ( + PROJECT_ROOT + '/locale', +) + INSTALLED_APPS = ( 'django.contrib.auth', 'django.contrib.contenttypes', @@ -66,6 +72,7 @@ INSTALLED_APPS = ( 'django.contrib.sites', 'django.contrib.admin', 'django.contrib.admindocs', + 'django.contrib.staticfiles', 'cas_provider', 'gravatar', @@ -74,6 +81,17 @@ INSTALLED_APPS = ( 'accounts', ) +TEMPLATE_CONTEXT_PROCESSORS = ( + "django.contrib.auth.context_processors.auth", + "django.core.context_processors.debug", + "django.core.context_processors.i18n", + "django.core.context_processors.media", + "django.core.context_processors.static", + "django.core.context_processors.tz", + "django.contrib.messages.context_processors.messages", + "django.core.context_processors.request", +) + # django-cas-provider settings LOGIN_URL = '/cas/login/' LOGOUT_URL = '/cas/logout/' diff --git a/src/cas/static/brackets.png b/src/cas/static/brackets.png new file mode 100644 index 0000000..b4593f9 Binary files /dev/null and b/src/cas/static/brackets.png differ diff --git a/src/cas/static/css/main.css b/src/cas/static/css/main.css new file mode 100644 index 0000000..d4b74b5 --- /dev/null +++ b/src/cas/static/css/main.css @@ -0,0 +1,129 @@ +.enclose { + text-align: center; + min-height: 500px; + background: url(../brackets.png) no-repeat 50% 0; + margin-top: 1em; + background-size: auto 450px; +} + +.enclosed { + margin-top: 70px; + display: inline-block; + text-align: left; + max-width: 300px; + background-color: rgb(247, 247, 247); + background-color: rgba(247, 247, 247, .5); +} + +a { + text-decoration: none; +} +a:hover { + text-decoration: underline; +} + + +form p { + margin: 0; +} +form label, form input { + display: block; + width: 100%; +} +#login-form input { + font-size: 1.75em; + margin-bottom: .4em; +} + + + + +html, body { + margin: 0; + padding: 0; + height: 100%; +} +body { + background-color: #F7F7F7; + color: black; + font-family: Lato; +} + +#header-wrap { + background: #191919; + color: #989898; +} +header { + max-width: 600px; + margin: auto; + padding: 1em 0; +} +header img { + margin: 0 20px; + vertical-align: middle; +} +footer, #content_push { + height: 10em; +} + +#content { + max-width: 600px; + margin: auto; +} + + +#details { + margin: 1em; + float: left; + max-width: 75%; +} + +#details form table th { + text-align: left; +} + +#details form { + margin-bottom: 2em; +} + +#details #messages { + background: white; + box-shadow: 0 0 10px black; + font-size: 1.75em; + padding: 20px; + margin-bottom: 20px; +} +#details #messages p { + margin: 0; + color: green; +} + +#details h2 { + margin-top: 0; +} + +.user_avatar { + float: left; + margin: 1em; + max-width: 20%; + text-align: center; +} + +.user_avatar img { + box-shadow: 0 0 .2em black; +} + +#services-list { + clear: both; + border-top: 1px solid black; +} + +#services-list h1 { + margin-bottom: 0; +} + +#services-list img { + width: 90px; + height: 50px; + margin: 10px 10px 0 0; +} diff --git a/src/cas/templates/base.html b/src/cas/templates/base.html index a0dd91e..4e56e12 100644 --- a/src/cas/templates/base.html +++ b/src/cas/templates/base.html @@ -1,9 +1,10 @@ + {% load static %} {% block title %}Fundacja Nowoczesna Polska - Logowanie{% block subtitle %}{% endblock subtitle %}{% endblock title%} - + {% block extrahead %} {% endblock %} diff --git a/src/cas/templates/cas/login.html b/src/cas/templates/cas/login.html index f3a08cf..21c622b 100644 --- a/src/cas/templates/cas/login.html +++ b/src/cas/templates/cas/login.html @@ -13,7 +13,7 @@ {% endfor %} {{ form.as_p }} - + diff --git a/src/cas/templates/cas/logout.html b/src/cas/templates/cas/logout.html index 5a38a42..d390660 100644 --- a/src/cas/templates/cas/logout.html +++ b/src/cas/templates/cas/logout.html @@ -2,7 +2,7 @@ {% load i18n %} {% block title %} -Logged out +{% trans "Logged out" %} {% endblock %} {% block content %} diff --git a/src/cas/urls.py b/src/cas/urls.py index 175d5fb..5b67eb1 100644 --- a/src/cas/urls.py +++ b/src/cas/urls.py @@ -17,9 +17,12 @@ urlpatterns = patterns('', url(r'^admin/', include(admin.site.urls)), url(r'^accounts/', include('accounts.urls')), - - url(r'^%s(?P.+)$' % settings.MEDIA_URL[1:], 'django.views.static.serve', - {'document_root': settings.MEDIA_ROOT, 'show_indexes': True}), ) +if settings.DEBUG: + urlpatterns += patterns('', + url(r'^media/(?P.*)$', 'django.views.static.serve', { + 'document_root': settings.MEDIA_ROOT, + }), + ) diff --git a/src/cas/wsgi.py b/src/cas/wsgi.py new file mode 100644 index 0000000..718d43f --- /dev/null +++ b/src/cas/wsgi.py @@ -0,0 +1,28 @@ +""" +WSGI config for cas project. + +This module contains the WSGI application used by Django's development server +and any production WSGI deployments. It should expose a module-level variable +named ``application``. Django's ``runserver`` and ``runfcgi`` commands discover +this application via the ``WSGI_APPLICATION`` setting. + +Usually you will have the standard Django WSGI application here, but it also +might make sense to replace the whole Django WSGI application with a custom one +that later delegates to the Django one. For example, you could introduce WSGI +middleware here, or combine a Django application with an application of another +framework. + +""" +import os + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "cas.settings") + +# This application object is used by any WSGI server configured to use this +# file. This includes Django's development server, if the WSGI_APPLICATION +# setting points here. +from django.core.wsgi import get_wsgi_application +application = get_wsgi_application() + +# Apply WSGI middleware here. +# from helloworld.wsgi import HelloWorldApplication +# application = HelloWorldApplication(application) diff --git a/src/manage.py b/src/manage.py new file mode 100755 index 0000000..6936adf --- /dev/null +++ b/src/manage.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python +import os +import sys + +if __name__ == "__main__": + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "cas.settings") + + from django.core.management import execute_from_command_line + + execute_from_command_line(sys.argv)