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
|
||||
|
||||
from channels.asgi import get_channel_layer
|
||||
import django
|
||||
from channels.routing import get_default_application
|
||||
|
||||
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")
|
||||
|
||||
|
||||
ASGI_APPLICATION = "gestioasso.routing.application"
|
||||
|
||||
# ---
|
||||
# Auth-related stuff
|
||||
# ---
|
||||
|
@ -147,7 +149,7 @@ CACHES = {
|
|||
|
||||
CHANNEL_LAYERS = {
|
||||
"default": {
|
||||
"BACKEND": "asgi_redis.RedisChannelLayer",
|
||||
"BACKEND": "channels_redis.core.RedisChannelLayer",
|
||||
"CONFIG": {
|
||||
"hosts": [
|
||||
(
|
||||
|
@ -160,11 +162,9 @@ CHANNEL_LAYERS = {
|
|||
)
|
||||
]
|
||||
},
|
||||
"ROUTING": "gestioasso.routing.routing",
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# ---
|
||||
# reCAPTCHA settings
|
||||
# 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
|
||||
CHANNEL_LAYERS = {
|
||||
"default": {
|
||||
"BACKEND": "asgiref.inmemory.ChannelLayer",
|
||||
"ROUTING": "gestioasso.routing.routing",
|
||||
"BACKEND": "channels.layers.InMemoryChannelLayer",
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,3 +4,6 @@ from .utils import DjangoJsonWebsocketConsumer, PermConsumerMixin
|
|||
class KPsul(PermConsumerMixin, DjangoJsonWebsocketConsumer):
|
||||
groups = ["kfet.kpsul"]
|
||||
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):
|
||||
"""Select which group the user should be connected."""
|
||||
if kfet_is_team(user):
|
||||
return ["kfet.open.team"]
|
||||
return ["kfet.open.base"]
|
||||
async def open_status(self, event):
|
||||
await self.send_json(event)
|
||||
|
||||
def connect(self, message, *args, **kwargs):
|
||||
async def connect(self):
|
||||
"""Send current status on connect."""
|
||||
super().connect(message, *args, **kwargs)
|
||||
self.send(kfet_open.export(message.user))
|
||||
await super().connect()
|
||||
|
||||
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 channels.layers import get_channel_layer
|
||||
from django.utils import timezone
|
||||
|
||||
from ..decorators import kfet_is_team
|
||||
|
@ -77,7 +78,7 @@ class OpenKfet(CachedMixin, object):
|
|||
|
||||
"""
|
||||
status = self.status()
|
||||
base = {"status": status}
|
||||
base = {"status": status, "type": "open.status"}
|
||||
restrict = {
|
||||
"admin_status": self.admin_status(status),
|
||||
"force_close": self.force_close,
|
||||
|
@ -95,13 +96,14 @@ class OpenKfet(CachedMixin, object):
|
|||
base, team = self._export()
|
||||
return team if kfet_is_team(user) else base
|
||||
|
||||
def send_ws(self):
|
||||
async def send_ws(self):
|
||||
"""Send internal state to websocket channels."""
|
||||
from .consumers import OpenKfetConsumer
|
||||
|
||||
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()
|
||||
|
|
|
@ -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.contrib.auth.decorators import permission_required
|
||||
from django.core.exceptions import PermissionDenied
|
||||
|
@ -18,7 +19,7 @@ def raw_open(request):
|
|||
raise PermissionDenied
|
||||
raw_open = request.POST.get("raw_open") in TRUE_STR
|
||||
kfet_open.raw_open = raw_open
|
||||
kfet_open.send_ws()
|
||||
async_to_sync(kfet_open.send_ws)()
|
||||
return HttpResponse()
|
||||
|
||||
|
||||
|
@ -27,5 +28,5 @@ def raw_open(request):
|
|||
def force_close(request):
|
||||
force_close = request.POST.get("force_close") in TRUE_STR
|
||||
kfet_open.force_close = force_close
|
||||
kfet_open.send_ws()
|
||||
async_to_sync(kfet_open.send_ws)()
|
||||
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 = [
|
||||
route_class(consumers.KPsul, path=r"^/k-psul/$"),
|
||||
include("kfet.open.routing.routing", path=r"^/open"),
|
||||
]
|
||||
from .consumers import KPsul
|
||||
|
||||
KFRouter = URLRouter(
|
||||
[
|
||||
path("k-psul/", KPsul),
|
||||
path("open", OpenRouter),
|
||||
]
|
||||
)
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
import json
|
||||
import math
|
||||
|
||||
from channels.channel import Group
|
||||
from channels.generic.websockets import JsonWebsocketConsumer
|
||||
from channels.generic.websocket import AsyncJsonWebsocketConsumer
|
||||
from django.core.cache import cache
|
||||
from django.core.serializers.json import DjangoJSONEncoder
|
||||
|
||||
|
@ -63,7 +62,7 @@ class CachedMixin:
|
|||
# Consumers
|
||||
|
||||
|
||||
class DjangoJsonWebsocketConsumer(JsonWebsocketConsumer):
|
||||
class DjangoJsonWebsocketConsumer(AsyncJsonWebsocketConsumer):
|
||||
"""Custom Json Websocket Consumer.
|
||||
|
||||
Encode to JSON with DjangoJSONEncoder.
|
||||
|
@ -71,7 +70,7 @@ class DjangoJsonWebsocketConsumer(JsonWebsocketConsumer):
|
|||
"""
|
||||
|
||||
@classmethod
|
||||
def encode_json(cls, content):
|
||||
async def encode_json(cls, content):
|
||||
return json.dumps(content, cls=DjangoJSONEncoder)
|
||||
|
||||
|
||||
|
@ -89,31 +88,35 @@ class PermConsumerMixin:
|
|||
http_user = True # Enable message.user
|
||||
perms_connect = []
|
||||
|
||||
def connect(self, message, **kwargs):
|
||||
async def connect(self):
|
||||
"""Check permissions on connection."""
|
||||
if message.user.has_perms(self.perms_connect):
|
||||
super().connect(message, **kwargs)
|
||||
self.user = self.scope["user"]
|
||||
|
||||
if self.user.has_perms(self.perms_connect):
|
||||
await super().connect()
|
||||
else:
|
||||
self.close()
|
||||
await self.close()
|
||||
|
||||
def raw_connect(self, message, **kwargs):
|
||||
# Same as original raw_connect method of JsonWebsocketConsumer
|
||||
# We add user to connection_groups call.
|
||||
groups = self.connection_groups(user=message.user, **kwargs)
|
||||
for group in groups:
|
||||
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
|
||||
# We add user to connection_groups call.
|
||||
groups = self.connection_groups(user=message.user, **kwargs)
|
||||
for group in groups:
|
||||
Group(group, channel_layer=message.channel_layer).discard(
|
||||
message.reply_channel
|
||||
)
|
||||
self.disconnect(message, **kwargs)
|
||||
|
||||
def connection_groups(self, user, **kwargs):
|
||||
"""`message.user` is available as `user` arg. Original behavior."""
|
||||
return super().connection_groups(user=user, **kwargs)
|
||||
# async def raw_connect(self, message, **kwargs):
|
||||
# # Same as original raw_connect method of JsonWebsocketConsumer
|
||||
# # We add user to connection_groups call.
|
||||
# groups = self.connection_groups(user=message.user, **kwargs)
|
||||
# for group in groups:
|
||||
# await self.channel_layer.group_add(group, message.reply_channel)
|
||||
# # Group(group, channel_layer=message.channel_layer).add(message.reply_channel)
|
||||
# self.connect(message, **kwargs)
|
||||
#
|
||||
# async def raw_disconnect(self, message, **kwargs):
|
||||
# # Same as original raw_connect method of JsonWebsocketConsumer
|
||||
# # We add user to connection_groups call.
|
||||
# groups = self.connection_groups(user=message.user, **kwargs)
|
||||
# for group in groups:
|
||||
# await self.channel_layer.group_discard(group, message.reply_channel)
|
||||
# # Group(group, channel_layer=message.channel_layer).discard(
|
||||
# # message.reply_channel
|
||||
# # )
|
||||
# self.disconnect(message, **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 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.contrib import messages
|
||||
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 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.autocomplete import kfet_account_only_autocomplete, kfet_autocomplete
|
||||
from kfet.config import kfet_config
|
||||
|
@ -1054,8 +1056,14 @@ def kpsul_update_addcost(request):
|
|||
|
||||
kfet_config.set(addcost_for=account, addcost_amount=amount)
|
||||
|
||||
data = {"addcost": {"for": account and account.trigramme or None, "amount": amount}}
|
||||
consumers.KPsul.group_send("kfet.kpsul", data)
|
||||
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)
|
||||
|
||||
|
||||
|
@ -1239,7 +1247,7 @@ def kpsul_perform_operations(request):
|
|||
)
|
||||
|
||||
# Websocket data
|
||||
websocket_data = {}
|
||||
websocket_data = {"type": "kpsul"}
|
||||
websocket_data["groups"] = [
|
||||
{
|
||||
"add": True,
|
||||
|
@ -1286,7 +1294,10 @@ def kpsul_perform_operations(request):
|
|||
websocket_data["articles"].append(
|
||||
{"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)
|
||||
|
||||
|
||||
|
@ -1481,7 +1492,7 @@ def cancel_operations(request):
|
|||
articles = Article.objects.values("id", "stock").filter(pk__in=articles_pk)
|
||||
|
||||
# Websocket data
|
||||
websocket_data = {"checkouts": [], "articles": []}
|
||||
websocket_data = {"checkouts": [], "articles": [], "type": "kpsul"}
|
||||
for checkout in checkouts:
|
||||
websocket_data["checkouts"].append(
|
||||
{"id": checkout["id"], "balance": checkout["balance"]}
|
||||
|
@ -1490,7 +1501,10 @@ def cancel_operations(request):
|
|||
websocket_data["articles"].append(
|
||||
{"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["opegroups_to_update"] = list(opegroups)
|
||||
|
|
|
@ -6,7 +6,7 @@ psycopg2<2.8
|
|||
# Redis
|
||||
django-redis-cache==2.1.*
|
||||
redis~=2.10.6
|
||||
asgi-redis==1.4.*
|
||||
channels-redis==2.4.*
|
||||
|
||||
# ASGI protocol and HTTP server
|
||||
asgiref~=1.1.2
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
Django==2.2.*
|
||||
Pillow==7.2.0
|
||||
authens==0.1b0
|
||||
channels==1.1.*
|
||||
channels==2.4.*
|
||||
configparser==3.5.0
|
||||
django-autocomplete-light==3.3.*
|
||||
django-bootstrap-form==3.3
|
||||
|
|
Loading…
Reference in a new issue