Coverage for src/mesh/app_settings.py: 75%

51 statements  

« prev     ^ index     » next       coverage.py v7.7.0, created at 2025-04-28 07:45 +0000

1import os 

2from datetime import timedelta 

3from enum import Enum, unique 

4from typing import Any 

5 

6from django.conf import settings 

7from django.core.exceptions import ImproperlyConfigured 

8 

9 

10@unique 

11class BlindMode(Enum): 

12 NO_BLIND = "no_blind" 

13 SINGLE_BLIND = "single_blind" 

14 DOUBLE_BLIND = "double_blind" 

15 

16 

17class AppSettings: 

18 """Wrapper for django settings related to this application.""" 

19 

20 REQUIRED_SETTINGS = ["FILES_DIRECTORY"] 

21 

22 def __init__(self): 

23 self.prefix = "MESH_" 

24 for setting in self.REQUIRED_SETTINGS: 

25 if self._setting(setting, "__NOT_CONFIGURED__") == "__NOT_CONFIGURED__": 25 ↛ 26line 25 didn't jump to line 26 because the condition on line 25 was never true

26 raise ImproperlyConfigured( 

27 f"`mesh` - You must set the following setting(s): {setting}" 

28 ) 

29 if not os.path.isdir(self.FILES_DIRECTORY): 29 ↛ exitline 29 didn't return from function '__init__' because the condition on line 29 was always true

30 try: 

31 os.makedirs(self.FILES_DIRECTORY, mode=511) 

32 except OSError: 

33 raise ImproperlyConfigured( 

34 f"`mesh` - The provided FILES_DIRECTORY is not an accessible directory and cannot be created automatically: {self.FILES_DIRECTORY}" 

35 ) 

36 

37 def _setting(self, name: str, default: Any = None): 

38 """ 

39 Gets the provided setting with the app prefix (see `self.prefix`). 

40 

41 Params: 

42 - `name`: The name of the setting. 

43 - `default`: Fallback if the settings is not defined. 

44 """ 

45 return getattr(settings, self.prefix + name, default) 

46 

47 @property 

48 def ENABLED_ROLES(self) -> list[str]: 

49 """ 

50 List of role codes enabled for this application. 

51 Defaults to `["author", "journal_manager"]`. 

52 """ 

53 return self._setting("ENABLED_ROLES", ["author", "reviewer", "editor", "journal_manager"]) 

54 

55 @property 

56 def BLIND_MODE(self) -> BlindMode: 

57 """ 

58 Return the blind mode of the application. 

59 """ 

60 blind_mode = self._setting("BLIND_MODE", BlindMode.SINGLE_BLIND.value) 

61 try: 

62 return BlindMode(blind_mode) 

63 except ValueError: 

64 raise ImproperlyConfigured( 

65 f"Invalid setting value for BLIND_MODE: {blind_mode}. " 

66 f"Available values are: {[b.value for b in BlindMode]}." 

67 ) 

68 

69 @property 

70 def FILES_DIRECTORY(self) -> str: 

71 """ 

72 Directory used to store all user files. 

73 Files are served using django-sendfile package (XSendFile with Apache). 

74 This should lie outside of Django directory. 

75 The directory is automatically created on startup if required. 

76 """ 

77 return self._setting("FILES_DIRECTORY") 

78 

79 @property 

80 def USER_TOKEN_EXPIRATION_DAYS(self) -> timedelta: 

81 """ 

82 Expiration time (in days) when an user token is delivered. 

83 """ 

84 return timedelta(days=self._setting("USER_TOKEN_EXPIRATION_DAYS", 180)) 

85 

86 @property 

87 def EMAIL_PREFIX(self) -> str: 

88 """ 

89 Prefix for every e-mail manually sent by the MESH application. 

90 Defaults to `[MESH] `. 

91 """ 

92 prefix = self._setting("EMAIL_PREFIX", "[MESH] ") 

93 if prefix[-1] != " ": 

94 prefix = f"{prefix} " 

95 return prefix 

96 

97 @property 

98 def JOURNAL_EMAIL_CONTACT(self) -> str: 

99 return self._setting("JOURNAL_EMAIL_CONTACT", "") 

100 

101 

102app_settings = AppSettings()