Coverage for /opt/conda/envs/apienv/lib/python3.10/site-packages/daiquiri/core/components/chat.py: 92%

75 statements  

« prev     ^ index     » next       coverage.py v7.6.5, created at 2024-11-15 02:12 +0000

1#!/usr/bin/env python 

2# -*- coding: utf-8 -*- 

3import time 

4import logging 

5 

6from marshmallow import Schema, fields 

7from flask import g 

8 

9from daiquiri.core import marshal 

10from daiquiri.core.components import Component, ComponentResource 

11from daiquiri.core.schema import ErrorSchema, MessageSchema 

12from daiquiri.core.schema.metadata import paginated 

13 

14logger = logging.getLogger(__name__) 

15 

16 

17class NewChatSchema(Schema): 

18 """New Chat Message Schema""" 

19 

20 message = fields.Str(required=True, metadata={"description": "The message"}) 

21 

22 

23class ChatSchema(NewChatSchema): 

24 """Chat Message Schema""" 

25 

26 messageid = fields.Int(metadata={"description": "Unique id of the message"}) 

27 timestamp = fields.Int(metadata={"description": "Epoch timestamp message was sent"}) 

28 sessionid = fields.Str(metadata={"description": "Author sessionid"}) 

29 user = fields.Str(metadata={"description": "User name associated with sessionid"}) 

30 read = fields.List( 

31 fields.Str(), 

32 metadata={"description": "List of sessions that have read the message"}, 

33 ) 

34 

35 

36class AllMessagesReadSchema(Schema): 

37 """All messages read schema""" 

38 

39 maxid = fields.Int(metadata={"description": "Maximum chat messageid"}) 

40 

41 

42class ChatResource(ComponentResource): 

43 @marshal( 

44 inp={"limit": fields.Int(), "offset": fields.Int()}, 

45 out=[[200, paginated(ChatSchema), "List of chat messages"]], 

46 ) 

47 def get(self, **kwargs): 

48 """Get the last n chat messages""" 

49 return self._parent.get_messages(**kwargs) 

50 

51 @marshal( 

52 inp=ChatSchema, 

53 out=[ 

54 [200, ChatSchema(), "Sent message"], 

55 [400, ErrorSchema(), "Could not send messsage"], 

56 ], 

57 ) 

58 def post(self, **kwargs): 

59 """Add a new chat message""" 

60 message = self._parent.add_message(**kwargs) 

61 if message: 

62 return message 

63 

64 return {"error": "Could not send message"}, 400 

65 

66 @marshal( 

67 out=[ 

68 [200, AllMessagesReadSchema(), "All messages marked as read"], 

69 [400, ErrorSchema(), "Could not mark all messsages read"], 

70 ], 

71 ) 

72 def patch(self, **kwargs): 

73 """Mark all chat message as read""" 

74 maxid = self._parent.mark_all(**kwargs) 

75 if maxid is not None: 

76 return {"maxid": maxid} 

77 

78 return {"error": "Could not mark all messages read"}, 400 

79 

80 

81class ChatMessageResource(ComponentResource): 

82 @marshal( 

83 out=[ 

84 [200, MessageSchema(), "Message marked as read"], 

85 [400, ErrorSchema(), "Could not mark messsage read"], 

86 ], 

87 ) 

88 def patch(self, messageid, **kwargs): 

89 """Mark a chat message as read""" 

90 read = self._parent.mark_message(messageid, **kwargs) 

91 if read: 

92 return {"message": "Message marked as read"} 

93 

94 return {"error": "Could not mark message read"}, 400 

95 

96 

97class Chat(Component): 

98 """Chat Component 

99 

100 A simple chat component 

101 """ 

102 

103 _require_blsession = False 

104 

105 _messageid = 0 

106 _messages = [] 

107 

108 def setup(self, *args, **kwargs): 

109 self.register_route(ChatResource, "") 

110 self.register_route(ChatMessageResource, "/<int:messageid>") 

111 

112 def add_message(self, **kwargs): 

113 """Add a new message""" 

114 self._messageid += 1 

115 message = { 

116 "messageid": self._messageid, 

117 "timestamp": time.time(), 

118 "sessionid": g.sessionid, 

119 "user": g.user.get("fullname"), 

120 "message": kwargs["message"], 

121 "read": [g.sessionid], 

122 } 

123 

124 self._messages.append(message) 

125 self.emit("new_message", message) 

126 

127 return message 

128 

129 def get_messages(self, **kwargs): 

130 """Get all messages""" 

131 limit = kwargs.get("limit", 50) 

132 offset = kwargs.get("offset", 0) 

133 

134 return { 

135 "rows": self._messages[::-1][offset : offset + limit], 

136 "total": len(self._messages), 

137 } 

138 

139 def mark_message(self, messageid, **kwargs): 

140 """Mark a message as read""" 

141 message = next( 

142 (msg for msg in self._messages if msg["messageid"] == messageid), None 

143 ) 

144 if message: 

145 if g.sessionid not in message["read"]: 

146 message["read"].append(g.sessionid) 

147 

148 self.emit( 

149 "message_read", 

150 message, 

151 ) 

152 

153 return True 

154 

155 def mark_all(self, **kwargs): 

156 """Mark all messages read""" 

157 maxid = 0 

158 for message in self._messages: 

159 if g.sessionid not in message["read"]: 

160 message["read"].append(g.sessionid) 

161 

162 if message["messageid"] > maxid: 

163 maxid = message["messageid"] 

164 

165 self.emit( 

166 "all_message_read", 

167 {"sessionid": g.sessionid}, 

168 ) 

169 

170 return maxid