Skip to content
This repository has been archived by the owner on Oct 1, 2020. It is now read-only.

Commit

Permalink
scheduled sms dashboard
Browse files Browse the repository at this point in the history
 - staff users can no view queued messages
 - messages can be cancelled
 - closes #29
  • Loading branch information
monty5811 committed Apr 26, 2016
1 parent 0929ca5 commit a13de5f
Show file tree
Hide file tree
Showing 21 changed files with 335 additions and 32,589 deletions.
52 changes: 52 additions & 0 deletions api/serializers.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import ast

from django.contrib.auth.models import User
from rest_framework import serializers
from django_q.models import Schedule

from apostello.models import (
Keyword, Recipient, RecipientGroup, SmsInbound, SmsOutbound, UserProfile
Expand Down Expand Up @@ -162,3 +165,52 @@ class Meta:
'can_import',
'can_archive',
)


class QScheduleSerializer(serializers.ModelSerializer):

next_run = serializers.DateTimeField()
message_body = serializers.SerializerMethodField()
recipient = serializers.SerializerMethodField()
recipient_group = serializers.SerializerMethodField()
queued_by = serializers.SerializerMethodField()

@staticmethod
def _split_args(sched_args):
"""Convert the schedule's args value to tuple."""
return ast.literal_eval(sched_args)

def get_message_body(self, obj):
return self._split_args(obj.args)[1]

def get_recipient(self, obj):
pk = self._split_args(obj.args)[0]
if pk is not None:
grp = Recipient.objects.get(pk=pk)
serializer = RecipientSerializer(grp)
return serializer.data
else:
return {'url': '#', 'full_name': 'n/a'}

def get_recipient_group(self, obj):
grp_name = self._split_args(obj.args)[2]
if grp_name is not None:
grp = RecipientGroup.objects.get(name=grp_name)
serializer = RecipientGroupSerializer(grp)
return serializer.data
else:
return {'url': '#', 'name': 'n/a'}

def get_queued_by(self, obj):
return self._split_args(obj.args)[3]

class Meta:
model = Schedule
fields = (
'pk',
'message_body',
'recipient',
'recipient_group',
'queued_by',
'next_run',
)
107 changes: 59 additions & 48 deletions api/urls.py
Original file line number Diff line number Diff line change
@@ -1,79 +1,69 @@
from django.conf.urls import url
from django_q.models import Schedule
from rest_framework.permissions import IsAuthenticated

from api import serializers as s
from api import views as v
from api.drf_permissions import (
CanSeeContactNames, CanSeeGroups, CanSeeIncoming, CanSeeKeyword,
CanSeeKeywords, CanSeeOutgoing, CanImport, IsStaff
)
from api.serializers import (
ElvantoGroupSerializer,
KeywordSerializer,
RecipientGroupSerializer,
RecipientSerializer,
SmsInboundSerializer,
SmsOutboundSerializer,
UserProfileSerializer,
)
from api.views import (
ApiCollection, ApiCollectionAllWall, ApiCollectionKeywordSms,
ApiCollectionRecentSms, ApiMember, ElvantoFetchButton, ElvantoPullButton
CanImport, CanSeeContactNames, CanSeeGroups, CanSeeIncoming, CanSeeKeyword,
CanSeeKeywords, CanSeeOutgoing, IsStaff
)
from apostello.models import (
Keyword, Recipient, RecipientGroup, SmsInbound, SmsOutbound, UserProfile
)
from elvanto.models import ElvantoGroup
from rest_framework.permissions import IsAuthenticated

# api
urlpatterns = [
# user profiles
url(
r'^v1/users/profiles/$',
ApiCollection.as_view(
v.ApiCollection.as_view(
model_class=UserProfile,
serializer_class=UserProfileSerializer,
serializer_class=s.UserProfileSerializer,
permission_classes=(IsAuthenticated, IsStaff),
),
name='user_profiles'
),
url(
r'^v1/users/profiles/(?P<pk>[0-9]+)$',
ApiMember.as_view(
v.ApiMember.as_view(
model_class=UserProfile,
serializer_class=UserProfileSerializer,
serializer_class=s.UserProfileSerializer,
permission_classes=(IsAuthenticated, IsStaff),
),
name='user_profiles_member'
),
# sms views
url(
r'^v1/sms/in/$',
ApiCollection.as_view(
v.ApiCollection.as_view(
model_class=SmsInbound,
serializer_class=SmsInboundSerializer,
serializer_class=s.SmsInboundSerializer,
permission_classes=(IsAuthenticated, CanSeeIncoming)
),
name='in_log'
),
url(
r'^v1/sms/out/$',
ApiCollection.as_view(
v.ApiCollection.as_view(
model_class=SmsOutbound,
serializer_class=SmsOutboundSerializer,
serializer_class=s.SmsOutboundSerializer,
permission_classes=(IsAuthenticated, CanSeeOutgoing),
related_field='recipient',
),
name='out_log'
),
url(
r'^v1/sms/live_wall/all/$',
ApiCollectionAllWall.as_view(
v.ApiCollectionAllWall.as_view(
permission_classes=(IsAuthenticated, CanSeeIncoming)
),
name='live_wall_all'
),
url(
r'^v1/sms/in/recpient/(?P<pk>\d+)/$',
ApiCollectionRecentSms.as_view(
v.ApiCollectionRecentSms.as_view(
permission_classes=(
IsAuthenticated, CanSeeContactNames, CanSeeIncoming
)
Expand All @@ -82,7 +72,7 @@
),
url(
r'^v1/sms/in/keyword/(?P<pk>\d+)/$',
ApiCollectionKeywordSms.as_view(
v.ApiCollectionKeywordSms.as_view(
permission_classes=(
IsAuthenticated, CanSeeKeywords, CanSeeKeyword, CanSeeIncoming
),
Expand All @@ -92,7 +82,7 @@
),
url(
r'^v1/sms/in/keyword/(?P<pk>\d+)/archive/$',
ApiCollectionKeywordSms.as_view(
v.ApiCollectionKeywordSms.as_view(
permission_classes=(
IsAuthenticated, CanSeeKeywords, CanSeeKeyword, CanSeeIncoming
),
Expand All @@ -102,19 +92,19 @@
),
url(
r'^v1/sms/in/(?P<pk>[0-9]+)$',
ApiMember.as_view(
v.ApiMember.as_view(
model_class=SmsInbound,
serializer_class=SmsInboundSerializer,
serializer_class=s.SmsInboundSerializer,
permission_classes=(IsAuthenticated, CanSeeIncoming),
),
name='sms_in_member'
),
# recipient views
url(
r'^v1/recipients/$',
ApiCollection.as_view(
v.ApiCollection.as_view(
model_class=Recipient,
serializer_class=RecipientSerializer,
serializer_class=s.RecipientSerializer,
filter_list=True,
filters={'is_archived': False},
permission_classes=(IsAuthenticated, CanSeeContactNames)
Expand All @@ -123,19 +113,19 @@
),
url(
r'^v1/recipients/(?P<pk>[0-9]+)$',
ApiMember.as_view(
v.ApiMember.as_view(
model_class=Recipient,
serializer_class=RecipientSerializer,
serializer_class=s.RecipientSerializer,
permission_classes=(IsAuthenticated, CanSeeContactNames)
),
name='recipient'
),
# group views
url(
r'^v1/groups/$',
ApiCollection.as_view(
v.ApiCollection.as_view(
model_class=RecipientGroup,
serializer_class=RecipientGroupSerializer,
serializer_class=s.RecipientGroupSerializer,
filter_list=True,
filters={'is_archived': False},
permission_classes=(IsAuthenticated, CanSeeGroups)
Expand All @@ -144,49 +134,49 @@
),
url(
r'^v1/groups/(?P<pk>[0-9]+)$',
ApiMember.as_view(
v.ApiMember.as_view(
model_class=RecipientGroup,
serializer_class=RecipientGroupSerializer,
serializer_class=s.RecipientGroupSerializer,
permission_classes=(IsAuthenticated, CanSeeGroups)
),
name='group'
),
# Elvanto groups
url(
r'^v1/elvanto/groups/$',
ApiCollection.as_view(
v.ApiCollection.as_view(
model_class=ElvantoGroup,
serializer_class=ElvantoGroupSerializer,
serializer_class=s.ElvantoGroupSerializer,
permission_classes=(IsAuthenticated, CanSeeGroups, CanImport)
),
name='elvanto_groups'
),
url(
r'^v1/elvanto/group/(?P<pk>[0-9]+)$',
ApiMember.as_view(
v.ApiMember.as_view(
model_class=ElvantoGroup,
serializer_class=ElvantoGroupSerializer,
serializer_class=s.ElvantoGroupSerializer,
permission_classes=(IsAuthenticated, CanSeeGroups, CanImport)
),
name='elvanto_group'
),
# Elvanto group buttons
url(
r'^v1/elvanto/group_fetch/$',
ElvantoFetchButton.as_view(),
v.ElvantoFetchButton.as_view(),
name='fetch_elvanto_groups'
),
url(
r'^v1/elvanto/group_pull/$',
ElvantoPullButton.as_view(),
v.ElvantoPullButton.as_view(),
name='pull_elvanto_groups'
),
# keyword views
url(
r'^v1/keywords/$',
ApiCollection.as_view(
v.ApiCollection.as_view(
model_class=Keyword,
serializer_class=KeywordSerializer,
serializer_class=s.KeywordSerializer,
filter_list=True,
filters={'is_archived': False},
permission_classes=(IsAuthenticated, CanSeeKeywords)
Expand All @@ -195,11 +185,32 @@
),
url(
r'^v1/keywords/(?P<pk>[0-9]+)$',
ApiMember.as_view(
v.ApiMember.as_view(
model_class=Keyword,
serializer_class=KeywordSerializer,
serializer_class=s.KeywordSerializer,
permission_classes=(IsAuthenticated, CanSeeKeyword)
),
name='keyword'
),
# scheduled task views
url(
r'^v1/q/scheduled/sms/$',
v.ApiCollection.as_view(
model_class=Schedule,
serializer_class=s.QScheduleSerializer,
filter_list=True,
filters={'func__contains': 'send'},
permission_classes=(IsAuthenticated, IsStaff)
),
name='q_schedules'
),
url(
r'^v1/q/scheduled/sms/(?P<pk>[0-9]+)$',
v.ApiMember.as_view(
model_class=Schedule,
serializer_class=s.QScheduleSerializer,
permission_classes=(IsAuthenticated, IsStaff)
),
name='q_schedule'
),
]
6 changes: 6 additions & 0 deletions api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,12 @@ def post(self, request, format=None, **kwargs):
setattr(obj, x, user_profile[x])
obj.save()

cancel_task = request.data.get('cancel_task')
if cancel_task is not None:
r = Response({'pk': obj.pk}, status=status.HTTP_200_OK)
obj.delete()
return r

serializer = self.serializer_class(obj)
return Response(serializer.data)

Expand Down
18 changes: 18 additions & 0 deletions apostello/assets/js/components/cancel_button.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React, { Component } from 'react';

class CancelButton extends Component {
constructor() {
super();
this._onClick = this._onClick.bind(this);
}
_onClick() {
this.props.cancelFn(this.props.item);
}
render() {
return (
<a className="ui tiny grey button" onClick={this._onClick}>Cancel</a>
);
}
}

export default CancelButton;

0 comments on commit a13de5f

Please sign in to comment.