diff --git a/synapse/app/homeserver.py b/synapse/app/homeserver.py
index 49cf928cc1..d675d8c8f9 100755
--- a/synapse/app/homeserver.py
+++ b/synapse/app/homeserver.py
@@ -57,7 +57,7 @@ SCHEMAS = [
# Remember to update this number every time an incompatible change is made to
# database schema files, so the users will be informed on server restarts.
-SCHEMA_VERSION = 2
+SCHEMA_VERSION = 3
class SynapseHomeServer(HomeServer):
diff --git a/synapse/handlers/presence.py b/synapse/handlers/presence.py
index c79bb6ff76..c225b7428a 100644
--- a/synapse/handlers/presence.py
+++ b/synapse/handlers/presence.py
@@ -178,9 +178,6 @@ class PresenceHandler(BaseHandler):
if not visible:
raise SynapseError(404, "Presence information not visible")
state = yield self.store.get_presence_state(target_user.localpart)
- if "mtime" in state:
- del state["mtime"]
- state["presence"] = state.pop("state")
if target_user in self._user_cachemap:
state["last_active"] = (
@@ -226,13 +223,17 @@ class PresenceHandler(BaseHandler):
logger.debug("Updating presence state of %s to %s",
target_user.localpart, state["presence"])
- state_to_store = dict(state)
- state_to_store["state"] = state_to_store.pop("presence")
-
statuscache=self._get_or_offline_usercache(target_user)
- was_level = self.STATE_LEVELS[statuscache.get_state()["presence"]]
+ oldstate = statuscache.get_state()
+
+ was_level = self.STATE_LEVELS[oldstate["presence"]]
now_level = self.STATE_LEVELS[state["presence"]]
+ if now_level > was_level:
+ state["last_active"] = self.clock.time_msec()
+
+ state_to_store = dict(state)
+
yield defer.DeferredList([
self.store.set_presence_state(
target_user.localpart, state_to_store
@@ -242,9 +243,6 @@ class PresenceHandler(BaseHandler):
),
])
- if now_level > was_level:
- state["last_active"] = self.clock.time_msec()
-
now_online = state["presence"] != PresenceState.OFFLINE
was_polling = target_user in self._user_cachemap
@@ -595,8 +593,6 @@ class PresenceHandler(BaseHandler):
def _push_presence_remote(self, user, destination, state=None):
if state is None:
state = yield self.store.get_presence_state(user.localpart)
- del state["mtime"]
- state["presence"] = state.pop("state")
if user in self._user_cachemap:
state["last_active"] = (
@@ -884,8 +880,6 @@ class UserPresenceCache(object):
self.serial = None
def update(self, state, serial):
- assert("mtime_age" not in state)
-
self.state.update(state)
# Delete keys that are now 'None'
for k in self.state.keys():
diff --git a/synapse/storage/presence.py b/synapse/storage/presence.py
index 71b2bb084d..67f5bf54d0 100644
--- a/synapse/storage/presence.py
+++ b/synapse/storage/presence.py
@@ -35,17 +35,15 @@ class PresenceStore(SQLBaseStore):
return self._simple_select_one(
table="presence",
keyvalues={"user_id": user_localpart},
- retcols=["state", "status_msg", "mtime"],
+ retcols=["presence", "status_msg", "last_active"],
)
def set_presence_state(self, user_localpart, new_state):
return self._simple_update_one(
table="presence",
keyvalues={"user_id": user_localpart},
- updatevalues={"state": new_state["state"],
- "status_msg": new_state["status_msg"],
- "mtime": self._clock.time_msec()},
- retcols=["state"],
+ updatevalues=new_state,
+ retcols=["presence"],
)
def allow_presence_visible(self, observed_localpart, observer_userid):
diff --git a/synapse/storage/schema/delta/v3.sql b/synapse/storage/schema/delta/v3.sql
new file mode 100644
index 0000000000..42b0ae64e8
--- /dev/null
+++ b/synapse/storage/schema/delta/v3.sql
@@ -0,0 +1,35 @@
+/* Copyright 2014 matrix.org
+ *
+ * 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.
+ */
+
+-- SQLite3 doesn't support renaming or dropping columns. We'll have to go the
+-- long way round
+
+CREATE TABLE NEW_presence(
+ user_id INTEGER NOT NULL,
+ presence INTEGER,
+ status_msg TEXT,
+ last_active INTEGER,
+ FOREIGN KEY(user_id) REFERENCES users(id)
+);
+
+-- rename the 'state' field to 'presence'; migrate the old 'mtime' field into
+-- the new 'last_active' field
+INSERT INTO NEW_presence (user_id, presence, status_msg, last_active)
+ SELECT user_id, state, status_msg, mtime FROM presence;
+
+DROP TABLE presence;
+ALTER TABLE NEW_presence RENAME TO presence;
+
+PRAGMA user_version = 3;
diff --git a/synapse/storage/schema/presence.sql b/synapse/storage/schema/presence.sql
index 595b3b5a69..50d9cb46d1 100644
--- a/synapse/storage/schema/presence.sql
+++ b/synapse/storage/schema/presence.sql
@@ -14,9 +14,9 @@
*/
CREATE TABLE IF NOT EXISTS presence(
user_id INTEGER NOT NULL,
- state INTEGER,
+ presence INTEGER,
status_msg TEXT,
- mtime INTEGER, -- miliseconds since last state change
+ last_active INTEGER,
FOREIGN KEY(user_id) REFERENCES users(id)
);
diff --git a/tests/handlers/test_presence.py b/tests/handlers/test_presence.py
index 9eb8b6909f..45a44e21d6 100644
--- a/tests/handlers/test_presence.py
+++ b/tests/handlers/test_presence.py
@@ -134,7 +134,7 @@ class PresenceStateTestCase(unittest.TestCase):
def test_get_my_state(self):
mocked_get = self.datastore.get_presence_state
mocked_get.return_value = defer.succeed(
- {"state": ONLINE, "status_msg": "Online"}
+ {"presence": ONLINE, "status_msg": "Online"}
)
state = yield self.handler.get_state(
@@ -151,7 +151,7 @@ class PresenceStateTestCase(unittest.TestCase):
def test_get_allowed_state(self):
mocked_get = self.datastore.get_presence_state
mocked_get.return_value = defer.succeed(
- {"state": ONLINE, "status_msg": "Online"}
+ {"presence": ONLINE, "status_msg": "Online"}
)
state = yield self.handler.get_state(
@@ -168,7 +168,7 @@ class PresenceStateTestCase(unittest.TestCase):
def test_get_same_room_state(self):
mocked_get = self.datastore.get_presence_state
mocked_get.return_value = defer.succeed(
- {"state": ONLINE, "status_msg": "Online"}
+ {"presence": ONLINE, "status_msg": "Online"}
)
self.room_members = [self.u_apple, self.u_clementine]
@@ -186,7 +186,7 @@ class PresenceStateTestCase(unittest.TestCase):
def test_get_disallowed_state(self):
mocked_get = self.datastore.get_presence_state
mocked_get.return_value = defer.succeed(
- {"state": ONLINE, "status_msg": "Online"}
+ {"presence": ONLINE, "status_msg": "Online"}
)
self.room_members = []
@@ -201,14 +201,17 @@ class PresenceStateTestCase(unittest.TestCase):
@defer.inlineCallbacks
def test_set_my_state(self):
mocked_set = self.datastore.set_presence_state
- mocked_set.return_value = defer.succeed({"state": OFFLINE})
+ mocked_set.return_value = defer.succeed({"presence": OFFLINE})
yield self.handler.set_state(
target_user=self.u_apple, auth_user=self.u_apple,
state={"presence": UNAVAILABLE, "status_msg": "Away"})
mocked_set.assert_called_with("apple",
- {"state": UNAVAILABLE, "status_msg": "Away"}
+ {"presence": UNAVAILABLE,
+ "status_msg": "Away",
+ "last_active": 1000000, # MockClock
+ }
)
self.mock_start.assert_called_with(self.u_apple,
state={
@@ -624,7 +627,7 @@ class PresencePushTestCase(unittest.TestCase):
self.room_members = [self.u_apple, self.u_elderberry]
self.datastore.set_presence_state.return_value = defer.succeed(
- {"state": ONLINE}
+ {"presence": ONLINE}
)
# TODO(paul): Gut-wrenching
@@ -793,7 +796,7 @@ class PresencePushTestCase(unittest.TestCase):
self.room_members = [self.u_apple, self.u_onion]
self.datastore.set_presence_state.return_value = defer.succeed(
- {"state": ONLINE}
+ {"presence": ONLINE}
)
# TODO(paul): Gut-wrenching
@@ -1043,16 +1046,16 @@ class PresencePollingTestCase(unittest.TestCase):
def get_presence_state(user_localpart):
return defer.succeed(
- {"state": self.current_user_state[user_localpart],
+ {"presence": self.current_user_state[user_localpart],
"status_msg": None,
- "mtime": 123456000}
+ "last_active": 500000}
)
self.datastore.get_presence_state = get_presence_state
def set_presence_state(user_localpart, new_state):
was = self.current_user_state[user_localpart]
- self.current_user_state[user_localpart] = new_state["state"]
- return defer.succeed({"state": was})
+ self.current_user_state[user_localpart] = new_state["presence"]
+ return defer.succeed({"presence": was})
self.datastore.set_presence_state = set_presence_state
def get_presence_list(user_localpart, accepted):
@@ -1249,7 +1252,8 @@ class PresencePollingTestCase(unittest.TestCase):
"push": [
{"user_id": "@banana:test",
"presence": "offline",
- "status_msg": None},
+ "status_msg": None,
+ "last_active_ago": 500000},
],
},
),
diff --git a/tests/handlers/test_presencelike.py b/tests/handlers/test_presencelike.py
index b35980d948..97fdc576c7 100644
--- a/tests/handlers/test_presencelike.py
+++ b/tests/handlers/test_presencelike.py
@@ -144,14 +144,16 @@ class PresenceProfilelikeDataTestCase(unittest.TestCase):
]
mocked_set = self.datastore.set_presence_state
- mocked_set.return_value = defer.succeed({"state": OFFLINE})
+ mocked_set.return_value = defer.succeed({"presence": OFFLINE})
yield self.handlers.presence_handler.set_state(
target_user=self.u_apple, auth_user=self.u_apple,
state={"presence": UNAVAILABLE, "status_msg": "Away"})
mocked_set.assert_called_with("apple",
- {"state": UNAVAILABLE, "status_msg": "Away"}
+ {"presence": UNAVAILABLE,
+ "status_msg": "Away",
+ "last_active": 1000000}
)
@defer.inlineCallbacks
@@ -162,7 +164,7 @@ class PresenceProfilelikeDataTestCase(unittest.TestCase):
]
self.datastore.set_presence_state.return_value = defer.succeed(
- {"state": ONLINE}
+ {"presence": ONLINE}
)
# TODO(paul): Gut-wrenching
@@ -244,7 +246,7 @@ class PresenceProfilelikeDataTestCase(unittest.TestCase):
]
self.datastore.set_presence_state.return_value = defer.succeed(
- {"state": ONLINE}
+ {"presence": ONLINE}
)
# TODO(paul): Gut-wrenching
diff --git a/tests/rest/test_presence.py b/tests/rest/test_presence.py
index a1db0fbcf3..78a60c137e 100644
--- a/tests/rest/test_presence.py
+++ b/tests/rest/test_presence.py
@@ -21,7 +21,7 @@ from twisted.internet import defer
from mock import Mock
import logging
-from ..utils import MockHttpResource
+from ..utils import MockHttpResource, MockClock
from synapse.api.constants import PresenceState
from synapse.handlers.presence import PresenceHandler
@@ -51,6 +51,7 @@ class PresenceStateTestCase(unittest.TestCase):
self.mock_resource = MockHttpResource(prefix=PATH_PREFIX)
hs = HomeServer("test",
+ clock=MockClock(),
db_pool=None,
datastore=Mock(spec=[
"get_presence_state",
@@ -91,7 +92,7 @@ class PresenceStateTestCase(unittest.TestCase):
def test_get_my_status(self):
mocked_get = self.datastore.get_presence_state
mocked_get.return_value = defer.succeed(
- {"state": ONLINE, "status_msg": "Available"}
+ {"presence": ONLINE, "status_msg": "Available"}
)
(code, response) = yield self.mock_resource.trigger("GET",
@@ -107,7 +108,7 @@ class PresenceStateTestCase(unittest.TestCase):
@defer.inlineCallbacks
def test_set_my_status(self):
mocked_set = self.datastore.set_presence_state
- mocked_set.return_value = defer.succeed({"state": OFFLINE})
+ mocked_set.return_value = defer.succeed({"presence": OFFLINE})
(code, response) = yield self.mock_resource.trigger("PUT",
"/presence/%s/status" % (myid),
@@ -115,7 +116,9 @@ class PresenceStateTestCase(unittest.TestCase):
self.assertEquals(200, code)
mocked_set.assert_called_with("apple",
- {"state": UNAVAILABLE, "status_msg": "Away"}
+ {"presence": UNAVAILABLE,
+ "status_msg": "Away",
+ "last_active": 1000000}
)
@@ -312,7 +315,7 @@ class PresenceEventStreamTestCase(unittest.TestCase):
self.room_members = [self.u_apple, self.u_banana]
self.mock_datastore.set_presence_state.return_value = defer.succeed(
- {"state": ONLINE}
+ {"presence": ONLINE}
)
self.mock_datastore.get_presence_list.return_value = defer.succeed(
[]
@@ -332,7 +335,7 @@ class PresenceEventStreamTestCase(unittest.TestCase):
)
self.mock_datastore.set_presence_state.return_value = defer.succeed(
- {"state": ONLINE}
+ {"presence": ONLINE}
)
self.mock_datastore.get_presence_list.return_value = defer.succeed(
[]
|