diff --git a/src/snek/model/channel_message.py b/src/snek/model/channel_message.py index 7fd1a27..505a40d 100644 --- a/src/snek/model/channel_message.py +++ b/src/snek/model/channel_message.py @@ -7,6 +7,7 @@ class ChannelMessageModel(BaseModel): user_uid = ModelField(name="user_uid", required=True, kind=str) message = ModelField(name="message", required=True, kind=str) html = ModelField(name="html", required=False, kind=str) + is_final = ModelField(name="is_final", required=True, kind=bool, value=True) def get_seconds_since_last_update(self): return int((datetime.now(timezone.utc) - datetime.fromisoformat(self["updated_at"])).total_seconds()) diff --git a/src/snek/service/channel_message.py b/src/snek/service/channel_message.py index ee355e5..c512e21 100644 --- a/src/snek/service/channel_message.py +++ b/src/snek/service/channel_message.py @@ -4,12 +4,13 @@ from snek.system.service import BaseService class ChannelMessageService(BaseService): mapper_name = "channel_message" - async def create(self, channel_uid, user_uid, message): + async def create(self, channel_uid, user_uid, message, is_final=True): model = await self.new() model["channel_uid"] = channel_uid model["user_uid"] = user_uid model["message"] = message + model['is_final'] = is_final context = {} diff --git a/src/snek/service/chat.py b/src/snek/service/chat.py index 7fbe787..9346e40 100644 --- a/src/snek/service/chat.py +++ b/src/snek/service/chat.py @@ -4,12 +4,38 @@ from snek.system.service import BaseService class ChatService(BaseService): - async def send(self, user_uid, channel_uid, message): + async def finalize(self, message_uid): + channel_message = await self.services.channel_message.get(uid=message_uid) + channel_message["is_final"] = True + await self.services.channel_message.save(channel_message) + user = await self.services.user.get(uid=channel_message["user_uid"]) + channel = await self.services.channel.get(uid=channel_message["channel_uid"]) + channel["last_message_on"] = now() + await self.services.channel.save(channel) + await self.services.socket.broadcast( + channel_uid, + { + "message": channel_message["message"], + "html": channel_message["html"], + "user_uid": user['uid'], + "color": user["color"], + "channel_uid": channel['uid'], + "created_at": channel_message["created_at"], + "updated_at": channel_message["updated_at"], + "username": user["username"], + "uid": channel_message["uid"], + "user_nick": user["nick"], + "is_final": channel_message["is_final"], + }, + ) + + + async def send(self, user_uid, channel_uid, message, is_final=True): channel = await self.services.channel.get(uid=channel_uid) if not channel: raise Exception("Channel not found.") channel_message = await self.services.channel_message.create( - channel_uid, user_uid, message + channel_uid, user_uid, message,is_final ) channel_message_uid = channel_message["uid"] @@ -30,6 +56,7 @@ class ChatService(BaseService): "username": user["username"], "uid": channel_message["uid"], "user_nick": user["nick"], + "is_final": is_final, }, ) await self.app.create_task( diff --git a/src/snek/static/chat-input.js b/src/snek/static/chat-input.js index 943769c..cab4285 100644 --- a/src/snek/static/chat-input.js +++ b/src/snek/static/chat-input.js @@ -179,6 +179,9 @@ levenshteinDistance(a, b) { if (e.key === "Enter" && !e.shiftKey) { this.value = ""; e.target.value = ""; + if(this.messageUid){ + app.rpc.finalizeMessage(this.messageUid) + } return; } this.value = e.target.value; @@ -249,7 +252,7 @@ levenshteinDistance(a, b) { e.detail.files.forEach((file) => { message += `[${file.name}](/channel/attachment/${file.relative_url})`; }); - app.rpc.sendMessage(this.channelUid, message); + app.rpc.sendMessage(this.channelUid, message,true); }); setTimeout(()=>{ this.focus(); @@ -278,7 +281,7 @@ levenshteinDistance(a, b) { } this.value = this.replaceMentionsWithAuthors(this.value); - this.sendMessage(this.channelUid, this.value).then((uid) => { + this.sendMessage(this.channelUid, this.value,!this.liveType).then((uid) => { if (this.liveType) { this.messageUid = uid; } @@ -348,11 +351,11 @@ levenshteinDistance(a, b) { } } - async sendMessage(channelUid, value) { + async sendMessage(channelUid, value,is_final) { if (!value.trim()) { return null; } - return await app.rpc.sendMessage(channelUid, value); + return await app.rpc.sendMessage(channelUid, value,is_final); } } diff --git a/src/snek/view/rpc.py b/src/snek/view/rpc.py index 96d9833..3251035 100644 --- a/src/snek/view/rpc.py +++ b/src/snek/view/rpc.py @@ -193,6 +193,18 @@ class RPCView(BaseView): ) return channels + async def finalize_message(self, message_uid): + self._require_login() + message = await self.services.channel_message.get(message_uid) + if message["user_uid"] != self.user_uid: + raise Exception("Not allowed") + + + if not message['is_final']: + await self.services.chat.finalize(message['uid']) + + return {"success": True} + async def update_message_text(self,message_uid, text): self._require_login() message = await self.services.channel_message.get(message_uid) @@ -200,6 +212,7 @@ class RPCView(BaseView): raise Exception("Not allowed") if message.get_seconds_since_last_update() > 3: + await self.finalize_message(message["uid"]) return {"error": "Message too old","seconds_since_last_update": message.get_seconds_since_last_update(),"success": False} message['message'] = text @@ -221,9 +234,9 @@ class RPCView(BaseView): return {"success": True} - async def send_message(self, channel_uid, message): + async def send_message(self, channel_uid, message,is_final=True): self._require_login() - message = await self.services.chat.send(self.user_uid, channel_uid, message) + message = await self.services.chat.send(self.user_uid, channel_uid, message,is_final) return message["uid"]