Coverage for config.py: 97%

71 statements  

« prev     ^ index     » next       coverage.py v7.9.1, created at 2025-06-14 23:13 +0000

1# -*- coding: utf-8 -*- 

2""" 

3Configuration overrides for settings.py 

4""" 

5 

6import os 

7import sys 

8from django.urls import reverse_lazy 

9from django.utils.translation import gettext_lazy as _ 

10from django.contrib.messages import constants as message_constants 

11from ivatar.settings import BASE_DIR 

12 

13from ivatar.settings import MIDDLEWARE 

14from ivatar.settings import INSTALLED_APPS 

15from ivatar.settings import TEMPLATES 

16 

17ADMIN_USERS = [] 

18ALLOWED_HOSTS = ["*"] 

19 

20INSTALLED_APPS.extend( 

21 [ 

22 "django_extensions", 

23 "django_openid_auth", 

24 "bootstrap4", 

25 "anymail", 

26 "ivatar", 

27 "ivatar.ivataraccount", 

28 "ivatar.tools", 

29 ] 

30) 

31 

32MIDDLEWARE.extend( 

33 [ 

34 "django.middleware.locale.LocaleMiddleware", 

35 ] 

36) 

37MIDDLEWARE.insert( 

38 0, 

39 "ivatar.middleware.MultipleProxyMiddleware", 

40) 

41 

42AUTHENTICATION_BACKENDS = ( 

43 # Enable this to allow LDAP authentication. 

44 # See INSTALL for more information. 

45 # 'django_auth_ldap.backend.LDAPBackend', 

46 "django_openid_auth.auth.OpenIDBackend", 

47 "ivatar.ivataraccount.auth.FedoraOpenIdConnect", 

48 "django.contrib.auth.backends.ModelBackend", 

49) 

50 

51TEMPLATES[0]["DIRS"].extend( 

52 [ 

53 os.path.join(BASE_DIR, "templates"), 

54 ] 

55) 

56TEMPLATES[0]["OPTIONS"]["context_processors"].append( 

57 "ivatar.context_processors.basepage", 

58) 

59 

60OPENID_CREATE_USERS = True 

61OPENID_UPDATE_DETAILS_FROM_SREG = True 

62SOCIAL_AUTH_JSONFIELD_ENABLED = True 

63# Fedora authentication (OIDC). You need to set these two values to use it. 

64SOCIAL_AUTH_FEDORA_KEY = None # Also known as client_id 

65SOCIAL_AUTH_FEDORA_SECRET = None # Also known as client_secret 

66 

67SITE_NAME = os.environ.get("SITE_NAME", "libravatar") 

68IVATAR_VERSION = "1.8.0" 

69 

70SCHEMAROOT = "https://www.libravatar.org/schemas/export/0.2" 

71 

72SECURE_BASE_URL = os.environ.get( 

73 "SECURE_BASE_URL", "https://avatars.linux-kernel.at/avatar/" 

74) 

75BASE_URL = os.environ.get("BASE_URL", "http://avatars.linux-kernel.at/avatar/") 

76 

77LOGIN_REDIRECT_URL = reverse_lazy("profile") 

78MAX_LENGTH_EMAIL = 254 # http://stackoverflow.com/questions/386294 

79 

80MAX_NUM_PHOTOS = 5 

81MAX_NUM_UNCONFIRMED_EMAILS = 5 

82MAX_PHOTO_SIZE = 10485760 # in bytes 

83MAX_PIXELS = 7000 

84AVATAR_MAX_SIZE = 512 

85JPEG_QUALITY = 85 

86 

87# I'm not 100% sure if single character domains are possible 

88# under any tld... so MIN_LENGTH_EMAIL/_URL, might be +1 

89MIN_LENGTH_URL = 11 # eg. http://a.io 

90MAX_LENGTH_URL = 255 # MySQL can't handle more than that (LP: 1018682) 

91MIN_LENGTH_EMAIL = 6 # eg. x@x.xx 

92MAX_LENGTH_EMAIL = 254 # http://stackoverflow.com/questions/386294 

93 

94BOOTSTRAP4 = { 

95 "include_jquery": False, 

96 "javascript_in_head": False, 

97 "css_url": { 

98 "href": "/static/css/bootstrap.min.css", 

99 "integrity": "sha384-WskhaSGFgHYWDcbwN70/dfYBj47jz9qbsMId/iRN3ewGhXQFZCSftd1LZCfmhktB", 

100 "crossorigin": "anonymous", 

101 }, 

102 "javascript_url": { 

103 "url": "/static/js/bootstrap.min.js", 

104 "integrity": "", 

105 "crossorigin": "anonymous", 

106 }, 

107 "popper_url": { 

108 "url": "/static/js/popper.min.js", 

109 "integrity": "sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49", 

110 "crossorigin": "anonymous", 

111 }, 

112} 

113 

114if "EMAIL_BACKEND" in os.environ: 

115 EMAIL_BACKEND = os.environ["EMAIL_BACKEND"] # pragma: no cover 

116else: 

117 if "test" in sys.argv or "collectstatic" in sys.argv: 

118 EMAIL_BACKEND = "django.core.mail.backends.locmem.EmailBackend" 

119 else: 

120 try: 

121 ANYMAIL = { # pragma: no cover 

122 "MAILGUN_API_KEY": os.environ["IVATAR_MAILGUN_API_KEY"], 

123 "MAILGUN_SENDER_DOMAIN": os.environ["IVATAR_MAILGUN_SENDER_DOMAIN"], 

124 } 

125 EMAIL_BACKEND = "anymail.backends.mailgun.EmailBackend" # pragma: no cover 

126 except Exception: # pragma: nocover # pylint: disable=broad-except 

127 EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend" 

128 

129SERVER_EMAIL = os.environ.get("SERVER_EMAIL", "ivatar@mg.linux-kernel.at") 

130DEFAULT_FROM_EMAIL = os.environ.get("DEFAULT_FROM_EMAIL", "ivatar@mg.linux-kernel.at") 

131 

132try: 

133 from ivatar.settings import DATABASES 

134except ImportError: # pragma: no cover 

135 DATABASES = [] # pragma: no cover 

136 

137if "default" not in DATABASES: 

138 DATABASES["default"] = { # pragma: no cover 

139 "ENGINE": "django.db.backends.sqlite3", 

140 "NAME": os.path.join(BASE_DIR, "db.sqlite3"), 

141 } 

142 

143if "MYSQL_DATABASE" in os.environ: 

144 DATABASES["default"] = { # pragma: no cover 

145 "ENGINE": "django.db.backends.mysql", 

146 "NAME": os.environ["MYSQL_DATABASE"], 

147 "USER": os.environ["MYSQL_USER"], 

148 "PASSWORD": os.environ["MYSQL_PASSWORD"], 

149 "HOST": "mysql", 

150 } 

151 

152if "POSTGRESQL_DATABASE" in os.environ: 

153 DATABASES["default"] = { # pragma: no cover 

154 "ENGINE": "django.db.backends.postgresql", 

155 "NAME": os.environ["POSTGRESQL_DATABASE"], 

156 "USER": os.environ["POSTGRESQL_USER"], 

157 "PASSWORD": os.environ["POSTGRESQL_PASSWORD"], 

158 "HOST": "postgresql", 

159 } 

160 

161# CI/CD config has different naming 

162if "POSTGRES_DB" in os.environ: 

163 DATABASES["default"] = { # pragma: no cover 

164 "ENGINE": "django.db.backends.postgresql", 

165 "NAME": os.environ["POSTGRES_DB"], 

166 "USER": os.environ["POSTGRES_USER"], 

167 "PASSWORD": os.environ["POSTGRES_PASSWORD"], 

168 "HOST": os.environ["POSTGRES_HOST"], 

169 "TEST": { 

170 "NAME": os.environ["POSTGRES_DB"], 

171 }, 

172 } 

173 

174SESSION_SERIALIZER = "django.contrib.sessions.serializers.JSONSerializer" 

175 

176USE_X_FORWARDED_HOST = True 

177ALLOWED_EXTERNAL_OPENID_REDIRECT_DOMAINS = [ 

178 "avatars.linux-kernel.at", 

179 "localhost", 

180] 

181 

182DEFAULT_AVATAR_SIZE = 80 

183 

184LANGUAGES = ( 

185 ("de", _("Deutsch")), 

186 ("en", _("English")), 

187 ("ca", _("Català")), 

188 ("cs", _("Česky")), 

189 ("es", _("Español")), 

190 ("eu", _("Basque")), 

191 ("fr", _("Français")), 

192 ("it", _("Italiano")), 

193 ("ja", _("日本語")), 

194 ("nl", _("Nederlands")), 

195 ("pt", _("Português")), 

196 ("ru", _("Русский")), 

197 ("sq", _("Shqip")), 

198 ("tr", _("Türkçe")), 

199 ("uk", _("Українська")), 

200) 

201 

202MESSAGE_TAGS = { 

203 message_constants.DEBUG: "debug", 

204 message_constants.INFO: "info", 

205 message_constants.SUCCESS: "success", 

206 message_constants.WARNING: "warning", 

207 message_constants.ERROR: "danger", 

208} 

209 

210CACHES = { 

211 "default": { 

212 "BACKEND": "django.core.cache.backends.memcached.PyMemcacheCache", 

213 "LOCATION": [ 

214 "127.0.0.1:11211", 

215 ], 

216 }, 

217 "filesystem": { 

218 "BACKEND": "django.core.cache.backends.filebased.FileBasedCache", 

219 "LOCATION": "/var/tmp/ivatar_cache", 

220 "TIMEOUT": 900, # 15 minutes 

221 }, 

222} 

223 

224# This is 5 minutes caching for generated/resized images, 

225# so the sites don't hit ivatar so much - it's what's set in the HTTP header 

226CACHE_IMAGES_MAX_AGE = 5 * 60 

227 

228CACHE_RESPONSE = True 

229 

230# Trusted URLs for default redirection 

231TRUSTED_DEFAULT_URLS = [ 

232 {"schemes": ["https"], "host_equals": "ui-avatars.com", "path_prefix": "/api/"}, 

233 { 

234 "schemes": ["http", "https"], 

235 "host_equals": "gravatar.com", 

236 "path_prefix": "/avatar/", 

237 }, 

238 { 

239 "schemes": ["http", "https"], 

240 "host_suffix": ".gravatar.com", 

241 "path_prefix": "/avatar/", 

242 }, 

243 { 

244 "schemes": ["http", "https"], 

245 "host_equals": "www.gravatar.org", 

246 "path_prefix": "/avatar/", 

247 }, 

248 { 

249 "schemes": ["https"], 

250 "host_equals": "avatars.dicebear.com", 

251 "path_prefix": "/api/", 

252 }, 

253 { 

254 "schemes": ["https"], 

255 "host_equals": "api.dicebear.com", 

256 "path_prefix": "/", 

257 }, 

258 { 

259 "schemes": ["https"], 

260 "host_equals": "badges.fedoraproject.org", 

261 "path_prefix": "/static/img/", 

262 }, 

263 { 

264 "schemes": ["http"], 

265 "host_equals": "www.planet-libre.org", 

266 "path_prefix": "/themes/planetlibre/images/", 

267 }, 

268 {"schemes": ["https"], "host_equals": "www.azuracast.com", "path_prefix": "/img/"}, 

269 { 

270 "schemes": ["https"], 

271 "host_equals": "reps.mozilla.org", 

272 "path_prefix": "/static/base/img/remo/", 

273 }, 

274] 

275 

276URL_TIMEOUT = 10 

277 

278 

279def map_legacy_config(trusted_url): 

280 """ 

281 For backward compability with the legacy configuration 

282 for trusting URLs. Adapts them to fit the new config. 

283 """ 

284 if isinstance(trusted_url, str): 

285 return {"url_prefix": trusted_url} 

286 

287 return trusted_url 

288 

289 

290# Backward compability for legacy behavior 

291TRUSTED_DEFAULT_URLS = list(map(map_legacy_config, TRUSTED_DEFAULT_URLS)) 

292 

293# Bluesky settings 

294BLUESKY_IDENTIFIER = os.environ.get("BLUESKY_IDENTIFIER", None) 

295BLUESKY_APP_PASSWORD = os.environ.get("BLUESKY_APP_PASSWORD", None) 

296 

297# This MUST BE THE LAST! 

298if os.path.isfile(os.path.join(BASE_DIR, "config_local.py")): 

299 from config_local import * # noqa # flake8: noqa # NOQA # pragma: no cover