Première version : mise en route du suivi.
authorCyril Robert <Cyril Robert crobert@inverse.ca>
Fri, 12 Feb 2010 21:38:41 +0000 (16:38 -0500)
committerCyril Robert <Cyril Robert crobert@inverse.ca>
Fri, 12 Feb 2010 21:38:41 +0000 (16:38 -0500)
27 files changed:
.gitignore [new file with mode: 0644]
__init__.py [new file with mode: 0644]
exemple-client/__init__.py [new file with mode: 0644]
exemple-client/client/__init__.py [new file with mode: 0644]
exemple-client/client/models.py [new file with mode: 0644]
exemple-client/client/tests.py [new file with mode: 0644]
exemple-client/client/views.py [new file with mode: 0644]
exemple-client/conf.py.edit [new file with mode: 0644]
exemple-client/manage.py [new file with mode: 0644]
exemple-client/settings.py [new file with mode: 0644]
exemple-client/templates/container_base.html [new file with mode: 0644]
exemple-client/templates/index.html [new file with mode: 0644]
exemple-client/templates/login.html [new file with mode: 0644]
exemple-client/templates/login_form.html [new file with mode: 0644]
exemple-client/urls.py [new file with mode: 0644]
lib/__init__.py [new file with mode: 0644]
lib/backends.py [new file with mode: 0644]
lib/models.py [new file with mode: 0644]
lib/serializers.py [new file with mode: 0644]
lib/tests.py [new file with mode: 0644]
lib/views.py [new file with mode: 0644]
serveur/__init__.py [new file with mode: 0644]
serveur/conf.py.edit [new file with mode: 0644]
serveur/handlers.py [new file with mode: 0644]
serveur/manage.py [new file with mode: 0644]
serveur/settings.py [new file with mode: 0644]
serveur/urls.py [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..9b83f5b
--- /dev/null
@@ -0,0 +1,18 @@
+# All compiled binaries..
+*.pyc
+*.pyo
+
+# Fichier temporaires:
+*~
+\#*#
+
+# Ignore merged stuff
+*.orig
+*.rej
+
+# Configuration du projet - par environnement
+conf.py
+django.wsgi
+
+# les évaluations passées en PDF
+evaluation/docs/*
diff --git a/__init__.py b/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/exemple-client/__init__.py b/exemple-client/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/exemple-client/client/__init__.py b/exemple-client/client/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/exemple-client/client/models.py b/exemple-client/client/models.py
new file mode 100644 (file)
index 0000000..71a8362
--- /dev/null
@@ -0,0 +1,3 @@
+from django.db import models
+
+# Create your models here.
diff --git a/exemple-client/client/tests.py b/exemple-client/client/tests.py
new file mode 100644 (file)
index 0000000..2247054
--- /dev/null
@@ -0,0 +1,23 @@
+"""
+This file demonstrates two different styles of tests (one doctest and one
+unittest). These will both pass when you run "manage.py test".
+
+Replace these with more appropriate tests for your application.
+"""
+
+from django.test import TestCase
+
+class SimpleTest(TestCase):
+    def test_basic_addition(self):
+        """
+        Tests that 1 + 1 always equals 2.
+        """
+        self.failUnlessEqual(1 + 1, 2)
+
+__test__ = {"doctest": """
+Another way to test that 1 + 1 is equal to 2.
+
+>>> 1 + 1 == 2
+True
+"""}
+
diff --git a/exemple-client/client/views.py b/exemple-client/client/views.py
new file mode 100644 (file)
index 0000000..2e6f25a
--- /dev/null
@@ -0,0 +1,40 @@
+from django.http import HttpResponseRedirect
+from django.contrib.auth.decorators import login_required
+from django.contrib.auth import authenticate, login
+from django.contrib.auth.views import logout
+from django.shortcuts import render_to_response
+from django.template import Context, RequestContext
+
+@login_required
+def index (request):
+    return render_to_response ("index.html", \
+            Context ({"user": request.user}), \
+            context_instance = RequestContext(request))
+
+def login_view (request):
+    error = None
+
+    # Identification envoyee
+    if request.method == "POST":
+        try:
+            username = request.POST['email']
+            password = request.POST['pass']
+        except:
+            error = ""
+
+        user = authenticate (username=username, password=password)
+        if user is not None:
+            if user.is_active:
+                login(request, user)
+                return HttpResponseRedirect (request.GET['next'])
+            else:
+                error = "Compte inactif."
+        else:
+            error = "Compte invalide."
+
+    return render_to_response ("login.html", \
+            Context ({"error": error}), \
+            context_instance = RequestContext(request))
+
+def logout_view (request):
+    return logout (request, "/")
diff --git a/exemple-client/conf.py.edit b/exemple-client/conf.py.edit
new file mode 100644 (file)
index 0000000..c10957a
--- /dev/null
@@ -0,0 +1,11 @@
+# -*- encoding: utf-8 -*-
+DEBUG = True
+TEMPLATE_DEBUG = DEBUG
+AUTH_PASSWORD_REQUIRED = False
+
+DATABASE_ENGINE = 'sqlite'
+DATABASE_NAME = 'dev.db'
+DATABASE_USER = ''
+DATABASE_PASSWORD = ''
+DATABASE_HOST = ''
+DATABASE_PORT = ''
diff --git a/exemple-client/manage.py b/exemple-client/manage.py
new file mode 100644 (file)
index 0000000..5e78ea9
--- /dev/null
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+from django.core.management import execute_manager
+try:
+    import settings # Assumed to be in the same directory.
+except ImportError:
+    import sys
+    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__":
+    execute_manager(settings)
diff --git a/exemple-client/settings.py b/exemple-client/settings.py
new file mode 100644 (file)
index 0000000..0c05339
--- /dev/null
@@ -0,0 +1,104 @@
+# Django settings for exemple_client project.
+import os
+from conf import DEBUG, TEMPLATE_DEBUG, AUTH_PASSWORD_REQUIRED, \
+    DATABASE_ENGINE, DATABASE_NAME, DATABASE_USER, DATABASE_PASSWORD, \
+    DATABASE_HOST, DATABASE_PORT
+
+if DEBUG:
+    import sys
+    sys.path.append ("../../")
+
+ADMINS = (
+    # ('Your Name', 'your_email@domain.com'),
+)
+
+MANAGERS = ADMINS
+
+# Local time zone for this installation. Choices can be found here:
+# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
+# although not all choices may be available on all operating systems.
+# If running in a Windows environment this must be set to the same as your
+# system time zone.
+TIME_ZONE = 'America/Montreal'
+
+# Language code for this installation. All choices can be found here:
+# http://www.i18nguy.com/unicode/language-identifiers.html
+LANGUAGE_CODE = 'en-us'
+
+SITE_ID = 1
+
+# If you set this to False, Django will make some optimizations so as not
+# to load the internationalization machinery.
+USE_I18N = True
+
+# Absolute path to the directory that holds media.
+# Example: "/home/media/media.lawrence.com/"
+MEDIA_ROOT = ''
+
+# 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 = ''
+
+# 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 = '/media/'
+
+# Make this unique, and don't share it with anybody.
+SECRET_KEY = 'm1$u@d+jhgt#n=8t0z))=xg=92q(p+km8#16km)lx_b6^l+vt8'
+
+# List of callables that know how to import templates from various sources.
+TEMPLATE_LOADERS = (
+    'django.template.loaders.filesystem.load_template_source',
+    'django.template.loaders.app_directories.load_template_source',
+#     'django.template.loaders.eggs.load_template_source',
+)
+
+MIDDLEWARE_CLASSES = (
+    'django.middleware.common.CommonMiddleware',
+    'django.contrib.sessions.middleware.SessionMiddleware',
+    'django.contrib.auth.middleware.AuthenticationMiddleware',
+)
+
+ROOT_URLCONF = 'urls'
+
+TEMPLATE_DIRS = (
+    # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
+    # Always use forward slashes, even on Windows.
+    # Don't forget to use absolute paths, not relative paths.
+    os.path.join(os.path.dirname(__file__), 'templates').replace('\\', '/'),
+)
+
+INSTALLED_APPS = (
+    'django.contrib.auth',
+    'django.contrib.contenttypes',
+    'django.contrib.sessions',
+    'django.contrib.sites',
+    'django_roa',
+    'django_roa.remoteauth',
+    'client',
+    'auf_roa_authentification.lib',
+)
+
+###################3
+# Important! 
+
+AUTHENTICATION_BACKENDS = (
+    'auf_roa_authentification.lib.backends.CascadeBackend',
+)
+ROA_MODELS = True   # set to False if you'd like to develop/test locally
+ROA_FORMAT = 'django'
+ROA_HEADERS = {
+    'Content-Type': 'application/x-www-form-urlencoded',
+}
+ROA_DJANGO_ERRORS = True # useful to ease debugging if you use test server
+
+ROA_MODEL_NAME_MAPPING = (
+    ('remoteauth.', 'auth.'),
+)
+ROA_BASE_URL = 'http://localhost:8000/auth/'
+SERIALIZATION_MODULES = {
+    'django' : 'auf_roa_authentification.lib.serializers',
+}
+
diff --git a/exemple-client/templates/container_base.html b/exemple-client/templates/container_base.html
new file mode 100644 (file)
index 0000000..282d2ef
--- /dev/null
@@ -0,0 +1,8 @@
+<html>
+<head>
+    <title>ROA</title>
+</head>
+<body>
+<div id="contenu">{% block contenu %}{% endblock %}</div>
+</body>
+</html>
diff --git a/exemple-client/templates/index.html b/exemple-client/templates/index.html
new file mode 100644 (file)
index 0000000..f5f7cf0
--- /dev/null
@@ -0,0 +1,9 @@
+{% extends "container_base.html" %}
+
+{% block contenu %}
+<h1>AUF-ROA</h1>
+
+Utilisateur: {{ user.username }}
+<a href="{% url client.views.logout_view %}">Logout</a>
+
+{% endblock %}
diff --git a/exemple-client/templates/login.html b/exemple-client/templates/login.html
new file mode 100644 (file)
index 0000000..d079aa2
--- /dev/null
@@ -0,0 +1,13 @@
+{% extends "container_base.html" %}
+
+{% block contenu %}
+<h1>AUF-ROA</h1>
+
+{% if error %}
+    <p class="error">{{error}}</p>
+{%endif%}
+    <p>
+    {% include 'login_form.html' %}
+    </p>
+
+{% endblock %}
diff --git a/exemple-client/templates/login_form.html b/exemple-client/templates/login_form.html
new file mode 100644 (file)
index 0000000..f668042
--- /dev/null
@@ -0,0 +1,18 @@
+<form method="post">
+    <table cellspacing="0" cellpadding="0" border="0" summary="" class="Rech">
+        <tbody>
+            <tr>
+                <td>Utilisateur :</td>
+                <td><input type="text" size="32" name="email"/></td>
+            </tr>
+            <tr>
+                <td>Mot de passe :</td>
+                <td><input type="password" size="32" name="pass"/></td>
+            </tr>
+            <tr>
+                <td colspan="2"><br/>
+                    <input type="submit" value="Continuer" name="entrer"/></td>
+            </tr>
+        </tbody>
+    </table>
+</form>
diff --git a/exemple-client/urls.py b/exemple-client/urls.py
new file mode 100644 (file)
index 0000000..5136d45
--- /dev/null
@@ -0,0 +1,20 @@
+from django.conf.urls.defaults import *
+
+# Uncomment the next two lines to enable the admin:
+from django.contrib import admin
+admin.autodiscover()
+
+urlpatterns = patterns('',
+    # Example:
+    # (r'^exemple_client/', include('exemple_client.foo.urls')),
+
+    # Uncomment the admin/doc line below and add 'django.contrib.admindocs' 
+    # to INSTALLED_APPS to enable admin documentation:
+    # (r'^admin/doc/', include('django.contrib.admindocs.urls')),
+
+    # Uncomment the next line to enable the admin:
+    (r'^admin/', include(admin.site.urls)),
+    (r'^$', 'client.views.index'),
+    (r'^accounts/login/', 'client.views.login_view'),
+    (r'^accounts/logout/', 'client.views.logout_view'),
+)
diff --git a/lib/__init__.py b/lib/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/lib/backends.py b/lib/backends.py
new file mode 100644 (file)
index 0000000..0e54ed6
--- /dev/null
@@ -0,0 +1,80 @@
+from django.conf import settings
+from django.contrib.auth.backends import ModelBackend
+from django.contrib.auth.models import User as DjangoUser, check_password
+from django_roa.remoteauth.models import User as RemoteUser
+
+class CascadeBackend(ModelBackend):
+    def authenticate(self, username=None, password=None):
+        user = None
+        try:
+            print "as user?"
+            user = self.as_user (username, password)
+        except:
+            print "fail"
+            user = None
+
+        if user is None:
+            try:
+                print "as remote?"
+                user = self.as_remote (username, password)
+                print user
+            except:
+                print "fail"
+                user = None
+
+            if user is not None:
+                newser = DjangoUser (username=user.username,
+                        email = user.email,
+                        first_name = user.first_name,
+                        last_name = user.last_name,
+                        is_staff = False,
+                        is_active = True,
+                        is_superuser = False)
+                newser.set_password (password)
+                newser.save ()
+        return user
+
+
+    def as_user(self, username, password):
+        user = DjangoUser.objects.get(username=username, is_active=True)
+        if settings.AUTH_PASSWORD_REQUIRED:
+            if not user.check_password(password):
+                raise DjangoUser.DoesNotExist()
+        return user
+
+    def as_remote(self, username, password):
+        user = RemoteUser.objects.get (username=username, is_active=True)
+        if settings.AUTH_PASSWORD_REQUIRED:
+            if not user.check_password(password):
+                raise RemoteUser.DoesNotExist()
+        return user
+
+# Copie depuis sigma
+    def is_admin(self, username, password):
+        """Verifie que l'utilisateur, username, est l'administrateur et que
+        son mot de passe correspond a notre configuration
+
+        @param username Nom d'utilisateur
+        @param password Mot de passe
+        """
+        return (settings.ADMIN_LOGIN == username) and \
+                check_password(password, settings.ADMIN_PASSWORD)
+
+    def as_admin(self, username, password):
+        """Authentification de l'utilisateur en tant qu'administrateur
+
+        @param username
+        @param password
+        """
+        user = None
+
+        if self.is_admin(username, password):
+            try:
+                user = DjangoUser.objects.get(username=username)
+            except DjangoUser.DoesNotExist:
+                if settings.AUTOMATIC_ADMIN_CREATE:
+                    user = DjangoUser(username=username, password='get from settings.py')
+                    user.is_staff = True
+                    user.is_superuser = True
+                    user.save()
+        return user
diff --git a/lib/models.py b/lib/models.py
new file mode 100644 (file)
index 0000000..71a8362
--- /dev/null
@@ -0,0 +1,3 @@
+from django.db import models
+
+# Create your models here.
diff --git a/lib/serializers.py b/lib/serializers.py
new file mode 100644 (file)
index 0000000..c5b6550
--- /dev/null
@@ -0,0 +1,31 @@
+from django.conf import settings
+from django.utils.xmlutils import SimplerXMLGenerator
+
+from django.core.serializers.xml_serializer import Serializer as XMLSerializer, \
+                                                   Deserializer as XMLDeserializer
+
+class Serializer(XMLSerializer):
+    """
+    A test serializer which removes ``django-objects`` xml tag from default
+    Django's xml serializer, adapt it to your own usage.
+    """
+    
+    def start_serialization(self):
+        """
+        Start serialization -- open the XML document and the root element.
+        """
+        self.xml = SimplerXMLGenerator(self.stream, self.options.get("encoding", settings.DEFAULT_CHARSET))
+        self.xml.startDocument()
+        self.xml.startElement("django-test", {"version" : "1.0"})
+
+    def end_serialization(self):
+        """
+        End serialization -- end the document.
+        """
+        self.indent(0)
+        self.xml.endElement("django-test")
+        self.xml.endDocument()
+
+
+class Deserializer(XMLDeserializer):
+    pass
diff --git a/lib/tests.py b/lib/tests.py
new file mode 100644 (file)
index 0000000..2247054
--- /dev/null
@@ -0,0 +1,23 @@
+"""
+This file demonstrates two different styles of tests (one doctest and one
+unittest). These will both pass when you run "manage.py test".
+
+Replace these with more appropriate tests for your application.
+"""
+
+from django.test import TestCase
+
+class SimpleTest(TestCase):
+    def test_basic_addition(self):
+        """
+        Tests that 1 + 1 always equals 2.
+        """
+        self.failUnlessEqual(1 + 1, 2)
+
+__test__ = {"doctest": """
+Another way to test that 1 + 1 is equal to 2.
+
+>>> 1 + 1 == 2
+True
+"""}
+
diff --git a/lib/views.py b/lib/views.py
new file mode 100644 (file)
index 0000000..60f00ef
--- /dev/null
@@ -0,0 +1 @@
+# Create your views here.
diff --git a/serveur/__init__.py b/serveur/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/serveur/conf.py.edit b/serveur/conf.py.edit
new file mode 100644 (file)
index 0000000..c10957a
--- /dev/null
@@ -0,0 +1,11 @@
+# -*- encoding: utf-8 -*-
+DEBUG = True
+TEMPLATE_DEBUG = DEBUG
+AUTH_PASSWORD_REQUIRED = False
+
+DATABASE_ENGINE = 'sqlite'
+DATABASE_NAME = 'dev.db'
+DATABASE_USER = ''
+DATABASE_PASSWORD = ''
+DATABASE_HOST = ''
+DATABASE_PORT = ''
diff --git a/serveur/handlers.py b/serveur/handlers.py
new file mode 100644 (file)
index 0000000..b40e229
--- /dev/null
@@ -0,0 +1,214 @@
+from django.contrib.auth.models import User, Message, Group, Permission
+from django.db import models
+from django.http import Http404
+from django.shortcuts import get_object_or_404, _get_queryset
+
+from piston.handler import BaseHandler
+from piston.utils import rc
+
+
+class ROAHandler(BaseHandler):
+
+    def flatten_dict(self, dct):
+        return dict([ (str(k), dct.get(k)) for k in dct.keys() \
+            if (k, dct.get(k)) != (u'id', u'None')])
+
+    @staticmethod
+    def _get_object(model, *args, **kwargs):
+        return get_object_or_404(model, id=kwargs['id'])
+        
+    def read(self, request, *args, **kwargs):
+        """
+        Retrieves an object or a list of objects.
+        """
+        if not self.has_model():
+            return rc.NOT_IMPLEMENTED
+        
+        if kwargs.values() != [None]:
+            # Returns a single object
+            return [self._get_object(self.model, *args, **kwargs)]
+        
+        # Initialization
+        queryset = _get_queryset(self.model)
+        
+        # Filtering
+        filters, excludes = {}, {}
+        for k, v in request.GET.iteritems():
+            if k.startswith('filter_'):
+                filters[k[7:]] = v
+            if k.startswith('exclude_'):
+                excludes[k[8:]] = v
+        queryset = queryset.filter(*filters.items()).exclude(*excludes.items())
+        
+        # Ordering (test custom parameters' name)
+        if 'order' in request.GET:
+            order_bys = request.GET['order'].split(',')
+            queryset = queryset.order_by(*order_bys)
+        
+        # Slicing
+        limit_start = int(request.GET.get('limit_start', 0))
+        limit_stop = request.GET.get('limit_stop', False) and int(request.GET['limit_stop']) or None
+        queryset = queryset[limit_start:limit_stop]
+        
+        obj_list = list(queryset)
+        if not obj_list:
+            raise Http404('No %s matches the given query.' % queryset.model._meta.object_name)
+        return queryset
+        
+    def create(self, request, *args, **kwargs):
+        """
+        Creates an object given request args, returned as a list.
+        """
+        if not self.has_model():
+            return rc.NOT_IMPLEMENTED
+        
+        data = request.POST.copy()
+        keys = data.keys()
+        
+        values = {}
+        for field in self.model._meta.local_fields:
+            field_value = data.get(field.name, None)
+            
+            if field_value not in (u'', u'None'):
+                
+                # Handle FK fields
+                if field.rel and isinstance(field.rel, models.ManyToOneRel):
+                    field_value = data.get(field.attname, None)
+                    if field_value not in (u'', u'None'):
+                        values[field.attname] = field.rel.to._meta.get_field(field.rel.field_name).to_python(field_value)
+                    else:
+                        values[field.attname] = None
+                
+                # Handle all other fields
+                else:
+                    if isinstance(field, models.fields.BooleanField):
+                        field_value = field.to_python(field_value)
+                    elif isinstance(field, models.fields.FloatField):
+                        if field_value is not None:
+                            field_value = float(field_value)
+                    values[field.name] = field_value
+
+        object = self.model.objects.create(**values)
+        
+        response = [self.model.objects.get(id=object.id)]
+        #response = [object]
+        return response
+
+    def update(self, request, *args, **kwargs):
+        """
+        Modifies an object given request args, returned as a list.
+        """
+        if not self.has_model():
+            return rc.NOT_IMPLEMENTED
+        
+        data = request.PUT.copy()
+        object = self._get_object(self.model, *args, **kwargs)
+        
+        for field in self.model._meta.local_fields:
+            field_name = field.name
+            
+            # Handle FK fields
+            if field.rel and isinstance(field.rel, models.ManyToOneRel):
+                field_value = data.get(field.attname, None)
+                if field_value not in (u'', u'None', None):
+                    field_value = field.rel.to._meta.get_field(field.rel.field_name).to_python(field_value)
+                else:
+                    field_value = None
+                setattr(object, field.attname, field_value)
+            
+            # Handle all other fields
+            elif field_name in data:
+                field_value = data[field_name]
+                if field_value in (u'', u'None'):
+                    field_value = None
+                if isinstance(field, models.fields.BooleanField) \
+                or isinstance(field, models.fields.NullBooleanField) \
+                or isinstance(field, models.fields.IntegerField):
+                    field_value = field.to_python(field_value)
+                elif isinstance(field, models.fields.FloatField):
+                    if field_value is not None:
+                        field_value = float(field_value)
+                elif isinstance(field, models.fields.CharField):
+                    if field_value is None:
+                        field_value = u''
+                setattr(object, field_name, field_value)
+        
+        object.save()
+        
+        response = [self.model.objects.get(id=object.id)]
+        #response = [object]
+        return response
+
+    def delete(self, request, *args, **kwargs):
+        """
+        Deletes an object.
+        """
+        if not self.has_model():
+            raise NotImplementedError
+        
+        try:
+            object = self._get_object(self.model, *args, **kwargs)
+            object.delete()
+
+            return rc.DELETED
+        except self.model.MultipleObjectsReturned:
+            return rc.DUPLICATE_ENTRY
+        except self.model.DoesNotExist:
+            return rc.NOT_HERE
+
+
+class ROACountHandler(BaseHandler):
+    allowed_methods = ('GET', )
+
+    def read(self, request, *args, **kwargs):
+        """
+        Retrieves the number of objects.
+        """
+        if not self.has_model():
+            return rc.NOT_IMPLEMENTED
+        
+        # Initialization
+        queryset = _get_queryset(self.model)
+        
+        # Filtering
+        filters, excludes = {}, {}
+        for k, v in request.GET.iteritems():
+            if k.startswith('filter_'):
+                filters[k[7:]] = v
+            if k.startswith('exclude_'):
+                excludes[k[8:]] = v
+        queryset = queryset.filter(*filters.items()).exclude(*excludes.items())
+        
+        # Ordering
+        if 'order_by' in request.GET:
+            order_bys = request.GET['order_by'].split(',')
+            queryset = queryset.order_by(*order_bys)
+        
+        # Counting
+        counter = queryset.count()
+        return counter
+
+
+class ROAWithSlugHandler(ROAHandler):
+    
+    @staticmethod
+    def _get_object(model, *args, **kwargs):
+        """Returns an object from a slug.
+        
+        Useful when the slug is a combination of many fields.
+        """
+        id, slug = kwargs['object_slug'].split('-', 1)
+        object = get_object_or_404(model, id=id, slug=slug)
+        return object
+
+class UserHandler(ROAHandler):
+    model = User
+
+class MessageHandler(ROAHandler):
+    model = Message
+
+class PermissionHandler(ROAHandler):
+    model = Permission
+    
+class GroupHandler(ROAHandler):
+    model = Group
diff --git a/serveur/manage.py b/serveur/manage.py
new file mode 100644 (file)
index 0000000..5e78ea9
--- /dev/null
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+from django.core.management import execute_manager
+try:
+    import settings # Assumed to be in the same directory.
+except ImportError:
+    import sys
+    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__":
+    execute_manager(settings)
diff --git a/serveur/settings.py b/serveur/settings.py
new file mode 100644 (file)
index 0000000..53ebe34
--- /dev/null
@@ -0,0 +1,75 @@
+# Django settings for auf_roa_authentification project.
+from conf import DEBUG, TEMPLATE_DEBUG, AUTH_PASSWORD_REQUIRED, \
+    DATABASE_ENGINE, DATABASE_NAME, DATABASE_USER, DATABASE_PASSWORD, \
+    DATABASE_HOST, DATABASE_PORT
+
+ADMINS = (
+    # ('Your Name', 'your_email@domain.com'),
+)
+
+MANAGERS = ADMINS
+
+# Local time zone for this installation. Choices can be found here:
+# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
+# although not all choices may be available on all operating systems.
+# If running in a Windows environment this must be set to the same as your
+# system time zone.
+TIME_ZONE = 'America/Montreal'
+
+# Language code for this installation. All choices can be found here:
+# http://www.i18nguy.com/unicode/language-identifiers.html
+LANGUAGE_CODE = 'en-us'
+
+SITE_ID = 1
+
+# If you set this to False, Django will make some optimizations so as not
+# to load the internationalization machinery.
+USE_I18N = True
+
+# Absolute path to the directory that holds media.
+# Example: "/home/media/media.lawrence.com/"
+MEDIA_ROOT = ''
+
+# 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 = ''
+
+# 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 = '/media/'
+
+# Make this unique, and don't share it with anybody.
+SECRET_KEY = 'n4u4e2*txjz6sl08k%=n_z0^6k5(0yl#)q)24gtg!wefe!4&_n'
+
+# List of callables that know how to import templates from various sources.
+TEMPLATE_LOADERS = (
+    'django.template.loaders.filesystem.load_template_source',
+    'django.template.loaders.app_directories.load_template_source',
+#     'django.template.loaders.eggs.load_template_source',
+)
+
+MIDDLEWARE_CLASSES = (
+    'django.middleware.common.CommonMiddleware',
+    'django.contrib.sessions.middleware.SessionMiddleware',
+    'django.contrib.auth.middleware.AuthenticationMiddleware',
+)
+
+ROOT_URLCONF = 'urls'
+
+TEMPLATE_DIRS = (
+    # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
+    # Always use forward slashes, even on Windows.
+    # Don't forget to use absolute paths, not relative paths.
+)
+
+INSTALLED_APPS = (
+    'django.contrib.auth',
+    'django.contrib.contenttypes',
+    'django.contrib.sessions',
+    'django.contrib.sites',
+    'django.contrib.admin',
+    'django_roa',
+    'serveur'
+)
diff --git a/serveur/urls.py b/serveur/urls.py
new file mode 100644 (file)
index 0000000..c125675
--- /dev/null
@@ -0,0 +1,30 @@
+from django.conf.urls.defaults import *
+from handlers import UserHandler, MessageHandler, PermissionHandler, GroupHandler
+from piston.resource import Resource
+
+# Uncomment the next two lines to enable the admin:
+from django.contrib import admin
+admin.autodiscover()
+
+users = Resource(handler=UserHandler)
+messages = Resource(handler=MessageHandler)
+permissions = Resource(handler=PermissionHandler)
+groups = Resource(handler=GroupHandler)
+
+urlpatterns = patterns('',
+    # Example:
+    # (r'^auf_roa_authentification/', include('auf_roa_authentification.foo.urls')),
+
+    # Uncomment the admin/doc line below and add 'django.contrib.admindocs' 
+    # to INSTALLED_APPS to enable admin documentation:
+    # (r'^admin/doc/', include('django.contrib.admindocs.urls')),
+
+    # Uncomment the next line to enable the admin:
+    # (r'^admin/', include(admin.site.urls)),
+
+    # Auth application
+    url(r'^auth/user/?(?P<id>\d+)?/?$', users),
+    url(r'^auth/message/?(?P<id>\d+)?/?$', messages),
+    url(r'^auth/permission/?(?P<id>\d+)?/?$', permissions),
+    url(r'^auth/group/?(?P<id>\d+)?/?$', groups)
+)