1 # Copyright (C) 2014 Ipsilon project Contributors, for license see COPYING
3 from ipsilon.util.log import Log
12 def name_from_image(image):
16 fext = imghdr.what(None, base64.b64decode(image))
18 m.update(base64.b64decode(image))
20 return '%s.%s' % (m.hexdigest(), fext)
23 def url_from_image(image):
27 return '%s/cache/%s' % (
28 cherrypy.config.get('base.mount', ""),
29 name_from_image(image)
35 def __init__(self, name, *args):
40 if not isinstance(item, Option):
41 raise ValueError('Invalid option type for %s' % repr(item))
42 self._list.append(item.name)
43 self._dict[item.name] = item
44 self.debug('Config(%s) %s' % (self.name, self._dict))
47 return '%s: %s' % (self.__class__, ', '.join(self._list))
50 return str(self._list)
53 return len(self._list)
55 def __getitem__(self, key):
56 return self._dict[key]
58 def __setitem__(self, key, value):
59 if not isinstance(value, Option):
60 raise ValueError('Invalid type for %s' % value)
62 raise NameError('Name mismatch, key=%s but value.name=%s' % (
64 if key not in self._list:
65 self._list.append(key)
66 self._dict[key] = value
68 def __delitem__(self, key):
69 self._list.remove(key)
74 while i < len(self._list):
78 def __reversed__(self):
81 yield self._list[i - 1]
84 def __contains__(self, item):
85 return (item in self._dict)
89 while i < len(self._list):
90 yield (self._list[i], self._dict[self._list[i]])
94 return [(k, self._dict[k]) for k in self._list]
99 def __init__(self, name, description, readonly=False):
101 self.description = description
102 self._default_value = None
103 self._assigned_value = None
104 self._readonly = readonly
107 return "%s: %s {%s}, value = %s [def: %s] readonly=%s" % (
111 self._assigned_value,
116 return '%s=%s' % (self.name, self.get_value())
118 def get_value(self, default=True):
119 if self._assigned_value is not None:
120 return self._assigned_value
121 elif default is True:
122 return self._default_value
126 def set_value(self, value):
127 self._assigned_value = value
129 def export_value(self):
130 raise NotImplementedError
132 def import_value(self, value):
133 raise NotImplementedError
135 def _str_export_value(self):
136 if self._assigned_value:
137 return str(self._assigned_value)
140 def _str_import_value(self, value):
141 if not isinstance(value, str):
142 raise ValueError('Value must be string')
143 self._assigned_value = value
145 def is_readonly(self):
146 return self._readonly
149 class String(Option):
151 def __init__(self, name, description, default_value=None, readonly=False):
152 super(String, self).__init__(name, description, readonly=readonly)
153 self._default_value = str(default_value)
155 def set_value(self, value):
156 self._assigned_value = str(value)
158 def export_value(self):
159 return self._str_export_value()
161 def import_value(self, value):
162 self._str_import_value(value)
167 An image has two components: the binary blob of the image itself and
168 the SHA1 sum of the image.
170 We only need the image blob when writing to the cache file or
171 updating the database.
173 For the purposes of the UI we only need the filename which is
174 the SHA1 sum of file type the blob + file type.
177 def __init__(self, name, description, default_value=None, readonly=False):
178 super(Image, self).__init__(name, description, readonly=readonly)
182 self._image = default_value
184 self._assigned_value = url_from_image(self._image)
185 self.__write_cache_file()
187 def set_value(self, value):
191 if os.path.exists(self.__filename()):
193 os.remove(self.__filename())
195 self.error('Error removing %s: %s' % (self.__filename(), e))
197 self._image = base64.b64encode(value)
198 self._assigned_value = url_from_image(value)
200 def export_value(self):
201 if self._image is None:
204 self.__write_cache_file()
205 return base64.b64decode(self._image)
207 def import_value(self, value):
211 if os.path.exists(self.__filename()):
213 os.remove(self.__filename())
215 self.error('Error removing %s: %s' % (self.__filename(), e))
216 self._image = base64.b64encode(value)
217 self._assigned_value = url_from_image(self._image)
218 self.__write_cache_file()
220 def __filename(self):
221 if self._image is None:
224 cdir = cherrypy.config.get('cache_dir', '/var/cache/ipsilon')
226 return '%s/%s' % (cdir, name_from_image(self._image))
228 def __write_cache_file(self):
229 if self._image is None:
232 if not os.path.exists(self.__filename()):
233 with open(self.__filename(), 'w') as imagefile:
234 imagefile.write(base64.b64decode(self._image))
237 class Template(Option):
239 def __init__(self, name, description, default_template=None,
241 super(Template, self).__init__(name, description, readonly=readonly)
242 self._default_value = str(default_template)
244 def set_value(self, value):
245 self._assigned_value = str(value)
247 def templatize(self, args):
249 raise ValueError('Templatized called w/o arguments')
251 return self.get_value() % args
253 def export_value(self):
254 return self._str_export_value()
256 def import_value(self, value):
257 self._str_import_value(value)
262 def __init__(self, name, description, default_list=None, readonly=False):
263 super(List, self).__init__(name, description, readonly=readonly)
265 self._default_value = default_list
267 self._default_value = []
269 def set_value(self, value):
270 self._assigned_value = list(value)
272 def export_value(self):
273 if self._assigned_value:
274 return ','.join(self._assigned_value)
277 def import_value(self, value):
278 if not isinstance(value, str):
279 raise ValueError('Value (type: %s) must be string' % type(value))
280 self._assigned_value = [x.strip() for x in value.split(',')]
283 class ComplexList(List):
285 def _check_value(self, value):
288 if not isinstance(value, list):
289 raise ValueError('The value type must be a list, not "%s"' %
292 def set_value(self, value):
293 self._check_value(value)
294 self._assigned_value = value
296 def export_value(self):
297 if self._assigned_value:
298 return json.dumps(self._assigned_value)
301 def import_value(self, value):
302 if not isinstance(value, str):
303 raise ValueError('The value type must be a string, not "%s"' %
305 jsonval = json.loads(value)
306 self.set_value(jsonval)
309 class MappingList(ComplexList):
311 def _check_value(self, value):
314 if not isinstance(value, list):
315 raise ValueError('The value type must be a list, not "%s"' %
318 if not isinstance(v, list):
319 raise ValueError('Each element must be a list, not "%s"' %
322 raise ValueError('Each element must contain 2 values,'
325 def import_value(self, value):
326 if not isinstance(value, str):
327 raise ValueError('Value (type: %s) must be string' % type(value))
328 jsonval = json.loads(value)
329 self.set_value(jsonval)
332 class Choice(Option):
334 def __init__(self, name, description, allowed=None, default=None,
336 super(Choice, self).__init__(name, description, readonly=readonly)
338 self._allowed_values = list(allowed)
340 self._allowed_values = list()
341 self._default_value = list()
345 if name not in self._allowed_values:
347 'item [%s] is not in allowed [%s]' % (name, allowed))
348 self._default_value.append(name)
351 return "%s: %s {%s}, values = %s d:%s ok:%s" % (self.__class__,
354 self._assigned_value,
356 self._allowed_values)
359 return '%s=%s' % (self.name, self.get_value())
361 def set_value(self, value):
362 if not isinstance(value, list):
364 self._assigned_value = list()
366 if val not in self._allowed_values:
368 'Value "%s" not allowed [%s]' % (val,
369 self._allowed_values))
370 self._assigned_value.append(val)
372 if not self._assigned_value:
373 self._assigned_value = None
375 def unset_value(self, value):
376 if isinstance(value, str):
380 unset.append((val, False))
381 self.set_value(unset)
383 def get_allowed(self):
384 return self._allowed_values
386 def export_value(self):
387 enabled = self.get_value()
388 return ', '.join(enabled)
390 def import_value(self, value):
391 enabled = [x.strip() for x in value.split(',')]
393 if self._assigned_value is None:
394 self._assigned_value = list()
396 if val not in self._allowed_values:
397 # We silently ignore invalid options on import for now
399 self._assigned_value.append(val)
404 def __init__(self, name, description, allowed, default_value,
406 super(Pick, self).__init__(name, description, readonly=readonly)
407 self._allowed_values = list(allowed)
408 if default_value not in self._allowed_values:
409 raise ValueError('The default value is not in the allowed list')
410 self._default_value = default_value
412 def set_value(self, value):
413 if value not in self._allowed_values:
415 'Value "%s" not allowed [%s]' % (value, self._allowed_values))
416 self._assigned_value = value
418 def get_allowed(self):
419 return self._allowed_values
421 def export_value(self):
422 return self._str_export_value()
424 def import_value(self, value):
425 self._str_import_value(value)
428 class Condition(Pick):
430 def __init__(self, name, description, default_value=False,
432 # The db stores 1/0. Convert the passed-in value if
434 if default_value in [u'1', 'True', True]:
437 default_value = False
438 super(Condition, self).__init__(name, description,
439 [True, False], default_value,
442 def import_value(self, value):
443 self._assigned_value = value
446 class ConfigHelper(Log):
451 def new_config(self, name, *config_args):
452 self._config = Config(name, *config_args)
454 def get_config_obj(self):
455 if self._config is None:
456 raise AttributeError('Config not initialized')
459 def import_config(self, config):
461 raise AttributeError('Config not initialized, cannot import')
463 for key, value in config.iteritems():
464 if key in self._config:
465 self._config[key].import_value(str(value))
467 def export_config(self):
469 for name, option in self._config.iteritems():
470 config[name] = option.export_value()
473 def get_config_value(self, name):
475 raise AttributeError('Config not initialized')
476 return self._config[name].get_value()
478 def set_config_value(self, name, value):
480 raise AttributeError('Config not initialized')
481 return self._config[name].set_value(value)