Coverage for app/backend/src/couchers/constants.py: 100%
51 statements
« prev ^ index » next coverage.py v7.14.2, created at 2026-06-21 09:29 +0000
« prev ^ index » next coverage.py v7.14.2, created at 2026-06-21 09:29 +0000
1from datetime import UTC, datetime, timedelta
3# terms of service version
4TOS_VERSION = 2
6# community guidelines version
7GUIDELINES_VERSION = 1
9# When updating this, also update the "activeness_probe" notification strings in
10# src/couchers/email/locales/en.json
11LATEST_RELEASE_BLOG_URL = "https://couchers.org/blog/2026/05/25/couchers-spring-release"
13EMAIL_REGEX = r"^[0-9a-z]([0-9a-z\-\_\+]|(\.[0-9a-z\-\_\+]))*@([0-9a-z\-]+\.)*[0-9a-z\-]+\.[a-z]{2,}$"
15# Must match the frontend values in app/web/utils/validation.ts
16VALID_NAME_MIN_LENGTH = 2
17VALID_NAME_MAX_LENGTH = 100
18VALID_NAME_REGEX = r"^[\p{L}'-]+(\s+[\p{L}'-]+)*$"
20BANNED_USERNAME_PHRASES = [
21 "admin",
22 "bot",
23 "safety",
24 "security",
25 "secure",
26 "trust",
27 "couchers",
28 "help",
29 "moderation",
30 "moderator",
31 "noreply",
32 "official",
33 "security",
34 "staff",
35 "support",
36 "system",
37 "team",
38 "verify",
39]
41# expiry time for a verified phone number
42PHONE_VERIFICATION_LIFETIME = timedelta(days=2 * 365)
44# shortest period between phone verification code requests
45PHONE_REVERIFICATION_INTERVAL = timedelta(days=2)
47# expiry time for an sms code
48SMS_CODE_LIFETIME = timedelta(hours=24)
50# max attempts to enter the sms code
51SMS_CODE_ATTEMPTS = 3
53# Postal verification constants
54POSTAL_VERIFICATION_CODE_LENGTH = 6
55# Reduced alphabet to avoid confusion (no I, O, 0, 1)
56POSTAL_VERIFICATION_CODE_ALPHABET = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789"
57# Code valid for 90 days after postcard sent
58POSTAL_VERIFICATION_CODE_LIFETIME = timedelta(days=90)
59# Max wrong code attempts before lockout
60POSTAL_VERIFICATION_MAX_ATTEMPTS = 5
61# Can only initiate once per 30 days
62POSTAL_VERIFICATION_RATE_LIMIT = timedelta(days=30)
64SIGNUP_EMAIL_TOKEN_VALIDITY = timedelta(hours=48)
66DATETIME_MINUS_INFINITY = datetime(1, 1, 1, tzinfo=UTC)
67DATETIME_INFINITY = datetime(9876, 12, 31, hour=23, minute=59, second=59, tzinfo=UTC)
69# the api workers listen on API_BASE_PORT .. API_BASE_PORT + API_WORKER_COUNT - 1; must stay in sync with
70# proxy/envoy.yaml and docker-compose.prod.yml
71API_WORKER_COUNT = 4
72API_BASE_PORT = 1761
73MEDIA_PORT = 1753
75# per API worker process; kept small since we parallelize across processes (API_WORKER_COUNT), not threads
76SERVER_THREADS = 8
78# on SIGTERM, how long to let in-flight RPCs drain before the server is forced down; kept under the
79# container's stop_grace_period (docker-compose stop_grace_period: 30s) so workers drain, not SIGKILLed
80GRACEFUL_SHUTDOWN_TIMEOUT = 5
82# how long the user has to undelete their account
83UNDELETE_DAYS = 7
85# expiry time for preferred language cookie
86PREFERRED_LANGUAGE_COOKIE_EXPIRY = timedelta(days=3650)
89# activeness probe settings
90# wait about 11 months before sending one out
91ACTIVENESS_PROBE_INACTIVITY_PERIOD = timedelta(days=333)
92# times at which to send notifications after inactivity (cumulative since start of probe)
93ACTIVENESS_PROBE_TIME_REMINDERS = [timedelta(days=0), timedelta(days=2, hours=8)]
94# total time from initiation after which to expire the probe
95ACTIVENESS_PROBE_EXPIRY_TIME = timedelta(days=4)
97HOST_REQUEST_MAX_REMINDERS = 1
98HOST_REQUEST_REMINDER_INTERVAL = timedelta(days=2)
100# Note: Javascript's string.length is in utf16 code units, Python's len(str) is in utf8 code units.
101HOST_REQUEST_MIN_LENGTH_UTF16 = 250 # Must match frontend
102PUBLIC_TRIP_DESCRIPTION_MIN_LENGTH_UTF16 = 150 # Must match frontend
104ANTIBOT_FREQ = timedelta(hours=48)
106EVENT_REMINDER_TIMEDELTA = timedelta(hours=24)
108COMMUNITIES_SEARCH_FUZZY_SIMILARITY_THRESHOLD = 0.35
110UNKNOWN_ERROR_MESSAGE = "An unknown backend error occurred. Please consider filing a bug!"
112# NOTE: these codes are on purpose not translatable
113NONEXISTENT_API_CALL_ERROR_MESSAGE = "API call does not exist. Please refresh and try again."
114MISSING_AUTH_LEVEL_ERROR_MESSAGE = "Internal authentication error."
115COOKIES_AND_AUTH_HEADER_ERROR_MESSAGE = 'Both "cookie" and "authorization" in request'
116CALL_CANCELLED_ERROR_MESSAGE = "Call cancelled."
118# NOTE: the frontend uses these (and error codes) to distinguish between jailed and logged out
119UNAUTHORIZED_ERROR_MESSAGE = "Unauthorized"
120PERMISSION_DENIED_ERROR_MESSAGE = "Permission denied"
122GHOST_USERNAME = "ghost"
124# Photo gallery limits
125GALLERY_MAX_PHOTOS_NOT_VERIFIED = 2
126GALLERY_MAX_PHOTOS_VERIFIED = 5
128COMPLETED_PROFILE_MINIMUM_CHAR_LENGTH = 150
130# How long a container must run uninterrupted before /status reports stable=true
131STABLE_THRESHOLD_SECONDS = 5 * 60
133MODERATION_AUTO_APPROVE_FLAG_PRIORITY = 1000