Coverage for extras/constants.py: 100%

14 statements  

« prev     ^ index     » next       coverage.py v7.15.2, created at 2026-10-10 18:35 +0000

1from jinja2 import ChainableUndefined, DebugUndefined, StrictUndefined, Undefined 

2 

3from core.events import * 

4from extras.choices import LogLevelChoices 

5 

6# Custom fields 

7CUSTOMFIELD_EMPTY_VALUES = (None, '', []) 

8 

9# Timeout (in seconds) applied to the background jobs which provision and purge custom field data. 

10# These jobs exist precisely because the work is too large for the request which triggered it, so 

11# the default RQ timeout -- being of the same order as the request timeout being escaped -- would 

12# reimpose the limit they were introduced to avoid. A timeout is recoverable, as each job commits 

13# its batches independently and both are idempotent, but it leaves the field pending until the job 

14# is run again. Three hours is well beyond what a batched update of any real table takes, while 

15# still releasing a worker blocked on an unresponsive database. 

16CUSTOMFIELD_JOB_TIMEOUT = 10800 

17 

18# ImageAttachment 

19IMAGE_ATTACHMENT_IMAGE_FORMATS = { 

20 'avif': 'image/avif', 

21 'bmp': 'image/bmp', 

22 'gif': 'image/gif', 

23 'jpeg': 'image/jpeg', 

24 'jpg': 'image/jpeg', 

25 'png': 'image/png', 

26 'webp': 'image/webp', 

27} 

28 

29# Template Export 

30DEFAULT_MIME_TYPE = 'text/plain; charset=utf-8' 

31 

32# Scripts 

33# Prefix applied to dynamically-loaded script/report module names so that a script whose filename 

34# matches a core app or package (e.g. "circuits.py") cannot shadow it in sys.modules. 

35SCRIPT_MODULE_NAME_PREFIX = '_netbox_script_module_' 

36 

37# Webhooks 

38HTTP_CONTENT_TYPE_JSON = 'application/json' 

39 

40WEBHOOK_EVENT_TYPES = { 

41 # Map registered event types to public webhook "event" equivalents 

42 OBJECT_CREATED: 'created', 

43 OBJECT_UPDATED: 'updated', 

44 OBJECT_DELETED: 'deleted', 

45 JOB_STARTED: 'job_started', 

46 JOB_COMPLETED: 'job_ended', 

47 JOB_FAILED: 'job_ended', 

48 JOB_ERRORED: 'job_ended', 

49} 

50 

51# Allowed Jinja2 environment parameters and their permitted values. 

52# Only keys listed here may appear in a template's environment_params. 

53# None = any JSON-serializable value accepted (scalars, booleans, etc.) 

54# dict = only dict keys accepted; dict values are the resolved Python objects 

55# 

56# Note: 'finalize' is intentionally absent. It is deprecated and handled as a 

57# legacy carve-out in RenderTemplateMixin (blocked from new use, but existing 

58# stored values continue to resolve via import_string at render time). 

59JINJA_ENV_PARAMS_ALLOWED = { 

60 # Boolean / scalar params (accept any JSON-serializable value) 

61 'auto_reload': None, 

62 'autoescape': None, 

63 'cache_size': None, 

64 'enable_async': None, 

65 'keep_trailing_newline': None, 

66 'lstrip_blocks': None, 

67 'optimized': None, 

68 'trim_blocks': None, 

69 # String params (template syntax delimiters) 

70 'block_start_string': None, 

71 'block_end_string': None, 

72 'comment_start_string': None, 

73 'comment_end_string': None, 

74 'line_comment_prefix': None, 

75 'line_statement_prefix': None, 

76 'newline_sequence': None, 

77 'variable_start_string': None, 

78 'variable_end_string': None, 

79 # Mapped params (value must be a key in the dict; resolved to the dict value) 

80 'undefined': { 

81 'jinja2.ChainableUndefined': ChainableUndefined, 

82 'jinja2.DebugUndefined': DebugUndefined, 

83 'jinja2.StrictUndefined': StrictUndefined, 

84 'jinja2.Undefined': Undefined, 

85 }, 

86 # Excluded (dangerous — accept callables or trigger imports): 

87 # 'bytecode_cache' — accepts arbitrary object 

88 # 'extensions' — Jinja2 internally calls import_string() on string entries 

89 # 'finalize' — deprecated; legacy carve-out in RenderTemplateMixin 

90 # 'loader' — accepts arbitrary object 

91} 

92 

93# Dashboard 

94DEFAULT_DASHBOARD = [ 

95 { 

96 'widget': 'extras.BookmarksWidget', 

97 'width': 4, 

98 'height': 5, 

99 'title': 'Bookmarks', 

100 'color': 'orange', 

101 }, 

102 { 

103 'widget': 'extras.ObjectCountsWidget', 

104 'width': 4, 

105 'height': 2, 

106 'title': 'Organization', 

107 'config': { 

108 'models': [ 

109 'dcim.site', 

110 'tenancy.tenant', 

111 'tenancy.contact', 

112 ] 

113 } 

114 }, 

115 { 

116 'widget': 'extras.NoteWidget', 

117 'width': 4, 

118 'height': 2, 

119 'title': 'Welcome!', 

120 'color': 'green', 

121 'config': { 

122 'content': ( 

123 'This is your personal dashboard. Feel free to customize it by rearranging, resizing, or removing ' 

124 'widgets. You can also add new widgets using the "add widget" button below. Any changes affect only ' 

125 '_your_ dashboard, so feel free to experiment!' 

126 ) 

127 } 

128 }, 

129 { 

130 'widget': 'extras.ObjectCountsWidget', 

131 'width': 4, 

132 'height': 3, 

133 'title': 'IPAM', 

134 'config': { 

135 'models': [ 

136 'ipam.vrf', 

137 'ipam.aggregate', 

138 'ipam.prefix', 

139 'ipam.iprange', 

140 'ipam.ipaddress', 

141 'ipam.vlan', 

142 ] 

143 } 

144 }, 

145 { 

146 'widget': 'extras.RSSFeedWidget', 

147 'width': 4, 

148 'height': 4, 

149 'title': 'NetBox News', 

150 'config': { 

151 'feed_url': 'https://api.netbox.oss.netboxlabs.com/v1/newsfeed/', 

152 'max_entries': 10, 

153 'cache_timeout': 14400, 

154 'requires_internet': True, 

155 } 

156 }, 

157 { 

158 'widget': 'extras.ObjectCountsWidget', 

159 'width': 4, 

160 'height': 3, 

161 'title': 'Circuits', 

162 'config': { 

163 'models': [ 

164 'circuits.provider', 

165 'circuits.circuit', 

166 'circuits.providernetwork', 

167 'circuits.provideraccount', 

168 ] 

169 } 

170 }, 

171 { 

172 'widget': 'extras.ObjectCountsWidget', 

173 'width': 4, 

174 'height': 3, 

175 'title': 'DCIM', 

176 'config': { 

177 'models': [ 

178 'dcim.site', 

179 'dcim.rack', 

180 'dcim.devicetype', 

181 'dcim.device', 

182 'dcim.cable', 

183 ], 

184 } 

185 }, 

186 { 

187 'widget': 'extras.ObjectCountsWidget', 

188 'width': 4, 

189 'height': 2, 

190 'title': 'Virtualization', 

191 'config': { 

192 'models': [ 

193 'virtualization.cluster', 

194 'virtualization.virtualmachine', 

195 ] 

196 } 

197 }, 

198 { 

199 'widget': 'extras.ObjectListWidget', 

200 'width': 12, 

201 'height': 5, 

202 'title': 'Change Log', 

203 'color': 'blue', 

204 'config': { 

205 'model': 'core.objectchange', 

206 'page_size': 25, 

207 } 

208 }, 

209] 

210 

211LOG_LEVEL_RANK = { 

212 LogLevelChoices.LOG_DEBUG: 0, 

213 LogLevelChoices.LOG_INFO: 1, 

214 LogLevelChoices.LOG_SUCCESS: 2, 

215 LogLevelChoices.LOG_WARNING: 3, 

216 LogLevelChoices.LOG_FAILURE: 4, 

217} 

218 

219# Config context cache: fields whose modification on an object requires re-rendering its config 

220# context cache, keyed by model label. 

221CC_FIELDS_BY_MODEL = { 

222 'dcim.device': ( 

223 'site_id', 'location_id', 'device_type_id', 'role_id', 'tenant_id', 'platform_id', 

224 'cluster_id', 'local_context_data', 

225 ), 

226 'virtualization.virtualmachine': ( 

227 'site_id', 'cluster_id', 'tenant_id', 'platform_id', 'role_id', 'local_context_data', 

228 ), 

229}