Commit af9aad08 authored by Thomas Mignot's avatar Thomas Mignot

refacto

parent 84ca42ee
No preview for this file type
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.auth import AuthMiddlewareStack
import todos.routing
import ryzom.routing
application = ProtocolTypeRouter({
'websocket': AuthMiddlewareStack(
URLRouter(
todos.routing.websocket_urlpatterns
ryzom.routing.websocket_urlpatterns
)
),
})
......@@ -32,6 +32,7 @@ ALLOWED_HOSTS = []
INSTALLED_APPS = [
'channels',
'ryzom',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
......@@ -128,3 +129,7 @@ USE_TZ = True
STATIC_URL = 'static/'
STATIC_ROOT = 'static/'
# ryzom settings
DDP_URLPATTERNS = 'todos.routing'
SERVER_METHODS = 'todos.methods'
......@@ -16,5 +16,5 @@ Including another URLconf
from django.conf.urls import include, url
urlpatterns = [
url('^', include('todos.urls')),
url('^', include('ryzom.urls')),
]
from django.apps import AppConfig
class RyzomConfig(AppConfig):
name = 'ryzom'
......@@ -6,9 +6,11 @@ from channels.auth import get_user
from django.contrib.auth.models import User
from asgiref.sync import async_to_sync
from todos.methods import Methods
from todos.ddp_routing import ddp_urlpatterns
from todos.models import Clients, Subscriptions
from django.conf import settings
from ryzom.models import Clients, Subscriptions
ddp_urlpatterns = importlib.import_module(settings.DDP_URLPATTERNS).urlpatterns
server_methods = importlib.import_module(settings.SERVER_METHODS).Methods
class Consumer(JsonWebsocketConsumer, object):
......@@ -79,7 +81,7 @@ class Consumer(JsonWebsocketConsumer, object):
if (cview.onurl(to_url)):
self.send(json.dumps({
'_id': data['_id'],
'type': 'Result',
'type': 'Success',
'params': []
}))
else:
......@@ -89,7 +91,7 @@ class Consumer(JsonWebsocketConsumer, object):
self.view.oncreate(to_url)
data = {
'_id': data['_id'],
'type': 'Result',
'type': 'Success',
'params': self.view.render()
}
self.send(json.dumps(data))
......@@ -98,7 +100,7 @@ class Consumer(JsonWebsocketConsumer, object):
def recv_method(self, data):
to_send = {'_id': data['_id']}
params = data['params']
method = getattr(Methods, params['name'], None)
method = getattr(server_methods, params['name'], None)
if method is None:
to_send.update({
'type': 'Error',
......@@ -112,7 +114,7 @@ class Consumer(JsonWebsocketConsumer, object):
ret = method(params['params'])
if ret:
to_send.update({
'type': 'Result',
'type': 'Success',
'params': ret
})
else:
......@@ -181,7 +183,7 @@ class Consumer(JsonWebsocketConsumer, object):
template_class=params['template'][1],
client=client)
to_send.update({
'type': 'Result',
'type': 'Success',
'params': {
'name': params['name'],
'sub_id': sub.id
......@@ -199,4 +201,3 @@ class Consumer(JsonWebsocketConsumer, object):
'name': params['name']
}
}))
# Generated by Django 2.1.7 on 2019-02-24 15:44
# Generated by Django 2.1.7 on 2019-02-28 14:37
from django.conf import settings
from django.db import migrations, models
......@@ -7,18 +7,30 @@ import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('todos', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='Tasks',
name='Clients',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('about', models.CharField(max_length=1024)),
('channel', models.CharField(max_length=255)),
('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)),
],
),
migrations.CreateModel(
name='Subscriptions',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=255)),
('parent', models.CharField(max_length=255)),
('template_module', models.CharField(max_length=255)),
('template_class', models.CharField(max_length=255)),
('client', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='ryzom.Clients')),
],
),
]
import importlib
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_delete, post_save
from django.dispatch import receiver
from asgiref.sync import async_to_sync
from channels.layers import get_channel_layer
class Clients(models.Model):
channel = models.CharField(max_length=255)
user = models.ForeignKey(
User,
models.SET_NULL,
blank=True,
null=True
)
class Subscriptions(models.Model):
name = models.CharField(max_length=255)
parent = models.CharField(max_length=255)
template_module = models.CharField(max_length=255)
template_class = models.CharField(max_length=255)
client = models.ForeignKey(Clients, models.CASCADE)
@receiver(post_save)
def ddp_insert_change(sender, **kwargs):
created = kwargs.pop('created')
instance = kwargs.pop('instance')
data = {
'type': 'handle.ddp',
'params': {
'type': 'inserted' if created else 'changed',
}
}
subs = Subscriptions.objects.filter(name=sender.__name__)
for sub in subs:
mfile, mpath = sub.template_module[::-1].split('.', 1)
tmpl_module = importlib.import_module(f'.{mfile[::-1]}', mpath[::-1])
tmpl_class = getattr(tmpl_module, sub.template_class)
tmpl_instance = tmpl_class(instance)
tmpl_instance.parent = sub.parent
data['params']['instance'] = tmpl_instance.to_obj()
client = sub.client
channel = get_channel_layer()
async_to_sync(channel.send)(client.channel, data)
@receiver(post_delete)
def ddp_delete(sender, **kwargs):
instance = kwargs.pop('instance')
data = {
'type': 'handle.ddp',
'params': {
'type': 'removed',
}
}
subs = Subscriptions.objects.filter(name=sender.__name__)
for sub in subs:
mfile, mpath = sub.template_module[::-1].split('.', 1)
tmpl_module = importlib.import_module(f'.{mfile[::-1]}', mpath[::-1])
tmpl_class = getattr(tmpl_module, sub.template_class)
tmpl_instance = tmpl_class(instance)
data['params']['parent'] = sub.parent
data['params']['_id'] = tmpl_instance._id
client = sub.client
channel = get_channel_layer()
async_to_sync(channel.send)(client.channel, data)
from project.component import Div
from asgiref.sync import async_to_sync
from channels.layers import get_channel_layer
from ryzom.components import Component
class ReactiveDiv(Div):
def __init__(self, name, view, content):
super().__init__(content=content, _id=f'reactive_div_{name}')
class ReactiveComponent(Component):
def __init__(self, name, view, tag='div', content=[], attr={},
events={}, parent='body', _id=None):
self.name = name
self.view = view
self.view.addReactiveDiv(self)
super().__init__(tag, content, attr, events, parent, _id)
self.view.addReactiveComponent(self)
def setcontent(self, content):
self.content = content
......@@ -22,3 +21,10 @@ class ReactiveDiv(Div):
'instance': self.to_obj()
}
})
class ReactiveDiv(ReactiveComponent):
def __init__(self, name, view, content):
super().__init__(name, view, 'div',
content=content,
_id=f'reactive_div_{name}')
from django.conf.urls import url
from . import consumers
websocket_urlpatterns = [
url(r'^ws/ddp/$', consumers.Consumer),
]
......@@ -87,6 +87,10 @@
};
constructDOM = function(data) {
if (!Array.isArray(data)) {
data = [data]
}
data.forEach(function(component) {
var elem = createDOMelement(component);
getElementByUuid(component.parent).appendChild(elem);
......@@ -115,7 +119,7 @@
default:
if (data.type == 'Error')
error = data;
else if (data.type == 'Result')
else if (data.type == 'Success')
result = data;
ws.callbacks[data._id](result, error);
......@@ -166,8 +170,12 @@
};
window.onpopstate = function(event) {
route(event.state.path, '', true);
event.preventDefault()
if (event.state) {
route(event.state.path, '', true);
event.preventDefault()
} else {
history.back()
}
};
onwsready = function(cb) {
......
import json
from django.shortcuts import render
class View():
def __init__(self, channel_name):
self.channel_name = channel_name
self.reactive_divs = {}
self.reactive_components = {}
def addReactiveDiv(self, div):
self.reactive_divs[div.name] = div
def addReactiveComponent(self, component):
self.reactive_components[component.name] = component
def setcontent(self, name, content):
div = self.reactive_divs[name]
div.setcontent(content)
def reactive(self, name, content):
component = self.reactive_components[name]
component.setcontent(content)
def onurl(self, url):
raise NotImplementedError
......@@ -21,3 +25,11 @@ class View():
def ondestroy(self, url):
pass
def index(request, url=''):
print(json.dumps(request.GET))
return render(request, 'index.html', {
'url': url,
'query_string': request.GET.urlencode()
})
from project.component import Div, Ul, Li, Span, Input, Button
from project.component import Nav, H1
from project.reactivediv import ReactiveDiv
from todos.models import Tasks
class Task(Li):
def __init__(self, task_object):
attr = {'class': 'list-group-item'}
content = [
Span(task_object.about),
Button('Done', {'class': 'btn float-right'}, {
'click': f'call("remove_task", {{id: {task_object.id}}})'
})
]
super().__init__(content, attr, _id=f'task_{task_object.id}')
class Tasklist(Ul):
def __init__(self):
self.subscriptions = [('tasks', ('todos.components.base', 'Task'))]
content = [
Task(t)
for t in Tasks.objects.filter()
]
super().__init__(content, {'class': 'list-group'}, _id='tasklist')
class Taskform(Div):
def __init__(self):
attr = {
'class': 'form-group',
'style': 'margin:20px',
'action': '#'
}
content = [
Div(
attr={'class': 'input-group'},
content=[
Input(attr={
'id': 'task_input',
'type': 'text',
'class': 'form-control'
}),
Div(
attr={'class': 'input-group-append'},
content=[
Button(
content='Add',
attr={
'class': 'btn btn-primary'
},
events={
'click': 'call("insert_task", { \
about: $("#task_input").value \
}); $("#task_input").value = ""'
}
)
]
)
]
)
]
super().__init__(content, attr, _id='task_form')
class Welcome(Div):
def __init__(self):
content = [
H1('WELCOME !'),
Button('todos', events={
'click': 'route("todos")'
})]
super().__init__(content)
from ryzom.components import Div, Nav, H1
from ryzom.reactive import ReactiveDiv
from todos.components.home import Welcome
from todos.components.tasks import Tasklist, Taskform
class Base(Div):
......
from ryzom.components import Div, Button, H1
class Welcome(Div):
def __init__(self):
content = [
H1('WELCOME !'),
Button('todos', events={
'click': 'route("todos")'
})]
super().__init__(content)
from ryzom.components import Div, Ul, Li, Span, Input, Button
from todos.models import Tasks
class Task(Li):
def __init__(self, task_object):
attr = {'class': 'list-group-item'}
content = [
Span(task_object.about),
Button('Done', {'class': 'btn float-right'}, {
'click': f'call("remove_task", {{id: {task_object.id}}})'
})
]
super().__init__(content, attr, _id=f'task_{task_object.id}')
class Tasklist(Ul):
def __init__(self):
# Array of ('ModelName', ('template.module.file', 'TemplateClass'))
self.subscriptions = [('Tasks', ('todos.components.tasks', 'Task'))]
content = [
Task(t)
for t in Tasks.objects.filter()
]
super().__init__(content, {'class': 'list-group'}, _id='tasklist')
class Taskform(Div):
def __init__(self):
attr = {
'class': 'form-group',
'style': 'margin:20px',
'action': '#'
}
content = [
Div(
attr={'class': 'input-group'},
content=[
Input(attr={
'id': 'task_input',
'type': 'text',
'class': 'form-control'
}),
Div(
attr={'class': 'input-group-append'},
content=[
Button(
content='Add',
attr={
'class': 'btn btn-primary'
},
events={
'click': 'call("insert_task", { \
about: $("#task_input").value \
}); $("#task_input").value = ""'
}
)
]
)
]
)
]
super().__init__(content, attr, _id='task_form')
from django.conf.urls import url
from .pages import Layout
ddp_urlpatterns = [
url(r'todos', Layout),
url(r'', Layout),
]
# Generated by Django 2.1.7 on 2019-02-23 10:29
# Generated by Django 2.1.7 on 2019-02-28 14:37
from django.conf import settings
from django.db import migrations, models
......@@ -15,19 +15,11 @@ class Migration(migrations.Migration):
operations = [
migrations.CreateModel(
name='Clients',
name='Tasks',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('channel', models.CharField(max_length=255)),
('about', models.CharField(max_length=1024)),
('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)),
],
),
migrations.CreateModel(
name='Subscriptions',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=255)),
('client', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='todos.Clients')),
],
),
]
# Generated by Django 2.1.7 on 2019-02-24 19:03
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('todos', '0002_tasks'),
]
operations = [
migrations.AddField(
model_name='subscriptions',
name='parent',
field=models.CharField(default='body', max_length=255),
preserve_default=False,
),
]
# Generated by Django 2.1.7 on 2019-02-25 04:46
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('todos', '0003_subscriptions_parent'),
]
operations = [
migrations.AddField(
model_name='subscriptions',
name='template_class',
field=models.CharField(default='Task', max_length=255),
preserve_default=False,
),
migrations.AddField(
model_name='subscriptions',
name='template_module',
field=models.CharField(default='todos.components.base', max_length=255),
preserve_default=False,
),
]
import importlib
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_delete, post_save
from django.dispatch import receiver
from asgiref.sync import async_to_sync
from channels.layers import get_channel_layer
class Clients(models.Model):
channel = models.CharField(max_length=255)
user = models.ForeignKey(
User,
models.SET_NULL,
blank=True,
null=True
)
class Subscriptions(models.Model):
name = models.CharField(max_length=255)
parent = models.CharField(max_length=255)
template_module = models.CharField(max_length=255)
template_class = models.CharField(max_length=255)
client = models.ForeignKey(Clients, models.CASCADE)
class Tasks(models.Model):
user = models.ForeignKey(User, models.SET_NULL, blank=True, null=True)
about = models.CharField(max_length=1024)
@receiver(post_save, sender=Tasks)
def ddp_insert_change(sender, **kwargs):
created = kwargs.pop('created')
instance = kwargs.pop('instance')
data = {
'type': 'handle.ddp',
'params': {
'type': 'inserted' if created else 'changed',
}
}
subs = Subscriptions.objects.filter(name='tasks')
for sub in subs:
mfile, mpath = sub.template_module[::-1].split('.', 1)
tmpl_module = importlib.import_module(f'.{mfile[::-1]}', mpath[::-1])
tmpl_class = getattr(tmpl_module, sub.template_class)
tmpl_instance = tmpl_class(instance)
tmpl_instance.parent = sub.parent
data['params']['instance'] = tmpl_instance.to_obj()
client = sub.client
channel = get_channel_layer()
async_to_sync(channel.send)(client.channel, data)
@receiver(post_delete, sender=Tasks)
def ddp_delete(sender, **kwargs):
instance = kwargs.pop('instance')
data = {
'type': 'handle.ddp',
'params': {
'type': 'removed',
}
}
subs = Subscriptions.objects.filter(name='tasks')
for sub in subs:
mfile, mpath = sub.template_module[::-1].split('.', 1)
tmpl_module = importlib.import_module(f'.{mfile[::-1]}', mpath[::-1])
tmpl_class = getattr(tmpl_module, sub.template_class)
tmpl_instance = tmpl_class(instance)
data['params']['parent'] = sub.parent
data['params']['_id'] = tmpl_instance._id
client = sub.client
channel = get_channel_layer()
async_to_sync(channel.send)(client.channel, data)
from .view import View
from .components.base import Base, Tasklist, Taskform, Welcome
from ryzom.views import View
from todos.components.base import Base
from todos.components.home import Welcome
from todos.components.tasks import Tasklist, Taskform
class Layout(View):
......@@ -10,9 +12,9 @@ class Layout(View):
def onurl(self, url):
self.url = url
if url == 'todos':
self.setcontent('main-container', [Tasklist(), Taskform()])
self.reactive('main-container', [Tasklist(), Taskform()])
else:
self.setcontent('main-container', [Welcome()])