runtime/NevowServer.py
changeset 3881 0b3ac94f494c
parent 3804 ef65e5b07464
parent 3861 7e17f7e02a2b
child 3882 c7ec55cbd35a
equal deleted inserted replaced
3880:89549813a6c1 3881:0b3ac94f494c
    26 
    26 
    27 
    27 
    28 import os
    28 import os
    29 import collections
    29 import collections
    30 import shutil
    30 import shutil
    31 import platform as platform_module
       
    32 from zope.interface import implementer
    31 from zope.interface import implementer
    33 from nevow import appserver, inevow, tags, loaders, athena, url, rend
    32 from nevow import appserver, inevow, tags, loaders, athena, url, rend
    34 from nevow.page import renderer
    33 from nevow.page import renderer
    35 from nevow.static import File
    34 from nevow.static import File
    36 from formless import annotate
    35 from formless import annotate
    97 
    96 
    98         setattr(self, 'action_' + name, callback)
    97         setattr(self, 'action_' + name, callback)
    99 
    98 
   100         self.bindingsNames.append(name)
    99         self.bindingsNames.append(name)
   101             
   100             
       
   101     customSettingsURLs = {}
       
   102     def addCustomURL(self, segment, func):
       
   103         self.customSettingsURLs[segment] = func
       
   104 
       
   105     def removeCustomURL(self, segment):
       
   106         del self.customSettingsURLs[segment]
       
   107 
       
   108     def customLocateChild(self, ctx, segments):
       
   109         segment = segments[0]
       
   110         if segment in self.customSettingsURLs:
       
   111             return self.customSettingsURLs[segment](ctx, segments)
   102 
   112 
   103 ConfigurableSettings = ConfigurableBindings()
   113 ConfigurableSettings = ConfigurableBindings()
   104 
   114 
   105 def newExtensionSetting(display, token):
   115 def newExtensionSetting(display, token):
   106     global extensions_settings_od
   116     global extensions_settings_od
   110 
   120 
   111 def removeExtensionSetting(token):
   121 def removeExtensionSetting(token):
   112     global extensions_settings_od
   122     global extensions_settings_od
   113     extensions_settings_od.pop(token)
   123     extensions_settings_od.pop(token)
   114 
   124 
       
   125 
   115 class ISettings(annotate.TypedInterface):
   126 class ISettings(annotate.TypedInterface):
   116     platform = annotate.String(label=_("Platform"),
   127     platform = annotate.String(label=_("Platform"),
   117                                default=platform_module.system() +
   128                                default=lambda *a,**k:GetPLCObjectSingleton().GetVersions(),
   118                                " " + platform_module.release(),
       
   119                                immutable=True)
   129                                immutable=True)
   120 
   130 
   121     # TODO version ?
       
   122 
   131 
   123     # pylint: disable=no-self-argument
   132     # pylint: disable=no-self-argument
   124     def sendLogMessage(
   133     def sendLogMessage(
   125             ctx=annotate.Context(),
   134             ctx=annotate.Context(),
   126             level=annotate.Choice(LogLevels,
   135             level=annotate.Choice(LogLevels,
   157     uploadFile = annotate.autocallable(uploadFile,
   166     uploadFile = annotate.autocallable(uploadFile,
   158                                            label=_(
   167                                            label=_(
   159                                                "Upload a file to PLC working directory"),
   168                                                "Upload a file to PLC working directory"),
   160                                            action=_("Upload"))
   169                                            action=_("Upload"))
   161 
   170 
   162 customSettingsURLs = {
       
   163 }
       
   164 
       
   165 extensions_settings_od = collections.OrderedDict()
   171 extensions_settings_od = collections.OrderedDict()
   166 
   172 
       
   173 
       
   174 CSS_tags = [tags.link(rel='stylesheet',
       
   175                       type='text/css',
       
   176                       href=url.here.child("webform_css")),
       
   177            tags.link(rel='stylesheet',
       
   178                       type='text/css',
       
   179                       href=url.here.child("webinterface_css"))]
       
   180 
   167 @implementer(ISettings)
   181 @implementer(ISettings)
   168 class SettingsPage(rend.Page):
   182 class StyledSettingsPage(rend.Page):
   169     # We deserve a slash
       
   170     addSlash = True
   183     addSlash = True
   171 
   184 
   172     # This makes webform_css url answer some default CSS
   185     # This makes webform_css url answer some default CSS
   173     child_webform_css = webform.defaultCSS
   186     child_webform_css = webform.defaultCSS
   174     child_webinterface_css = File(paths.AbsNeighbourFile(__file__, 'webinterface.css'), 'text/css')
   187     child_webinterface_css = File(paths.AbsNeighbourFile(__file__, 'webinterface.css'), 'text/css')
       
   188 
       
   189 class SettingsPage(StyledSettingsPage):
   175    
   190    
   176     def __getattr__(self, name):
       
   177         global extensions_settings_od
       
   178         if name.startswith('configurable_'):
       
   179             token = name[13:]
       
   180             def configurable_something(ctx):
       
   181                 settings, _display = extensions_settings_od[token]
       
   182                 return settings
       
   183             return configurable_something
       
   184         raise AttributeError
       
   185     
       
   186     def extensions_settings(self, context, data):
   191     def extensions_settings(self, context, data):
   187         """ Project extensions settings
   192         """ Project extensions settings
   188         Extensions added to Configuration Tree in IDE have their setting rendered here
   193         Extensions added to Configuration Tree in IDE have their setting rendered here
   189         """
   194         """
   190         global extensions_settings_od
   195         global extensions_settings_od
   191         res = []
   196         res = []
   192         for token in extensions_settings_od:
   197         for token in extensions_settings_od:
   193             _settings, display = extensions_settings_od[token]
   198             _settings, display = extensions_settings_od[token]
   194             res += [tags.h2[display], webform.renderForms(token)] 
   199             res += [tags.p[tags.a(href=token)[display]]]
   195         return res
   200         return res
   196 
   201 
   197     docFactory = loaders.stan([tags.html[
   202     docFactory = loaders.stan([tags.html[
   198         tags.head[
   203         tags.head[
   199             tags.title[_("Beremiz Runtime Settings")],
   204             tags.title[_("Beremiz Runtime Settings")],
   200             tags.link(rel='stylesheet',
   205             CSS_tags
   201                       type='text/css',
       
   202                       href=url.here.child("webform_css")),
       
   203             tags.link(rel='stylesheet',
       
   204                       type='text/css',
       
   205                       href=url.here.child("webinterface_css"))
       
   206         ],
   206         ],
   207         tags.body[
   207         tags.body[
       
   208             tags.h1["Settings"],
   208             tags.a(href='/')['Back'],
   209             tags.a(href='/')['Back'],
   209             tags.h1["Runtime settings:"],
   210             tags.h2["Runtime service"],
   210             webform.renderForms('staticSettings'),
   211             webform.renderForms('staticSettings'),
   211             tags.h1["Extensions settings:"],
   212             tags.h2["Target specific"],
   212             webform.renderForms('dynamicSettings'),
   213             webform.renderForms('dynamicSettings'),
       
   214             tags.h2["Extensions"],
   213             extensions_settings
   215             extensions_settings
   214         ]]])
   216         ]]])
   215 
   217 
   216     def configurable_staticSettings(self, ctx):
   218     def configurable_staticSettings(self, ctx):
   217         return configurable.TypedInterfaceConfigurable(self)
   219         return configurable.TypedInterfaceConfigurable(self)
   240             with open(uploadedfile.filename, 'wb') as destfd:
   242             with open(uploadedfile.filename, 'wb') as destfd:
   241                 fobj.seek(0)
   243                 fobj.seek(0)
   242                 shutil.copyfileobj(fobj,destfd)
   244                 shutil.copyfileobj(fobj,destfd)
   243 
   245 
   244     def locateChild(self, ctx, segments):
   246     def locateChild(self, ctx, segments):
   245         if segments[0] in customSettingsURLs:
   247         segment = segments[0]
   246             return customSettingsURLs[segments[0]](ctx, segments)
   248         if segment in extensions_settings_od:
       
   249             settings, display = extensions_settings_od[segment]
       
   250             return ExtensionSettingsPage(settings, display), segments[1:]
       
   251         else:
       
   252             res = ConfigurableSettings.customLocateChild(ctx, segments)
       
   253             if res:
       
   254                 return res 
   247         return super(SettingsPage, self).locateChild(ctx, segments)
   255         return super(SettingsPage, self).locateChild(ctx, segments)
       
   256 
       
   257 class ExtensionSettingsPage(StyledSettingsPage):
       
   258 
       
   259     docFactory = loaders.stan([
       
   260         tags.html[
       
   261             tags.head()[
       
   262                 tags.title[tags.directive("title")],
       
   263                 CSS_tags
       
   264             ],
       
   265             tags.body[
       
   266                 tags.h1[tags.directive("title")],
       
   267                 tags.a(href='/settings')['Back'],
       
   268                 webform.renderForms('settings')
       
   269             ]]])
       
   270 
       
   271     def render_title(self, ctx, data):
       
   272         return self._display_name
       
   273 
       
   274     def configurable_settings(self, ctx):
       
   275         return self._settings
       
   276 
       
   277     def __init__(self, settings, display):
       
   278         self._settings = settings
       
   279         self._display_name = display
       
   280 
       
   281     def locateChild(self, ctx, segments):
       
   282         res = self._settings.customLocateChild(ctx, segments)
       
   283         if res:
       
   284             return res 
       
   285         return super(ExtensionSettingsPage, self).locateChild(ctx, segments)
       
   286 
   248 
   287 
   249 def RegisterWebsite(iface, port):
   288 def RegisterWebsite(iface, port):
   250     website = SettingsPage()
   289     website = SettingsPage()
   251     site = appserver.NevowSite(website)
   290     site = appserver.NevowSite(website)
   252 
   291