*.pyc
*.sqlite
localsettings.py
+/media
+/static
+
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 <http://www.jasig.org/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 <http://www.jasig.org/cas>
+w wersjach 1.0 i 2.0.
Wymagania
---------
-* Django 1.1 <http://djangoproject.com/>
-* zuber/django-cas-provider <http://github.com/zuber/django-cas-provider>
+* Zobacz requirements.txt
Instalacja i uruchomienie
-------------------------
-1. Ściągnij i zainstaluj pip <http://pypi.python.org/pypi/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.
+++ /dev/null
-<VirtualHost *:80>
- 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
-
- <Directory $WSGI_DIR>
- Order allow,deny
- Allow from all
- </Directory>
-
- <Location /media>
- # Insert filter
- SetOutputFilter DEFLATE
-
- # Don't compress images
- SetEnvIfNoCase Request_URI \
- \.(?:xsl|xml|json|gif|jpe?g|png)$ no-gzip dont-vary
- </Location>
-
- <Directory $MEDIA_ROOT >
- Order allow,deny
- Allow from all
- </Directory>
-
- #<Directory $MEDIA_ROOT/static >
- # Header unset ETag
- # FileETag None
- # ExpiresActive On
- # ExpiresDefault "now plus 1 year"
- #</Directory>
-
- LogLevel info
- ErrorLog /var/log/apache2/$PROJECT_NAME/error.log
- CustomLog /var/log/apache2/$PROJECT_NAME/access.log combined
-</VirtualHost>
-
\ No newline at end of file
+++ /dev/null
-#!$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()
--- /dev/null
+from django.contrib import admin
+from .models import Service
+
+admin.site.register(Service)
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 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 <EMAIL@ADDRESS>\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 <radoslaw.czajka@nowoczesnapolska.org.pl>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
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:"
+
--- /dev/null
+# -*- 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
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', )
{% load gravatar i18n %}
{% block content %}
- <div class="user_avatar">
+ <aside class="user_avatar">
<img src="{% gravatar_for_email request.user.email 120 %}"
alt="Gravatar"
title="{% trans 'Change at Gravatar.com' %}">
<p><a href="{% url 'cas_provider.views.logout' %}">{% trans "Logout" %}</a></p>
- </div>
+ </aside>
<div id="details">
{% if messages %}
- <p>{% for message in messages %}<span class="message">{{ message }}</span>{% endfor %}</p>
+ <section id="messages">
+ {% for message in messages %}<p>{{ message }}</p>{% endfor %}
+ </section>
{% endif %}
- <h2>{% trans "Your profile" %}</h2>
+ <h2>{% trans "Your profile" %}</h2>
<form method="post" action="/accounts/change_profile">
{% csrf_token %}
<table>
</form>
</div>
- <div id="services-list">
- <a href="http://redakcja.wolnelektury.pl/">
- <img src="{{ MEDIA_URL }}static/platforma.png">
- </a>
- </div>
+ {% if services %}
+ <section id="services-list">
+ <h1>{% trans "Sign in to:" %}</h1>
+ {% for service in services %}
+ <a href="{{ service.url }}" title="{{ service.name }}">
+ <img src="{{ service.image.url }}" alt="{{ service.name }}">
+ </a>
+ {% endfor %}
+ </section>
+ {% endif %}
{% endblock %}
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(),
})
--- /dev/null
+# 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 <EMAIL@ADDRESS>, 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 <radoslaw.czajka@nowoczesnapolska.org.pl>\n"
+"Language-Team: LANGUAGE <LL@li.org>\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: <a href=\"%(url)s\">%(url)s</a>"
+msgstr "Możesz wrócić do serwisu: <a href=\"%(url)s\">%(url)s</a>."
+
+#: templates/cas/logout.html:21
+#, python-format
+msgid "You can also <a href=\"%(login_url)s\">login again</a>"
+msgstr "Możesz też <a href=\"%(login_url)s\">zalogować się ponownie</a>."
+++ /dev/null
-#!/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)
+++ /dev/null
-.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;
-}
# 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'
PROJECT_ROOT + '/templates',
)
+LOCALE_PATHS = (
+ PROJECT_ROOT + '/locale',
+)
+
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sites',
'django.contrib.admin',
'django.contrib.admindocs',
+ 'django.contrib.staticfiles',
'cas_provider',
'gravatar',
'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/'
--- /dev/null
+.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;
+}
<!DOCTYPE html>
<html>
+ {% load static %}
<head>
<meta charset="utf-8" />
<title>{% block title %}Fundacja Nowoczesna Polska - Logowanie{% block subtitle %}{% endblock subtitle %}{% endblock title%}</title>
- <link rel="stylesheet" href="{{ MEDIA_URL }}static/css/main.css"/>
+ <link rel="stylesheet" href="{% static 'css/main.css' %}"/>
{% block extrahead %}
{% endblock %}
</head>
{% endfor %}
{{ form.as_p }}
- <input type="submit" value="{% trans 'Login me in' %}" tabindex="10" />
+ <input type="submit" value="{% trans 'Log me in' %}" tabindex="10" />
</form>
</div>
{% load i18n %}
{% block title %}
-Logged out
+{% trans "Logged out" %}
{% endblock %}
{% block content %}
url(r'^admin/', include(admin.site.urls)),
url(r'^accounts/', include('accounts.urls')),
-
- url(r'^%s(?P<path>.+)$' % 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<path>.*)$', 'django.views.static.serve', {
+ 'document_root': settings.MEDIA_ROOT,
+ }),
+ )
--- /dev/null
+"""
+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)
--- /dev/null
+#!/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)