Standardize on the spelling of "Invirt project"...just because
[invirt/packages/invirt-web.git] / code / webcommon.py
1 """Exceptions for the web interface."""
2
3 import time
4 from invirt import database
5 from invirt.database import Machine, MachineAccess
6
7 class MyException(Exception):
8     """Base class for my exceptions"""
9     pass
10
11 class InvalidInput(MyException):
12     """Exception for user-provided input is invalid but maybe in good faith.
13
14     This would include setting memory to negative (which might be a
15     typo) but not setting an invalid boot CD (which requires bypassing
16     the select box).
17     """
18     def __init__(self, err_field, err_value, expl=None):
19         MyException.__init__(self, expl)
20         self.err_field = err_field
21         self.err_value = err_value
22
23 class CodeError(MyException):
24     """Exception for internal errors or bad faith input."""
25     pass
26
27 import controls
28
29 def cachedproperty(func):
30     name = '__cache_' + func.__name__ + '_' + str(id(func))
31     def getter(self):
32         try:
33             return getattr(self, name)
34         except AttributeError:
35             value = func(self)
36             setattr(self, name, value)
37             return value
38     return property(getter)
39
40 class State(object):
41     """State for a request"""
42     def __init__(self, user, isadmin=False):
43         self.username = user
44         self.isadmin = isadmin
45
46     def getMachines(self):
47         if self.isadmin:
48             return Machine.query().join('acl').filter(
49                 database.or_(MachineAccess.user==self.username,
50                              Machine.adminable==True))
51         else:
52             return Machine.query().join('acl').filter_by(user=self.username)
53
54     machines = cachedproperty(getMachines)
55     xmlist_raw = cachedproperty(lambda self: controls.getList())
56     xmlist = cachedproperty(lambda self:
57                                 dict((m, self.xmlist_raw[m.name])
58                                      for m in self.machines
59                                      if m.name in self.xmlist_raw))
60
61     def clear(self):
62         """Clear the state so future accesses reload it."""
63         for attr in list(self.__dict__):
64             if attr.startswith('__cache_'):
65                 delattr(self, attr)