Mark the service as readonly in the UI in authpam plugin
[cascardo/ipsilon.git] / ipsilon / util / config.py
1 # Copyright (C) 2014 Ipsilon project Contributors, for license see COPYING
2
3 from ipsilon.util.log import Log
4 import json
5
6
7 class Config(Log):
8
9     def __init__(self, name, *args):
10         self.name = name
11         self._list = list()
12         self._dict = dict()
13         for item in args:
14             if not isinstance(item, Option):
15                 raise ValueError('Invalid option type for %s' % repr(item))
16             self._list.append(item.name)
17             self._dict[item.name] = item
18         self.debug('Config(%s) %s' % (self.name, self._dict))
19
20     def __repr__(self):
21         return '%s: %s' % (self.__class__, ', '.join(self._list))
22
23     def __str__(self):
24         return str(self._list)
25
26     def __len__(self):
27         return len(self._list)
28
29     def __getitem__(self, key):
30         return self._dict[key]
31
32     def __setitem__(self, key, value):
33         if not isinstance(value, Option):
34             raise ValueError('Invalid type for %s' % value)
35         if key != value.name:
36             raise NameError('Name mismatch, key=%s but value.name=%s' % (
37                 key, value.name))
38         if key not in self._list:
39             self._list.append(key)
40         self._dict[key] = value
41
42     def __delitem__(self, key):
43         self._list.remove(key)
44         del self._dict[key]
45
46     def __iter__(self):
47         i = 0
48         while i < len(self._list):
49             yield self._list[i]
50             i += 1
51
52     def __reversed__(self):
53         i = len(self._list)
54         while i > 0:
55             yield self._list[i - 1]
56             i -= 1
57
58     def __contains__(self, item):
59         return (item in self._dict)
60
61     def iteritems(self):
62         i = 0
63         while i < len(self._list):
64             yield (self._list[i], self._dict[self._list[i]])
65             i += 1
66
67     def items(self):
68         return [(k, self._dict[k]) for k in self._list]
69
70
71 class Option(Log):
72
73     def __init__(self, name, description, readonly=False):
74         self.name = name
75         self.description = description
76         self._default_value = None
77         self._assigned_value = None
78         self._readonly = readonly
79
80     def __repr__(self):
81         return "%s: %s {%s}, value = %s [def: %s] readonly=%s" % (
82             self.__class__,
83             self.name,
84             self.description,
85             self._assigned_value,
86             self._default_value,
87             self._readonly)
88
89     def __str__(self):
90         return '%s=%s' % (self.name, self.get_value())
91
92     def get_value(self, default=True):
93         if self._assigned_value is not None:
94             return self._assigned_value
95         elif default is True:
96             return self._default_value
97         else:
98             return None
99
100     def set_value(self, value):
101         self._assigned_value = value
102
103     def export_value(self):
104         raise NotImplementedError
105
106     def import_value(self, value):
107         raise NotImplementedError
108
109     def _str_export_value(self):
110         if self._assigned_value:
111             return str(self._assigned_value)
112         return None
113
114     def _str_import_value(self, value):
115         if not isinstance(value, str):
116             raise ValueError('Value must be string')
117         self._assigned_value = value
118
119     def is_readonly(self):
120         return self._readonly
121
122
123 class String(Option):
124
125     def __init__(self, name, description, default_value=None, readonly=False):
126         super(String, self).__init__(name, description, readonly=readonly)
127         self._default_value = str(default_value)
128
129     def set_value(self, value):
130         self._assigned_value = str(value)
131
132     def export_value(self):
133         return self._str_export_value()
134
135     def import_value(self, value):
136         self._str_import_value(value)
137
138
139 class Template(Option):
140
141     def __init__(self, name, description, default_template=None,
142                  readonly=False):
143         super(Template, self).__init__(name, description, readonly=readonly)
144         self._default_value = str(default_template)
145
146     def set_value(self, value):
147         self._assigned_value = str(value)
148
149     def templatize(self, args):
150         if not args:
151             raise ValueError('Templatized called w/o arguments')
152
153         return self.get_value() % args
154
155     def export_value(self):
156         return self._str_export_value()
157
158     def import_value(self, value):
159         self._str_import_value(value)
160
161
162 class List(Option):
163
164     def __init__(self, name, description, default_list=None, readonly=False):
165         super(List, self).__init__(name, description, readonly=readonly)
166         if default_list:
167             self._default_value = default_list
168         else:
169             self._default_value = []
170
171     def set_value(self, value):
172         self._assigned_value = list(value)
173
174     def export_value(self):
175         if self._assigned_value:
176             return ','.join(self._assigned_value)
177         return None
178
179     def import_value(self, value):
180         if not isinstance(value, str):
181             raise ValueError('Value (type: %s) must be string' % type(value))
182         self._assigned_value = [x.strip() for x in value.split(',')]
183
184
185 class ComplexList(List):
186
187     def _check_value(self, value):
188         if value is None:
189             return
190         if not isinstance(value, list):
191             raise ValueError('The value type must be a list, not "%s"' %
192                              type(value))
193
194     def set_value(self, value):
195         self._check_value(value)
196         self._assigned_value = value
197
198     def export_value(self):
199         if self._assigned_value:
200             return json.dumps(self._assigned_value)
201         return None
202
203     def import_value(self, value):
204         if not isinstance(value, str):
205             raise ValueError('The value type must be a string, not "%s"' %
206                              type(value))
207         jsonval = json.loads(value)
208         self.set_value(jsonval)
209
210
211 class MappingList(ComplexList):
212
213     def _check_value(self, value):
214         if value is None:
215             return
216         if not isinstance(value, list):
217             raise ValueError('The value type must be a list, not "%s"' %
218                              type(value))
219         for v in value:
220             if not isinstance(v, list):
221                 raise ValueError('Each element must be a list, not "%s"' %
222                                  type(v))
223             if len(v) != 2:
224                 raise ValueError('Each element must contain 2 values,'
225                                  ' not %d' % len(v))
226
227     def import_value(self, value):
228         if not isinstance(value, str):
229             raise ValueError('Value (type: %s) must be string' % type(value))
230         jsonval = json.loads(value)
231         self.set_value(jsonval)
232
233
234 class Choice(Option):
235
236     def __init__(self, name, description, allowed=None, default=None,
237                  readonly=False):
238         super(Choice, self).__init__(name, description, readonly=readonly)
239         if allowed:
240             self._allowed_values = list(allowed)
241         else:
242             self._allowed_values = list()
243         self._default_value = list()
244         if default is None:
245             default = []
246         for name in default:
247             if name not in self._allowed_values:
248                 raise ValueError(
249                     'item [%s] is not in allowed [%s]' % (name, allowed))
250             self._default_value.append(name)
251
252     def __repr__(self):
253         return "%s: %s {%s}, values = %s d:%s ok:%s" % (self.__class__,
254                                                         self.name,
255                                                         self.description,
256                                                         self._assigned_value,
257                                                         self._default_value,
258                                                         self._allowed_values)
259
260     def __str__(self):
261         return '%s=%s' % (self.name, self.get_value())
262
263     def set_value(self, value):
264         if not isinstance(value, list):
265             value = [value]
266         self._assigned_value = list()
267         for val in value:
268             if val not in self._allowed_values:
269                 raise ValueError(
270                     'Value "%s" not allowed [%s]' % (val,
271                                                      self._allowed_values))
272             self._assigned_value.append(val)
273
274         if not self._assigned_value:
275             self._assigned_value = None
276
277     def unset_value(self, value):
278         if isinstance(value, str):
279             value = [value]
280         unset = list()
281         for val in value:
282             unset.append((val, False))
283         self.set_value(unset)
284
285     def get_allowed(self):
286         return self._allowed_values
287
288     def export_value(self):
289         enabled = self.get_value()
290         return ', '.join(enabled)
291
292     def import_value(self, value):
293         enabled = [x.strip() for x in value.split(',')]
294         if enabled:
295             if self._assigned_value is None:
296                 self._assigned_value = list()
297         for val in enabled:
298             if val not in self._allowed_values:
299                 # We silently ignore invalid options on import for now
300                 continue
301             self._assigned_value.append(val)
302
303
304 class Pick(Option):
305
306     def __init__(self, name, description, allowed, default_value,
307                  readonly=False):
308         super(Pick, self).__init__(name, description, readonly=readonly)
309         self._allowed_values = list(allowed)
310         if default_value not in self._allowed_values:
311             raise ValueError('The default value is not in the allowed list')
312         self._default_value = default_value
313
314     def set_value(self, value):
315         if value not in self._allowed_values:
316             raise ValueError(
317                 'Value "%s" not allowed [%s]' % (value, self._allowed_values))
318         self._assigned_value = value
319
320     def get_allowed(self):
321         return self._allowed_values
322
323     def export_value(self):
324         return self._str_export_value()
325
326     def import_value(self, value):
327         self._str_import_value(value)
328
329
330 class Condition(Pick):
331
332     def __init__(self, name, description, default_value=False,
333                  readonly=False):
334         super(Condition, self).__init__(name, description,
335                                         [True, False], default_value,
336                                         readonly=readonly)
337
338     def import_value(self, value):
339         self._assigned_value = value == 'True'
340
341
342 class ConfigHelper(Log):
343
344     def __init__(self):
345         self._config = None
346
347     def new_config(self, name, *config_args):
348         self._config = Config(name, *config_args)
349
350     def get_config_obj(self):
351         if self._config is None:
352             raise AttributeError('Config not initialized')
353         return self._config
354
355     def import_config(self, config):
356         if not self._config:
357             raise AttributeError('Config not initialized, cannot import')
358
359         for key, value in config.iteritems():
360             if key in self._config:
361                 self._config[key].import_value(str(value))
362
363     def export_config(self):
364         config = dict()
365         for name, option in self._config.iteritems():
366             config[name] = option.export_value()
367         return config
368
369     def get_config_value(self, name):
370         if not self._config:
371             raise AttributeError('Config not initialized')
372         return self._config[name].get_value()
373
374     def set_config_value(self, name, value):
375         if not self._config:
376             raise AttributeError('Config not initialized')
377         return self._config[name].set_value(value)