diff --git a/puppet/zulip/files/postgresql/process_fts_updates b/puppet/zulip/files/postgresql/process_fts_updates index de0ae3f9b86905..b3b17082bac57d 100755 --- a/puppet/zulip/files/postgresql/process_fts_updates +++ b/puppet/zulip/files/postgresql/process_fts_updates @@ -37,11 +37,11 @@ def update_fts_columns(cursor): if USING_PGROONGA: cursor.execute("UPDATE zerver_message SET " "search_pgroonga = " - "escape_html(subject) || ' ' || rendered_content " + "escape_html(topic) || ' ' || rendered_content " "WHERE id = %s", (message_id,)) cursor.execute("UPDATE zerver_message SET " "search_tsvector = to_tsvector('zulip.english_us_search', " - "subject || rendered_content) " + "topic || rendered_content) " "WHERE id = %s", (message_id,)) ids.append(id) cursor.execute("DELETE FROM fts_update_log WHERE id = ANY(%s)", (ids,)) diff --git a/zerver/lib/fix_unreads.py b/zerver/lib/fix_unreads.py index 66e4e0ae18e2b4..d2bf3751949943 100644 --- a/zerver/lib/fix_unreads.py +++ b/zerver/lib/fix_unreads.py @@ -195,7 +195,7 @@ def find_old_ids() -> None: SELECT zerver_usermessage.id, zerver_message.recipient_id, - zerver_message.subject + zerver_message.topic FROM zerver_usermessage INNER JOIN zerver_message ON ( diff --git a/zerver/lib/topic.py b/zerver/lib/topic.py index bef5e3543e91a3..346dd09ac20442 100644 --- a/zerver/lib/topic.py +++ b/zerver/lib/topic.py @@ -34,7 +34,7 @@ # This constant is pretty closely coupled to the # database, but it's the JSON field. -EXPORT_TOPIC_NAME = "subject" +EXPORT_TOPIC_NAME = "topic" ''' The following functions are for user-facing APIs @@ -75,35 +75,35 @@ def REQ_topic() -> Optional[str]: # This is used in low-level message functions in # zerver/lib/message.py, and it's not user facing. -DB_TOPIC_NAME = "subject" -MESSAGE__TOPIC = 'message__subject' +DB_TOPIC_NAME = "topic" +MESSAGE__TOPIC = 'message__topic' def topic_match_sa(topic_name: str) -> Any: # _sa is short for Sql Alchemy, which we use mostly for # queries that search messages - topic_cond = func.upper(column("subject")) == func.upper(literal(topic_name)) + topic_cond = func.upper(column("topic")) == func.upper(literal(topic_name)) return topic_cond def topic_column_sa() -> Any: - return column("subject") + return column("topic") def filter_by_exact_message_topic(query: QuerySet, message: Message) -> QuerySet: topic_name = message.topic_name() - return query.filter(subject=topic_name) + return query.filter(topic=topic_name) def filter_by_topic_name_via_message(query: QuerySet, topic_name: str) -> QuerySet: - return query.filter(message__subject__iexact=topic_name) + return query.filter(message__topic__iexact=topic_name) def messages_for_topic(stream_id: int, topic_name: str) -> QuerySet: - # It might be the case that we really want subject__contains + # It might be the case that we really want topic__contains # here. This code is used for the archive. return Message.objects.filter( recipient__type_id=stream_id, - subject=topic_name, + topic=topic_name, ) def save_message_for_edit_use_case(message: Message) -> None: - message.save(update_fields=["subject", "content", "rendered_content", + message.save(update_fields=["topic", "content", "rendered_content", "rendered_content_version", "last_edit_time", "edit_history"]) @@ -113,14 +113,14 @@ def user_message_exists_for_topic(user_profile: UserProfile, return UserMessage.objects.filter( user_profile=user_profile, message__recipient=recipient, - message__subject__iexact=topic_name, + message__topic__iexact=topic_name, ).exists() def update_messages_for_topic_edit(message: Message, propagate_mode: str, orig_topic_name: str, topic_name: str) -> List[Message]: - propagate_query = Q(recipient = message.recipient, subject = orig_topic_name) + propagate_query = Q(recipient = message.recipient, topic = orig_topic_name) # We only change messages up to 2 days in the past, to avoid hammering our # DB by changing an unbounded amount of messages if propagate_mode == 'change_all': @@ -135,7 +135,7 @@ def update_messages_for_topic_edit(message: Message, # Evaluate the query before running the update messages_list = list(messages) - messages.update(subject=topic_name) + messages.update(topic=topic_name) for m in messages_list: # The cached ORM object is not changed by messages.update() @@ -171,14 +171,14 @@ def get_topic_history_for_stream(user_profile: UserProfile, if public_history: query = ''' SELECT - "zerver_message"."subject" as topic, + "zerver_message"."topic" as topic, max("zerver_message".id) as max_message_id FROM "zerver_message" WHERE ( "zerver_message"."recipient_id" = %s ) GROUP BY ( - "zerver_message"."subject" + "zerver_message"."topic" ) ORDER BY max("zerver_message".id) DESC ''' @@ -186,7 +186,7 @@ def get_topic_history_for_stream(user_profile: UserProfile, else: query = ''' SELECT - "zerver_message"."subject" as topic, + "zerver_message"."topic" as topic, max("zerver_message".id) as max_message_id FROM "zerver_message" INNER JOIN "zerver_usermessage" ON ( @@ -197,7 +197,7 @@ def get_topic_history_for_stream(user_profile: UserProfile, "zerver_message"."recipient_id" = %s ) GROUP BY ( - "zerver_message"."subject" + "zerver_message"."topic" ) ORDER BY max("zerver_message".id) DESC ''' @@ -211,14 +211,14 @@ def get_topic_history_for_web_public_stream(recipient: Recipient) -> List[Dict[s cursor = connection.cursor() query = ''' SELECT - "zerver_message"."subject" as topic, + "zerver_message"."topic" as topic, max("zerver_message".id) as max_message_id FROM "zerver_message" WHERE ( "zerver_message"."recipient_id" = %s ) GROUP BY ( - "zerver_message"."subject" + "zerver_message"."topic" ) ORDER BY max("zerver_message".id) DESC ''' @@ -233,6 +233,6 @@ def get_turtle_message(message_ids: List[int]) -> Message: # here to make subject -> topic sweeping easier. turtle_message = Message.objects.get( # nolint id__in=message_ids, - subject='topic demonstration', + topic='topic demonstration', content__icontains='cute/turtle.png') return turtle_message diff --git a/zerver/migrations/0191_rename_message_subject.py b/zerver/migrations/0191_rename_message_subject.py new file mode 100644 index 00000000000000..073c22359200a4 --- /dev/null +++ b/zerver/migrations/0191_rename_message_subject.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.14 on 2018-11-11 20:27 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('zerver', '0190_cleanup_pushdevicetoken'), + ] + + operations = [ + migrations.RenameField( + model_name='archivedmessage', + old_name='subject', + new_name='topic', + ), + migrations.RenameField( + model_name='message', + old_name='subject', + new_name='topic', + ), + ] diff --git a/zerver/models.py b/zerver/models.py index d439e750eaad3f..5882199365d409 100644 --- a/zerver/models.py +++ b/zerver/models.py @@ -1305,13 +1305,13 @@ class AbstractMessage(models.Model): # The message's topic. # - # Early versions of Zulip called this concept a "subject", as in an email - # "subject line", before changing to "topic" in 2013 (commit dac5a46fa). + # Early versions of Zulip called this concept a "subject", as in an email, + # before changing to "topic" in 2013 (commit dac5a46fa). # UI and user documentation now consistently say "topic". New APIs and # new code should generally also say "topic". # # See also the `topic_name` method on `Message`. - subject = models.CharField(max_length=MAX_TOPIC_NAME_LENGTH, db_index=True) # type: str + topic = models.CharField(max_length=MAX_TOPIC_NAME_LENGTH, db_index=True) # type: str content = models.TextField() # type: str rendered_content = models.TextField(null=True) # type: Optional[str] @@ -1336,7 +1336,7 @@ class Meta: def __str__(self) -> str: display_recipient = get_display_recipient(self.recipient) return "<%s: %s / %s / %s>" % (self.__class__.__name__, display_recipient, - self.subject, self.sender) + self.topic, self.sender) class ArchivedMessage(AbstractMessage): @@ -1354,10 +1354,10 @@ def topic_name(self) -> str: Please start using this helper to facilitate an eventual switch over to a separate topic table. """ - return self.subject + return self.topic def set_topic_name(self, topic_name: str) -> None: - self.subject = topic_name + self.topic = topic_name def is_stream_message(self) -> bool: ''' @@ -1394,7 +1394,7 @@ def to_log_dict(self) -> Dict[str, Any]: sending_client = self.sending_client.name, type = self.recipient.type_name(), recipient = get_display_recipient(self.recipient), - subject = self.topic_name(), + topic = self.topic_name(), content = self.content, timestamp = datetime_to_timestamp(self.pub_date)) @@ -1458,7 +1458,7 @@ def get_context_for_message(message: Message) -> Sequence[Message]: # TODO: Change return type to QuerySet[Message] return Message.objects.filter( recipient_id=message.recipient_id, - subject=message.subject, + topic=message.topic, id__lt=message.id, pub_date__gt=message.pub_date - timedelta(minutes=15), ).order_by('-id')[:10] diff --git a/zerver/tests/test_narrow.py b/zerver/tests/test_narrow.py index 91410db20b0a17..f5afa353f20758 100644 --- a/zerver/tests/test_narrow.py +++ b/zerver/tests/test_narrow.py @@ -159,21 +159,21 @@ def test_add_term_using_non_supported_operator_should_raise_error(self) -> None: def test_add_term_using_topic_operator_and_lunch_operand(self) -> None: term = dict(operator='topic', operand='lunch') - self._do_add_term_test(term, 'WHERE upper(subject) = upper(:param_1)') + self._do_add_term_test(term, 'WHERE upper(topic) = upper(:param_1)') def test_add_term_using_topic_operator_lunch_operand_and_negated( self) -> None: # NEGATED term = dict(operator='topic', operand='lunch', negated=True) - self._do_add_term_test(term, 'WHERE upper(subject) != upper(:param_1)') + self._do_add_term_test(term, 'WHERE upper(topic) != upper(:param_1)') def test_add_term_using_topic_operator_and_personal_operand(self) -> None: term = dict(operator='topic', operand='personal') - self._do_add_term_test(term, 'WHERE upper(subject) = upper(:param_1)') + self._do_add_term_test(term, 'WHERE upper(topic) = upper(:param_1)') def test_add_term_using_topic_operator_personal_operand_and_negated( self) -> None: # NEGATED term = dict(operator='topic', operand='personal', negated=True) - self._do_add_term_test(term, 'WHERE upper(subject) != upper(:param_1)') + self._do_add_term_test(term, 'WHERE upper(topic) != upper(:param_1)') def test_add_term_using_sender_operator(self) -> None: term = dict(operator='sender', operand=self.example_email("othello")) @@ -270,13 +270,13 @@ def test_add_term_using_group_pm_operator_with_non_existing_user_as_operand(self @override_settings(USING_PGROONGA=False) def test_add_term_using_search_operator(self) -> None: term = dict(operator='search', operand='"french fries"') - self._do_add_term_test(term, 'WHERE (lower(content) LIKE lower(:content_1) OR lower(subject) LIKE lower(:subject_1)) AND (search_tsvector @@ plainto_tsquery(:param_2, :param_3))') + self._do_add_term_test(term, 'WHERE (lower(content) LIKE lower(:content_1) OR lower(topic) LIKE lower(:topic_1)) AND (search_tsvector @@ plainto_tsquery(:param_2, :param_3))') @override_settings(USING_PGROONGA=False) def test_add_term_using_search_operator_and_negated( self) -> None: # NEGATED term = dict(operator='search', operand='"french fries"', negated=True) - self._do_add_term_test(term, 'WHERE NOT (lower(content) LIKE lower(:content_1) OR lower(subject) LIKE lower(:subject_1)) AND NOT (search_tsvector @@ plainto_tsquery(:param_2, :param_3))') + self._do_add_term_test(term, 'WHERE NOT (lower(content) LIKE lower(:content_1) OR lower(topic) LIKE lower(:topic_1)) AND NOT (search_tsvector @@ plainto_tsquery(:param_2, :param_3))') @override_settings(USING_PGROONGA=True) def test_add_term_using_search_operator_pgroonga(self) -> None: @@ -1410,7 +1410,7 @@ def _update_tsvector_index(self) -> None: cursor.execute(""" UPDATE zerver_message SET search_tsvector = to_tsvector('zulip.english_us_search', - subject || rendered_content) + topic || rendered_content) """) @override_settings(USING_PGROONGA=False) @@ -1655,7 +1655,7 @@ def test_get_messages_with_search_pgroonga(self) -> None: with connection.cursor() as cursor: cursor.execute(""" UPDATE zerver_message SET - search_pgroonga = escape_html(subject) || ' ' || rendered_content + search_pgroonga = escape_html(topic) || ' ' || rendered_content """) narrow = [ @@ -2365,7 +2365,7 @@ def test_use_first_unread_anchor_with_muted_topics(self) -> None: stream = get_stream('Scotland', realm) recipient_id = get_stream_recipient(stream.id).id - cond = '''AND NOT (recipient_id = {scotland} AND upper(subject) = upper('golf'))'''.format(scotland=recipient_id) + cond = '''AND NOT (recipient_id = {scotland} AND upper(topic) = upper('golf'))'''.format(scotland=recipient_id) self.assertIn(cond, queries[0]['sql']) # Next, verify the use_first_unread_anchor setting invokes @@ -2414,7 +2414,7 @@ def test_exclude_muting_conditions(self) -> None: expected_query = ''' SELECT id AS message_id FROM zerver_message - WHERE NOT (recipient_id = :recipient_id_1 AND upper(subject) = upper(:param_1)) + WHERE NOT (recipient_id = :recipient_id_1 AND upper(topic) = upper(:param_1)) ''' self.assertEqual(fix_ws(query), fix_ws(expected_query)) params = get_sqlalchemy_query_params(query) @@ -2439,8 +2439,8 @@ def test_exclude_muting_conditions(self) -> None: FROM zerver_message WHERE recipient_id NOT IN (:recipient_id_1) AND NOT - (recipient_id = :recipient_id_2 AND upper(subject) = upper(:param_1) OR - recipient_id = :recipient_id_3 AND upper(subject) = upper(:param_2))''' + (recipient_id = :recipient_id_2 AND upper(topic) = upper(:param_1) OR + recipient_id = :recipient_id_3 AND upper(topic) = upper(:param_2))''' self.assertEqual(fix_ws(query), fix_ws(expected_query)) params = get_sqlalchemy_query_params(query) self.assertEqual(params['recipient_id_1'], get_recipient_id_for_stream_name(realm, 'Verona')) @@ -2515,13 +2515,13 @@ def test_get_messages_with_narrow_queries(self) -> None: 'narrow': '[["stream", "Scotland"]]'}, sql) - sql_template = "SELECT anon_1.message_id, anon_1.flags \nFROM (SELECT message_id, flags \nFROM zerver_usermessage JOIN zerver_message ON zerver_usermessage.message_id = zerver_message.id \nWHERE user_profile_id = {hamlet_id} AND upper(subject) = upper('blah') ORDER BY message_id ASC \n LIMIT 10) AS anon_1 ORDER BY message_id ASC" + sql_template = "SELECT anon_1.message_id, anon_1.flags \nFROM (SELECT message_id, flags \nFROM zerver_usermessage JOIN zerver_message ON zerver_usermessage.message_id = zerver_message.id \nWHERE user_profile_id = {hamlet_id} AND upper(topic) = upper('blah') ORDER BY message_id ASC \n LIMIT 10) AS anon_1 ORDER BY message_id ASC" sql = sql_template.format(**query_ids) self.common_check_get_messages_query({'anchor': 0, 'num_before': 0, 'num_after': 9, 'narrow': '[["topic", "blah"]]'}, sql) - sql_template = "SELECT anon_1.message_id \nFROM (SELECT id AS message_id \nFROM zerver_message \nWHERE recipient_id = {scotland_recipient} AND upper(subject) = upper('blah') ORDER BY zerver_message.id ASC \n LIMIT 10) AS anon_1 ORDER BY message_id ASC" + sql_template = "SELECT anon_1.message_id \nFROM (SELECT id AS message_id \nFROM zerver_message \nWHERE recipient_id = {scotland_recipient} AND upper(topic) = upper('blah') ORDER BY zerver_message.id ASC \n LIMIT 10) AS anon_1 ORDER BY message_id ASC" sql = sql_template.format(**query_ids) self.common_check_get_messages_query({'anchor': 0, 'num_before': 0, 'num_after': 9, 'narrow': '[["stream", "Scotland"], ["topic", "blah"]]'}, @@ -2544,19 +2544,19 @@ def test_get_messages_with_narrow_queries(self) -> None: def test_get_messages_with_search_queries(self) -> None: query_ids = self.get_query_ids() - sql_template = "SELECT anon_1.message_id, anon_1.flags, anon_1.subject, anon_1.rendered_content, anon_1.content_matches, anon_1.topic_matches \nFROM (SELECT message_id, flags, subject, rendered_content, ts_match_locs_array('zulip.english_us_search', rendered_content, plainto_tsquery('zulip.english_us_search', 'jumping')) AS content_matches, ts_match_locs_array('zulip.english_us_search', escape_html(subject), plainto_tsquery('zulip.english_us_search', 'jumping')) AS topic_matches \nFROM zerver_usermessage JOIN zerver_message ON zerver_usermessage.message_id = zerver_message.id \nWHERE user_profile_id = {hamlet_id} AND (search_tsvector @@ plainto_tsquery('zulip.english_us_search', 'jumping')) ORDER BY message_id ASC \n LIMIT 10) AS anon_1 ORDER BY message_id ASC" # type: str + sql_template = "SELECT anon_1.message_id, anon_1.flags, anon_1.topic, anon_1.rendered_content, anon_1.content_matches, anon_1.topic_matches \nFROM (SELECT message_id, flags, topic, rendered_content, ts_match_locs_array('zulip.english_us_search', rendered_content, plainto_tsquery('zulip.english_us_search', 'jumping')) AS content_matches, ts_match_locs_array('zulip.english_us_search', escape_html(topic), plainto_tsquery('zulip.english_us_search', 'jumping')) AS topic_matches \nFROM zerver_usermessage JOIN zerver_message ON zerver_usermessage.message_id = zerver_message.id \nWHERE user_profile_id = {hamlet_id} AND (search_tsvector @@ plainto_tsquery('zulip.english_us_search', 'jumping')) ORDER BY message_id ASC \n LIMIT 10) AS anon_1 ORDER BY message_id ASC" # type: str sql = sql_template.format(**query_ids) self.common_check_get_messages_query({'anchor': 0, 'num_before': 0, 'num_after': 9, 'narrow': '[["search", "jumping"]]'}, sql) - sql_template = "SELECT anon_1.message_id, anon_1.subject, anon_1.rendered_content, anon_1.content_matches, anon_1.topic_matches \nFROM (SELECT id AS message_id, subject, rendered_content, ts_match_locs_array('zulip.english_us_search', rendered_content, plainto_tsquery('zulip.english_us_search', 'jumping')) AS content_matches, ts_match_locs_array('zulip.english_us_search', escape_html(subject), plainto_tsquery('zulip.english_us_search', 'jumping')) AS topic_matches \nFROM zerver_message \nWHERE recipient_id = {scotland_recipient} AND (search_tsvector @@ plainto_tsquery('zulip.english_us_search', 'jumping')) ORDER BY zerver_message.id ASC \n LIMIT 10) AS anon_1 ORDER BY message_id ASC" + sql_template = "SELECT anon_1.message_id, anon_1.topic, anon_1.rendered_content, anon_1.content_matches, anon_1.topic_matches \nFROM (SELECT id AS message_id, topic, rendered_content, ts_match_locs_array('zulip.english_us_search', rendered_content, plainto_tsquery('zulip.english_us_search', 'jumping')) AS content_matches, ts_match_locs_array('zulip.english_us_search', escape_html(topic), plainto_tsquery('zulip.english_us_search', 'jumping')) AS topic_matches \nFROM zerver_message \nWHERE recipient_id = {scotland_recipient} AND (search_tsvector @@ plainto_tsquery('zulip.english_us_search', 'jumping')) ORDER BY zerver_message.id ASC \n LIMIT 10) AS anon_1 ORDER BY message_id ASC" sql = sql_template.format(**query_ids) self.common_check_get_messages_query({'anchor': 0, 'num_before': 0, 'num_after': 9, 'narrow': '[["stream", "Scotland"], ["search", "jumping"]]'}, sql) - sql_template = 'SELECT anon_1.message_id, anon_1.flags, anon_1.subject, anon_1.rendered_content, anon_1.content_matches, anon_1.topic_matches \nFROM (SELECT message_id, flags, subject, rendered_content, ts_match_locs_array(\'zulip.english_us_search\', rendered_content, plainto_tsquery(\'zulip.english_us_search\', \'"jumping" quickly\')) AS content_matches, ts_match_locs_array(\'zulip.english_us_search\', escape_html(subject), plainto_tsquery(\'zulip.english_us_search\', \'"jumping" quickly\')) AS topic_matches \nFROM zerver_usermessage JOIN zerver_message ON zerver_usermessage.message_id = zerver_message.id \nWHERE user_profile_id = {hamlet_id} AND (content ILIKE \'%jumping%\' OR subject ILIKE \'%jumping%\') AND (search_tsvector @@ plainto_tsquery(\'zulip.english_us_search\', \'"jumping" quickly\')) ORDER BY message_id ASC \n LIMIT 10) AS anon_1 ORDER BY message_id ASC' + sql_template = 'SELECT anon_1.message_id, anon_1.flags, anon_1.topic, anon_1.rendered_content, anon_1.content_matches, anon_1.topic_matches \nFROM (SELECT message_id, flags, topic, rendered_content, ts_match_locs_array(\'zulip.english_us_search\', rendered_content, plainto_tsquery(\'zulip.english_us_search\', \'"jumping" quickly\')) AS content_matches, ts_match_locs_array(\'zulip.english_us_search\', escape_html(topic), plainto_tsquery(\'zulip.english_us_search\', \'"jumping" quickly\')) AS topic_matches \nFROM zerver_usermessage JOIN zerver_message ON zerver_usermessage.message_id = zerver_message.id \nWHERE user_profile_id = {hamlet_id} AND (content ILIKE \'%jumping%\' OR topic ILIKE \'%jumping%\') AND (search_tsvector @@ plainto_tsquery(\'zulip.english_us_search\', \'"jumping" quickly\')) ORDER BY message_id ASC \n LIMIT 10) AS anon_1 ORDER BY message_id ASC' sql = sql_template.format(**query_ids) self.common_check_get_messages_query({'anchor': 0, 'num_before': 0, 'num_after': 9, 'narrow': '[["search", "\\"jumping\\" quickly"]]'},