Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

Commit

Permalink
Add mau_appservice_trial_days config (#12619)
Browse files Browse the repository at this point in the history
* Add mau_appservice_trial_days

* Add a test

* Tweaks

* changelog

* Ensure we sync after the delay

* Fix types

* Add config statement

* Fix test

* Reinstate logging that got removed

* Fix feature name
  • Loading branch information
Half-Shot authored May 4, 2022
1 parent 7fbf424 commit 2d74a8c
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 2 deletions.
1 change: 1 addition & 0 deletions changelog.d/12619.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add new `mau_appservice_trial_days` configuration option to specify a different trial period for users registered via an appservice.
7 changes: 7 additions & 0 deletions docs/sample_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,11 @@ manhole_settings:
# sign up in a short space of time never to return after their initial
# session.
#
# The option `mau_appservice_trial_days` is similar to `mau_trial_days`, but
# applies a different trial number if the user was registered by an appservice.
# A value of 0 means no trial days are applied. Appservices not listed in this
# dictionary use the value of `mau_trial_days` instead.
#
# 'mau_limit_alerting' is a means of limiting client side alerting
# should the mau limit be reached. This is useful for small instances
# where the admin has 5 mau seats (say) for 5 specific people and no
Expand All @@ -417,6 +422,8 @@ manhole_settings:
#max_mau_value: 50
#mau_trial_days: 2
#mau_limit_alerting: false
#mau_appservice_trial_days:
# "appservice-id": 1

# If enabled, the metrics for the number of monthly active users will
# be populated, however no one will be limited. If limit_usage_by_mau
Expand Down
14 changes: 14 additions & 0 deletions docs/usage/configuration/config_documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,20 @@ Example configuration:
mau_trial_days: 5
```
---
Config option: `mau_appservice_trial_days`

The option `mau_appservice_trial_days` is similar to `mau_trial_days`, but applies a different
trial number if the user was registered by an appservice. A value
of 0 means no trial days are applied. Appservices not listed in this dictionary
use the value of `mau_trial_days` instead.

Example configuration:
```yaml
mau_appservice_trial_days:
my_appservice_id: 3
another_appservice_id: 6
```
---
Config option: `mau_limit_alerting`

The option `mau_limit_alerting` is a means of limiting client-side alerting
Expand Down
8 changes: 8 additions & 0 deletions synapse/config/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,7 @@ def read_config(self, config: JsonDict, **kwargs: Any) -> None:
)

self.mau_trial_days = config.get("mau_trial_days", 0)
self.mau_appservice_trial_days = config.get("mau_appservice_trial_days", {})
self.mau_limit_alerting = config.get("mau_limit_alerting", True)

# How long to keep redacted events in the database in unredacted form
Expand Down Expand Up @@ -1105,6 +1106,11 @@ def generate_config_section(
# sign up in a short space of time never to return after their initial
# session.
#
# The option `mau_appservice_trial_days` is similar to `mau_trial_days`, but
# applies a different trial number if the user was registered by an appservice.
# A value of 0 means no trial days are applied. Appservices not listed in this
# dictionary use the value of `mau_trial_days` instead.
#
# 'mau_limit_alerting' is a means of limiting client side alerting
# should the mau limit be reached. This is useful for small instances
# where the admin has 5 mau seats (say) for 5 specific people and no
Expand All @@ -1115,6 +1121,8 @@ def generate_config_section(
#max_mau_value: 50
#mau_trial_days: 2
#mau_limit_alerting: false
#mau_appservice_trial_days:
# "appservice-id": 1
# If enabled, the metrics for the number of monthly active users will
# be populated, however no one will be limited. If limit_usage_by_mau
Expand Down
8 changes: 6 additions & 2 deletions synapse/storage/databases/main/registration.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,8 @@ async def get_userinfo_by_id(self, user_id: str) -> Optional[UserInfo]:

async def is_trial_user(self, user_id: str) -> bool:
"""Checks if user is in the "trial" period, i.e. within the first
N days of registration defined by `mau_trial_days` config
N days of registration defined by `mau_trial_days` config or the
`mau_appservice_trial_days` config.
Args:
user_id: The user to check for trial status.
Expand All @@ -226,7 +227,10 @@ async def is_trial_user(self, user_id: str) -> bool:
return False

now = self._clock.time_msec()
trial_duration_ms = self.config.server.mau_trial_days * 24 * 60 * 60 * 1000
days = self.config.server.mau_appservice_trial_days.get(
info["appservice_id"], self.config.server.mau_trial_days
)
trial_duration_ms = days * 24 * 60 * 60 * 1000
is_trial = (now - info["creation_ts"] * 1000) < trial_duration_ms
return is_trial

Expand Down
74 changes: 74 additions & 0 deletions tests/test_mau.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

"""Tests REST events for /rooms paths."""

from typing import List

from synapse.api.constants import APP_SERVICE_REGISTRATION_TYPE, LoginType
from synapse.api.errors import Codes, HttpResponseException, SynapseError
from synapse.appservice import ApplicationService
Expand Down Expand Up @@ -229,6 +231,78 @@ def test_tracked_but_not_limited(self):
self.reactor.advance(100)
self.assertEqual(2, self.successResultOf(count))

@override_config(
{
"mau_trial_days": 3,
"mau_appservice_trial_days": {"SomeASID": 1, "AnotherASID": 2},
}
)
def test_as_trial_days(self):
user_tokens: List[str] = []

def advance_time_and_sync():
self.reactor.advance(24 * 60 * 61)
for token in user_tokens:
self.do_sync_for_user(token)

# Cheekily add an application service that we use to register a new user
# with.
as_token_1 = "foobartoken1"
self.store.services_cache.append(
ApplicationService(
token=as_token_1,
hostname=self.hs.hostname,
id="SomeASID",
sender="@as_sender_1:test",
namespaces={"users": [{"regex": "@as_1.*", "exclusive": True}]},
)
)

as_token_2 = "foobartoken2"
self.store.services_cache.append(
ApplicationService(
token=as_token_2,
hostname=self.hs.hostname,
id="AnotherASID",
sender="@as_sender_2:test",
namespaces={"users": [{"regex": "@as_2.*", "exclusive": True}]},
)
)

user_tokens.append(self.create_user("kermit1"))
user_tokens.append(self.create_user("kermit2"))
user_tokens.append(
self.create_user("as_1kermit3", token=as_token_1, appservice=True)
)
user_tokens.append(
self.create_user("as_2kermit4", token=as_token_2, appservice=True)
)

# Advance time by 1 day to include the first appservice
advance_time_and_sync()
self.assertEqual(
self.get_success(self.store.get_monthly_active_count_by_service()),
{"SomeASID": 1},
)

# Advance time by 1 day to include the next appservice
advance_time_and_sync()
self.assertEqual(
self.get_success(self.store.get_monthly_active_count_by_service()),
{"SomeASID": 1, "AnotherASID": 1},
)

# Advance time by 1 day to include the native users
advance_time_and_sync()
self.assertEqual(
self.get_success(self.store.get_monthly_active_count_by_service()),
{
"SomeASID": 1,
"AnotherASID": 1,
"native": 2,
},
)

def create_user(self, localpart, token=None, appservice=False):
request_data = {
"username": localpart,
Expand Down

0 comments on commit 2d74a8c

Please sign in to comment.