需求:用户购买了该产品的付费服务,当该服务即将到期时,发送通知给用户。
实现方案:
- 在付费服务系统中设计一个命令脚本,每天扫描所有用户,在服务到期前7天进行发送通知给用户
- 在社区服务系统中设计API,包含创建通知、获取通知、删除通知、更改通知
1. 数据库设计
CREATE TABLE `notifications` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`message` longtext NOT NULL,
`to_user` varchar(255) NOT NULL,
`seen` tinyint(1) NOT NULL,
`created_at` datetime(6) NOT NULL,
PRIMARY KEY (`id`),
KEY `notifications_sysusernotification_to_user_e0c9101e` (`to_user`),
KEY `notifications_sysusernotification_seen_9d851bf7` (`seen`),
KEY `notifications_sysusernotification_created_at_56ffd2a0` (`created_at`)
) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci;
- message:存储通知信息
- to_user:接收用户
- seen:是否已读
- created:创建时间
2. API设计
api/v2/user-notifications/:nid/seen/ #将当前用户的指定通知设为已读
api/v2/user-notifications/unseen/ #获取当前用户未读的通知
api/v2/admin/user-notifications/ #管理员给指定用户创建通知、获取所有全局通知
api/v2/admin/user-notifications/:nid/ #管理员删除指定通知
3. Model定义
class NotificationManager(models.Manager):
def create_sys_user_notificatioin(self, msg, user):
notification = self.create(
message = msg,
to_user = user,
)
return notification
def unseen_notes(self, user):
notes = self.filter(to_user=user, seen=0)
return notes
class Notification(models.Model):
message = models.TextField(null=False, blank=False)
to_user = models.CharField(max_length=255, db_index=True)
seen = models.BooleanField(default=False, db_index=True)
created_at = models.DateTimeField(auto_now_add=True, db_index=True)
objects = NotificationManager()
class Meta:
ordering = ["-created_at"]
def update_notification_to_seen(self):
self.seen = True
self.save()
def to_dict(self):
email = self.to_user
...
return {
'email': email,
....
}
4. 方法实现
- 管理员API
class AdminUserNotificationsView(APIView):
authentication_classes = (TokenAuthentication, SessionAuthentication)
permission_classes = (IsAdminUser,)
def get(self, request):
'''获取用户通知''''
try:
page = int(request.GET.get('page', 1))
per_page = int(request.GET.get('per_page', 25))
except Exception as e:
...
start, end = (page - 1) * per_page, page * per_page
try:
notifications = Notification.objects.all().order_by('-id')
except Exception as e:
...
return Response({
'notifications': [n.to_dict() for n in notifications[start: end]]
})
def post(self,request):
'''创建用户通知'''
msg = request.data.get('msg', '')
user = request.data.get('user', '')
# arguments check
....
# resource check
try:
User.objects.get(email=user)
except User.DoesNotExist:
...
try:
notification = Notification.objects.create(msg, user)
except Exception as e:
...
return Response({'notification': notification.to_dict()})
class NotificationView(APIView):
# power check
...
def delete(self, request, nid):
"""
删除指定用户通知
"""
# arguments check
...
# resource check
notification = Notification.objects.filter(id=nid).first()
if not notification:
...
try:
notification.delete()
except Exception as e:
...
return Response({'success': True})
- 用户API
class UserNotificationUnseenView(APIView):
# power check
.....
def get(self, request):
"""
获取当前用户未读通知
"""
user = request.user
notifications = Notification.objects.unseen_notes(user)
return Response({
'notifications': [n.to_dict() for n in notifications],
})
class UserNotificationSeenView(APIView):
# power check
...
def put(self, request, nid):
"""
将通知设为已读
"""
user = request.user.user
# arguments check
....
# resouce check
notification = Notification.objects.filter(id=nid).first()
if not notification:
...
if notification.to_user != user:
...
# set notification to seen
try:
notification.update_notification_to_seen()
except Exception as e:
...
return Response({'notification': notification.to_dict()})
5. 前端请求方案
当前端用户登录时,直接请求该接口获取是否有对应通知,即componentDidMount挂载
结语
*乾坤未定,你我皆是牛马!!! *