Calculate has_* fields before saving Messages

Before saving a Message object, call update_calculated_fields()
to set the has_attachment/has_image/has_link fields.

Note that the pre_save hook we added here does not get called
if you call bulk_create, hence the explicit call to
update_calculated_fields() in do_send_messages().

(imported from commit 1d60ae5908ef186aa5ff1e39277dbb2b765e60d4)
This commit is contained in:
Steve Howell
2014-02-21 15:18:38 -05:00
parent 16df239f39
commit eec12ff268
3 changed files with 49 additions and 1 deletions

View File

@@ -376,6 +376,7 @@ def do_send_messages(messages):
message['active_recipients'] = filter(lambda user_profile: user_profile.is_active,
message['recipients'])
message['message'].maybe_render_content(None)
message['message'].update_calculated_fields()
# Save the message receipts in the database
user_message_flags = defaultdict(dict)

View File

@@ -4,6 +4,7 @@ from django.db import models
from django.conf import settings
from django.contrib.auth.models import AbstractBaseUser, UserManager, \
PermissionsMixin
from django.dispatch import receiver
from zerver.lib.cache import cache_with_key, flush_user_profile, flush_realm, \
user_profile_by_id_cache_key, user_profile_by_email_cache_key, \
generic_bulk_cached_fetch, cache_set, flush_stream, \
@@ -15,13 +16,14 @@ from zerver.lib.avatar import gravatar_hash, get_avatar_url
from django.utils import timezone
from django.contrib.sessions.models import Session
from zerver.lib.timestamp import datetime_to_timestamp
from django.db.models.signals import post_save, post_delete
from django.db.models.signals import pre_save, post_save, post_delete
from guardian.shortcuts import get_users_with_perms
import zlib
from bitfield import BitField
from collections import defaultdict
import pylibmc
import re
import ujson
import logging
@@ -935,6 +937,31 @@ class Message(models.Model):
'website', 'ios', 'android')) or \
('desktop app' in sending_client)
@staticmethod
def content_has_attachment(content):
return '/user_uploads/' in content
@staticmethod
def content_has_image(content):
return bool(re.search('/user_uploads/\S+\.(bmp|gif|jpg|jpeg|png|webp)', content, re.IGNORECASE))
@staticmethod
def content_has_link(content):
return 'http://' in content or 'https://' in content or '/user_uploads' in content
def update_calculated_fields(self):
# TODO: rendered_content could also be considered a calculated field
content = self.content
self.has_attachment = bool(Message.content_has_attachment(content))
self.has_image = bool(Message.content_has_image(content))
self.has_link = bool(Message.content_has_link(content))
@receiver(pre_save, sender=Message)
def pre_save_message(sender, **kwargs):
if kwargs['update_fields'] is None or "content" in kwargs['update_fields']:
message = kwargs['instance']
message.update_calculated_fields()
class UserMessage(models.Model):
user_profile = models.ForeignKey(UserProfile)
message = models.ForeignKey(Message)

View File

@@ -4,6 +4,7 @@ from django.db.models import Q
from sqlalchemy.sql import (
and_, select, column, compiler
)
from django.test import TestCase
from zerver.lib import bugdown
from zerver.decorator import JsonableError
from zerver.lib.test_runner import slow
@@ -1277,6 +1278,25 @@ class StarTests(AuthedTestCase):
self.assertEqual(sent_message.message.content, content)
self.assertFalse(sent_message.flags.starred)
class AttachmentTest(TestCase):
def test_basics(self):
self.assertFalse(Message.content_has_attachment('whatever'))
self.assertFalse(Message.content_has_attachment('yo http://foo.com'))
self.assertTrue(Message.content_has_attachment('yo\n https://staging.zulip.com/user_uploads/'))
self.assertTrue(Message.content_has_attachment('yo\n /user_uploads/1/wEAnI-PEmVmCjo15xxNaQbnj/photo-10.jpg foo'))
self.assertFalse(Message.content_has_image('whatever'))
self.assertFalse(Message.content_has_image('yo http://foo.com'))
self.assertFalse(Message.content_has_image('yo\n /user_uploads/1/wEAnI-PEmVmCjo15xxNaQbnj/photo-10.pdf foo'))
for ext in [".bmp", ".gif", ".jpg", "jpeg", ".png", ".webp", ".JPG"]:
content = 'yo\n /user_uploads/1/wEAnI-PEmVmCjo15xxNaQbnj/photo-10.%s foo' % (ext,)
self.assertTrue(Message.content_has_image(content))
self.assertFalse(Message.content_has_link('whatever'))
self.assertTrue(Message.content_has_link('yo\n http://foo.com'))
self.assertTrue(Message.content_has_link('yo\n https://example.com?spam=1&eggs=2'))
self.assertTrue(Message.content_has_link('yo /user_uploads/1/wEAnI-PEmVmCjo15xxNaQbnj/photo-10.pdf foo'))
class CheckMessageTest(AuthedTestCase):
def test_basic_check_message_call(self):
sender = get_user_profile_by_email('othello@zulip.com')