From 7e61a123a0b4b5f6641cb791f76cda92369dca4b Mon Sep 17 00:00:00 2001 From: Radek Czajka Date: Wed, 20 Mar 2013 16:40:32 +0100 Subject: [PATCH] Some reorganizing. --- .gitignore | 3 ++ README.md | 21 ++++---- cas.vhost.template | 50 ------------------ cas.wsgi.template | 23 -------- src/accounts/admin.py | 4 ++ .../locale/pl_PL/LC_MESSAGES/django.mo | Bin 825 -> 962 bytes .../locale/pl_PL/LC_MESSAGES/django.po | 31 +++++++---- src/accounts/migrations/0001_initial.py | 38 +++++++++++++ src/accounts/migrations/__init__.py | 0 src/accounts/models.py | 10 +++- src/accounts/templates/account/profile.html | 25 +++++---- src/accounts/views.py | 2 + src/cas/locale/pl/LC_MESSAGES/django.mo | Bin 0 -> 1156 bytes src/cas/locale/pl/LC_MESSAGES/django.po | 50 ++++++++++++++++++ src/cas/manage.py | 22 -------- src/cas/media/static/brackets.png | Bin 2372 -> 0 bytes src/cas/media/static/platforma.png | Bin 9688 -> 0 bytes src/cas/media/static/redmine_logo.png | Bin 8827 -> 0 bytes src/cas/settings.py | 28 ++++++++-- src/cas/static/brackets.png | Bin 0 -> 1660 bytes src/cas/{media => }/static/css/main.css | 46 +++++++--------- src/cas/templates/base.html | 3 +- src/cas/templates/cas/login.html | 2 +- src/cas/templates/cas/logout.html | 2 +- src/cas/urls.py | 9 ++-- src/cas/wsgi.py | 28 ++++++++++ src/manage.py | 10 ++++ 27 files changed, 240 insertions(+), 167 deletions(-) delete mode 100644 cas.vhost.template delete mode 100644 cas.wsgi.template create mode 100644 src/accounts/admin.py create mode 100644 src/accounts/migrations/0001_initial.py create mode 100644 src/accounts/migrations/__init__.py create mode 100644 src/cas/locale/pl/LC_MESSAGES/django.mo create mode 100644 src/cas/locale/pl/LC_MESSAGES/django.po delete mode 100755 src/cas/manage.py delete mode 100644 src/cas/media/static/brackets.png delete mode 100644 src/cas/media/static/platforma.png delete mode 100644 src/cas/media/static/redmine_logo.png create mode 100644 src/cas/static/brackets.png rename src/cas/{media => }/static/css/main.css (75%) create mode 100644 src/cas/wsgi.py create mode 100755 src/manage.py 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 59955aea57d967fff3545284703851b908cae52d..f568b22c348fa5e269f8543720817c81dde081e6 100644 GIT binary patch literal 962 zcmZva-EPw`6vqvWukyKFzzrAP-4JqVH!)3NppCASiEOL748$amOyXtkQaf_oh4m5* zi3b27u90|wi6_{0$20IO{GFw(kg#;}%lYvC_{8}$HSv{TU4z|&S=c1(H_WZu=Loq2 zPJ*|<8So~!0A2!HWqcjH3;!MH_V0sE^KA|GdqNLu!48{HM5WvdZ;B}^u@@@RXx@p8GZng1fheu+MHU_-A$LXTskwzx3hDBgW>0E~cktv?)B-`Uv zZQ^R0JgxZn=zSgw76{(+sK314+H&(O`uz>bF8hdHOIr(tF=l)D=QSva*$#u zD?ZqVX~Ly??5@IO!amswp0kBOFvl}6=4-y^syDrMHuc+bVMNvv6O?7UMkIX1A2)6`~7w zx_4I)TzXsk1d2X`FW?_q{o&)AbLPx}d5%6tx}S;gwSbI(S#S!*!9DQv1>)cvOoAUU z0YZU(oq(rNFTnnsJg^Rrp+17w!18IqFZbS5dSNK$MsFBVwa;+A8JDs3{E>}yIvH1eXVke$42tBW}Yvv+BYx^O0Lb 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 0000000000000000000000000000000000000000..e155fa0a1651debbe60e9a891030ea08ff561285 GIT binary patch literal 1156 zcmah{zi$&s6y5`lQ+!m^6i<OUPT0uOQbT zKS46&{DmMuN^lN9sj#+JN;xJJJ8LnbjwYdOX#}}GyNaD*%tA=_(7OCu-(IIe3buk$sqsZS zh7OD#p}#0-8+|BJ7w&e$N5a@#t2(tex9)D<*``O^`ww>S->dD5LK_$E*(~pdx5~_h z9bKnd`+g_fGJ+kF!rSabotEQdC5%_X<(QIR>Tz-{PU0AW;l4P^J^Aox*t)P| zSXs$Vn>y`tR}5%t!iNKd-cW-+(d=kaAEv=kT=w)1BC?}q{8->I}uTk1(V})xz z?CgX$XK}vgo-pCIN_96^S)FbkeWT>jvGl#PoGwP9}_PjCqd5g(poKe%y|3qkcKK3!Ea+2dc;b9 z^#^TM QgFNl~?MC_I*P|%-47FWVW&i*H literal 0 HcmV?d00001 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 c8567c5f496282c1ed6c36fdeacd37a1c756892d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2372 zcmeAS@N?(olHy`uVBq!ia0y~yV0;P0UpUx+B9d)aF99i*VkgfK4j`!ENa+CbISV`@ zi-GE|gD|6$#_S4^+7j1@lHmNblJdl&REF~Ma=pyF?Be9af>gcyqV(DCY@`?%I1YNc zIEGZrd3#rJ-IQ{X_J_{-esDWy~^X*CEZfyE2W&@4=WTj?6}Gz z)OO+Y|G6hWuX*tN-jf-{&wo8#Jex7BdbjNN+^-x9p1ym<$Z+6#rwM}#EwOAEzs13` zXa4N1V!5-ad^J0R?Q?;b{kIG2_f@el{K+|Ymq9@F5_!0k@BflU0Ef`YIda{ILE8?}vAI83L7PjN7j=H*|l>OZyjP%e3#|!!v(2RvpoN7qh>nWOLOK z^O_rdzyDrUX4t{=`|7vXXa4N2I<7fqH=}~rl2JSw2BT?UG!2ZVfx(alUTvs4z{v+J zqpQAh>_~mT{qeu&uLK=VTe|$ZcVzopr01%wI7ytkO diff --git a/src/cas/media/static/platforma.png b/src/cas/media/static/platforma.png deleted file mode 100644 index bb649f211d9116fafdc4aaaad591d47c9ab92586..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9688 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 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 0000000000000000000000000000000000000000..b4593f907faa07d73d4b52c270f08f43af9b7072 GIT binary patch literal 1660 zcmeAS@N?(olHy`uVBq!ia0y~yVB7)3hd9`PB6ExHhyW>;VkgfK4j`!ENa+CbISV`@ ziy0VrNmmtT}V`<;yx0|V<% zPZ!6Kid%1Q7Y%b@i2aG{8V)d`A%y}4G{hmpfQ(LGGySn_ zyNda~Hn-Xt3@mx!_NgnbUT63q?>7ZS9Z(OdT|h3-t^6-n%Xc0@oG++^gyUc+UJ`sJul1G25{!uQO p8(t3@oGZ*3DRvexpf*(OKh>({E1`ba4Omk!c)I$ztaD0e0svNWYwQ33 literal 0 HcmV?d00001 diff --git a/src/cas/media/static/css/main.css b/src/cas/static/css/main.css similarity index 75% rename from src/cas/media/static/css/main.css rename to src/cas/static/css/main.css index b1f4c1e..d4b74b5 100644 --- a/src/cas/media/static/css/main.css +++ b/src/cas/static/css/main.css @@ -1,12 +1,13 @@ .enclose { text-align: center; min-height: 500px; - background: url(/media/static/brackets.png) no-repeat 50% 0; + background: url(../brackets.png) no-repeat 50% 0; margin-top: 1em; + background-size: auto 450px; } .enclosed { - margin-top: 7em; + margin-top: 70px; display: inline-block; text-align: left; max-width: 300px; @@ -53,7 +54,7 @@ body { color: #989898; } header { - max-width: 960px; + max-width: 600px; margin: auto; padding: 1em 0; } @@ -64,29 +65,17 @@ header img { footer, #content_push { height: 10em; } -footer { - -} - -#content-wrap { -} #content { - max-width: 960px; + max-width: 600px; margin: auto; } -#content-inner { -} - - - #details { margin: 1em; float: left; max-width: 75%; - } #details form table th { @@ -97,14 +86,20 @@ footer { margin-bottom: 2em; } -#details .message { - border: 2px solid green; - font-size: 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: 40px; + margin-top: 0; } .user_avatar { @@ -120,11 +115,11 @@ footer { #services-list { clear: both; - border-top: 1px solid red; + border-top: 1px solid black; } -#services-list a { - +#services-list h1 { + margin-bottom: 0; } #services-list img { @@ -132,8 +127,3 @@ footer { height: 50px; margin: 10px 10px 0 0; } - - -img.small_logo { - width: 250px; -} 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) -- 2.20.1