summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--synapse/handlers/appservice.py7
-rw-r--r--synapse/rest/appservice/v1/register.py4
-rw-r--r--synapse/storage/__init__.py1
-rw-r--r--synapse/storage/appservice.py89
-rw-r--r--synapse/storage/schema/application_services.sql32
5 files changed, 117 insertions, 16 deletions
diff --git a/synapse/handlers/appservice.py b/synapse/handlers/appservice.py
index c9f56c41eb..8bd475cbfd 100644
--- a/synapse/handlers/appservice.py
+++ b/synapse/handlers/appservice.py
@@ -16,7 +16,7 @@
 from twisted.internet import defer
 
 from ._base import BaseHandler
-from synapse.api.errors import StoreError, SynapseError
+from synapse.api.errors import Codes, StoreError, SynapseError
 
 import logging
 
@@ -36,11 +36,12 @@ class ApplicationServicesHandler(BaseHandler):
         try:
             stored_service = yield self.store.get_app_service(app_service.token)
             if not stored_service:
-                raise StoreError(404, "Not found")
+                raise StoreError(404, "Application Service Not found")
         except StoreError:
             raise SynapseError(
                 403, "Unrecognised application services token. "
-                "Consult the home server admin."
+                "Consult the home server admin.",
+                errcode=Codes.FORBIDDEN
             )
         # TODO store this AS
 
diff --git a/synapse/rest/appservice/v1/register.py b/synapse/rest/appservice/v1/register.py
index 5786cf873e..e374d538e7 100644
--- a/synapse/rest/appservice/v1/register.py
+++ b/synapse/rest/appservice/v1/register.py
@@ -64,9 +64,9 @@ class RegisterRestServlet(AppServiceRestServlet):
         yield self.handler.register(app_service)
         hs_token = "_not_implemented_yet"  # TODO: Pull this from self.hs?
 
-        defer.returnValue({
+        defer.returnValue((200, {
           "hs_token": hs_token
-        })
+        }))
 
     def _parse_namespace(self, target_ns, origin_ns, ns):
         if ns not in target_ns or ns not in origin_ns:
diff --git a/synapse/storage/__init__.py b/synapse/storage/__init__.py
index 9431c1a32d..e86b981b47 100644
--- a/synapse/storage/__init__.py
+++ b/synapse/storage/__init__.py
@@ -62,6 +62,7 @@ SCHEMAS = [
     "event_edges",
     "event_signatures",
     "media_repository",
+    "application_services"
 ]
 
 
diff --git a/synapse/storage/appservice.py b/synapse/storage/appservice.py
index 533fac4972..5a0e47e0d4 100644
--- a/synapse/storage/appservice.py
+++ b/synapse/storage/appservice.py
@@ -12,12 +12,15 @@
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
-
-from synapse.api.errors import StoreError
+import logging
+from twisted.internet import defer
 
 from ._base import SQLBaseStore
 
 
+logger = logging.getLogger(__name__)
+
+
 # XXX: This feels like it should belong in a "models" module, not storage.
 class ApplicationService(object):
     """Defines an application service.
@@ -30,7 +33,22 @@ class ApplicationService(object):
         if url:
             self.url = url
         if namespaces:
-            self.namespaces = namespaces
+            self._set_namespaces(namespaces)
+
+    def _set_namespaces(self, namespaces):
+        # Sanity check that it is of the form:
+        # {
+        #   users: ["regex",...],
+        #   aliases: ["regex",...],
+        #   rooms: ["regex",...],
+        # }
+        for ns in ["users", "rooms", "aliases"]:
+            if type(namespaces[ns]) != list:
+                raise ValueError("Bad namespace value for '%s'", ns)
+            for regex in namespaces[ns]:
+                if not isinstance(regex, basestring):
+                    raise ValueError("Expected string regex for ns '%s'", ns)
+        self.namespaces = namespaces
 
     def is_interested(self, event):
         """Check if this service is interested in this event.
@@ -133,15 +151,64 @@ class ApplicationServiceStore(SQLBaseStore):
                     return service
             return None
 
+        # TODO: The from_cache=False impl
         # TODO: This should be JOINed with the application_services_regex table.
-        row = self._simple_select_one(
-            "application_services", {"token": token},
-            ["url", "token"]
-        )
-        if not row:
-            raise StoreError(400, "Bad application services token supplied.")
-        return row
 
+
+    @defer.inlineCallbacks
     def _populate_cache(self):
         """Populates the ApplicationServiceCache from the database."""
-        pass
+        sql = ("SELECT * FROM application_services LEFT JOIN "
+               "application_services_regex ON application_services.id = "
+               "application_services_regex.as_id")
+
+        namespace_enum = [
+            "users",    # 0
+            "aliases",  # 1
+            "rooms"   # 2
+        ]
+        # SQL results in the form:
+        # [
+        #   {
+        #     'regex': "something",
+        #     'url': "something",
+        #     'namespace': enum,
+        #     'as_id': 0,
+        #     'token': "something",
+        #     'id': 0
+        #   }
+        # ]
+        services = {}
+        results = yield self._execute_and_decode(sql)
+        for res in results:
+            as_token = res["token"]
+            if as_token not in services:
+                # add the service
+                services[as_token] = {
+                    "url": res["url"],
+                    "token": as_token,
+                    "namespaces": {
+                        "users": [],
+                        "aliases": [],
+                        "rooms": []
+                    }
+                }
+            # add the namespace regex if one exists
+            ns_int = res["namespace"]
+            if ns_int is None:
+                continue
+            try:
+                services[as_token]["namespaces"][namespace_enum[ns_int]].append(
+                    res["regex"]
+                )
+            except IndexError:
+                logger.error("Bad namespace enum '%s'. %s", ns_int, res)
+
+        for service in services.values():
+            logger.info("Found application service: %s", service)
+            self.cache.services.append(ApplicationService(
+                service["token"],
+                service["url"],
+                service["namespaces"]
+            ))
+
diff --git a/synapse/storage/schema/application_services.sql b/synapse/storage/schema/application_services.sql
new file mode 100644
index 0000000000..6d245fc807
--- /dev/null
+++ b/synapse/storage/schema/application_services.sql
@@ -0,0 +1,32 @@
+/* Copyright 2015 OpenMarket Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+CREATE TABLE IF NOT EXISTS application_services(
+    id INTEGER PRIMARY KEY AUTOINCREMENT,
+    url TEXT,
+    token TEXT,
+    UNIQUE(token) ON CONFLICT ROLLBACK
+);
+
+CREATE TABLE IF NOT EXISTS application_services_regex(
+    id INTEGER PRIMARY KEY AUTOINCREMENT,
+    as_id INTEGER NOT NULL,
+    namespace INTEGER,  /* enum[room_id|room_alias|user_id] */
+    regex TEXT,
+    FOREIGN KEY(as_id) REFERENCES application_services(id)
+);
+
+
+