create support user (#4141)

Allow for the creation of a support user.

A support user can access the server, join rooms, interact with other users, but does not appear in the user directory nor does it contribute to monthly active user limits.
This commit is contained in:
Neil Johnson 2018-12-14 18:20:59 +00:00 committed by GitHub
parent e93a0ebf50
commit d2f7c4e6b1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 371 additions and 47 deletions

View file

@ -55,9 +55,12 @@ class MonthlyActiveUsersStore(SQLBaseStore):
txn,
tp["medium"], tp["address"]
)
if user_id:
self.upsert_monthly_active_user_txn(txn, user_id)
reserved_user_list.append(user_id)
is_support = self.is_support_user_txn(txn, user_id)
if not is_support:
self.upsert_monthly_active_user_txn(txn, user_id)
reserved_user_list.append(user_id)
else:
logger.warning(
"mau limit reserved threepid %s not found in db" % tp
@ -182,6 +185,18 @@ class MonthlyActiveUsersStore(SQLBaseStore):
Args:
user_id (str): user to add/update
"""
# Support user never to be included in MAU stats. Note I can't easily call this
# from upsert_monthly_active_user_txn because then I need a _txn form of
# is_support_user which is complicated because I want to cache the result.
# Therefore I call it here and ignore the case where
# upsert_monthly_active_user_txn is called directly from
# _initialise_reserved_users reasoning that it would be very strange to
# include a support user in this context.
is_support = yield self.is_support_user(user_id)
if is_support:
return
is_insert = yield self.runInteraction(
"upsert_monthly_active_user", self.upsert_monthly_active_user_txn,
user_id
@ -200,6 +215,16 @@ class MonthlyActiveUsersStore(SQLBaseStore):
in a database thread rather than the main thread, and we can't call
txn.call_after because txn may not be a LoggingTransaction.
We consciously do not call is_support_txn from this method because it
is not possible to cache the response. is_support_txn will be false in
almost all cases, so it seems reasonable to call it only for
upsert_monthly_active_user and to call is_support_txn manually
for cases where upsert_monthly_active_user_txn is called directly,
like _initialise_reserved_users
In short, don't call this method with support users. (Support users
should not appear in the MAU stats).
Args:
txn (cursor):
user_id (str): user to add/update
@ -208,6 +233,7 @@ class MonthlyActiveUsersStore(SQLBaseStore):
bool: True if a new entry was created, False if an
existing one was updated.
"""
# Am consciously deciding to lock the table on the basis that is ought
# never be a big table and alternative approaches (batching multiple
# upserts into a single txn) introduced a lot of extra complexity.

View file

@ -19,6 +19,7 @@ from six.moves import range
from twisted.internet import defer
from synapse.api.constants import UserTypes
from synapse.api.errors import Codes, StoreError
from synapse.storage import background_updates
from synapse.storage._base import SQLBaseStore
@ -168,7 +169,7 @@ class RegistrationStore(RegistrationWorkerStore,
def register(self, user_id, token=None, password_hash=None,
was_guest=False, make_guest=False, appservice_id=None,
create_profile_with_displayname=None, admin=False):
create_profile_with_displayname=None, admin=False, user_type=None):
"""Attempts to register an account.
Args:
@ -184,6 +185,10 @@ class RegistrationStore(RegistrationWorkerStore,
appservice_id (str): The ID of the appservice registering the user.
create_profile_with_displayname (unicode): Optionally create a profile for
the user, setting their displayname to the given value
admin (boolean): is an admin user?
user_type (str|None): type of user. One of the values from
api.constants.UserTypes, or None for a normal user.
Raises:
StoreError if the user_id could not be registered.
"""
@ -197,7 +202,8 @@ class RegistrationStore(RegistrationWorkerStore,
make_guest,
appservice_id,
create_profile_with_displayname,
admin
admin,
user_type
)
def _register(
@ -211,6 +217,7 @@ class RegistrationStore(RegistrationWorkerStore,
appservice_id,
create_profile_with_displayname,
admin,
user_type,
):
user_id_obj = UserID.from_string(user_id)
@ -247,6 +254,7 @@ class RegistrationStore(RegistrationWorkerStore,
"is_guest": 1 if make_guest else 0,
"appservice_id": appservice_id,
"admin": 1 if admin else 0,
"user_type": user_type,
}
)
else:
@ -260,6 +268,7 @@ class RegistrationStore(RegistrationWorkerStore,
"is_guest": 1 if make_guest else 0,
"appservice_id": appservice_id,
"admin": 1 if admin else 0,
"user_type": user_type,
}
)
except self.database_engine.module.IntegrityError:
@ -456,6 +465,31 @@ class RegistrationStore(RegistrationWorkerStore,
defer.returnValue(res if res else False)
@cachedInlineCallbacks()
def is_support_user(self, user_id):
"""Determines if the user is of type UserTypes.SUPPORT
Args:
user_id (str): user id to test
Returns:
Deferred[bool]: True if user is of type UserTypes.SUPPORT
"""
res = yield self.runInteraction(
"is_support_user", self.is_support_user_txn, user_id
)
defer.returnValue(res)
def is_support_user_txn(self, txn, user_id):
res = self._simple_select_one_onecol_txn(
txn=txn,
table="users",
keyvalues={"name": user_id},
retcol="user_type",
allow_none=True,
)
return True if res == UserTypes.SUPPORT else False
@defer.inlineCallbacks
def user_add_threepid(self, user_id, medium, address, validated_at, added_at):
yield self._simple_upsert("user_threepids", {

View file

@ -0,0 +1,19 @@
/* Copyright 2018 New Vector 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.
*/
/* The type of the user: NULL for a regular user, or one of the constants in
* synapse.api.constants.UserTypes
*/
ALTER TABLE users ADD COLUMN user_type TEXT DEFAULT NULL;