summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--synapse/handlers/message.py6
-rw-r--r--synapse/rest/client/v2_alpha/tags.py12
-rw-r--r--synapse/storage/schema/delta/25/tags.sql1
-rw-r--r--synapse/storage/tags.py44
4 files changed, 41 insertions, 22 deletions
diff --git a/synapse/handlers/message.py b/synapse/handlers/message.py
index 8f156e5c84..0f947993d1 100644
--- a/synapse/handlers/message.py
+++ b/synapse/handlers/message.py
@@ -405,7 +405,6 @@ class MessageHandler(BaseHandler):
                 tags = tags_by_room.get(event.room_id)
                 if tags:
                     private_user_data.append({
-                        "room_id": event.room_id,
                         "type": "m.tag",
                         "content": {"tags": tags},
                     })
@@ -466,7 +465,6 @@ class MessageHandler(BaseHandler):
             private_user_data.append({
                 "type": "m.tag",
                 "content": {"tags": tags},
-                "room_id": room_id,
             })
         result["private_user_data"] = private_user_data
 
@@ -499,8 +497,8 @@ class MessageHandler(BaseHandler):
             user_id, messages
         )
 
-        start_token = StreamToken(token[0], 0, 0, 0)
-        end_token = StreamToken(token[1], 0, 0, 0)
+        start_token = StreamToken(token[0], 0, 0, 0, 0)
+        end_token = StreamToken(token[1], 0, 0, 0, 0)
 
         time_now = self.clock.time_msec()
 
diff --git a/synapse/rest/client/v2_alpha/tags.py b/synapse/rest/client/v2_alpha/tags.py
index 486add9909..4e3f917fc5 100644
--- a/synapse/rest/client/v2_alpha/tags.py
+++ b/synapse/rest/client/v2_alpha/tags.py
@@ -16,12 +16,14 @@
 from ._base import client_v2_pattern
 
 from synapse.http.servlet import RestServlet
-from synapse.api.errors import AuthError
+from synapse.api.errors import AuthError, SynapseError
 
 from twisted.internet import defer
 
 import logging
 
+import simplejson as json
+
 logger = logging.getLogger(__name__)
 
 
@@ -70,7 +72,13 @@ class TagServlet(RestServlet):
         if user_id != auth_user.to_string():
             raise AuthError(403, "Cannot add tags for other users.")
 
-        max_id = yield self.store.add_tag_to_room(user_id, room_id, tag)
+        try:
+            content_bytes = request.content.read()
+            body = json.loads(content_bytes)
+        except:
+            raise SynapseError(400, "Invalid tag JSON")
+
+        max_id = yield self.store.add_tag_to_room(user_id, room_id, tag, body)
 
         yield self.notifier.on_new_event(
             "private_user_data_key", max_id, users=[user_id]
diff --git a/synapse/storage/schema/delta/25/tags.sql b/synapse/storage/schema/delta/25/tags.sql
index 168766dcf3..527424c998 100644
--- a/synapse/storage/schema/delta/25/tags.sql
+++ b/synapse/storage/schema/delta/25/tags.sql
@@ -18,6 +18,7 @@ CREATE TABLE IF NOT EXISTS room_tags(
     user_id TEXT NOT NULL,
     room_id TEXT NOT NULL,
     tag     TEXT NOT NULL,  -- The name of the tag.
+    content TEXT NOT NULL,  -- The JSON content of the tag.
     CONSTRAINT room_tag_uniqueness UNIQUE (user_id, room_id, tag)
 );
 
diff --git a/synapse/storage/tags.py b/synapse/storage/tags.py
index 2d5c49144a..34aa38c06a 100644
--- a/synapse/storage/tags.py
+++ b/synapse/storage/tags.py
@@ -18,6 +18,7 @@ from synapse.util.caches.descriptors import cached
 from twisted.internet import defer
 from .util.id_generators import StreamIdGenerator
 
+import ujson as json
 import logging
 
 logger = logging.getLogger(__name__)
@@ -52,14 +53,15 @@ class TagsStore(SQLBaseStore):
         """
 
         deferred = self._simple_select_list(
-            "room_tags", {"user_id": user_id}, ["room_id", "tag"]
+            "room_tags", {"user_id": user_id}, ["room_id", "tag", "content"]
         )
 
         @deferred.addCallback
         def tags_by_room(rows):
             tags_by_room = {}
             for row in rows:
-                tags_by_room.setdefault(row["room_id"], []).append(row["tag"])
+                room_tags = tags_by_room.setdefault(row["room_id"], {})
+                room_tags[row["tag"]] = json.loads(row["content"])
             return tags_by_room
 
         return deferred
@@ -105,31 +107,41 @@ class TagsStore(SQLBaseStore):
         Returns:
             A deferred list of string tags.
         """
-        return self._simple_select_onecol(
+        return self._simple_select_list(
             table="room_tags",
             keyvalues={"user_id": user_id, "room_id": room_id},
-            retcol="tag",
+            retcols=("tag", "content"),
             desc="get_tags_for_room",
-        )
+        ).addCallback(lambda rows: {
+            row["tag"]: json.loads(row["content"]) for row in rows
+        })
 
     @defer.inlineCallbacks
-    def add_tag_to_room(self, user_id, room_id, tag):
+    def add_tag_to_room(self, user_id, room_id, tag, content):
         """Add a tag to a room for a user.
+        Args:
+            user_id(str): The user to add a tag for.
+            room_id(str): The room to add a tag for.
+            tag(str): The tag name to add.
+            content(dict): A json object to associate with the tag.
         Returns:
             A deferred that completes once the tag has been added.
         """
+        content_json = json.dumps(content)
+
         def add_tag_txn(txn, next_id):
-            sql = (
-                "INSERT INTO room_tags (user_id, room_id, tag)"
-                " VALUES (?, ?, ?)"
+            self._simple_upsert_txn(
+                txn,
+                table="room_tags",
+                keyvalues={
+                    "user_id": user_id,
+                    "room_id": room_id,
+                    "tag": tag,
+                },
+                values={
+                    "content": content_json,
+                }
             )
-            try:
-                txn.execute(sql, (user_id, room_id, tag))
-            except self.database_engine.module.IntegrityError:
-                # Return early if the row is already in the table
-                # and we don't need to bump the revision number of the
-                # private_user_data.
-                return
             self._update_revision_txn(txn, user_id, room_id, next_id)
 
         with (yield self._private_user_data_id_gen.get_next(self)) as next_id: