Coverage for app / backend / src / couchers / constants.py: 100%
46 statements
« prev ^ index » next coverage.py v7.13.2, created at 2026-02-03 06:18 +0000
« prev ^ index » next coverage.py v7.13.2, created at 2026-02-03 06:18 +0000
1from datetime import datetime, timedelta
3import pytz
5# terms of service version
6TOS_VERSION = 2
8# community guidelines version
9GUIDELINES_VERSION = 1
11EMAIL_REGEX = r"^[0-9a-z][0-9a-z\-\_\+\.]*@([0-9a-z\-]+\.)*[0-9a-z\-]+\.[a-z]{2,}$"
13BANNED_USERNAME_PHRASES = [
14 "admin",
15 "couchers",
16 "help",
17 "moderation",
18 "moderator",
19 "noreply",
20 "official",
21 "security",
22 "staff",
23 "support",
24 "system",
25 "team",
26]
28# expiry time for a verified phone number
29PHONE_VERIFICATION_LIFETIME = timedelta(days=2 * 365)
31# shortest period between phone verification code requests
32PHONE_REVERIFICATION_INTERVAL = timedelta(days=2)
34# expiry time for an sms code
35SMS_CODE_LIFETIME = timedelta(hours=24)
37# max attempts to enter the sms code
38SMS_CODE_ATTEMPTS = 3
40# Postal verification constants
41POSTAL_VERIFICATION_CODE_LENGTH = 6
42# Reduced alphabet to avoid confusion (no I, O, 0, 1)
43POSTAL_VERIFICATION_CODE_ALPHABET = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789"
44# Code valid for 90 days after postcard sent
45POSTAL_VERIFICATION_CODE_LIFETIME = timedelta(days=90)
46# Max wrong code attempts before lockout
47POSTAL_VERIFICATION_MAX_ATTEMPTS = 5
48# Can only initiate once per 30 days
49POSTAL_VERIFICATION_RATE_LIMIT = timedelta(days=30)
51SIGNUP_EMAIL_TOKEN_VALIDITY = timedelta(hours=48)
53DATETIME_MINUS_INFINITY = pytz.UTC.localize(datetime(1, 1, 1))
54DATETIME_INFINITY = pytz.UTC.localize(datetime(9876, 12, 31, hour=23, minute=59, second=59))
56SERVER_THREADS = 128
58WORKER_THREADS = 1
60# how long the user has to undelete their account
61UNDELETE_DAYS = 7
63# expiry time for preferred language cookie
64PREFERRED_LANGUAGE_COOKIE_EXPIRY = timedelta(days=3650)
67# activeness probe settings
68# wait about 11 months before sending one out
69ACTIVENESS_PROBE_INACTIVITY_PERIOD = timedelta(days=333)
70# times at which to send notifications after inactivity (cumulative since start of probe)
71ACTIVENESS_PROBE_TIME_REMINDERS = [timedelta(days=0), timedelta(days=2, hours=8)]
72# total time from initiation after which to expire the probe
73ACTIVENESS_PROBE_EXPIRY_TIME = timedelta(days=4)
75HOST_REQUEST_MAX_REMINDERS = 1
76HOST_REQUEST_REMINDER_INTERVAL = timedelta(days=2)
78# Note: Javascript's string.length is in utf16 code units, Python's len(str) is in utf8 code units.
79HOST_REQUEST_MIN_LENGTH_UTF16 = 250 # Must match frontend
81ANTIBOT_FREQ = timedelta(hours=48)
83EVENT_REMINDER_TIMEDELTA = timedelta(hours=24)
85COMMUNITIES_SEARCH_FUZZY_SIMILARITY_THRESHOLD = 0.35
87# Maximum node ID considered a "global" community (excluded from some notifications and event filters)
88# Node IDs <= this value are treated as too large for email notifications, etc.
89# Currently this is just the Global Community (node_id=1)
90GLOBAL_COMMUNITY_MAX_NODE_ID = 1
92UNKNOWN_ERROR_MESSAGE = "An unknown backend error occurred. Please consider filing a bug!"
94# NOTE: these codes are on purpose not translatable
95NONEXISTENT_API_CALL_ERROR_MESSAGE = "API call does not exist. Please refresh and try again."
96MISSING_AUTH_LEVEL_ERROR_MESSAGE = "Internal authentication error."
97COOKIES_AND_AUTH_HEADER_ERROR_MESSAGE = 'Both "cookie" and "authorization" in request'
98CALL_CANCELLED_ERROR_MESSAGE = "Call cancelled."
100# NOTE: the frontend uses these (and error codes) to distinguish between jailed and logged out
101UNAUTHORIZED_ERROR_MESSAGE = "Unauthorized"
102PERMISSION_DENIED_ERROR_MESSAGE = "Permission denied"
104GHOST_USERNAME = "ghost"
106# Donation drive start date - set to None to disable donation drive banner
107# When set, users who haven't donated since this date will see a donation banner
108DONATION_DRIVE_START: datetime | None = None
110DONATION_GOAL_USD = 5000
111# exclude big donations from Aapeli + Itsi that we're hoping to do without :)
112DONATION_OFFSET_USD = 2000
114# Photo gallery limits
115GALLERY_MAX_PHOTOS_NOT_VERIFIED = 1
116GALLERY_MAX_PHOTOS_VERIFIED = 4
118COMPLETED_PROFILE_MINIMUM_CHAR_LENGTH = 150