Thubrecht/daphne #815
14 changed files with 129 additions and 73 deletions
|
@ -1,8 +1,15 @@
|
||||||
|
"""
|
||||||
|
ASGI entrypoint. Configures Django and then runs the application
|
||||||
|
defined in the ASGI_APPLICATION setting.
|
||||||
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from channels.asgi import get_channel_layer
|
import django
|
||||||
|
from channels.routing import get_default_application
|
||||||
|
|
||||||
if "DJANGO_SETTINGS_MODULE" not in os.environ:
|
if "DJANGO_SETTINGS_MODULE" not in os.environ:
|
||||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "gestioasso.settings")
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "gestioasso.settings.local")
|
||||||
|
|
||||||
channel_layer = get_channel_layer()
|
django.setup()
|
||||||
|
application = get_default_application()
|
||||||
|
|
|
@ -1,3 +1,18 @@
|
||||||
from channels.routing import include
|
from channels.auth import AuthMiddlewareStack
|
||||||
|
from channels.routing import ProtocolTypeRouter, URLRouter
|
||||||
|
from django.urls import path
|
||||||
|
|
||||||
routing = [include("kfet.routing.routing", path=r"^/ws/k-fet")]
|
from kfet.routing import KFRouter
|
||||||
|
|
||||||
|
application = ProtocolTypeRouter(
|
||||||
|
{
|
||||||
|
# WebSocket chat handler
|
||||||
|
"websocket": AuthMiddlewareStack(
|
||||||
|
URLRouter(
|
||||||
|
[
|
||||||
|
path("ws/k-fet", KFRouter),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
|
@ -109,6 +109,8 @@ MEDIA_URL = "/gestion/media/"
|
||||||
CORS_ORIGIN_WHITELIST = ("bda.ens.fr", "www.bda.ens.fr" "cof.ens.fr", "www.cof.ens.fr")
|
CORS_ORIGIN_WHITELIST = ("bda.ens.fr", "www.bda.ens.fr" "cof.ens.fr", "www.cof.ens.fr")
|
||||||
|
|
||||||
|
|
||||||
|
ASGI_APPLICATION = "gestioasso.routing.application"
|
||||||
|
|
||||||
# ---
|
# ---
|
||||||
# Auth-related stuff
|
# Auth-related stuff
|
||||||
# ---
|
# ---
|
||||||
|
@ -147,7 +149,7 @@ CACHES = {
|
||||||
|
|
||||||
CHANNEL_LAYERS = {
|
CHANNEL_LAYERS = {
|
||||||
"default": {
|
"default": {
|
||||||
"BACKEND": "asgi_redis.RedisChannelLayer",
|
"BACKEND": "channels_redis.core.RedisChannelLayer",
|
||||||
"CONFIG": {
|
"CONFIG": {
|
||||||
"hosts": [
|
"hosts": [
|
||||||
(
|
(
|
||||||
|
@ -160,11 +162,9 @@ CHANNEL_LAYERS = {
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"ROUTING": "gestioasso.routing.routing",
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# ---
|
# ---
|
||||||
# reCAPTCHA settings
|
# reCAPTCHA settings
|
||||||
# https://github.com/praekelt/django-recaptcha
|
# https://github.com/praekelt/django-recaptcha
|
||||||
|
|
|
@ -47,8 +47,7 @@ CACHES = {"default": {"BACKEND": "django.core.cache.backends.locmem.LocMemCache"
|
||||||
# Use the default in memory asgi backend for local development
|
# Use the default in memory asgi backend for local development
|
||||||
CHANNEL_LAYERS = {
|
CHANNEL_LAYERS = {
|
||||||
"default": {
|
"default": {
|
||||||
"BACKEND": "asgiref.inmemory.ChannelLayer",
|
"BACKEND": "channels.layers.InMemoryChannelLayer",
|
||||||
"ROUTING": "gestioasso.routing.routing",
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,3 +4,6 @@ from .utils import DjangoJsonWebsocketConsumer, PermConsumerMixin
|
||||||
class KPsul(PermConsumerMixin, DjangoJsonWebsocketConsumer):
|
class KPsul(PermConsumerMixin, DjangoJsonWebsocketConsumer):
|
||||||
groups = ["kfet.kpsul"]
|
groups = ["kfet.kpsul"]
|
||||||
perms_connect = ["kfet.is_team"]
|
perms_connect = ["kfet.is_team"]
|
||||||
|
|
||||||
|
async def kpsul(self, event):
|
||||||
|
await self.send_json(event)
|
||||||
|
|
|
@ -12,13 +12,15 @@ class OpenKfetConsumer(PermConsumerMixin, DjangoJsonWebsocketConsumer):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def connection_groups(self, user, **kwargs):
|
async def open_status(self, event):
|
||||||
"""Select which group the user should be connected."""
|
await self.send_json(event)
|
||||||
if kfet_is_team(user):
|
|
||||||
return ["kfet.open.team"]
|
|
||||||
return ["kfet.open.base"]
|
|
||||||
|
|
||||||
def connect(self, message, *args, **kwargs):
|
async def connect(self):
|
||||||
"""Send current status on connect."""
|
"""Send current status on connect."""
|
||||||
super().connect(message, *args, **kwargs)
|
await super().connect()
|
||||||
self.send(kfet_open.export(message.user))
|
|
||||||
|
group = "team" if kfet_is_team(self.user) else "base"
|
||||||
|
|
||||||
|
await self.channel_layer.group_add(f"kfet.open.{group}", self.channel_name)
|
||||||
|
|
||||||
|
await self.send_json(kfet_open.export(self.user))
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
|
||||||
|
from channels.layers import get_channel_layer
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
from ..decorators import kfet_is_team
|
from ..decorators import kfet_is_team
|
||||||
|
@ -77,7 +78,7 @@ class OpenKfet(CachedMixin, object):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
status = self.status()
|
status = self.status()
|
||||||
base = {"status": status}
|
base = {"status": status, "type": "open.status"}
|
||||||
restrict = {
|
restrict = {
|
||||||
"admin_status": self.admin_status(status),
|
"admin_status": self.admin_status(status),
|
||||||
"force_close": self.force_close,
|
"force_close": self.force_close,
|
||||||
|
@ -95,13 +96,14 @@ class OpenKfet(CachedMixin, object):
|
||||||
base, team = self._export()
|
base, team = self._export()
|
||||||
return team if kfet_is_team(user) else base
|
return team if kfet_is_team(user) else base
|
||||||
|
|
||||||
def send_ws(self):
|
async def send_ws(self):
|
||||||
"""Send internal state to websocket channels."""
|
"""Send internal state to websocket channels."""
|
||||||
from .consumers import OpenKfetConsumer
|
|
||||||
|
|
||||||
base, team = self._export()
|
base, team = self._export()
|
||||||
OpenKfetConsumer.group_send("kfet.open.base", base)
|
|
||||||
OpenKfetConsumer.group_send("kfet.open.team", team)
|
channel_layer = get_channel_layer()
|
||||||
|
|
||||||
|
await channel_layer.group_send("kfet.open.base", base)
|
||||||
|
await channel_layer.group_send("kfet.open.team", team)
|
||||||
|
|
||||||
|
|
||||||
kfet_open = OpenKfet()
|
kfet_open = OpenKfet()
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
from channels.routing import route_class
|
from channels.routing import URLRouter
|
||||||
|
from django.urls import path
|
||||||
|
|
||||||
from . import consumers
|
from .consumers import OpenKfetConsumer
|
||||||
|
|
||||||
routing = [route_class(consumers.OpenKfetConsumer)]
|
OpenRouter = URLRouter(
|
||||||
|
[
|
||||||
|
path(r"", OpenKfetConsumer),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
from asgiref.sync import async_to_sync
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth.decorators import permission_required
|
from django.contrib.auth.decorators import permission_required
|
||||||
from django.core.exceptions import PermissionDenied
|
from django.core.exceptions import PermissionDenied
|
||||||
|
@ -18,7 +19,7 @@ def raw_open(request):
|
||||||
raise PermissionDenied
|
raise PermissionDenied
|
||||||
raw_open = request.POST.get("raw_open") in TRUE_STR
|
raw_open = request.POST.get("raw_open") in TRUE_STR
|
||||||
kfet_open.raw_open = raw_open
|
kfet_open.raw_open = raw_open
|
||||||
kfet_open.send_ws()
|
async_to_sync(kfet_open.send_ws)()
|
||||||
return HttpResponse()
|
return HttpResponse()
|
||||||
|
|
||||||
|
|
||||||
|
@ -27,5 +28,5 @@ def raw_open(request):
|
||||||
def force_close(request):
|
def force_close(request):
|
||||||
force_close = request.POST.get("force_close") in TRUE_STR
|
force_close = request.POST.get("force_close") in TRUE_STR
|
||||||
kfet_open.force_close = force_close
|
kfet_open.force_close = force_close
|
||||||
kfet_open.send_ws()
|
async_to_sync(kfet_open.send_ws)()
|
||||||
return HttpResponse()
|
return HttpResponse()
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
from channels.routing import include, route_class
|
from channels.routing import URLRouter
|
||||||
|
from django.urls import path
|
||||||
|
|
||||||
from . import consumers
|
from kfet.open.routing import OpenRouter
|
||||||
|
|
||||||
routing = [
|
from .consumers import KPsul
|
||||||
route_class(consumers.KPsul, path=r"^/k-psul/$"),
|
|
||||||
include("kfet.open.routing.routing", path=r"^/open"),
|
KFRouter = URLRouter(
|
||||||
|
[
|
||||||
|
path("k-psul/", KPsul),
|
||||||
|
path("open", OpenRouter),
|
||||||
]
|
]
|
||||||
|
)
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
import json
|
import json
|
||||||
import math
|
import math
|
||||||
|
|
||||||
from channels.channel import Group
|
from channels.generic.websocket import AsyncJsonWebsocketConsumer
|
||||||
from channels.generic.websockets import JsonWebsocketConsumer
|
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
from django.core.serializers.json import DjangoJSONEncoder
|
from django.core.serializers.json import DjangoJSONEncoder
|
||||||
|
|
||||||
|
@ -63,7 +62,7 @@ class CachedMixin:
|
||||||
# Consumers
|
# Consumers
|
||||||
|
|
||||||
|
|
||||||
class DjangoJsonWebsocketConsumer(JsonWebsocketConsumer):
|
class DjangoJsonWebsocketConsumer(AsyncJsonWebsocketConsumer):
|
||||||
"""Custom Json Websocket Consumer.
|
"""Custom Json Websocket Consumer.
|
||||||
|
|
||||||
Encode to JSON with DjangoJSONEncoder.
|
Encode to JSON with DjangoJSONEncoder.
|
||||||
|
@ -71,7 +70,7 @@ class DjangoJsonWebsocketConsumer(JsonWebsocketConsumer):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def encode_json(cls, content):
|
async def encode_json(cls, content):
|
||||||
return json.dumps(content, cls=DjangoJSONEncoder)
|
return json.dumps(content, cls=DjangoJSONEncoder)
|
||||||
|
|
||||||
|
|
||||||
|
@ -89,31 +88,35 @@ class PermConsumerMixin:
|
||||||
http_user = True # Enable message.user
|
http_user = True # Enable message.user
|
||||||
perms_connect = []
|
perms_connect = []
|
||||||
|
|
||||||
def connect(self, message, **kwargs):
|
async def connect(self):
|
||||||
"""Check permissions on connection."""
|
"""Check permissions on connection."""
|
||||||
if message.user.has_perms(self.perms_connect):
|
self.user = self.scope["user"]
|
||||||
super().connect(message, **kwargs)
|
|
||||||
|
if self.user.has_perms(self.perms_connect):
|
||||||
|
await super().connect()
|
||||||
else:
|
else:
|
||||||
self.close()
|
await self.close()
|
||||||
|
|
||||||
def raw_connect(self, message, **kwargs):
|
# async def raw_connect(self, message, **kwargs):
|
||||||
# Same as original raw_connect method of JsonWebsocketConsumer
|
# # Same as original raw_connect method of JsonWebsocketConsumer
|
||||||
# We add user to connection_groups call.
|
# # We add user to connection_groups call.
|
||||||
groups = self.connection_groups(user=message.user, **kwargs)
|
# groups = self.connection_groups(user=message.user, **kwargs)
|
||||||
for group in groups:
|
# for group in groups:
|
||||||
Group(group, channel_layer=message.channel_layer).add(message.reply_channel)
|
# await self.channel_layer.group_add(group, message.reply_channel)
|
||||||
self.connect(message, **kwargs)
|
# # Group(group, channel_layer=message.channel_layer).add(message.reply_channel)
|
||||||
|
# self.connect(message, **kwargs)
|
||||||
def raw_disconnect(self, message, **kwargs):
|
#
|
||||||
# Same as original raw_connect method of JsonWebsocketConsumer
|
# async def raw_disconnect(self, message, **kwargs):
|
||||||
# We add user to connection_groups call.
|
# # Same as original raw_connect method of JsonWebsocketConsumer
|
||||||
groups = self.connection_groups(user=message.user, **kwargs)
|
# # We add user to connection_groups call.
|
||||||
for group in groups:
|
# groups = self.connection_groups(user=message.user, **kwargs)
|
||||||
Group(group, channel_layer=message.channel_layer).discard(
|
# for group in groups:
|
||||||
message.reply_channel
|
# await self.channel_layer.group_discard(group, message.reply_channel)
|
||||||
)
|
# # Group(group, channel_layer=message.channel_layer).discard(
|
||||||
self.disconnect(message, **kwargs)
|
# # message.reply_channel
|
||||||
|
# # )
|
||||||
def connection_groups(self, user, **kwargs):
|
# self.disconnect(message, **kwargs)
|
||||||
"""`message.user` is available as `user` arg. Original behavior."""
|
#
|
||||||
return super().connection_groups(user=user, **kwargs)
|
# def connection_groups(self, user, **kwargs):
|
||||||
|
# """`message.user` is available as `user` arg. Original behavior."""
|
||||||
|
# return super().connection_groups(user=user, **kwargs)
|
||||||
|
|
|
@ -6,6 +6,8 @@ from decimal import Decimal
|
||||||
from typing import List, Tuple
|
from typing import List, Tuple
|
||||||
from urllib.parse import urlencode
|
from urllib.parse import urlencode
|
||||||
|
|
||||||
|
from asgiref.sync import async_to_sync
|
||||||
|
from channels.layers import get_channel_layer
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth.decorators import login_required, permission_required
|
from django.contrib.auth.decorators import login_required, permission_required
|
||||||
|
@ -44,7 +46,7 @@ from django.views.generic.detail import BaseDetailView
|
||||||
from django.views.generic.edit import CreateView, DeleteView, UpdateView
|
from django.views.generic.edit import CreateView, DeleteView, UpdateView
|
||||||
|
|
||||||
from gestioncof.models import CofProfile
|
from gestioncof.models import CofProfile
|
||||||
from kfet import KFET_DELETED_TRIGRAMME, consumers
|
from kfet import KFET_DELETED_TRIGRAMME
|
||||||
from kfet.auth.decorators import kfet_password_auth
|
from kfet.auth.decorators import kfet_password_auth
|
||||||
from kfet.autocomplete import kfet_account_only_autocomplete, kfet_autocomplete
|
from kfet.autocomplete import kfet_account_only_autocomplete, kfet_autocomplete
|
||||||
from kfet.config import kfet_config
|
from kfet.config import kfet_config
|
||||||
|
@ -1054,8 +1056,14 @@ def kpsul_update_addcost(request):
|
||||||
|
|
||||||
kfet_config.set(addcost_for=account, addcost_amount=amount)
|
kfet_config.set(addcost_for=account, addcost_amount=amount)
|
||||||
|
|
||||||
data = {"addcost": {"for": account and account.trigramme or None, "amount": amount}}
|
data = {
|
||||||
consumers.KPsul.group_send("kfet.kpsul", data)
|
"addcost": {"for": account and account.trigramme or None, "amount": amount},
|
||||||
|
"type": "kpsul",
|
||||||
|
}
|
||||||
|
|
||||||
|
channel_layer = get_channel_layer()
|
||||||
|
|
||||||
|
async_to_sync(channel_layer.group_send)("kfet.kpsul", data)
|
||||||
return JsonResponse(data)
|
return JsonResponse(data)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1239,7 +1247,7 @@ def kpsul_perform_operations(request):
|
||||||
)
|
)
|
||||||
|
|
||||||
# Websocket data
|
# Websocket data
|
||||||
websocket_data = {}
|
websocket_data = {"type": "kpsul"}
|
||||||
websocket_data["groups"] = [
|
websocket_data["groups"] = [
|
||||||
{
|
{
|
||||||
"add": True,
|
"add": True,
|
||||||
|
@ -1286,7 +1294,10 @@ def kpsul_perform_operations(request):
|
||||||
websocket_data["articles"].append(
|
websocket_data["articles"].append(
|
||||||
{"id": article["id"], "stock": article["stock"]}
|
{"id": article["id"], "stock": article["stock"]}
|
||||||
)
|
)
|
||||||
consumers.KPsul.group_send("kfet.kpsul", websocket_data)
|
|
||||||
|
channel_layer = get_channel_layer()
|
||||||
|
|
||||||
|
async_to_sync(channel_layer.group_send)("kfet.kpsul", websocket_data)
|
||||||
return JsonResponse(data)
|
return JsonResponse(data)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1481,7 +1492,7 @@ def cancel_operations(request):
|
||||||
articles = Article.objects.values("id", "stock").filter(pk__in=articles_pk)
|
articles = Article.objects.values("id", "stock").filter(pk__in=articles_pk)
|
||||||
|
|
||||||
# Websocket data
|
# Websocket data
|
||||||
websocket_data = {"checkouts": [], "articles": []}
|
websocket_data = {"checkouts": [], "articles": [], "type": "kpsul"}
|
||||||
for checkout in checkouts:
|
for checkout in checkouts:
|
||||||
websocket_data["checkouts"].append(
|
websocket_data["checkouts"].append(
|
||||||
{"id": checkout["id"], "balance": checkout["balance"]}
|
{"id": checkout["id"], "balance": checkout["balance"]}
|
||||||
|
@ -1490,7 +1501,10 @@ def cancel_operations(request):
|
||||||
websocket_data["articles"].append(
|
websocket_data["articles"].append(
|
||||||
{"id": article["id"], "stock": article["stock"]}
|
{"id": article["id"], "stock": article["stock"]}
|
||||||
)
|
)
|
||||||
consumers.KPsul.group_send("kfet.kpsul", websocket_data)
|
|
||||||
|
channel_layer = get_channel_layer()
|
||||||
|
|
||||||
|
async_to_sync(channel_layer.group_send)("kfet.kpsul", websocket_data)
|
||||||
|
|
||||||
data["canceled"] = list(opes)
|
data["canceled"] = list(opes)
|
||||||
data["opegroups_to_update"] = list(opegroups)
|
data["opegroups_to_update"] = list(opegroups)
|
||||||
|
|
|
@ -6,7 +6,7 @@ psycopg2<2.8
|
||||||
# Redis
|
# Redis
|
||||||
django-redis-cache==2.1.*
|
django-redis-cache==2.1.*
|
||||||
redis~=2.10.6
|
redis~=2.10.6
|
||||||
asgi-redis==1.4.*
|
channels-redis==2.4.*
|
||||||
|
|
||||||
# ASGI protocol and HTTP server
|
# ASGI protocol and HTTP server
|
||||||
asgiref~=1.1.2
|
asgiref~=1.1.2
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
Django==2.2.*
|
Django==2.2.*
|
||||||
Pillow==7.2.0
|
Pillow==7.2.0
|
||||||
authens==0.1b0
|
authens==0.1b0
|
||||||
channels==1.1.*
|
channels==2.4.*
|
||||||
configparser==3.5.0
|
configparser==3.5.0
|
||||||
django-autocomplete-light==3.3.*
|
django-autocomplete-light==3.3.*
|
||||||
django-bootstrap-form==3.3
|
django-bootstrap-form==3.3
|
||||||
|
|
Loading…
Reference in a new issue