add message
This commit is contained in:
parent
82e98070f3
commit
235bdc73aa
|
@ -1,7 +1,7 @@
|
||||||
import uuid
|
import uuid
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.db.models import Q
|
||||||
|
|
||||||
# 权限等级
|
# 权限等级
|
||||||
|
|
||||||
|
@ -179,7 +179,7 @@ class Userprofile(models.Model):
|
||||||
ordering = ["-created"]
|
ordering = ["-created"]
|
||||||
|
|
||||||
def is_level1(self):
|
def is_level1(self):
|
||||||
return self.organization.level.level == 1
|
return self.organization.level.level == 1 or self.organization.level.level == 9
|
||||||
|
|
||||||
def is_level2(self):
|
def is_level2(self):
|
||||||
return self.organization.level.level == 2
|
return self.organization.level.level == 2
|
||||||
|
@ -190,7 +190,7 @@ class Userprofile(models.Model):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def level1_admin(cls):
|
def level1_admin(cls):
|
||||||
return Userprofile.objects.filter(organization__level__level=1)
|
return Userprofile.objects.filter(Q(organization__level__level=1) | Q(organization__level__level=9))
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
if self.is_level1:
|
if self.is_level1:
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
from django.apps import AppConfig
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
class PollsConfig(AppConfig):
|
class PollsConfig(AppConfig):
|
||||||
name = 'polls'
|
name = 'polls'
|
||||||
|
|
|
@ -216,3 +216,9 @@ class AppVersion(models.Model):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ["-version"]
|
ordering = ["-version"]
|
||||||
|
|
||||||
|
|
||||||
|
class SMSNotifyRecord(models.Model):
|
||||||
|
id = models.UUIDField('id', primary_key=True, default=uuid.uuid4)
|
||||||
|
phone = models.CharField('phone', max_length=32)
|
||||||
|
added = models.DateField(auto_now_add=True)
|
||||||
|
|
|
@ -1,16 +1,19 @@
|
||||||
.title {
|
.title {
|
||||||
line-height: 1.42857;
|
line-height: 1.42857;
|
||||||
}
|
}
|
||||||
|
|
||||||
.source {
|
.source {
|
||||||
color: rgba(0, 0, 0, 0.35)
|
color: rgba(0, 0, 0, 0.35);
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content p {
|
.content p {
|
||||||
text-indent: 2em;
|
line-height: 1.4;
|
||||||
line-height: 1.4;
|
}
|
||||||
}
|
|
||||||
|
.content img {
|
||||||
|
max-width: 320px !important;
|
||||||
|
}
|
||||||
|
|
|
@ -1,19 +1,24 @@
|
||||||
from background_task import background
|
from background_task import background
|
||||||
from channels.layers import get_channel_layer
|
from datetime import date, datetime, timedelta
|
||||||
from asgiref.sync import async_to_sync
|
|
||||||
from polls.models import Message
|
from polls.models import Notice, SMSNotifyRecord
|
||||||
|
from polls.utils import sent_sms_notify
|
||||||
|
|
||||||
|
|
||||||
@background(schedule=1)
|
@background(remove_existing_tasks=True)
|
||||||
def process_task(task, groups, user_id):
|
def process_notify_task():
|
||||||
print(groups)
|
notices = Notice.objects.filter(is_read=False)
|
||||||
for g in groups:
|
for n in notices:
|
||||||
print(g)
|
two_hours_later = n.added + timedelta(minutes=2)
|
||||||
# async_to_sync(channel_layer.group_send)(g['id'], {
|
now = datetime.now()
|
||||||
# "type": 0,
|
if two_hours_later < now:
|
||||||
# "send_from": user_id,
|
phone = n.user.username
|
||||||
# "group_id": g['id'],
|
today = now.date()
|
||||||
# "content": task['content']
|
hour = now.hour
|
||||||
# })
|
exists = SMSNotifyRecord.objects.filter(phone=phone, added=today).exists()
|
||||||
channel_layer = get_channel_layer()
|
if exists: return
|
||||||
async_to_sync(channel_layer.send)('test_channel', {'type': g['id']})
|
if hour < 8 or hour > 17: return
|
||||||
|
print('============',phone, n.type)
|
||||||
|
SMSNotifyRecord.objects.create(phone=phone)
|
||||||
|
sent_sms_notify(phone, n.type)
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from django.urls import path
|
from django.urls import path
|
||||||
|
|
||||||
from . import views
|
from . import views
|
||||||
|
from . import tasks
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('', views.index, name='index'),
|
path('', views.index, name='index'),
|
||||||
path('status_500', views.status_500, name='status_500'),
|
path('status_500', views.status_500, name='status_500'),
|
||||||
|
@ -74,3 +74,5 @@ urlpatterns = [
|
||||||
path('app/download/', views.download, name='polls_app_download'),
|
path('app/download/', views.download, name='polls_app_download'),
|
||||||
path('app/has/update/', views.has_update, name='polls_app_has_update')
|
path('app/has/update/', views.has_update, name='polls_app_has_update')
|
||||||
]
|
]
|
||||||
|
|
||||||
|
tasks.process_notify_task(repeat=5)
|
|
@ -1,31 +1,28 @@
|
||||||
from aliyunsdkcore.client import AcsClient
|
|
||||||
from aliyunsdkcore.request import CommonRequest
|
|
||||||
import requests
|
import requests
|
||||||
import random
|
import random
|
||||||
from parsel import Selector
|
from parsel import Selector
|
||||||
from channels.db import database_sync_to_async
|
from channels.db import database_sync_to_async
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
|
from yunpian_python_sdk.model import constant as YC
|
||||||
|
from yunpian_python_sdk.ypclient import YunpianClient
|
||||||
|
|
||||||
|
|
||||||
def sent_sms_code(phone, code):
|
def sent_sms_code(phone, code):
|
||||||
client = AcsClient(settings.SMS_ACCESS_KEY_ID,
|
clnt = YunpianClient('304eb08353f7ebf00596737acfc31f53')
|
||||||
settings.SMS_ACCESS_KEY_SECRET, settings.SMS_REGION)
|
param = {YC.MOBILE: phone ,YC.TEXT:'【甘肃大未来科技】您的验证码是%s。如非本人操作,请忽略本短信' %(code,)}
|
||||||
request = CommonRequest()
|
r = clnt.sms().single_send(param)
|
||||||
request.set_accept_format('json')
|
return r
|
||||||
request.set_domain('dysmsapi.aliyuncs.com')
|
|
||||||
request.set_method('POST')
|
|
||||||
request.set_protocol_type('https') # https | http
|
|
||||||
request.set_version('2017-05-25')
|
|
||||||
request.set_action_name('SendSms')
|
|
||||||
|
|
||||||
request.add_query_param('RegionId', "cn-hangzhou")
|
|
||||||
request.add_query_param('PhoneNumbers', phone)
|
def sent_sms_notify(phone, type):
|
||||||
request.add_query_param('SignName', "短信验证")
|
clnt = YunpianClient('304eb08353f7ebf00596737acfc31f53')
|
||||||
request.add_query_param('TemplateCode', "SMS_12330409")
|
if type == 0:
|
||||||
request.add_query_param('TemplateParam', '{"number":"%s"}' % (code,))
|
param = {YC.MOBILE: phone ,YC.TEXT:'【甘肃大未来科技】政务新媒体管理APP有新消息,请及时登录处理。(若其他管理员已处理,请忽略)'}
|
||||||
response = client.do_action(request)
|
else:
|
||||||
return response
|
param = {YC.MOBILE: phone ,YC.TEXT:'【甘肃大未来科技】政务新媒体管理APP有新任务,请及时登录处理。'}
|
||||||
|
r = clnt.sms().single_send(param)
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
def generate_code():
|
def generate_code():
|
||||||
|
@ -109,14 +106,15 @@ def queryset_to_list(q, fields):
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
# sent_sms_code('13993199566')
|
r = sent_sms_code('13993199566', 4321)
|
||||||
|
print(r.code(), type(r.code()))
|
||||||
# og_title, og_description, og_url, og_image = parse(
|
# og_title, og_description, og_url, og_image = parse(
|
||||||
# 'https://mp.weixin.qq.com/s/EhX0Pm1e0FAfse0zz9ow8Q')
|
# 'https://mp.weixin.qq.com/s/EhX0Pm1e0FAfse0zz9ow8Q')
|
||||||
# og_title, og_description, og_url, og_image = parse(
|
# og_title, og_description, og_url, og_image = parse(
|
||||||
# 'https://m.toutiao.com/i6883651337003729420/?tt_from=weixin&utm_campaign=client_share&app=news_article&utm_source=weixin&iid=1494959660475024&utm_medium=toutiao_android&wxshare_count=1')
|
# 'https://m.toutiao.com/i6883651337003729420/?tt_from=weixin&utm_campaign=client_share&app=news_article&utm_source=weixin&iid=1494959660475024&utm_medium=toutiao_android&wxshare_count=1')
|
||||||
# og_title, og_description, og_url, og_image = parse(
|
# og_title, og_description, og_url, og_image = parse(
|
||||||
# 'http://www.gov.cn/xinwen/2020-10/13/content_5550906.htm')
|
# 'http://www.gov.cn/xinwen/2020-10/13/content_5550906.htm')
|
||||||
og_title, og_description, og_url, og_image = parse(
|
# og_title, og_description, og_url, og_image = parse(
|
||||||
'http://xgs.gansudaily.com.cn/pages/h5/hot/b3297046a53e47f594ed19db90c1183c.html')
|
# 'http://xgs.gansudaily.com.cn/pages/h5/hot/b3297046a53e47f594ed19db90c1183c.html')
|
||||||
|
|
||||||
print(og_title, og_description, og_url, og_image)
|
# print(og_title, og_description, og_url, og_image)
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -54,7 +54,8 @@ def pick_groups(request):
|
||||||
return HttpResponse(status=405)
|
return HttpResponse(status=405)
|
||||||
user_id = request.user.id
|
user_id = request.user.id
|
||||||
category = request.GET.get('category')
|
category = request.GET.get('category')
|
||||||
q = Group.objects.filter(status=1, group_admin__user__id=user_id).distinct()
|
q = Group.objects.filter(
|
||||||
|
status=1, group_admin__user__id=user_id).distinct()
|
||||||
groups = q.filter(classify=category) if category else q
|
groups = q.filter(classify=category) if category else q
|
||||||
results = []
|
results = []
|
||||||
for o in groups:
|
for o in groups:
|
||||||
|
@ -66,6 +67,7 @@ def pick_groups(request):
|
||||||
results.append(result)
|
results.append(result)
|
||||||
return JsonResponse({'status': 'success', 'message': results}, safe=False)
|
return JsonResponse({'status': 'success', 'message': results}, safe=False)
|
||||||
|
|
||||||
|
|
||||||
@csrf_exempt
|
@csrf_exempt
|
||||||
@polls_login_required
|
@polls_login_required
|
||||||
def group_manager(request):
|
def group_manager(request):
|
||||||
|
@ -74,12 +76,18 @@ def group_manager(request):
|
||||||
group_id = request.GET.get('group_id')
|
group_id = request.GET.get('group_id')
|
||||||
if not group_id:
|
if not group_id:
|
||||||
return JsonResponse({'status': 'error', 'message': '参数错误'})
|
return JsonResponse({'status': 'error', 'message': '参数错误'})
|
||||||
managers = Userprofile.objects.filter(user__group_admin__group_id=group_id).order_by('user__group_admin__created')
|
group = Group.objects.get(id=group_id)
|
||||||
|
q = Userprofile.objects.filter(user__group_admin__group_id=group_id)
|
||||||
|
if group.classify != '3':
|
||||||
|
q = q.exclude(Q(organization__level__level=1) |
|
||||||
|
Q(organization__level__level=9))
|
||||||
|
q = q.order_by('user__group_admin__created')
|
||||||
results = []
|
results = []
|
||||||
for m in managers:
|
for m in q:
|
||||||
result = dict()
|
result = dict()
|
||||||
result['id'] = m.user.id
|
result['id'] = m.user.id
|
||||||
result['name'] = m.name
|
result['name'] = m.name
|
||||||
|
result['status'] = m.status
|
||||||
result['thumbnail'] = request.build_absolute_uri(
|
result['thumbnail'] = request.build_absolute_uri(
|
||||||
m.image.url) if m.image else None
|
m.image.url) if m.image else None
|
||||||
result['phone'] = m.user.username
|
result['phone'] = m.user.username
|
||||||
|
@ -102,6 +110,7 @@ def group_member(request):
|
||||||
result = dict()
|
result = dict()
|
||||||
result['id'] = m.user.id
|
result['id'] = m.user.id
|
||||||
result['name'] = m.name
|
result['name'] = m.name
|
||||||
|
result['status'] = m.status
|
||||||
result['thumbnail'] = request.build_absolute_uri(
|
result['thumbnail'] = request.build_absolute_uri(
|
||||||
m.image.url) if m.image else None
|
m.image.url) if m.image else None
|
||||||
result['phone'] = m.user.username
|
result['phone'] = m.user.username
|
||||||
|
@ -119,7 +128,8 @@ def group_enter(request):
|
||||||
group_id = request.POST.get('group_id')
|
group_id = request.POST.get('group_id')
|
||||||
if not group_id:
|
if not group_id:
|
||||||
return JsonResponse({'status': 'error', 'message': '参数错误'})
|
return JsonResponse({'status': 'error', 'message': '参数错误'})
|
||||||
obj,created = GroupRecord.objects.get_or_create(user=user, group_id=group_id)
|
obj, created = GroupRecord.objects.get_or_create(
|
||||||
|
user=user, group_id=group_id)
|
||||||
return JsonResponse({'status': 'success'})
|
return JsonResponse({'status': 'success'})
|
||||||
|
|
||||||
|
|
||||||
|
@ -132,8 +142,9 @@ def group_leave(request):
|
||||||
group_id = request.POST.get('group_id')
|
group_id = request.POST.get('group_id')
|
||||||
if not group_id:
|
if not group_id:
|
||||||
return JsonResponse({'status': 'error', 'message': '参数错误'})
|
return JsonResponse({'status': 'error', 'message': '参数错误'})
|
||||||
obj,created = GroupRecord.objects.get_or_create(user=user, group_id=group_id)
|
obj, created = GroupRecord.objects.get_or_create(
|
||||||
|
user=user, group_id=group_id)
|
||||||
if not created:
|
if not created:
|
||||||
obj.leave_at = datetime.now()
|
obj.leave_at = datetime.now()
|
||||||
obj.save()
|
obj.save()
|
||||||
return JsonResponse({'status': 'success'})
|
return JsonResponse({'status': 'success'})
|
||||||
|
|
|
@ -54,7 +54,7 @@ def create_media(request):
|
||||||
attention = request.POST.get('attention', '')
|
attention = request.POST.get('attention', '')
|
||||||
remark = request.POST.get('remark', '')
|
remark = request.POST.get('remark', '')
|
||||||
model_name = ''
|
model_name = ''
|
||||||
status = 2 if o.directly == '省直部门' else 1
|
status = 2 if o.is_direct() else 1
|
||||||
|
|
||||||
if category == 'weixin':
|
if category == 'weixin':
|
||||||
model_name = 'Weixin'
|
model_name = 'Weixin'
|
||||||
|
@ -78,7 +78,7 @@ def create_media(request):
|
||||||
instance = Qita(code=code, qitaid=media_id, alias=alias,
|
instance = Qita(code=code, qitaid=media_id, alias=alias,
|
||||||
image=f, status=status, organization=o, attention=attention, remark=remark)
|
image=f, status=status, organization=o, attention=attention, remark=remark)
|
||||||
instance.save()
|
instance.save()
|
||||||
if o.directly == '省直部门':
|
if o.is_direct():
|
||||||
admins = Userprofile.level1_admin()
|
admins = Userprofile.level1_admin()
|
||||||
for a in admins:
|
for a in admins:
|
||||||
content = '%s创建了新媒体,请审核' % (profile,)
|
content = '%s创建了新媒体,请审核' % (profile,)
|
||||||
|
@ -224,7 +224,6 @@ def delete_media(request):
|
||||||
model_name = 'Qita'
|
model_name = 'Qita'
|
||||||
instance = Qita.objects.get(pk=media_id)
|
instance = Qita.objects.get(pk=media_id)
|
||||||
result['media_id'] = instance.qitaid
|
result['media_id'] = instance.qitaid
|
||||||
|
|
||||||
if o.is_direct():
|
if o.is_direct():
|
||||||
instance.status = 5
|
instance.status = 5
|
||||||
instance.save()
|
instance.save()
|
||||||
|
|
|
@ -79,6 +79,7 @@ def detail_notice(request, notice_id):
|
||||||
results['id'] = notice.id
|
results['id'] = notice.id
|
||||||
results['category'] = notice.type
|
results['category'] = notice.type
|
||||||
results['content'] = notice.content
|
results['content'] = notice.content
|
||||||
|
results['isRead'] = notice.is_read
|
||||||
if notice.type == 1:
|
if notice.type == 1:
|
||||||
ReplyModel = apps.get_model(notice.app, notice.model)
|
ReplyModel = apps.get_model(notice.app, notice.model)
|
||||||
if notice.model == 'Userprofile':
|
if notice.model == 'Userprofile':
|
||||||
|
@ -144,6 +145,10 @@ def pass_notice(request):
|
||||||
if p.admin_status == 4:
|
if p.admin_status == 4:
|
||||||
p.admin_status = 5
|
p.admin_status = 5
|
||||||
p.save()
|
p.save()
|
||||||
|
group_notices = Notice.objects.filter(record_id=notice.record_id)
|
||||||
|
for n in group_notices:
|
||||||
|
n.is_read = True
|
||||||
|
n.save()
|
||||||
admins = Userprofile.level1_admin()
|
admins = Userprofile.level1_admin()
|
||||||
for a in admins:
|
for a in admins:
|
||||||
Notice.create_reply_notice(
|
Notice.create_reply_notice(
|
||||||
|
@ -156,6 +161,10 @@ def pass_notice(request):
|
||||||
if p.admin_status == 2:
|
if p.admin_status == 2:
|
||||||
p.admin_status = 3
|
p.admin_status = 3
|
||||||
p.save()
|
p.save()
|
||||||
|
group_notices = Notice.objects.filter(record_id=notice.record_id)
|
||||||
|
for n in group_notices:
|
||||||
|
n.is_read = True
|
||||||
|
n.save()
|
||||||
return JsonResponse({'status': 'success', 'message': '申请已同意'})
|
return JsonResponse({'status': 'success', 'message': '申请已同意'})
|
||||||
else:
|
else:
|
||||||
m = ReplyModel.objects.get(pk=notice.record_id)
|
m = ReplyModel.objects.get(pk=notice.record_id)
|
||||||
|
@ -163,6 +172,10 @@ def pass_notice(request):
|
||||||
m.save(update_fields=[notice.field])
|
m.save(update_fields=[notice.field])
|
||||||
notice.is_read = True
|
notice.is_read = True
|
||||||
notice.save()
|
notice.save()
|
||||||
|
group_notices = Notice.objects.filter(record_id=notice.record_id)
|
||||||
|
for n in group_notices:
|
||||||
|
n.is_read = True
|
||||||
|
n.save()
|
||||||
pass_value = notice.record_pass_value
|
pass_value = notice.record_pass_value
|
||||||
if pass_value == '2':
|
if pass_value == '2':
|
||||||
admins = Userprofile.level1_admin()
|
admins = Userprofile.level1_admin()
|
||||||
|
@ -202,6 +215,11 @@ def reject_notice(request):
|
||||||
if p.admin_status == 4 or p.admin_status == 5:
|
if p.admin_status == 4 or p.admin_status == 5:
|
||||||
p.admin_status = 3
|
p.admin_status = 3
|
||||||
p.save()
|
p.save()
|
||||||
|
group_notices = Notice.objects.filter(record_id=notice.record_id)
|
||||||
|
for n in group_notices:
|
||||||
|
n.is_read = True
|
||||||
|
n.save()
|
||||||
|
|
||||||
return JsonResponse({'status': 'success', 'message': '申请已拒绝'})
|
return JsonResponse({'status': 'success', 'message': '申请已拒绝'})
|
||||||
else:
|
else:
|
||||||
m = ReplyModel.objects.get(pk=notice.record_id)
|
m = ReplyModel.objects.get(pk=notice.record_id)
|
||||||
|
@ -209,6 +227,10 @@ def reject_notice(request):
|
||||||
m.save(update_fields=[notice.field])
|
m.save(update_fields=[notice.field])
|
||||||
notice.is_read = True
|
notice.is_read = True
|
||||||
notice.save()
|
notice.save()
|
||||||
|
group_notices = Notice.objects.filter(record_id=notice.record_id)
|
||||||
|
for n in group_notices:
|
||||||
|
n.is_read = True
|
||||||
|
n.save()
|
||||||
return JsonResponse({'status': 'success', 'message': '申请已拒绝'})
|
return JsonResponse({'status': 'success', 'message': '申请已拒绝'})
|
||||||
except ObjectDoesNotExist:
|
except ObjectDoesNotExist:
|
||||||
return JsonResponse({'status': 'error', 'message': '通知ID错误'})
|
return JsonResponse({'status': 'error', 'message': '通知ID错误'})
|
||||||
|
|
|
@ -2,12 +2,9 @@ from django.shortcuts import render
|
||||||
from django.http import HttpResponse, JsonResponse
|
from django.http import HttpResponse, JsonResponse
|
||||||
from django.views.decorators.csrf import csrf_exempt
|
from django.views.decorators.csrf import csrf_exempt
|
||||||
import datetime
|
import datetime
|
||||||
from channels.layers import get_channel_layer
|
|
||||||
from asgiref.sync import async_to_sync
|
|
||||||
|
|
||||||
from polls.decorators import polls_login_required
|
from polls.decorators import polls_login_required
|
||||||
from polls.models import Message, Notice, Task, TaskAddition
|
from polls.models import Message, Notice, Task, TaskAddition
|
||||||
from polls.tasks import process_task
|
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
from polls.utils import model_to_dict, queryset_to_list, parse
|
from polls.utils import model_to_dict, queryset_to_list, parse
|
||||||
from dashboard.models import Group, Group_user, Userprofile
|
from dashboard.models import Group, Group_user, Userprofile
|
||||||
|
|
|
@ -84,13 +84,13 @@ def send_code(request):
|
||||||
now = datetime.datetime.now()
|
now = datetime.datetime.now()
|
||||||
after_1min = now + datetime.timedelta(minutes=1)
|
after_1min = now + datetime.timedelta(minutes=1)
|
||||||
response = sent_sms_code(phone, code)
|
response = sent_sms_code(phone, code)
|
||||||
result = response.decode('utf8')
|
result = response.code()
|
||||||
print(phone, result)
|
print(phone, result)
|
||||||
if "OK" in result:
|
if result == 0:
|
||||||
VerifyCode.objects.create(
|
VerifyCode.objects.create(
|
||||||
code=code, phone=phone, category=category, timeouted=after_1min)
|
code=code, phone=phone, category=category, timeouted=after_1min)
|
||||||
return JsonResponse({'status': 'success'})
|
return JsonResponse({'status': 'success'})
|
||||||
return JsonResponse({'status': 'error', 'message': '验证码发送失败'})
|
return JsonResponse({'status': 'error', 'message': response.msg()})
|
||||||
|
|
||||||
|
|
||||||
@csrf_exempt
|
@csrf_exempt
|
||||||
|
|
Loading…
Reference in New Issue