From ac81450e437cd26108068cd6e556b15b237690f2 Mon Sep 17 00:00:00 2001
From: Jean-Baptiste <bleme@pm.me>
Date: Mon, 25 Feb 2019 14:57:44 +0100
Subject: [PATCH 1/6] update: auto generates routes (urls.py is not needed
 anymore)

---
 djangoldp/models.py | 26 +++++++++++++++++++++-----
 djangoldp/urls.py   | 33 +++++++++++++++++++++++++++++++++
 djangoldp/views.py  |  2 +-
 3 files changed, 55 insertions(+), 6 deletions(-)
 create mode 100644 djangoldp/urls.py

diff --git a/djangoldp/models.py b/djangoldp/models.py
index 151cb7d8..f95d6c85 100644
--- a/djangoldp/models.py
+++ b/djangoldp/models.py
@@ -5,9 +5,26 @@ from django.urls import get_resolver
 
 class Model(models.Model):
     container_path = None
+    view_set = None
+    permission_classes = []
+    fields = []
+    nested_fields = []
 
-    def get_container_path(self):
-        return self.container_path
+    @classmethod
+    def get_view_set(cls):
+        view_set = cls.view_set
+        if view_set is None:
+            from djangoldp.views import LDPViewSet
+            view_set = LDPViewSet
+        return view_set
+
+    @classmethod
+    def get_container_path(cls):
+        path = cls.container_path
+        if path is None:
+            path = "{}s".format(cls._meta.object_name.lower())
+
+        return path
 
     def get_absolute_url(self):
         return Model.resource_id(self)
@@ -26,9 +43,7 @@ class Model(models.Model):
     @classmethod
     def container_id(cls, instance):
         if isinstance(instance, cls):
-            path = instance.container_path
-            if path is None:
-                path = "{}s".format(instance._meta.object_name.lower())
+            path = cls.get_container_path()
         else:
             view_name = '{}-list'.format(instance._meta.object_name.lower())
             path = get_resolver().reverse(view_name)
@@ -69,6 +84,7 @@ class Model(models.Model):
             path = "{}/".format(path)
         return path
 
+
 class LDPSource(models.Model):
     container = models.URLField()
     federation = models.CharField(max_length=255)
diff --git a/djangoldp/urls.py b/djangoldp/urls.py
new file mode 100644
index 00000000..f7f22a0c
--- /dev/null
+++ b/djangoldp/urls.py
@@ -0,0 +1,33 @@
+from importlib import import_module
+
+from django.conf import settings
+from django.conf.urls import url, include
+
+from djangoldp.models import LDPSource, Model
+from djangoldp.views import LDPSourceViewSet
+
+
+def __clean_path(path):
+    if path.startswith("/"):
+        path = path[1:]
+    if not path.endswith("/"):
+        path = "{}/".format(path)
+    return path
+
+
+urlpatterns = [
+    url(r'^sources/', LDPSourceViewSet.urls(model=LDPSource)),
+]
+
+for package in settings.DJANGOLDP_PACKAGES:
+    import_module('{}.models'.format(package))
+
+model_classes = {cls.__name__: cls for cls in Model.__subclasses__()}
+
+for class_name in model_classes:
+    model_class = model_classes[class_name]
+    path = __clean_path(model_class.get_container_path())
+    urls_fct = model_class.get_view_set().urls
+    urlpatterns.append(url(r'^' + path, include(
+        urls_fct(model=model_class, permission_classes=model_class.permission_classes, fields=model_class.fields,
+                 nested_fields=model_class.nested_fields))))
diff --git a/djangoldp/views.py b/djangoldp/views.py
index 3ccfdf73..a6e8c91b 100644
--- a/djangoldp/views.py
+++ b/djangoldp/views.py
@@ -6,6 +6,7 @@ from django.core.urlresolvers import get_resolver
 from django.db.utils import OperationalError
 from django.shortcuts import get_object_or_404
 from django.utils.decorators import classonlymethod
+from djangoldp.models import LDPSource
 from guardian.shortcuts import get_objects_for_user
 from pyld import jsonld
 from rest_framework.authentication import SessionAuthentication
@@ -13,7 +14,6 @@ from rest_framework.parsers import JSONParser
 from rest_framework.renderers import JSONRenderer
 from rest_framework.viewsets import ModelViewSet
 
-from .models import LDPSource
 from .serializers import LDPSerializer
 
 
-- 
GitLab


From a8dd5eaec1767a43c2bfacdb66d4512c9150a339 Mon Sep 17 00:00:00 2001
From: Jean-Baptiste <bleme@pm.me>
Date: Tue, 26 Feb 2019 15:13:43 +0100
Subject: [PATCH 2/6] update: fix tests

---
 djangoldp/models.py                |  2 +-
 djangoldp/tests/runner.py          |  1 +
 djangoldp/tests/tests_ldp_model.py |  3 +--
 djangoldp/tests/urls.py            | 11 ++++++-----
 4 files changed, 9 insertions(+), 8 deletions(-)

diff --git a/djangoldp/models.py b/djangoldp/models.py
index f95d6c85..0f96a36d 100644
--- a/djangoldp/models.py
+++ b/djangoldp/models.py
@@ -43,7 +43,7 @@ class Model(models.Model):
     @classmethod
     def container_id(cls, instance):
         if isinstance(instance, cls):
-            path = cls.get_container_path()
+            path = instance.get_container_path()
         else:
             view_name = '{}-list'.format(instance._meta.object_name.lower())
             path = get_resolver().reverse(view_name)
diff --git a/djangoldp/tests/runner.py b/djangoldp/tests/runner.py
index 70074c5b..7ecff27b 100644
--- a/djangoldp/tests/runner.py
+++ b/djangoldp/tests/runner.py
@@ -9,6 +9,7 @@ settings.configure(DEBUG=True,
                        }
                    },
                    ROOT_URLCONF='djangoldp.tests.urls',
+                   DJANGOLDP_PACKAGES=['djangoldp'],
                    INSTALLED_APPS=('django.contrib.auth',
                                    'django.contrib.contenttypes',
                                    'django.contrib.sessions',
diff --git a/djangoldp/tests/tests_ldp_model.py b/djangoldp/tests/tests_ldp_model.py
index 6400378c..329899c0 100644
--- a/djangoldp/tests/tests_ldp_model.py
+++ b/djangoldp/tests/tests_ldp_model.py
@@ -29,11 +29,10 @@ class LDPModelTest(TestCase):
         result = Model.resolve_container("/dummys/")
         self.assertEquals(Dummy, result)
 
-    @unittest.skip("futur feature: avoid urls.py on apps")
     def test_auto_url(self):
         from django.urls import get_resolver
         dummy = LDPDummy.objects.create(some="text")
         view_name = '{}-list'.format(dummy._meta.object_name.lower())
-        path = '/{}'.format(get_resolver().reverse_dict[view_name][0][0][0], dummy.pk)
+        path = '/{}{}'.format(get_resolver().reverse_dict[view_name][0][0][0], dummy.pk)
 
         self.assertEquals(path, dummy.get_absolute_url())
diff --git a/djangoldp/tests/urls.py b/djangoldp/tests/urls.py
index 392b0e2b..7dfbd980 100644
--- a/djangoldp/tests/urls.py
+++ b/djangoldp/tests/urls.py
@@ -1,9 +1,8 @@
 from django.conf import settings
+from django.conf.urls import url, include
 
-from djangoldp.tests.models import Skill, JobOffer, Message, Thread, Dummy, LDPDummy
+from djangoldp.tests.models import Skill, JobOffer, Message, Thread, Dummy
 from djangoldp.views import LDPViewSet
-from django.conf.urls import url
-
 
 urlpatterns = [
     url(r'^skills/', LDPViewSet.urls(model=Skill, permission_classes=[], fields=["@id", "title"], nested_fields=[])),
@@ -12,5 +11,7 @@ urlpatterns = [
     url(r'^threads/', LDPViewSet.urls(model=Thread, nested_fields=["message_set"], permission_classes=())),
     url(r'^users/', LDPViewSet.urls(model=settings.AUTH_USER_MODEL, permission_classes=[])),
     url(r'^dummys/', LDPViewSet.urls(model=Dummy, permission_classes=[])),
-    url(r'^ldp-dummys/', LDPViewSet.urls(model=LDPDummy, permission_classes=[])),
-]
\ No newline at end of file
+]
+
+for package in settings.DJANGOLDP_PACKAGES:
+    urlpatterns.append(url(r'^', include('{}.urls'.format(package))))
-- 
GitLab


From 1b8cceef3d388e23ddf3f1a77a33c081710dad6c Mon Sep 17 00:00:00 2001
From: Jean-Baptiste <bleme@pm.me>
Date: Tue, 26 Feb 2019 15:27:19 +0100
Subject: [PATCH 3/6] syntax: urls include simplification

---
 djangoldp/tests/urls.py | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/djangoldp/tests/urls.py b/djangoldp/tests/urls.py
index 7dfbd980..5062860e 100644
--- a/djangoldp/tests/urls.py
+++ b/djangoldp/tests/urls.py
@@ -11,7 +11,6 @@ urlpatterns = [
     url(r'^threads/', LDPViewSet.urls(model=Thread, nested_fields=["message_set"], permission_classes=())),
     url(r'^users/', LDPViewSet.urls(model=settings.AUTH_USER_MODEL, permission_classes=[])),
     url(r'^dummys/', LDPViewSet.urls(model=Dummy, permission_classes=[])),
+    url(r'^', include('djangoldp.urls')),
 ]
 
-for package in settings.DJANGOLDP_PACKAGES:
-    urlpatterns.append(url(r'^', include('{}.urls'.format(package))))
-- 
GitLab


From 3dced943a0376bd5130a2ab2608bb437f9a4373f Mon Sep 17 00:00:00 2001
From: Jean-Baptiste <bleme@pm.me>
Date: Tue, 26 Feb 2019 15:34:24 +0100
Subject: [PATCH 4/6] update: urls section of the README

---
 README.md                 | 4 ++--
 djangoldp/tests/runner.py | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/README.md b/README.md
index 07ac1cf2..392fbe7f 100644
--- a/README.md
+++ b/README.md
@@ -68,12 +68,12 @@ from djangoldp.views import LDPViewSet
 from .models import Todo
 
 urlpatterns = [
-    url(r'^todos/', LDPViewSet.urls(model=Todo)),
+    url(r'^', include('djangoldp.urls')),
     url(r'^admin/', admin.site.urls),
 ]
 ```
 
-This creates 2 routes, one for the list, and one with an ID listing the detail of an object.
+This creates 2 routes for each Model, one for the list, and one with an ID listing the detail of an object.
 
 5. In the settings.py file, add your application name at the beginning of the application list, and add the following lines
 
diff --git a/djangoldp/tests/runner.py b/djangoldp/tests/runner.py
index 7ecff27b..47a4548b 100644
--- a/djangoldp/tests/runner.py
+++ b/djangoldp/tests/runner.py
@@ -9,7 +9,7 @@ settings.configure(DEBUG=True,
                        }
                    },
                    ROOT_URLCONF='djangoldp.tests.urls',
-                   DJANGOLDP_PACKAGES=['djangoldp'],
+                   DJANGOLDP_PACKAGES=['djangoldp.tests'],
                    INSTALLED_APPS=('django.contrib.auth',
                                    'django.contrib.contenttypes',
                                    'django.contrib.sessions',
-- 
GitLab


From 535e1357c70e66c467d2f2e0ca90e719fc1e3135 Mon Sep 17 00:00:00 2001
From: Jean-Baptiste <bleme@pm.me>
Date: Tue, 26 Feb 2019 17:09:44 +0100
Subject: [PATCH 5/6] update: use _meta to put class fields

---
 djangoldp/models.py | 9 ++-------
 djangoldp/urls.py   | 6 ++++--
 2 files changed, 6 insertions(+), 9 deletions(-)

diff --git a/djangoldp/models.py b/djangoldp/models.py
index 0f96a36d..242dea66 100644
--- a/djangoldp/models.py
+++ b/djangoldp/models.py
@@ -4,15 +4,10 @@ from django.urls import get_resolver
 
 
 class Model(models.Model):
-    container_path = None
-    view_set = None
-    permission_classes = []
-    fields = []
-    nested_fields = []
 
     @classmethod
     def get_view_set(cls):
-        view_set = cls.view_set
+        view_set = getattr(cls._meta, 'view_set', None)
         if view_set is None:
             from djangoldp.views import LDPViewSet
             view_set = LDPViewSet
@@ -20,7 +15,7 @@ class Model(models.Model):
 
     @classmethod
     def get_container_path(cls):
-        path = cls.container_path
+        path = getattr(cls._meta, 'container_path', None)
         if path is None:
             path = "{}s".format(cls._meta.object_name.lower())
 
diff --git a/djangoldp/urls.py b/djangoldp/urls.py
index f7f22a0c..3fc889b9 100644
--- a/djangoldp/urls.py
+++ b/djangoldp/urls.py
@@ -29,5 +29,7 @@ for class_name in model_classes:
     path = __clean_path(model_class.get_container_path())
     urls_fct = model_class.get_view_set().urls
     urlpatterns.append(url(r'^' + path, include(
-        urls_fct(model=model_class, permission_classes=model_class.permission_classes, fields=model_class.fields,
-                 nested_fields=model_class.nested_fields))))
+        urls_fct(model=model_class,
+                 permission_classes=getattr(model_class._meta, 'permission_classes', []),
+                 fields=getattr(model_class._meta, 'serializer_fields', []),
+                 nested_fields=getattr(model_class._meta, 'nested_fields', [])))))
-- 
GitLab


From 753df5943efdedbe19f954e5d284588191cc1f1a Mon Sep 17 00:00:00 2001
From: Jean-Baptiste <bleme@pm.me>
Date: Tue, 26 Feb 2019 17:28:54 +0100
Subject: [PATCH 6/6] update: README

---
 README.md | 18 +++++++++++++++---
 1 file changed, 15 insertions(+), 3 deletions(-)

diff --git a/README.md b/README.md
index 392fbe7f..316e9a27 100644
--- a/README.md
+++ b/README.md
@@ -34,13 +34,19 @@ In the future it could also be used to auto configure django router (e.g. urls.p
 from djangoldp.models import Model
 
 class Todo(Model):
-    container_path = "/my-path/"
     name = models.CharField(max_length=255)
     deadline = models.DateTimeField()
 
 ```
 
-3.1. Configure field visibility (optional) 
+3.1. Configure container path (optional)
+By default it will be "todos/" with an S for model called Todo
+
+```
+<Model>._meta.container_path = "/my-path/"
+```
+
+3.2. Configure field visibility (optional) 
 Note that at this stage you can limit access to certain fields of models using
 
 ```
@@ -69,12 +75,18 @@ from .models import Todo
 
 urlpatterns = [
     url(r'^', include('djangoldp.urls')),
-    url(r'^admin/', admin.site.urls),
+    url(r'^admin/', admin.site.urls), # Optional
 ]
 ```
 
 This creates 2 routes for each Model, one for the list, and one with an ID listing the detail of an object.
 
+You could also only use this line in settings.py instead:
+
+```
+ROOT_URLCONF = 'djangoldp.urls'
+```
+
 5. In the settings.py file, add your application name at the beginning of the application list, and add the following lines
 
 ```
-- 
GitLab