models/drafts: Add a model for storing Draft messages.

Also add a Draft object-to-dictionary conversion method.
The following commits will provide an API around this
model using which our clients can sync drafts across each
other (if they so wish too). As of making this commit, we
haven't finalized exactly how our clients will use this.

See https://chat.zulip.org/#narrow/stream/2-general/topic/drafts
For some of the discussion around this model and in general,
around this feature.

Signed-off-by: Hemanth V. Alluri <hdrive1999@gmail.com>
This commit is contained in:
Hemanth V. Alluri 2020-07-23 22:54:22 +05:30 committed by Tim Abbott
parent d5f42e2722
commit 0e893b9045
3 changed files with 69 additions and 1 deletions

View File

@ -124,6 +124,7 @@ ALL_ZULIP_TABLES = {
'zerver_defaultstream',
'zerver_defaultstreamgroup',
'zerver_defaultstreamgroup_streams',
'zerver_draft',
'zerver_emailchangestatus',
'zerver_huddle',
'zerver_message',
@ -237,6 +238,9 @@ NON_EXPORTED_TABLES = {
# This is low priority, since users can easily just reset themselves to away.
'zerver_userstatus',
# Drafts don't need to be exported as they are supposed to be more ephemeral.
'zerver_draft',
# For any tables listed below here, it's a bug that they are not present in the export.
}

View File

@ -0,0 +1,26 @@
# Generated by Django 2.2.14 on 2020-07-23 17:07
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('zerver', '0296_remove_userprofile_short_name'),
]
operations = [
migrations.CreateModel(
name='Draft',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('topic', models.CharField(db_index=True, max_length=60)),
('content', models.TextField()),
('last_edit_time', models.DateTimeField(db_index=True)),
('recipient', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='zerver.Recipient')),
('user_profile', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
),
]

View File

@ -66,7 +66,7 @@ from zerver.lib.cache import (
)
from zerver.lib.exceptions import JsonableError
from zerver.lib.pysa import mark_sanitized
from zerver.lib.timestamp import datetime_to_timestamp
from zerver.lib.timestamp import datetime_to_precise_timestamp, datetime_to_timestamp
from zerver.lib.types import (
DisplayRecipientT,
ExtendedFieldElement,
@ -1899,6 +1899,44 @@ class ArchivedSubMessage(AbstractSubMessage):
post_save.connect(flush_submessage, sender=SubMessage)
class Draft(models.Model):
""" Server-side storage model for storing drafts so that drafts can be synced across
multiple clients/devices.
"""
user_profile: UserProfile = models.ForeignKey(UserProfile, on_delete=models.CASCADE)
recipient: Optional[Recipient] = models.ForeignKey(Recipient, null=True, on_delete=models.SET_NULL)
topic: str = models.CharField(max_length=MAX_TOPIC_NAME_LENGTH, db_index=True)
content: str = models.TextField() # Length should not exceed MAX_MESSAGE_LENGTH
last_edit_time: datetime.datetime = models.DateTimeField(db_index=True)
def __str__(self) -> str:
return f"<{self.__class__.__name__}: {self.user_profile.email} / {self.id} / {self.last_edit_time}>"
def to_dict(self) -> Dict[str, Any]: # nocoverage # Will be added in a later commit.
if self.recipient is None:
_type = ""
to = []
elif self.recipient.type == Recipient.STREAM:
_type = "stream"
to = [self.recipient.type_id]
else:
_type = "private"
if self.recipient.type == Recipient.PERSONAL:
to = [self.recipient.type_id]
else:
to = []
for r in get_display_recipient(self.recipient):
assert(not isinstance(r, str)) # It will only be a string for streams
if not r["id"] == self.user_profile_id:
to.append(r["id"])
return {
"type": _type,
"to": to,
"topic": self.topic,
"content": self.content,
"timestamp": datetime_to_precise_timestamp(self.last_edit_time),
}
class AbstractReaction(models.Model):
"""For emoji reactions to messages (and potentially future reaction types).