Removed outdated documentation
@ -1,153 +0,0 @@
|
||||
# Makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = sphinx-build
|
||||
PAPER = a4
|
||||
BUILDDIR = _build
|
||||
|
||||
# Internal variables.
|
||||
PAPEROPT_a4 = -D latex_paper_size=a4
|
||||
PAPEROPT_letter = -D latex_paper_size=letter
|
||||
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||
# the i18n builder cannot share the environment and doctrees with the others
|
||||
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||
|
||||
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
|
||||
|
||||
help:
|
||||
@echo "Please use \`make <target>' where <target> is one of"
|
||||
@echo " html to make standalone HTML files"
|
||||
@echo " dirhtml to make HTML files named index.html in directories"
|
||||
@echo " singlehtml to make a single large HTML file"
|
||||
@echo " pickle to make pickle files"
|
||||
@echo " json to make JSON files"
|
||||
@echo " htmlhelp to make HTML files and a HTML help project"
|
||||
@echo " qthelp to make HTML files and a qthelp project"
|
||||
@echo " devhelp to make HTML files and a Devhelp project"
|
||||
@echo " epub to make an epub"
|
||||
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
|
||||
@echo " latexpdf to make LaTeX files and run them through pdflatex"
|
||||
@echo " text to make text files"
|
||||
@echo " man to make manual pages"
|
||||
@echo " texinfo to make Texinfo files"
|
||||
@echo " info to make Texinfo files and run them through makeinfo"
|
||||
@echo " gettext to make PO message catalogs"
|
||||
@echo " changes to make an overview of all changed/added/deprecated items"
|
||||
@echo " linkcheck to check all external links for integrity"
|
||||
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
|
||||
|
||||
clean:
|
||||
-rm -rf $(BUILDDIR)/*
|
||||
|
||||
html:
|
||||
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
|
||||
|
||||
dirhtml:
|
||||
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
|
||||
|
||||
singlehtml:
|
||||
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
|
||||
|
||||
pickle:
|
||||
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
|
||||
@echo
|
||||
@echo "Build finished; now you can process the pickle files."
|
||||
|
||||
json:
|
||||
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
|
||||
@echo
|
||||
@echo "Build finished; now you can process the JSON files."
|
||||
|
||||
htmlhelp:
|
||||
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run HTML Help Workshop with the" \
|
||||
".hhp project file in $(BUILDDIR)/htmlhelp."
|
||||
|
||||
qthelp:
|
||||
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
|
||||
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
|
||||
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/UDS.qhcp"
|
||||
@echo "To view the help file:"
|
||||
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/UDS.qhc"
|
||||
|
||||
devhelp:
|
||||
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
|
||||
@echo
|
||||
@echo "Build finished."
|
||||
@echo "To view the help file:"
|
||||
@echo "# mkdir -p $$HOME/.local/share/devhelp/UDS"
|
||||
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/UDS"
|
||||
@echo "# devhelp"
|
||||
|
||||
epub:
|
||||
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
|
||||
@echo
|
||||
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
|
||||
|
||||
latex:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo
|
||||
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
|
||||
@echo "Run \`make' in that directory to run these through (pdf)latex" \
|
||||
"(use \`make latexpdf' here to do that automatically)."
|
||||
|
||||
latexpdf:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo "Running LaTeX files through pdflatex..."
|
||||
$(MAKE) -C $(BUILDDIR)/latex all-pdf
|
||||
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
||||
|
||||
text:
|
||||
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
|
||||
@echo
|
||||
@echo "Build finished. The text files are in $(BUILDDIR)/text."
|
||||
|
||||
man:
|
||||
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
|
||||
@echo
|
||||
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
|
||||
|
||||
texinfo:
|
||||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
||||
@echo
|
||||
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
|
||||
@echo "Run \`make' in that directory to run these through makeinfo" \
|
||||
"(use \`make info' here to do that automatically)."
|
||||
|
||||
info:
|
||||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
||||
@echo "Running Texinfo files through makeinfo..."
|
||||
make -C $(BUILDDIR)/texinfo info
|
||||
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
|
||||
|
||||
gettext:
|
||||
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
|
||||
@echo
|
||||
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
|
||||
|
||||
changes:
|
||||
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
|
||||
@echo
|
||||
@echo "The overview file is in $(BUILDDIR)/changes."
|
||||
|
||||
linkcheck:
|
||||
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
|
||||
@echo
|
||||
@echo "Link check complete; look for any errors in the above output " \
|
||||
"or in $(BUILDDIR)/linkcheck/output.txt."
|
||||
|
||||
doctest:
|
||||
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
|
||||
@echo "Testing of doctests in the sources finished, look at the " \
|
||||
"results in $(BUILDDIR)/doctest/output.txt."
|
@ -1,4 +0,0 @@
|
||||
# Sphinx build info version 1
|
||||
# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
|
||||
config: ecdf0c047589d7bf803c9f99cefd9819
|
||||
tags: 645f666f9bcd5a90fca523b33c5a78b7
|
@ -1,307 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2012 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
'''
|
||||
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
from django.utils.translation import ugettext_noop as translatable
|
||||
from uds.core.ui.UserInterface import gui
|
||||
from uds.core import auths
|
||||
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class SampleAuth(auths.Authenticator):
|
||||
'''
|
||||
This class represents a sample authenticator.
|
||||
|
||||
As this, it will provide:
|
||||
* The authenticator functionality
|
||||
* 3 Groups, "Mortals", "Gods" and "Daemons", just random group names selected.. :-),
|
||||
plus groups that we enter at Authenticator form, from admin interface.
|
||||
* Search of groups (inside the 3 groups used in this sample plus entered)
|
||||
* Search for people (will return the search string + 000...999 as usernames)
|
||||
* The Required form description for administration interface, so admins can create
|
||||
new authenticators of this kind.
|
||||
|
||||
In this sample, we will provide a simple standard auth, with owner drawn
|
||||
login form that will simply show users that has been created and allow web user
|
||||
to select one of them.
|
||||
|
||||
For this class to get visible at administration client as a authenticator type,
|
||||
we MUST register it at package __init__
|
||||
|
||||
:note: At class level, the translations must be simply marked as so
|
||||
using ugettext_noop. This is done in this way because we will translate
|
||||
the string when it is sent to the administration client.
|
||||
'''
|
||||
|
||||
#: Name of type, used at administration interface to identify this
|
||||
#: authenticator (i.e. LDAP, SAML, ...)
|
||||
#: This string will be translated when provided to admin interface
|
||||
#: using ugettext, so you can mark it as "translatable" at derived classes (using ugettext_noop)
|
||||
#: if you want so it can be translated.
|
||||
typeName = translatable('Sample Authenticator')
|
||||
|
||||
#: Name of type used by Managers to identify this type of service
|
||||
#: We could have used here the Class name, but we decided that the
|
||||
#: module implementator will be the one that will provide a name that
|
||||
#: will relation the class (type) and that name.
|
||||
typeType = 'SampleAuthenticator'
|
||||
|
||||
#: Description shown at administration level for this authenticator.
|
||||
#: This string will be translated when provided to admin interface
|
||||
#: using ugettext, so you can mark it as "translatable" at derived classes (using ugettext_noop)
|
||||
#: if you want so it can be translated.
|
||||
typeDescription = translatable('Sample dummy authenticator')
|
||||
|
||||
|
||||
#: Icon file, used to represent this authenticator at administration interface
|
||||
#: This file should be at same folder as this class is, except if you provide
|
||||
#: your own :py:meth:uds.core.BaseModule.BaseModule.icon method.
|
||||
iconFile = 'auth.png'
|
||||
|
||||
#: Mark this authenticator as that the users comes from outside the UDS
|
||||
#: database, that are most authenticator (except Internal DB)
|
||||
#: True is the default value, so we do not need it in fact
|
||||
# isExternalSource = True
|
||||
|
||||
#: If we need to enter the password for this user when creating a new
|
||||
#: user at administration interface. Used basically by internal authenticator.
|
||||
#: False is the default value, so this is not needed in fact
|
||||
#: needsPassword = False
|
||||
|
||||
#: Label for username field, shown at administration interface user form.
|
||||
userNameLabel = translatable('Fake User')
|
||||
|
||||
# Label for group field, shown at administration interface user form.
|
||||
groupNameLabel = translatable('Fake Group')
|
||||
|
||||
#: Definition of this type of authenticator form
|
||||
#: We will define a simple form where we will use a simple
|
||||
#: list editor to allow entering a few group names
|
||||
|
||||
groups = gui.EditableList(label=translatable('Groups'), values = ['Gods', 'Daemons', 'Mortals'])
|
||||
|
||||
def initialize(self, values):
|
||||
'''
|
||||
Simply check if we have
|
||||
at least one group in the list
|
||||
'''
|
||||
|
||||
# To avoid problems, we only check data if values are passed
|
||||
# If values are not passed in, form data will only be available after
|
||||
# unserialization, and at this point all will be default values
|
||||
# so self.groups.value will be []
|
||||
if values is not None and len(self.groups.value) < 2:
|
||||
raise auths.Authenticator.ValidationException(translatable('We need more that two items!'))
|
||||
|
||||
def searchUsers(self, pattern):
|
||||
'''
|
||||
Here we will receive a pattern for searching users.
|
||||
|
||||
This method is invoked from interface, so an administrator can search users.
|
||||
|
||||
If we do not provide this method, the authenticator will not provide search
|
||||
facility for users. In our case, we will simply return a list of users
|
||||
(array of dictionaries with ids and names) with the pattern plus 1..10
|
||||
'''
|
||||
return [ { 'id' : '{0}-{1}'.format(pattern, a), 'name' : '{0} number {1}'.format(pattern, a) } for a in range(1, 10)]
|
||||
|
||||
def searchGroups(self, pattern):
|
||||
'''
|
||||
Here we we will receive a patter for searching groups.
|
||||
|
||||
In this sample, we will try to locate elements that where entered at
|
||||
sample authenticator form (when created), and return the ones that
|
||||
contains the pattern indicated.
|
||||
'''
|
||||
pattern = pattern.lower()
|
||||
res = []
|
||||
for g in self.groups.value:
|
||||
if g.lower().find(pattern) != -1:
|
||||
res.append({'id' : g, 'name' : ''})
|
||||
return res
|
||||
|
||||
def authenticate(self, username, credentials, groupsManager):
|
||||
'''
|
||||
This method is invoked by UDS whenever it needs an user to be authenticated.
|
||||
It is used from web interface, but also from administration interface to
|
||||
check credentials and access of user.
|
||||
|
||||
The tricky part of this method is the groupsManager, but it's easy to
|
||||
understand what is used it for.
|
||||
|
||||
Imagine some authenticator, for example, an LDAP. It has its users, it has
|
||||
its groups, and it has it relations (which user belongs to which group).
|
||||
|
||||
Now think about UDS. UDS know nothing about this, it only knows what
|
||||
the administator has entered at admin interface (groups mainly, but he can
|
||||
create users also).
|
||||
|
||||
UDS knows about this groups, but we need to relation those with the ones
|
||||
know by the authenticator.
|
||||
|
||||
To do this, we have created a simple mechanism, where the authenticator
|
||||
receives a groupsManager, that knows all groups known by UDS, and has
|
||||
the method so the authenticator can say, for the username being validated,
|
||||
to which uds groups it belongs to.
|
||||
|
||||
This is done using the :py:meth:uds.core.auths.GroupsManager.GroupsManager.validate
|
||||
method of the provided groups manager.
|
||||
|
||||
At return, UDS will do two things:
|
||||
* If there is no group inside the groupsManager mareked as valid, it will
|
||||
denied access.
|
||||
* If there is some groups marked as valid, it will refresh the known
|
||||
UDS relations (this means that the database will be refresehd so the user
|
||||
has valid groups).
|
||||
|
||||
This also means that the group membership is only checked at user login (well,
|
||||
in fact its also checked when an administrator tries to modify an user)
|
||||
|
||||
So, authenticate must not also validate the user credentials, but also
|
||||
indicate the group membership of this user inside UDS.
|
||||
|
||||
:note: groupsManager is an in/out parameter
|
||||
'''
|
||||
if username != credentials: # All users with same username and password are allowed
|
||||
return False
|
||||
|
||||
# Now the tricky part. We will make this user belong to groups that contains at leat
|
||||
# two letters equals to the groups names known by UDS
|
||||
# For this, we will ask the groups manager for the groups names, and will check that and,
|
||||
# if the user match this criteria, will mark that group as valid
|
||||
for g in groupsManager.getGroupsNames():
|
||||
if len(set(g.lower()).intersection(username.lower())) >= 2:
|
||||
groupsManager.validate(g)
|
||||
|
||||
return True
|
||||
|
||||
def getGroups(self, username, groupsManager):
|
||||
'''
|
||||
As with authenticator part related to groupsManager, this
|
||||
method will fill the groups to which the specified username belongs to.
|
||||
|
||||
We have to fill up groupsManager from two different places, so it's not
|
||||
a bad idea to make a method that get the "real" authenticator groups and
|
||||
them simply call to :py:meth:uds.core.auths.GroupsManager.GroupsManager.validate
|
||||
|
||||
In our case, we simply repeat the process that we also do at authenticate
|
||||
'''
|
||||
for g in groupsManager.getGroupsNames():
|
||||
if len(set(g.lower()).intersection(username.lower())) >= 2:
|
||||
groupsManager.validate(g)
|
||||
|
||||
def getHtml(self, request):
|
||||
'''
|
||||
If we override this method from the base one, we are telling UDS
|
||||
that we want to draw our own authenticator.
|
||||
|
||||
This way, we can do whataver we want here (for example redirect to a site
|
||||
for a single sign on) generation our ouwn html (and javascript ofc).
|
||||
|
||||
'''
|
||||
# Here there is a sample, commented out
|
||||
# In this sample, we will make a list of valid users, and when clicked,
|
||||
# it will fill up original form with username and same password, and submit it.
|
||||
#res = ''
|
||||
#for u in self.dbAuthenticator().users.all():
|
||||
# res += '<a class="myNames" id="{0}" href="">{0}</a><br/>'.format(u.name)
|
||||
#
|
||||
#res += '<script type="text/javascript">$(".myNames").click(function() { '
|
||||
#res += '$("#id_user").val(this.id); $("#id_password").val(this.id); $("#loginform").submit(); return false;});</script>'
|
||||
#return res
|
||||
|
||||
# I know, this is a bit ugly, but this is just a sample :-)
|
||||
|
||||
res = '<p>Login name: <input id="logname" type="text"/></p>'
|
||||
res +='<p><a href="" onclick="window.location.replace(\'' + self.callbackUrl() + '?user='
|
||||
res += '\' + $(\'#logname\').val()); return false;">Login</a></p>'
|
||||
return res
|
||||
|
||||
|
||||
def authCallback(self, parameters):
|
||||
'''
|
||||
We provide this as a sample of callback for an user.
|
||||
We will accept all petitions that has "user" parameter
|
||||
|
||||
This method will get invoked by url redirections, probably by an SSO.
|
||||
|
||||
The idea behind this is that we can provide:
|
||||
* Simple user/password authentications
|
||||
* Own authentications (not UDS, authenticator "owned"), but with no redirections
|
||||
* Own authentications via redirections (as most SSO will do)
|
||||
|
||||
Here, we will receive the parameters for this
|
||||
'''
|
||||
user = parameters.get('user', None)
|
||||
|
||||
return user
|
||||
|
||||
def createUser(self, usrData):
|
||||
'''
|
||||
This method provides a "check oportunity" to authenticators for users created
|
||||
manually at administration interface.
|
||||
|
||||
If we do not provide this method, the administration interface will not allow
|
||||
to create new users "by hand", i mean, the "new" options from menus will dissapear.
|
||||
|
||||
usrData is a dictionary that contains the input parameters from user,
|
||||
with at least name, realName, comments, state & password.
|
||||
|
||||
We can modify this parameters, we can modify ALL, but name is not recommended to
|
||||
modify it unles you know what you are doing.
|
||||
|
||||
Here, we will set the state to "Inactive" and realName to the same as username, but twice :-)
|
||||
'''
|
||||
from uds.core.util.State import State
|
||||
usrData['realName'] = usrData['name'] + ' ' + usrData['name']
|
||||
usrData['state'] = State.INACTIVE
|
||||
|
||||
def modifyUser(self, usrData):
|
||||
'''
|
||||
This method provides a "check opportunity" to authenticator for users modified
|
||||
at administration interface.
|
||||
|
||||
If we do not provide this method, nothing will happen (default one does nothing, but
|
||||
it's valid).
|
||||
|
||||
usrData is a dictionary that contains the input parameters from user,
|
||||
with at least name, realName, comments, state & password.
|
||||
|
||||
We can modify this parameters, we can modify ALL, but name is not recommended to
|
||||
modify it unless you know what you are doing.
|
||||
|
||||
Here, we will simply update the realName of the user, and (we have to take care
|
||||
this this kind of things) modify the userName to a new one, the original plus '-1'
|
||||
'''
|
||||
usrData['realName'] = usrData['name'] + ' ' + usrData['name']
|
||||
usrData['name'] = usrData['name'] + '-1'
|
@ -1,196 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2012 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
'''
|
||||
Created on Jun 22, 2012
|
||||
|
||||
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
|
||||
from django.utils.translation import ugettext_noop as translatable, ugettext as _
|
||||
from uds.core.services import ServiceProvider
|
||||
from SampleService import ServiceOne, ServiceTwo
|
||||
from uds.core.ui import gui
|
||||
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Provider(ServiceProvider):
|
||||
'''
|
||||
This class represents the sample services provider
|
||||
|
||||
In this class we provide:
|
||||
* The Provider functionality
|
||||
* The basic configuration parameters for the provider
|
||||
* The form fields needed by administrators to configure this provider
|
||||
|
||||
:note: At class level, the translation must be simply marked as so
|
||||
using ugettext_noop. This is so cause we will translate the string when
|
||||
sent to the administration client.
|
||||
|
||||
For this class to get visible at administration client as a provider type,
|
||||
we MUST register it at package __init__.
|
||||
|
||||
'''
|
||||
#: What kind of services we offer, this are classes inherited from Service
|
||||
offers = [ServiceOne, ServiceTwo]
|
||||
#: Name to show the administrator. This string will be translated BEFORE
|
||||
#: sending it to administration interface, so don't forget to
|
||||
#: mark it as translatable (using ugettext_noop)
|
||||
typeName = translatable('Sample Provider')
|
||||
#: Type used internally to identify this provider
|
||||
typeType = 'SampleProvider'
|
||||
#: Description shown at administration interface for this provider
|
||||
typeDescription = translatable('Sample (and dummy) service provider')
|
||||
#: Icon file used as icon for this provider. This string will be translated
|
||||
#: BEFORE sending it to administration interface, so don't forget to
|
||||
#: mark it as translatable (using ugettext_noop)
|
||||
iconFile = 'provider.png'
|
||||
|
||||
# now comes the form fields
|
||||
# There is always two fields that are requested to the admin, that are:
|
||||
# Service Name, that is a name that the admin uses to name this provider
|
||||
# Description, that is a short description that the admin gives to this provider
|
||||
# Now we are going to add a few fields that we need to use this provider
|
||||
# Remember that these are "dummy" fields, that in fact are not required
|
||||
# but used for sample purposes
|
||||
# If we don't indicate an order, the output order of fields will be
|
||||
# "random"
|
||||
|
||||
#: Remote host. Here core will translate label and tooltip, remember to
|
||||
#: mark them as translatable using ugettext_noop.
|
||||
remoteHost = gui.TextField(oder=1,
|
||||
length = 64,
|
||||
label = translatable('Remote host'),
|
||||
tooltip = translatable('This fields contains a remote host'),
|
||||
required = True,
|
||||
)
|
||||
#: Name of your pet (sample, not really needed :-) )
|
||||
petName = gui.TextField(order=2,
|
||||
length = 32,
|
||||
label = translatable('Your pet\'s name'),
|
||||
tooltip = translatable('If you like, write the name of your pet'),
|
||||
requred = False,
|
||||
defvalue = 'Tux' #: This will not get translated
|
||||
)
|
||||
#: Age of Methuselah (matusalén in spanish)
|
||||
#: in Spain there is a well-known to say that something is very old,
|
||||
#: "Tiene mas años que matusalén"(is older than Methuselah)
|
||||
methAge = gui.NumericField(order = 3,
|
||||
length = 4, # That is, max allowed value is 9999
|
||||
label = translatable('Age of Methuselah'),
|
||||
tooltip = translatable('If you know it, please, tell me!!!'),
|
||||
required = True, #: Numeric fields have always a value, so this not really needed
|
||||
defvalue = '4500'
|
||||
)
|
||||
|
||||
#: Is Methuselah istill alive?
|
||||
methAlive = gui.CheckBoxField(order = 4,
|
||||
label = translatable('Is Methuselah still alive?'),
|
||||
tooltip = translatable('If you fail, this will not get saved :-)'),
|
||||
required = True, #: Also means nothing. Check boxes has always a value
|
||||
defvalue = gui.TRUE #: By default, at new item, check this
|
||||
)
|
||||
|
||||
# There is more fields type, but not here the best place to cover it
|
||||
def initialize(self, values = None):
|
||||
'''
|
||||
We will use the "autosave" feature for form fields, that is more than
|
||||
enought for most providers. (We simply need to store data provided by user
|
||||
and, maybe, initialize some kind of connection with this values).
|
||||
|
||||
Normally provider values are rally used at sevice level, cause we never
|
||||
instantiate nothing except a service from a provider.
|
||||
'''
|
||||
|
||||
# If you say meth is alive, you are wrong!!! (i guess..)
|
||||
# values are only passed from administration client. Internals
|
||||
# instantiations are always empty.
|
||||
if values is not None and self.methAlive.isTrue():
|
||||
raise ServiceProvider.ValidationException(_('Methuselah is not alive!!! :-)'))
|
||||
|
||||
# Marshal and unmarshal are defaults ones, also enought
|
||||
|
||||
# As we use "autosave" fields feature, dictValues is also provided by
|
||||
# base class so we don't have to mess with all those things...
|
||||
|
||||
@staticmethod
|
||||
def test(env, data):
|
||||
'''
|
||||
Create your test method here so the admin can push the "check" button
|
||||
and this gets executed.
|
||||
Args:
|
||||
env: environment passed for testing (temporal environment passed)
|
||||
|
||||
data: data passed for testing (data obtained from the form
|
||||
definition)
|
||||
|
||||
Returns:
|
||||
Array of two elements, first is True of False, depending on test
|
||||
(True is all right, false is error),
|
||||
second is an String with error, preferably internacionalizated..
|
||||
|
||||
In this case, wi well do nothing more that use the provider params
|
||||
|
||||
Note also that this is an static method, that will be invoked using
|
||||
the admin user provided data via administration client, and a temporary
|
||||
environment that will be erased after invoking this method
|
||||
'''
|
||||
try:
|
||||
# We instantiate the provider, but this may fail...
|
||||
instance = Provider(env, data)
|
||||
logger.debug('Methuselah has {0} years and is {1} :-)'
|
||||
.format(instance.methAge.value, instance.methAlive.value))
|
||||
except ServiceProvider.ValidationException as e:
|
||||
# If we say that meth is alive, instantiation will
|
||||
return [False, str(e)]
|
||||
except Exception as e:
|
||||
logger.exception("Exception caugth!!!")
|
||||
return [False, str(e)]
|
||||
return [True, _('Nothing tested, but all went fine..')]
|
||||
|
||||
# Congratulations!!!, the needed part of your first simple provider is done!
|
||||
# Now you can go to administration panel, and check it
|
||||
#
|
||||
# From now onwards, we implement our own methods, that will be used by,
|
||||
# for example, services derived from this provider
|
||||
def host(self):
|
||||
'''
|
||||
Sample method, in fact in this we just return
|
||||
the value of host field, that is an string
|
||||
'''
|
||||
return self.remoteHost.value
|
||||
|
||||
|
||||
def methYears(self):
|
||||
'''
|
||||
Another sample return, it will in fact return the Methuselah years
|
||||
'''
|
@ -1,272 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2012 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
'''
|
||||
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
|
||||
from django.utils.translation import ugettext as _
|
||||
from uds.core.services import Publication
|
||||
from uds.core.util.State import State
|
||||
from datetime import datetime
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class SamplePublication(Publication):
|
||||
'''
|
||||
This class shows how a publication is developed.
|
||||
|
||||
In order to a publication to work correctly, we must provide at least the
|
||||
following methods:
|
||||
* Of course, the __init__
|
||||
* :py:meth:`.publish`
|
||||
* :py:meth:`.checkState`
|
||||
* :py:meth:`.finish`
|
||||
|
||||
Also, of course, methods from :py:class:`uds.core.Serializable.Serializable`
|
||||
|
||||
|
||||
Publication do not have an configuration interface, all data contained
|
||||
inside an instance of a Publication must be serialized if you want them between
|
||||
method calls.
|
||||
|
||||
It's not waranteed that the class will not be serialized/deserialized
|
||||
between methods calls, so, first of all, implement the marshal and umnarshal
|
||||
mehods needed by all serializable classes.
|
||||
|
||||
Also a thing to note is that operations requested to Publications must be
|
||||
*as fast as posible*. The operations executes in a separated thread,
|
||||
and so it cant take a bit more time to execute, but it's recommended that
|
||||
the operations executes as fast as posible, and, if it will take a long time,
|
||||
split operation so we can keep track of state.
|
||||
|
||||
This means that, if we have "slow" operations, we must
|
||||
|
||||
We first of all declares an estimation of how long a publication will take.
|
||||
This value is instance based, so if we override it in our class, the suggested
|
||||
time could change.
|
||||
|
||||
The class attribute that indicates this suggested time is "suggestedTime", and
|
||||
it's expressed in seconds, (i.e. "suggestedTime = 10")
|
||||
'''
|
||||
|
||||
suggestedTime = 5 #: Suggested recheck time if publication is unfinished in seconds
|
||||
|
||||
def initialize(self):
|
||||
'''
|
||||
This method will be invoked by default __init__ of base class, so it gives
|
||||
us the oportunity to initialize whataver we need here.
|
||||
|
||||
In our case, we setup a few attributes..
|
||||
'''
|
||||
|
||||
# We do not check anything at marshal method, so we ensure that
|
||||
# default values are correctly handled by marshal.
|
||||
self._name = 'test'
|
||||
self._reason = '' # No error, no reason for it
|
||||
self._number = 1
|
||||
|
||||
def marshal(self):
|
||||
'''
|
||||
returns data from an instance of Sample Publication serialized
|
||||
'''
|
||||
return '\t'.join( [self._name, self._reason, str(self._number)] )
|
||||
|
||||
def unmarshal(self, data):
|
||||
'''
|
||||
deserializes the data and loads it inside instance.
|
||||
'''
|
||||
logger.debug('Data: {0}'.format(data))
|
||||
vals = data.split('\t')
|
||||
logger.debug('Values: {0}'.format(vals))
|
||||
self._name = vals[0]
|
||||
self._reason = vals[1]
|
||||
self._number = int(vals[2])
|
||||
|
||||
|
||||
def publish(self):
|
||||
'''
|
||||
This method is invoked whenever the administrator requests a new publication.
|
||||
|
||||
The method is not invoked directly (i mean, that the administration request
|
||||
do no makes a call to this method), but a DelayedTask is saved witch will
|
||||
initiate all publication stuff (and, of course, call this method).
|
||||
|
||||
You MUST implement it, so the publication do really something.
|
||||
All publications can be synchronous or asynchronous.
|
||||
|
||||
The main difference between both is that first do whatever needed, (the
|
||||
action must be fast enough to do not block core), returning State.FINISHED.
|
||||
|
||||
The second (asynchronous) are publications that could block the core, so
|
||||
it have to be done in more than one step.
|
||||
|
||||
An example publication could be a copy of a virtual machine, where:
|
||||
* First we invoke the copy operation to virtualization provider
|
||||
* Second, we kept needed values inside instance so we can serialize
|
||||
them whenever requested
|
||||
* Returns an State.RUNNING, indicating the core that the publication
|
||||
has started but has to finish sometime later. (We do no check
|
||||
again the state and keep waiting here, because we will block the
|
||||
core untill this operation is finished).
|
||||
|
||||
In our example wi will simple assign a name, and set number to 5. We
|
||||
will use this number later, to make a "delay" at check if the publication
|
||||
has finished. (see method checkState)
|
||||
|
||||
We also will make this publication an "stepped one", that is, it will not
|
||||
finish at publish call but a later checkState call
|
||||
|
||||
Take care with instantiating threads from here. Whenever a publish returns
|
||||
"State.RUNNING", the core will recheck it later, but not using this instance
|
||||
and maybe that even do not use this server.
|
||||
|
||||
If you want to use threadings or somethin likt it, use DelayedTasks and
|
||||
do not block it. You also musht provide the mechanism to allow those
|
||||
DelayedTask to communicate with the publication.
|
||||
|
||||
One sample could be, for example, to copy a bunch of files, but we know
|
||||
that this copy can take a long time and don't want it to take make it
|
||||
all here, but in a separate task. Now, do you remember that "environment"
|
||||
that is unique for every instance?, well, we can create a delayed task,
|
||||
and pass that environment (owned by this intance) as a mechanism for
|
||||
informing when the task is finished. (We insert at delayed tasks queue
|
||||
an instance, not a class itself, so we can instantiate a class and
|
||||
store it at delayed task queue.
|
||||
|
||||
Also note that, in that case, this class can also acomplish that by simply
|
||||
using the suggestedTime attribute and the checkState method in most cases.
|
||||
'''
|
||||
self._number = 5
|
||||
self._reason = ''
|
||||
return State.RUNNING
|
||||
|
||||
def checkState(self):
|
||||
'''
|
||||
Our publish method will initiate publication, but will not finish it.
|
||||
So in our sample, wi will only check if _number reaches 0, and if so
|
||||
return that we have finished, else we will return that we are working
|
||||
on it.
|
||||
|
||||
One publish returns State.RUNNING, this task will get called untill
|
||||
checkState returns State.FINISHED.
|
||||
|
||||
Also, wi will make the publication fail one of every 10 calls to this
|
||||
method.
|
||||
|
||||
Note: Destroying an publication also makes use of this method, so you
|
||||
must keep the info of that you are checking (publishing or destroying...)
|
||||
In our case, destroy is 1-step action so this will no get called while
|
||||
destroying...
|
||||
'''
|
||||
import random
|
||||
self._number -= 1
|
||||
# Serialization will take care of storing self._number
|
||||
|
||||
# One of every 10 calls
|
||||
if random.randint(0, 9) == 9:
|
||||
self._reason = _('Random integer was 9!!! :-)')
|
||||
return State.ERROR
|
||||
|
||||
if self._number <= 0:
|
||||
return State.FINISHED
|
||||
else:
|
||||
return State.RUNNING
|
||||
|
||||
|
||||
def finish(self):
|
||||
'''
|
||||
Invoked when Publication manager noticed that the publication has finished.
|
||||
This give us the oportunity of cleaning up things (as stored vars, etc..),
|
||||
or initialize variables that will be needed in a later phase (by deployed
|
||||
services)
|
||||
|
||||
Returned value, if any, is ignored
|
||||
'''
|
||||
import string
|
||||
import random
|
||||
# Make simply a random string
|
||||
self._name = ''.join(random.choice(string.ascii_uppercase + string.digits) for x in range(10))
|
||||
|
||||
def reasonOfError(self):
|
||||
'''
|
||||
If a publication produces an error, here we must notify the reason why
|
||||
it happened. This will be called just after publish or checkState
|
||||
if they return State.ERROR
|
||||
|
||||
Returns an string, in our case, set at checkState
|
||||
'''
|
||||
return self._reason
|
||||
|
||||
def destroy(self):
|
||||
'''
|
||||
This is called once a publication is no more needed.
|
||||
|
||||
This method do whatever needed to clean up things, such as
|
||||
removing created "external" data (environment gets cleaned by core),
|
||||
etc..
|
||||
|
||||
The retunred value is the same as when publishing, State.RUNNING,
|
||||
State.FINISHED or State.ERROR.
|
||||
'''
|
||||
self._name = ''
|
||||
self._reason = '' # In fact, this is not needed, but cleaning up things... :-)
|
||||
|
||||
# We do not do anything else to destroy this instance of publication
|
||||
return State.FINISHED
|
||||
|
||||
|
||||
def cancel(self):
|
||||
'''
|
||||
Invoked for canceling the current operation.
|
||||
This can be invoked directly by an administration or by the clean up
|
||||
of the deployed service (indirectly).
|
||||
When administrator requests it, the cancel is "delayed" and not
|
||||
invoked directly.
|
||||
|
||||
Also, take into account that cancel is the initiation of, maybe, a
|
||||
multiple-step action, so it returns, as publish and destroy does.
|
||||
|
||||
In our case, cancel simply invokes "destroy", that cleans up
|
||||
things and returns that the action has finished in 1 step.
|
||||
'''
|
||||
return self.destroy()
|
||||
|
||||
# Here ends the publication needed methods.
|
||||
# Methods provided below are specific for this publication
|
||||
# and will be used by user deployments that uses this kind of publication
|
||||
|
||||
def getBaseName(self):
|
||||
'''
|
||||
This sample method (just for this sample publication), provides
|
||||
the name generater for this publication. This is just a sample, and
|
||||
this will do the work
|
||||
'''
|
||||
return self._name
|
@ -1,236 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2012 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
'''
|
||||
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
|
||||
from django.utils.translation import ugettext_noop as translatable, ugettext as _
|
||||
from uds.core.services import Service
|
||||
from SamplePublication import SamplePublication
|
||||
from SampleUserDeploymentOne import SampleUserDeploymentOne
|
||||
from SampleUserDeploymentTwo import SampleUserDeploymentTwo
|
||||
|
||||
from uds.core.ui import gui
|
||||
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class ServiceOne(Service):
|
||||
'''
|
||||
Basic service, the first part (variables) include the description of the service.
|
||||
|
||||
Remember to fill all variables needed, but at least you must define:
|
||||
* typeName
|
||||
* typeType
|
||||
* typeDescription
|
||||
* iconFile (defaults to service.png)
|
||||
* publicationType, type of publication in case it needs publication.
|
||||
If this is not provided, core will assume that the service do not
|
||||
needs publishing.
|
||||
* deployedType, type of deployed user service. Do not forget this!!!
|
||||
|
||||
The rest of them can be ommited, but its recommended that you fill all
|
||||
declarations shown in this sample (that in fact, are all)
|
||||
|
||||
This description informs the core what this service really provides,
|
||||
and how this is done. Look at description of class variables for more
|
||||
information.
|
||||
|
||||
'''
|
||||
#: Name to show the administrator. This string will be translated BEFORE
|
||||
#: sending it to administration interface, so don't forget to
|
||||
#: mark it as translatable (using ugettext_noop)
|
||||
typeName = translatable('Sample Service One')
|
||||
#: Type used internally to identify this provider
|
||||
typeType = 'SampleService1'
|
||||
#: Description shown at administration interface for this provider
|
||||
typeDescription = translatable('Sample (and dummy) service ONE')
|
||||
#: Icon file used as icon for this provider. This string will be translated
|
||||
#: BEFORE sending it to administration interface, so don't forget to
|
||||
#: mark it as translatable (using ugettext_noop)
|
||||
iconFile = 'service.png'
|
||||
|
||||
# Functional related data
|
||||
|
||||
#: If the service provides more than 1 "deployed user" (-1 = no limit,
|
||||
#: 0 = ???? (do not use it!!!), N = max number to deploy
|
||||
maxDeployed = -1
|
||||
#: If we need to generate "cache" for this service, so users can access the
|
||||
#: provided services faster. Is usesCache is True, you will need also
|
||||
#: set publicationType, do take care about that!
|
||||
usesCache = False
|
||||
#: Tooltip shown to user when this item is pointed at admin interface, none
|
||||
#: because we don't use it
|
||||
cacheTooltip = translatable('None')
|
||||
#: If we need to generate a "Level 2" cache for this service (i.e., L1
|
||||
#: could be running machines and L2 suspended machines)
|
||||
usesCache_L2 = False
|
||||
#: Tooltip shown to user when this item is pointed at admin interface, None
|
||||
#: also because we don't use it
|
||||
cacheTooltip_L2 = translatable('None')
|
||||
|
||||
#: If the service needs a s.o. manager (managers are related to agents
|
||||
#: provided by services itselfs, i.e. virtual machines with actors)
|
||||
needsManager = False
|
||||
#: If true, the system can't do an automatic assignation of a deployed user
|
||||
#: service from this service
|
||||
mustAssignManually = False
|
||||
|
||||
#: Types of publications (preparated data for deploys)
|
||||
#: In our case, we do no need a publication, so this is None
|
||||
publicationType = None
|
||||
#: Types of deploys (services in cache and/or assigned to users)
|
||||
deployedType = SampleUserDeploymentOne
|
||||
|
||||
# Now the form part, this service will have only two "dummy" fields
|
||||
# If we don't indicate an order, the output order of fields will be
|
||||
# "random"
|
||||
|
||||
colour = gui.ChoiceField(order = 1,
|
||||
label = translatable('Colour'),
|
||||
tooltip = translatable('Colour of the field'),
|
||||
# In this case, the choice can have none value selected by default
|
||||
required = True,
|
||||
values = [ gui.choiceItem('red', 'Red'),
|
||||
gui.choiceItem('green', 'Green'),
|
||||
gui.choiceItem('blue', 'Blue'),
|
||||
gui.choiceItem('nonsense', 'Blagenta')
|
||||
],
|
||||
defvalue = '1' # Default value is the ID of the choicefield
|
||||
)
|
||||
|
||||
passw = gui.PasswordField(order = 2,
|
||||
label = translatable('Password'),
|
||||
tooltip = translatable('Password for testing purposes'),
|
||||
required = True,
|
||||
defvalue = '1234' #: Default password are nonsense?? :-)
|
||||
)
|
||||
|
||||
baseName = gui.TextField(order = 3,
|
||||
label = translatable('Services names'),
|
||||
tooltip = translatable('Base name for this user services'),
|
||||
# In this case, the choice can have none value selected by default
|
||||
required = True,
|
||||
defvalue = '' # Default value is the ID of the choicefield
|
||||
)
|
||||
|
||||
def initialize(self, values):
|
||||
'''
|
||||
We check here form values to see if they are valid.
|
||||
|
||||
Note that we check them throught FROM variables, that already has been
|
||||
initialized by __init__ method of base class, before invoking this.
|
||||
'''
|
||||
|
||||
# We don't need to check anything, bat because this is a sample, we do
|
||||
# As in provider, we receive values only at new Service creation,
|
||||
# so we only need to validate params if values is not None
|
||||
if values is not None:
|
||||
if self.colour.value == 'nonsense':
|
||||
raise Service.ValidationException('The selected colour is invalid!!!')
|
||||
|
||||
|
||||
# Services itself are non testeable right now, so we don't even have
|
||||
# to provide one!!!
|
||||
|
||||
|
||||
# Congratulations!!!, the needed part of your first simple service is done!
|
||||
# Now you can go to administration panel, and check it
|
||||
#
|
||||
# From now onwards, we implement our own methods, that will be used by,
|
||||
# for example, services derived from this provider
|
||||
|
||||
def getColour(self):
|
||||
'''
|
||||
Simply returns colour, for deployed user services.
|
||||
|
||||
Remember that choiceField.value returns the id part of the ChoiceItem
|
||||
'''
|
||||
return self.colour.value
|
||||
|
||||
def getPassw(self):
|
||||
'''
|
||||
Simply returns passwd, for deloyed user services
|
||||
'''
|
||||
return self.passw.value
|
||||
|
||||
def getBaseName(self):
|
||||
'''
|
||||
'''
|
||||
return self.baseName.value
|
||||
|
||||
|
||||
|
||||
class ServiceTwo(Service):
|
||||
'''
|
||||
Just a second service, no comments here (almost same that ServiceOne
|
||||
'''
|
||||
typeName = translatable('Sample Service Two')
|
||||
typeType = 'SampleService2'
|
||||
typeDescription = translatable('Sample (and dummy) service ONE+ONE')
|
||||
iconFile = 'provider.png' #: We reuse provider icon here :-)
|
||||
|
||||
# Functional related data
|
||||
maxDeployed = 5
|
||||
usesCache = True
|
||||
cacheTooltip = translatable('L1 cache for dummy elements')
|
||||
usesCache_L2 = True
|
||||
cacheTooltip_L2 = translatable('L2 cache for dummy elements')
|
||||
|
||||
needsManager = False
|
||||
mustAssignManually = False
|
||||
|
||||
#: Types of publications. In this case, we will include a publication
|
||||
#: type for this one
|
||||
#: Note that this is a MUST if you indicate that needPublication
|
||||
publicationType = SamplePublication
|
||||
#: Types of deploys (services in cache and/or assigned to users)
|
||||
deployedType = SampleUserDeploymentTwo
|
||||
|
||||
|
||||
# Gui, we will use here the EditableList field
|
||||
names = gui.EditableList(label=translatable('List of names'))
|
||||
|
||||
def __init__(self, environment, parent, values = None):
|
||||
'''
|
||||
We here can get a HUGE list from client.
|
||||
Right now, this is treated same as other fields, in a near
|
||||
future we will se how to handle this better
|
||||
'''
|
||||
super(ServiceTwo, self).__init__(environment, parent, values)
|
||||
|
||||
# No checks here
|
||||
|
||||
def getNames(self):
|
||||
'''
|
||||
For using at deployed services, really nothing
|
||||
'''
|
||||
return self.names.value
|
@ -1,373 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2012 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
'''
|
||||
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
|
||||
from uds.core.services import UserDeployment
|
||||
from uds.core.util.State import State
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class SampleUserDeploymentOne(UserDeployment):
|
||||
'''
|
||||
This class generates the user consumable elements of the service tree.
|
||||
|
||||
After creating at administration interface an Deployed Service, UDS will
|
||||
create consumable services for users using UserDeployment class as
|
||||
provider of this elements.
|
||||
|
||||
|
||||
At class instantiation, this will receive an environment with"generator",
|
||||
that are classes that provides a way to generate unique items.
|
||||
|
||||
The generators provided right now are 'mac' and 'name'. To get more info
|
||||
about this, look at py:class:`uds.core.util.UniqueMacGenerator.UniqueNameGenerator`
|
||||
and py:class:`uds.core.util.UniqueNameGenerator.UniqueNameGenerator`
|
||||
|
||||
This first sample do not uses cache. To see one with cache, see
|
||||
SampleUserDeploymentTwo. The main difference are the "...Cache".." methods,
|
||||
that here are not needed.
|
||||
|
||||
As sample also of environment storage usage, wi will use here the provider
|
||||
storage to keep all our needed info, leaving marshal and unmarshal (needed
|
||||
by Serializble classes, like this) empty (that is, returns '' first and does
|
||||
nothing the second one)
|
||||
|
||||
Also Remember, if you don't include this class as the deployedType of the
|
||||
SampleServiceOne, or whenever you trie to access a service of SampleServiceOne,
|
||||
you will get an excetion that says that you havent included the deployedType.
|
||||
'''
|
||||
|
||||
#: Recheck every five seconds by default (for task methods)
|
||||
suggestedTime = 5
|
||||
|
||||
# Serializable needed methods
|
||||
def marshal(self):
|
||||
'''
|
||||
Does nothing right here, we will use envoronment storage in this sample
|
||||
'''
|
||||
return ''
|
||||
|
||||
def unmarshal(self, str_):
|
||||
'''
|
||||
Does nothing here also, all data are keeped at environment storage
|
||||
'''
|
||||
pass
|
||||
|
||||
|
||||
def getName(self):
|
||||
'''
|
||||
We override this to return a name to display. Default inplementation
|
||||
(in base class), returns getUniqueIde() value
|
||||
This name will help user to identify elements, and is only used
|
||||
at administration interface.
|
||||
|
||||
We will use here the environment name provided generator to generate
|
||||
a name for this element.
|
||||
|
||||
The namaGenerator need two params, the base name and a length for a
|
||||
numeric incremental part for generating unique names. This are unique for
|
||||
all UDS names generations, that is, UDS will not generate this name again
|
||||
until this name is freed, or object is removed, what makes its environment
|
||||
to also get removed, that makes all uniques ids (names and macs right now)
|
||||
to also get released.
|
||||
|
||||
Every time get method of a generator gets called, the generator creates
|
||||
a new unique name, so we keep the first generated name cached and don't
|
||||
generate more names. (Generator are simple utility classes)
|
||||
'''
|
||||
name = self.storage().readData('name')
|
||||
if name is None:
|
||||
name = self.nameGenerator().get( self.service().getBaseName()
|
||||
+ '-' + self.service().getColour(), 3 )
|
||||
# Store value for persistence
|
||||
self.storage().saveData('name', name)
|
||||
|
||||
return name
|
||||
|
||||
def setIp(self, ip):
|
||||
'''
|
||||
In our case, there is no OS manager associated with this, so this method
|
||||
will never get called, but we put here as sample.
|
||||
|
||||
Whenever an os manager actor notifies the broker the state of the service
|
||||
(mainly machines), the implementation of that os manager can (an probably will)
|
||||
need to notify the IP of the deployed service. Remember that UDS treats with
|
||||
IP services, so will probable needed in every service that you will create.
|
||||
:note: This IP is the IP of the "consumed service", so the transport can
|
||||
access it.
|
||||
'''
|
||||
self.storage().saveData('ip', str(ip))
|
||||
|
||||
def getUniqueId(self):
|
||||
'''
|
||||
Return and unique identifier for this service.
|
||||
In our case, we will generate a mac name, that can be also as sample
|
||||
of 'mac' generator use, and probably will get used something like this
|
||||
at some services.
|
||||
|
||||
The get method of a mac generator takes one param, that is the mac range
|
||||
to use to get an unused mac.
|
||||
'''
|
||||
mac = self.storage().readData('mac')
|
||||
if mac is None:
|
||||
mac = self.macGenerator().get( '00:00:00:00:00:00-00:FF:FF:FF:FF:FF' )
|
||||
self.storage().saveData('mac', mac)
|
||||
return mac
|
||||
|
||||
def getIp(self):
|
||||
'''
|
||||
We need to implement this method, so we can return the IP for transports
|
||||
use. If no IP is known for this service, this must return None
|
||||
|
||||
If our sample do not returns an IP, IP transport will never work with
|
||||
this service. Remember in real cases to return a valid IP address if
|
||||
the service is accesible and you alredy know that (for example, because
|
||||
the IP has been assigend via setIp by an os manager) or because
|
||||
you get it for some other method.
|
||||
|
||||
Storage returns None if key is not stored.
|
||||
|
||||
:note: Keeping the IP address is responsibility of the User Deployment.
|
||||
Every time the core needs to provide the service to the user, or
|
||||
show the IP to the administrator, this method will get called
|
||||
|
||||
'''
|
||||
ip = self.storage().readData('ip')
|
||||
if ip is None:
|
||||
ip = '192.168.0.34' # Sample IP for testing purposses only
|
||||
return ip
|
||||
|
||||
def setReady(self):
|
||||
'''
|
||||
This is a task method. As that, the expected return values are
|
||||
State values RUNNING, FINISHED or ERROR.
|
||||
|
||||
The method is invoked whenever a machine is provided to an user, right
|
||||
before presenting it (via transport rendering) to the user.
|
||||
|
||||
This method exist for this kind of situations (i will explain it with a
|
||||
sample)
|
||||
|
||||
Imagine a Service tree (Provider, Service, ...) for virtual machines.
|
||||
This machines will get created by the UserDeployment implementation, but,
|
||||
at some time, the machine can be put at in an state (suspend, shut down)
|
||||
that will make the transport impossible to connect with it.
|
||||
|
||||
This method, in this case, will check the state of the machine, and if
|
||||
it is "ready", that is, powered on and accesible, it will return
|
||||
"State.FINISHED". If the machine is not accesible (has ben erased, for
|
||||
example), it will return "State.ERROR" and store a reason of error so UDS
|
||||
can ask for it and present this information to the Administrator.
|
||||
|
||||
If the machine powered off, or suspended, or any other state that is not
|
||||
directly usable but can be put in an usable state, it will return
|
||||
"State.RUNNING", and core will use checkState to see when the operation
|
||||
has finished.
|
||||
|
||||
I hope this sample is enough to explain the use of this method..
|
||||
'''
|
||||
|
||||
# In our case, the service is always ready
|
||||
return State.FINISHED
|
||||
|
||||
def deployForUser(self, user):
|
||||
'''
|
||||
Deploys an service instance for an user.
|
||||
|
||||
This is a task method. As that, the excepted return values are
|
||||
State values RUNNING, FINISHED or ERROR.
|
||||
|
||||
The user parameter is not realy neded, but provided. It indicates the
|
||||
Database User Object (see py:mod:`uds.modules`) to which this deployed
|
||||
user service will be assigned to.
|
||||
|
||||
This method will get called whenever a new deployed service for an user
|
||||
is needed. This will give this class the oportunity to create
|
||||
a service that is assigned to an user.
|
||||
|
||||
The way of using this method is as follows:
|
||||
|
||||
If the service gets created in "one step", that is, before the return
|
||||
of this method, the consumable service for the user gets created, it
|
||||
will return "State.FINISH".
|
||||
If the service needs more steps (as in this case), we will return
|
||||
"State.RUNNING", and if it has an error, it wil return "State.ERROR" and
|
||||
store an error string so administration interface can show it.
|
||||
|
||||
We do not use user for anything, as in most cases will be.
|
||||
'''
|
||||
import random
|
||||
|
||||
self.storage().saveData('count', '0')
|
||||
|
||||
# random fail
|
||||
if random.randint(0, 9) == 9:
|
||||
self.storage().saveData('error', 'Random error at deployForUser :-)')
|
||||
return State.ERROR
|
||||
|
||||
return State.RUNNING
|
||||
|
||||
|
||||
def checkState(self):
|
||||
'''
|
||||
Our deployForUser method will initiate the consumable service deployment,
|
||||
but will not finish it.
|
||||
|
||||
So in our sample, we will only check if a number reaches 5, and if so
|
||||
return that we have finished, else we will return that we are working
|
||||
on it.
|
||||
|
||||
One deployForUser returns State.RUNNING, this task will get called until
|
||||
checkState returns State.FINISHED.
|
||||
|
||||
Also, we will make the publication fail one of every 10 calls to this
|
||||
method.
|
||||
|
||||
Note: Destroying, canceling and deploying for cache also makes use of
|
||||
this method, so you must keep the info of that you are checking if you
|
||||
need it.
|
||||
In our case, destroy is 1-step action so this will no get called while
|
||||
destroying, and cancel will simply invoke destroy
|
||||
'''
|
||||
import random
|
||||
|
||||
count = int(self.storage().readData('count')) + 1
|
||||
# Count is always a valid value, because this method will never get
|
||||
# called before deployForUser, deployForCache, destroy or cancel.
|
||||
# In our sample, we only use checkState in case of deployForUser,
|
||||
# so at first call count will be 0.
|
||||
if count >= 5:
|
||||
return State.FINISHED
|
||||
|
||||
# random fail
|
||||
if random.randint(0, 9) == 9:
|
||||
self.storage().saveData('error', 'Random error at checkState :-)')
|
||||
return State.ERROR
|
||||
|
||||
self.storage().saveData('count', str(count))
|
||||
return State.RUNNING
|
||||
|
||||
def finish(self):
|
||||
'''
|
||||
Invoked when the core notices that the deployment of a service has finished.
|
||||
(No matter wether it is for cache or for an user)
|
||||
|
||||
This gives the oportunity to make something at that moment.
|
||||
:note: You can also make these operations at checkState, this is really
|
||||
not needed, but can be provided (default implementation of base class does
|
||||
nothing)
|
||||
'''
|
||||
# Note that this is not really needed, is just a sample of storage use
|
||||
self.storage().remove('count')
|
||||
|
||||
def assignToUser(self, user):
|
||||
'''
|
||||
This method is invoked whenever a cache item gets assigned to an user.
|
||||
This gives the User Deployment an oportunity to do whatever actions
|
||||
are required so the service puts at a correct state for using by a service.
|
||||
|
||||
In our sample, the service is always ready, so this does nothing.
|
||||
|
||||
This is not a task method. All level 1 cache items can be diretly
|
||||
assigned to an user with no more work needed, but, if something is needed,
|
||||
here you can do whatever you need
|
||||
'''
|
||||
pass
|
||||
|
||||
def userLoggedIn(self, user):
|
||||
'''
|
||||
This method must be available so os managers can invoke it whenever
|
||||
an user get logged into a service.
|
||||
|
||||
Default implementation does nothing, so if you are going to do nothing,
|
||||
you don't need to implement it.
|
||||
|
||||
The responability of notifying it is of os manager actor, and it's
|
||||
directly invoked by os managers (right now, linux os manager and windows
|
||||
os manager)
|
||||
|
||||
The user provided is just an string, that is provided by actor.
|
||||
'''
|
||||
# We store the value at storage, but never get used, just an example
|
||||
self.storage().saveData('user', user)
|
||||
|
||||
def userLoggedOut(self, user):
|
||||
'''
|
||||
This method must be available so os managers can invoke it whenever
|
||||
an user get logged out if a service.
|
||||
|
||||
Default implementation does nothing, so if you are going to do nothing,
|
||||
you don't need to implement it.
|
||||
|
||||
The responability of notifying it is of os manager actor, and it's
|
||||
directly invoked by os managers (right now, linux os manager and windows
|
||||
os manager)
|
||||
|
||||
The user provided is just an string, that is provided by actor.
|
||||
'''
|
||||
# We do nothing more that remove the user
|
||||
self.storage().remove('user')
|
||||
|
||||
def reasonOfError(self):
|
||||
'''
|
||||
Returns the reason of the error.
|
||||
|
||||
Remember that the class is responsible of returning this whenever asked
|
||||
for it, and it will be asked everytime it's needed to be shown to the
|
||||
user (when the administation asks for it).
|
||||
'''
|
||||
return self.storage().readData('error') or 'No error'
|
||||
|
||||
def destroy(self):
|
||||
'''
|
||||
This is a task method. As that, the excepted return values are
|
||||
State values RUNNING, FINISHED or ERROR.
|
||||
|
||||
Invoked for destroying a deployed service
|
||||
Do whatever needed here, as deleting associated data if needed (i.e. a copy of the machine, snapshots, etc...)
|
||||
@return: State.FINISHED if no more checks/steps for deployment are needed, State.RUNNING if more steps are needed (steps checked using checkState)
|
||||
'''
|
||||
return State.FINISHED
|
||||
|
||||
def cancel(self):
|
||||
'''
|
||||
This is a task method. As that, the excepted return values are
|
||||
State values RUNNING, FINISHED or ERROR.
|
||||
|
||||
This can be invoked directly by an administration or by the clean up
|
||||
of the deployed service (indirectly).
|
||||
When administrator requests it, the cancel is "delayed" and not
|
||||
invoked directly.
|
||||
'''
|
||||
return State.FINISHED
|
||||
|
@ -1,469 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2012 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
'''
|
||||
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
|
||||
from uds.core.services import UserDeployment
|
||||
from uds.core.util.State import State
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class SampleUserDeploymentTwo(UserDeployment):
|
||||
'''
|
||||
This class generates the user consumable elements of the service tree.
|
||||
|
||||
This is almost the same as SampleUserDeploymentOne, but differs that this one
|
||||
uses the publication to get data from it, in a very basic way.
|
||||
|
||||
After creating at administration interface an Deployed Service, UDS will
|
||||
create consumable services for users using UserDeployment class as
|
||||
provider of this elements.
|
||||
|
||||
At class instantiation, this will receive an environment with"generator",
|
||||
that are classes that provides a way to generate unique items.
|
||||
|
||||
The generators provided right now are 'mac' and 'name'. To get more info
|
||||
about this, look at py:class:`uds.core.util.UniqueMacGenerator.UniqueNameGenerator`
|
||||
and py:class:`uds.core.util.UniqueNameGenerator.UniqueNameGenerator`
|
||||
|
||||
As sample also of environment storage usage, wi will use here the provider
|
||||
storage to keep all our needed info, leaving marshal and unmarshal (needed
|
||||
by Serializable classes, like this) empty (that is, returns '' first and does
|
||||
nothing the second one)
|
||||
|
||||
Also Remember, if you don't include this class as the deployedType of the
|
||||
SampleServiceTwo, or whenever you try to access a service of SampleServiceTwo,
|
||||
you will get an exception that says that you haven't included the deployedType.
|
||||
'''
|
||||
|
||||
#: Recheck every five seconds by default (for task methods)
|
||||
suggestedTime = 2
|
||||
|
||||
def initialize(self):
|
||||
'''
|
||||
Initialize default attributes values here. We can do whatever we like,
|
||||
but for this sample this is just right...
|
||||
'''
|
||||
self._name = ''
|
||||
self._ip = ''
|
||||
self._mac = ''
|
||||
self._error = ''
|
||||
self._count = 0
|
||||
|
||||
# Serializable needed methods
|
||||
def marshal(self):
|
||||
'''
|
||||
Marshal own data, in this sample we will marshal internal needed
|
||||
attributes.
|
||||
|
||||
In this case, the data will be store with the database record. To
|
||||
minimize database storage usage, we will "zip" data before returning it.
|
||||
Anyway, we should keep this data as low as possible, we also have an
|
||||
storage for loading larger data.
|
||||
|
||||
:note: It's a good idea when providing marshalers, to store a 'version'
|
||||
beside the values, so we can, at a later stage, treat with old
|
||||
data for current modules.
|
||||
'''
|
||||
data = '\t'.join(['v1', self._name, self._ip, self._mac, self._error,
|
||||
str(self._count)])
|
||||
return data.encode('zip')
|
||||
|
||||
def unmarshal(self, str_):
|
||||
'''
|
||||
We unmarshal the content.
|
||||
'''
|
||||
data = str_.decode('zip').split('\t')
|
||||
# Data Version check
|
||||
# If we include some new data at some point in a future, we can
|
||||
# add "default" values at v1 check, and load new values at 'v2' check.
|
||||
if data[0] == 'v1':
|
||||
self._name, self._ip, self._mac, self._error, count = data[1:]
|
||||
self._count = int(count)
|
||||
|
||||
def getName(self):
|
||||
'''
|
||||
We override this to return a name to display. Default implementation
|
||||
(in base class), returns getUniqueIde() value
|
||||
This name will help user to identify elements, and is only used
|
||||
at administration interface.
|
||||
|
||||
We will use here the environment name provided generator to generate
|
||||
a name for this element.
|
||||
|
||||
The namaGenerator need two params, the base name and a length for a
|
||||
numeric incremental part for generating unique names. This are unique for
|
||||
all UDS names generations, that is, UDS will not generate this name again
|
||||
until this name is freed, or object is removed, what makes its environment
|
||||
to also get removed, that makes all unique ids (names and macs right now)
|
||||
to also get released.
|
||||
|
||||
Every time get method of a generator gets called, the generator creates
|
||||
a new unique name, so we keep the first generated name cached and don't
|
||||
generate more names. (Generator are simple utility classes)
|
||||
'''
|
||||
if self._name == '':
|
||||
self._name = self.nameGenerator().get( self.publication().getBaseName(),
|
||||
3 )
|
||||
# self._name will be stored when object is marshaled
|
||||
return self._name
|
||||
|
||||
def setIp(self, ip):
|
||||
'''
|
||||
In our case, there is no OS manager associated with this, so this method
|
||||
will never get called, but we put here as sample.
|
||||
|
||||
Whenever an os manager actor notifies the broker the state of the service
|
||||
(mainly machines), the implementation of that os manager can (an probably will)
|
||||
need to notify the IP of the deployed service. Remember that UDS treats with
|
||||
IP services, so will probable needed in every service that you will create.
|
||||
:note: This IP is the IP of the "consumed service", so the transport can
|
||||
access it.
|
||||
'''
|
||||
self._ip = ip
|
||||
|
||||
def getUniqueId(self):
|
||||
'''
|
||||
Return and unique identifier for this service.
|
||||
In our case, we will generate a mac name, that can be also as sample
|
||||
of 'mac' generator use, and probably will get used something like this
|
||||
at some services.
|
||||
|
||||
The get method of a mac generator takes one param, that is the mac range
|
||||
to use to get an unused mac.
|
||||
|
||||
The mac generated is not used by anyone, it will not depend on
|
||||
the range, the generator will take care that this mac is unique
|
||||
and in the range provided, or it will return None. The ranges
|
||||
are wide enough to ensure that we always will get a mac address
|
||||
in this case, but if this is not your case, take into account that
|
||||
None is a possible return value, and in that case, you should return an
|
||||
invalid id right now. Every time a task method is invoked, the core
|
||||
will try to update the value of the unique id using this method, so
|
||||
that id can change with time. (In fact, it's not unique at database level,
|
||||
it's unique in the sense that you must return an unique id that can, for
|
||||
example, be used by os managers to identify this element).
|
||||
|
||||
:note: Normally, getting out of macs in the mac pool is a bad thing... :-)
|
||||
'''
|
||||
if self._mac == '':
|
||||
self._mac = self.macGenerator().get( '00:00:00:00:00:00-00:FF:FF:FF:FF:FF' )
|
||||
return self._mac
|
||||
|
||||
def getIp(self):
|
||||
'''
|
||||
We need to implement this method, so we can return the IP for transports
|
||||
use. If no IP is known for this service, this must return None
|
||||
|
||||
If our sample do not returns an IP, IP transport will never work with
|
||||
this service. Remember in real cases to return a valid IP address if
|
||||
the service is accesible and you alredy know that (for example, because
|
||||
the IP has been assigend via setIp by an os manager) or because
|
||||
you get it for some other method.
|
||||
|
||||
Storage returns None if key is not stored.
|
||||
|
||||
:note: Keeping the IP address is responsibility of the User Deployment.
|
||||
Every time the core needs to provide the service to the user, or
|
||||
show the IP to the administrator, this method will get called
|
||||
|
||||
'''
|
||||
if self._ip == '':
|
||||
return '192.168.0.34' # Sample IP for testing purposes only
|
||||
return self._ip
|
||||
|
||||
def setReady(self):
|
||||
'''
|
||||
This is a task method. As that, the excepted return values are
|
||||
State values RUNNING, FINISHED or ERROR.
|
||||
|
||||
The method is invoked whenever a machine is provided to an user, right
|
||||
before presenting it (via transport rendering) to the user.
|
||||
|
||||
This method exist for this kind of situations (i will explain it with a
|
||||
sample)
|
||||
|
||||
Imagine a Service tree (Provider, Service, ...) for virtual machines.
|
||||
This machines will get created by the UserDeployment implementation, but,
|
||||
at some time, the machine can be put at in an state (suspend, shut down)
|
||||
that will make the transport impossible to connect with it.
|
||||
|
||||
This method, in this case, will check the state of the machine, and if
|
||||
it is "ready", that is, powered on and accessible, it will return
|
||||
"State.FINISHED". If the machine is not accessible (has been erased, for
|
||||
example), it will return "State.ERROR" and store a reason of error so UDS
|
||||
can ask for it and present this information to the Administrator.
|
||||
|
||||
If the machine powered off, or suspended, or any other state that is not
|
||||
directly usable but can be put in an usable state, it will return
|
||||
"State.RUNNING", and core will use checkState to see when the operation
|
||||
has finished.
|
||||
|
||||
I hope this sample is enough to explain the use of this method..
|
||||
'''
|
||||
|
||||
# In our case, the service is always ready
|
||||
return State.FINISHED
|
||||
|
||||
def deployForUser(self, user):
|
||||
'''
|
||||
Deploys an service instance for an user.
|
||||
|
||||
This is a task method. As that, the excepted return values are
|
||||
State values RUNNING, FINISHED or ERROR.
|
||||
|
||||
The user parameter is not realy neded, but provided. It indicates the
|
||||
Database User Object (see py:mod:`uds.modules`) to which this deployed
|
||||
user service will be assigned to.
|
||||
|
||||
This method will get called whenever a new deployed service for an user
|
||||
is needed. This will give this class the oportunity to create
|
||||
a service that is assigned to an user.
|
||||
|
||||
The way of using this method is as follows:
|
||||
|
||||
If the service gets created in "one step", that is, before the return
|
||||
of this method, the consumable service for the user gets created, it
|
||||
will return "State.FINISH".
|
||||
If the service needs more steps (as in this case), we will return
|
||||
"State.RUNNING", and if it has an error, it wil return "State.ERROR" and
|
||||
store an error string so administration interface can show it.
|
||||
|
||||
We do not use user for anything, as in most cases will be.
|
||||
'''
|
||||
import random
|
||||
|
||||
self._count = 0
|
||||
|
||||
# random fail
|
||||
if random.randint(0, 9) == 9:
|
||||
# Note that we can mark this string as translatable, and return
|
||||
# it translated at reasonOfError method
|
||||
self._error = 'Random error at deployForUser :-)'
|
||||
return State.ERROR
|
||||
|
||||
return State.RUNNING
|
||||
|
||||
def deployForCache(self, cacheLevel):
|
||||
'''
|
||||
Deploys a user deployment as cache.
|
||||
|
||||
This is a task method. As that, the expected return values are
|
||||
State values RUNNING, FINISHED or ERROR.
|
||||
|
||||
In our sample, this will do exactly the same as deploy for user,
|
||||
except that it will never will give an error.
|
||||
|
||||
See deployForUser for a description of what this method should do.
|
||||
|
||||
:note: deployForCache is invoked whenever a new cache element is needed
|
||||
for an specific user deployment. It will also indicate for what
|
||||
cache level (L1, L2) is the deployment
|
||||
'''
|
||||
self._count = 0
|
||||
return State.RUNNING
|
||||
|
||||
def moveToCache(self, newLevel):
|
||||
'''
|
||||
This method is invoked whenever the core needs to move from the current
|
||||
cache level to a new cache level an user deployment.
|
||||
|
||||
This is a task method. As that, the expected return values are
|
||||
State values RUNNING, FINISHED or ERROR.
|
||||
|
||||
We only provide newLevel, because there is only two cache levels, so if
|
||||
newLevel is L1, the actual is L2, and if it is L2, the actual is L1.
|
||||
|
||||
Actually there is no possibility to move assigned services again back to
|
||||
cache. If some service needs that kind of functionallity, this must be
|
||||
provided at service level (for example, when doing publishing creating
|
||||
a number of services that will be used, released and reused by users).
|
||||
|
||||
Also, user deployments that are at cache level 2 will never get directly
|
||||
assigned to user. First, it will pass to L1 and then it will get assigned.
|
||||
|
||||
A good sample of a real implementation of this is moving a virtual machine
|
||||
from a "suspended" state to "running" state to assign it to an user.
|
||||
|
||||
In this sample, there is L2 cache also, but moving from L1 to L2 and
|
||||
from L2 to L1 is doing really nothing, so this method will do nothing.
|
||||
|
||||
In a real scenario, we will, for example, suspend or resume virtual machine
|
||||
and, return State.RUNNING and at checkState check if this task is completed.
|
||||
'''
|
||||
pass
|
||||
|
||||
def checkState(self):
|
||||
'''
|
||||
Our deployForUser method will initiate the consumable service deployment,
|
||||
but will not finish it.
|
||||
|
||||
So in our sample, we will only check if a number reaches 5, and if so
|
||||
return that we have finished, else we will return that we are working
|
||||
on it.
|
||||
|
||||
One deployForUser returns State.RUNNING, this task will get called until
|
||||
checkState returns State.FINISHED.
|
||||
|
||||
Also, we will make the user deployment fail one of every 10 calls to this
|
||||
method.
|
||||
|
||||
Note: Destroying, canceling and deploying for cache also makes use of
|
||||
this method, so you must keep the info of that you are checking if you
|
||||
need it.
|
||||
|
||||
In our case, destroy is 1-step action so this will no get called while
|
||||
destroying, and cancel will simply invoke destroy. Cache deployment is
|
||||
exactly as user deployment, except that the core will not assign it to
|
||||
anyone, and cache moving operations is
|
||||
'''
|
||||
import random
|
||||
|
||||
self._count += 1
|
||||
# Count is always a valid value, because this method will never get
|
||||
# called before deployForUser, deployForCache, destroy or cancel.
|
||||
# In our sample, we only use checkState in case of deployForUser,
|
||||
# so at first call count will be 0.
|
||||
if self._count >= 5:
|
||||
return State.FINISHED
|
||||
|
||||
# random fail
|
||||
if random.randint(0, 9) == 9:
|
||||
self._error = 'Random error at checkState :-)'
|
||||
return State.ERROR
|
||||
|
||||
return State.RUNNING
|
||||
|
||||
def finish(self):
|
||||
'''
|
||||
Invoked when the core notices that the deployment of a service has finished.
|
||||
(No matter whether it is for cache or for an user)
|
||||
|
||||
This gives the opportunity to make something at that moment.
|
||||
|
||||
:note: You can also make these operations at checkState, this is really
|
||||
not needed, but can be provided (default implementation of base class does
|
||||
nothing)
|
||||
'''
|
||||
# We set count to 0, not needed but for sample purposes
|
||||
self._count = 0
|
||||
|
||||
def assignToUser(self, user):
|
||||
'''
|
||||
This method is invoked whenever a cache item gets assigned to an user.
|
||||
This is not a task method right now, simply a notification. This means
|
||||
that L1 cache items must be directly usable (except for the readyness part)
|
||||
by users in a single step operation.
|
||||
|
||||
Note that there will be an setReady call before letting the user consume
|
||||
this user deployment, so this is more informational (so, if you keep at
|
||||
what cache level is this instance, you can update it) than anything else.
|
||||
|
||||
This is not a task method. All level 1 cache items can be dircetly
|
||||
assigned to an user with no more work needed, but, if something is needed,
|
||||
here you can do whatever you need.
|
||||
|
||||
user is a Database user object.
|
||||
'''
|
||||
logger.debug('Assigned to user {0}'.format(user))
|
||||
|
||||
def userLoggedIn(self, user):
|
||||
'''
|
||||
This method must be available so os managers can invoke it whenever
|
||||
an user get logged into a service.
|
||||
|
||||
Default implementation does nothing, so if you are going to do nothing,
|
||||
you don't need to implement it.
|
||||
|
||||
The responsibility of notifying it is of os manager actor, and it's
|
||||
directly invoked by os managers (right now, linux os manager and windows
|
||||
os manager)
|
||||
|
||||
The user provided is just an string, that is provided by actors.
|
||||
'''
|
||||
# We store the value at storage, but never get used, just an example
|
||||
self.storage().saveData('user', user)
|
||||
|
||||
def userLoggedOut(self, user):
|
||||
'''
|
||||
This method must be available so os managers can invoke it whenever
|
||||
an user get logged out if a service.
|
||||
|
||||
Default implementation does nothing, so if you are going to do nothing,
|
||||
you don't need to implement it.
|
||||
|
||||
The responability of notifying it is of os manager actor, and it's
|
||||
directly invoked by os managers (right now, linux os manager and windows
|
||||
os manager)
|
||||
|
||||
The user provided is just an string, that is provided by actor.
|
||||
'''
|
||||
# We do nothing more that remove the user
|
||||
self.storage().remove('user')
|
||||
|
||||
def reasonOfError(self):
|
||||
'''
|
||||
Returns the reason of the error.
|
||||
|
||||
Remember that the class is responsible of returning this whenever asked
|
||||
for it, and it will be asked everytime it's needed to be shown to the
|
||||
user (when the administation asks for it).
|
||||
|
||||
:note: Remember that you can use ugettext to translate this error to
|
||||
user language whenever it is possible. (This one will get invoked
|
||||
directly from admin interface and, as so, will have translation
|
||||
environment correctly set up.
|
||||
'''
|
||||
return self._error
|
||||
|
||||
def destroy(self):
|
||||
'''
|
||||
This is a task method. As that, the excepted return values are
|
||||
State values RUNNING, FINISHED or ERROR.
|
||||
|
||||
Invoked for destroying a deployed service
|
||||
Do whatever needed here, as deleting associated data if needed (i.e. a copy of the machine, snapshots, etc...)
|
||||
@return: State.FINISHED if no more checks/steps for deployment are needed, State.RUNNING if more steps are needed (steps checked using checkState)
|
||||
'''
|
||||
return State.FINISHED
|
||||
|
||||
def cancel(self):
|
||||
'''
|
||||
This is a task method. As that, the excepted return values are
|
||||
State values RUNNING, FINISHED or ERROR.
|
||||
|
||||
This can be invoked directly by an administration or by the clean up
|
||||
of the deployed service (indirectly).
|
||||
When administrator requests it, the cancel is "delayed" and not
|
||||
invoked directly.
|
||||
'''
|
||||
return State.FINISHED
|
@ -1,44 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2012 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
'''
|
||||
Sample Service module.
|
||||
|
||||
This package simply shows how a new service can be implemented.
|
||||
|
||||
|
||||
The first thing to do in every package that is a module is register the
|
||||
class that is responsible of providing the module with the system.
|
||||
|
||||
For this, we must simply import the class at __init__, UDS will take care
|
||||
of the rest
|
||||
'''
|
||||
|
||||
from SampleProvider import Provider
|
||||
|
@ -1,96 +0,0 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
|
||||
<title>Overview: module code — UDS 1.0 documentation</title>
|
||||
|
||||
<link rel="stylesheet" href="../_static/sphinxdoc.css" type="text/css" />
|
||||
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
|
||||
|
||||
<script type="text/javascript">
|
||||
var DOCUMENTATION_OPTIONS = {
|
||||
URL_ROOT: '../',
|
||||
VERSION: '1.0',
|
||||
COLLAPSE_INDEX: false,
|
||||
FILE_SUFFIX: '.html',
|
||||
HAS_SOURCE: true
|
||||
};
|
||||
</script>
|
||||
<script type="text/javascript" src="../_static/jquery.js"></script>
|
||||
<script type="text/javascript" src="../_static/underscore.js"></script>
|
||||
<script type="text/javascript" src="../_static/doctools.js"></script>
|
||||
<script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
|
||||
<link rel="top" title="UDS 1.0 documentation" href="../index.html" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="related">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="../genindex.html" title="General Index"
|
||||
accesskey="I">index</a></li>
|
||||
<li class="right" >
|
||||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li><a href="../index.html">UDS 1.0 documentation</a> »</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="sphinxsidebar">
|
||||
<div class="sphinxsidebarwrapper">
|
||||
<div id="searchbox" style="display: none">
|
||||
<h3>Quick search</h3>
|
||||
<form class="search" action="../search.html" method="get">
|
||||
<input type="text" name="q" />
|
||||
<input type="submit" value="Go" />
|
||||
<input type="hidden" name="check_keywords" value="yes" />
|
||||
<input type="hidden" name="area" value="default" />
|
||||
</form>
|
||||
<p class="searchtip" style="font-size: 90%">
|
||||
Enter search terms or a module, class or function name.
|
||||
</p>
|
||||
</div>
|
||||
<script type="text/javascript">$('#searchbox').show(0);</script>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="document">
|
||||
<div class="documentwrapper">
|
||||
<div class="bodywrapper">
|
||||
<div class="body">
|
||||
|
||||
<h1>All modules for which code is available</h1>
|
||||
<ul><li><a href="uds/core.html">uds.core</a></li>
|
||||
<ul><li><a href="uds/core/auths.html">uds.core.auths</a></li>
|
||||
<li><a href="uds/core/services.html">uds.core.services</a></li>
|
||||
<ul><li><a href="uds/core/services/Exceptions.html">uds.core.services.Exceptions</a></li>
|
||||
</ul><li><a href="uds/core/ui/UserInterface.html">uds.core.ui.UserInterface</a></li>
|
||||
</ul><li><a href="uds/models.html">uds.models</a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearer"></div>
|
||||
</div>
|
||||
<div class="related">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="../genindex.html" title="General Index"
|
||||
>index</a></li>
|
||||
<li class="right" >
|
||||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li><a href="../index.html">UDS 1.0 documentation</a> »</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="footer">
|
||||
© Copyright 2012, Virtual Cable S.L.U..
|
||||
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2.2.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -1,136 +0,0 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
|
||||
<title>uds.core — UDS 1.0 documentation</title>
|
||||
|
||||
<link rel="stylesheet" href="../../_static/sphinxdoc.css" type="text/css" />
|
||||
<link rel="stylesheet" href="../../_static/pygments.css" type="text/css" />
|
||||
|
||||
<script type="text/javascript">
|
||||
var DOCUMENTATION_OPTIONS = {
|
||||
URL_ROOT: '../../',
|
||||
VERSION: '1.0',
|
||||
COLLAPSE_INDEX: false,
|
||||
FILE_SUFFIX: '.html',
|
||||
HAS_SOURCE: true
|
||||
};
|
||||
</script>
|
||||
<script type="text/javascript" src="../../_static/jquery.js"></script>
|
||||
<script type="text/javascript" src="../../_static/underscore.js"></script>
|
||||
<script type="text/javascript" src="../../_static/doctools.js"></script>
|
||||
<script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
|
||||
<link rel="top" title="UDS 1.0 documentation" href="../../index.html" />
|
||||
<link rel="up" title="Module code" href="../index.html" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="related">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="../../genindex.html" title="General Index"
|
||||
accesskey="I">index</a></li>
|
||||
<li class="right" >
|
||||
<a href="../../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li><a href="../../index.html">UDS 1.0 documentation</a> »</li>
|
||||
<li><a href="../index.html" accesskey="U">Module code</a> »</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="sphinxsidebar">
|
||||
<div class="sphinxsidebarwrapper">
|
||||
<div id="searchbox" style="display: none">
|
||||
<h3>Quick search</h3>
|
||||
<form class="search" action="../../search.html" method="get">
|
||||
<input type="text" name="q" />
|
||||
<input type="submit" value="Go" />
|
||||
<input type="hidden" name="check_keywords" value="yes" />
|
||||
<input type="hidden" name="area" value="default" />
|
||||
</form>
|
||||
<p class="searchtip" style="font-size: 90%">
|
||||
Enter search terms or a module, class or function name.
|
||||
</p>
|
||||
</div>
|
||||
<script type="text/javascript">$('#searchbox').show(0);</script>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="document">
|
||||
<div class="documentwrapper">
|
||||
<div class="bodywrapper">
|
||||
<div class="body">
|
||||
|
||||
<h1>Source code for uds.core</h1><div class="highlight"><pre>
|
||||
<span class="c"># -*- coding: utf-8 -*-</span>
|
||||
|
||||
<span class="c">#</span>
|
||||
<span class="c"># Copyright (c) 2012 Virtual Cable S.L.</span>
|
||||
<span class="c"># All rights reserved.</span>
|
||||
<span class="c">#</span>
|
||||
<span class="c"># Redistribution and use in source and binary forms, with or without modification,</span>
|
||||
<span class="c"># are permitted provided that the following conditions are met:</span>
|
||||
<span class="c">#</span>
|
||||
<span class="c"># * Redistributions of source code must retain the above copyright notice,</span>
|
||||
<span class="c"># this list of conditions and the following disclaimer.</span>
|
||||
<span class="c"># * Redistributions in binary form must reproduce the above copyright notice,</span>
|
||||
<span class="c"># this list of conditions and the following disclaimer in the documentation</span>
|
||||
<span class="c"># and/or other materials provided with the distribution.</span>
|
||||
<span class="c"># * Neither the name of Virtual Cable S.L. nor the names of its contributors</span>
|
||||
<span class="c"># may be used to endorse or promote products derived from this software</span>
|
||||
<span class="c"># without specific prior written permission.</span>
|
||||
<span class="c">#</span>
|
||||
<span class="c"># THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"</span>
|
||||
<span class="c"># AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE</span>
|
||||
<span class="c"># IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE</span>
|
||||
<span class="c"># DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE</span>
|
||||
<span class="c"># FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL</span>
|
||||
<span class="c"># DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR</span>
|
||||
<span class="c"># SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER</span>
|
||||
<span class="c"># CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,</span>
|
||||
<span class="c"># OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE</span>
|
||||
<span class="c"># OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</span>
|
||||
|
||||
<span class="sd">'''</span>
|
||||
<span class="sd">Core of UDS.</span>
|
||||
<span class="sd">This package contains all core-related code for UDS</span>
|
||||
<span class="sd">@author: Adolfo Gómez, dkmaster at dkmon dot com</span>
|
||||
<span class="sd">'''</span>
|
||||
<span class="kn">from</span> <span class="nn">__future__</span> <span class="kn">import</span> <span class="n">unicode_literals</span>
|
||||
|
||||
<span class="c"># Core needs tasks manager to register scheduled jobs, so we ensure of that here</span>
|
||||
<span class="kn">from</span> <span class="nn">Environment</span> <span class="kn">import</span> <span class="n">Environmentable</span>
|
||||
<span class="kn">from</span> <span class="nn">Serializable</span> <span class="kn">import</span> <span class="n">Serializable</span>
|
||||
<span class="kn">from</span> <span class="nn">BaseModule</span> <span class="kn">import</span> <span class="n">Module</span>
|
||||
<span class="kn">import</span> <span class="nn">services</span>
|
||||
<span class="kn">import</span> <span class="nn">auths</span>
|
||||
<span class="kn">import</span> <span class="nn">transports</span>
|
||||
</pre></div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearer"></div>
|
||||
</div>
|
||||
<div class="related">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="../../genindex.html" title="General Index"
|
||||
>index</a></li>
|
||||
<li class="right" >
|
||||
<a href="../../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li><a href="../../index.html">UDS 1.0 documentation</a> »</li>
|
||||
<li><a href="../index.html" >Module code</a> »</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="footer">
|
||||
© Copyright 2012, Virtual Cable S.L.U..
|
||||
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2.2.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -1,146 +0,0 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
|
||||
<title>uds.core.auths — UDS 1.0 documentation</title>
|
||||
|
||||
<link rel="stylesheet" href="../../../_static/sphinxdoc.css" type="text/css" />
|
||||
<link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" />
|
||||
|
||||
<script type="text/javascript">
|
||||
var DOCUMENTATION_OPTIONS = {
|
||||
URL_ROOT: '../../../',
|
||||
VERSION: '1.0',
|
||||
COLLAPSE_INDEX: false,
|
||||
FILE_SUFFIX: '.html',
|
||||
HAS_SOURCE: true
|
||||
};
|
||||
</script>
|
||||
<script type="text/javascript" src="../../../_static/jquery.js"></script>
|
||||
<script type="text/javascript" src="../../../_static/underscore.js"></script>
|
||||
<script type="text/javascript" src="../../../_static/doctools.js"></script>
|
||||
<script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
|
||||
<link rel="top" title="UDS 1.0 documentation" href="../../../index.html" />
|
||||
<link rel="up" title="uds.core" href="../core.html" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="related">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="../../../genindex.html" title="General Index"
|
||||
accesskey="I">index</a></li>
|
||||
<li class="right" >
|
||||
<a href="../../../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li><a href="../../../index.html">UDS 1.0 documentation</a> »</li>
|
||||
<li><a href="../../index.html" >Module code</a> »</li>
|
||||
<li><a href="../core.html" accesskey="U">uds.core</a> »</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="sphinxsidebar">
|
||||
<div class="sphinxsidebarwrapper">
|
||||
<div id="searchbox" style="display: none">
|
||||
<h3>Quick search</h3>
|
||||
<form class="search" action="../../../search.html" method="get">
|
||||
<input type="text" name="q" />
|
||||
<input type="submit" value="Go" />
|
||||
<input type="hidden" name="check_keywords" value="yes" />
|
||||
<input type="hidden" name="area" value="default" />
|
||||
</form>
|
||||
<p class="searchtip" style="font-size: 90%">
|
||||
Enter search terms or a module, class or function name.
|
||||
</p>
|
||||
</div>
|
||||
<script type="text/javascript">$('#searchbox').show(0);</script>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="document">
|
||||
<div class="documentwrapper">
|
||||
<div class="bodywrapper">
|
||||
<div class="body">
|
||||
|
||||
<h1>Source code for uds.core.auths</h1><div class="highlight"><pre>
|
||||
<span class="c"># -*- coding: utf-8 -*-</span>
|
||||
|
||||
<span class="c">#</span>
|
||||
<span class="c"># Copyright (c) 2012 Virtual Cable S.L.</span>
|
||||
<span class="c"># All rights reserved.</span>
|
||||
<span class="c">#</span>
|
||||
<span class="c"># Redistribution and use in source and binary forms, with or without modification,</span>
|
||||
<span class="c"># are permitted provided that the following conditions are met:</span>
|
||||
<span class="c">#</span>
|
||||
<span class="c"># * Redistributions of source code must retain the above copyright notice,</span>
|
||||
<span class="c"># this list of conditions and the following disclaimer.</span>
|
||||
<span class="c"># * Redistributions in binary form must reproduce the above copyright notice,</span>
|
||||
<span class="c"># this list of conditions and the following disclaimer in the documentation</span>
|
||||
<span class="c"># and/or other materials provided with the distribution.</span>
|
||||
<span class="c"># * Neither the name of Virtual Cable S.L. nor the names of its contributors</span>
|
||||
<span class="c"># may be used to endorse or promote products derived from this software</span>
|
||||
<span class="c"># without specific prior written permission.</span>
|
||||
<span class="c">#</span>
|
||||
<span class="c"># THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"</span>
|
||||
<span class="c"># AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE</span>
|
||||
<span class="c"># IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE</span>
|
||||
<span class="c"># DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE</span>
|
||||
<span class="c"># FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL</span>
|
||||
<span class="c"># DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR</span>
|
||||
<span class="c"># SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER</span>
|
||||
<span class="c"># CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,</span>
|
||||
<span class="c"># OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE</span>
|
||||
<span class="c"># OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</span>
|
||||
|
||||
<span class="sd">'''</span>
|
||||
<span class="sd">UDS authentication related interfaces and classes</span>
|
||||
|
||||
<span class="sd">.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com</span>
|
||||
<span class="sd">'''</span>
|
||||
<span class="kn">from</span> <span class="nn">__future__</span> <span class="kn">import</span> <span class="n">unicode_literals</span>
|
||||
|
||||
<span class="kn">from</span> <span class="nn">BaseAuthenticator</span> <span class="kn">import</span> <span class="n">Authenticator</span>
|
||||
<span class="kn">from</span> <span class="nn">User</span> <span class="kn">import</span> <span class="n">User</span>
|
||||
<span class="kn">from</span> <span class="nn">Group</span> <span class="kn">import</span> <span class="n">Group</span>
|
||||
<span class="kn">from</span> <span class="nn">GroupsManager</span> <span class="kn">import</span> <span class="n">GroupsManager</span>
|
||||
<span class="kn">import</span> <span class="nn">Exceptions</span>
|
||||
|
||||
<span class="n">__updated__</span> <span class="o">=</span> <span class="s">'2014-02-19'</span>
|
||||
|
||||
|
||||
<span class="k">def</span> <span class="nf">factory</span><span class="p">():</span>
|
||||
<span class="sd">'''</span>
|
||||
<span class="sd"> Returns factory for register/access to authenticators</span>
|
||||
<span class="sd"> '''</span>
|
||||
<span class="kn">from</span> <span class="nn">AuthsFactory</span> <span class="kn">import</span> <span class="n">AuthsFactory</span>
|
||||
<span class="k">return</span> <span class="n">AuthsFactory</span><span class="o">.</span><span class="n">factory</span><span class="p">()</span>
|
||||
</pre></div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearer"></div>
|
||||
</div>
|
||||
<div class="related">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="../../../genindex.html" title="General Index"
|
||||
>index</a></li>
|
||||
<li class="right" >
|
||||
<a href="../../../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li><a href="../../../index.html">UDS 1.0 documentation</a> »</li>
|
||||
<li><a href="../../index.html" >Module code</a> »</li>
|
||||
<li><a href="../core.html" >uds.core</a> »</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="footer">
|
||||
© Copyright 2012, Virtual Cable S.L.U..
|
||||
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2.2.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -1,152 +0,0 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
|
||||
<title>uds.core.services — UDS 1.0 documentation</title>
|
||||
|
||||
<link rel="stylesheet" href="../../../_static/sphinxdoc.css" type="text/css" />
|
||||
<link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" />
|
||||
|
||||
<script type="text/javascript">
|
||||
var DOCUMENTATION_OPTIONS = {
|
||||
URL_ROOT: '../../../',
|
||||
VERSION: '1.0',
|
||||
COLLAPSE_INDEX: false,
|
||||
FILE_SUFFIX: '.html',
|
||||
HAS_SOURCE: true
|
||||
};
|
||||
</script>
|
||||
<script type="text/javascript" src="../../../_static/jquery.js"></script>
|
||||
<script type="text/javascript" src="../../../_static/underscore.js"></script>
|
||||
<script type="text/javascript" src="../../../_static/doctools.js"></script>
|
||||
<script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
|
||||
<link rel="top" title="UDS 1.0 documentation" href="../../../index.html" />
|
||||
<link rel="up" title="uds.core" href="../core.html" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="related">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="../../../genindex.html" title="General Index"
|
||||
accesskey="I">index</a></li>
|
||||
<li class="right" >
|
||||
<a href="../../../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li><a href="../../../index.html">UDS 1.0 documentation</a> »</li>
|
||||
<li><a href="../../index.html" >Module code</a> »</li>
|
||||
<li><a href="../core.html" accesskey="U">uds.core</a> »</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="sphinxsidebar">
|
||||
<div class="sphinxsidebarwrapper">
|
||||
<div id="searchbox" style="display: none">
|
||||
<h3>Quick search</h3>
|
||||
<form class="search" action="../../../search.html" method="get">
|
||||
<input type="text" name="q" />
|
||||
<input type="submit" value="Go" />
|
||||
<input type="hidden" name="check_keywords" value="yes" />
|
||||
<input type="hidden" name="area" value="default" />
|
||||
</form>
|
||||
<p class="searchtip" style="font-size: 90%">
|
||||
Enter search terms or a module, class or function name.
|
||||
</p>
|
||||
</div>
|
||||
<script type="text/javascript">$('#searchbox').show(0);</script>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="document">
|
||||
<div class="documentwrapper">
|
||||
<div class="bodywrapper">
|
||||
<div class="body">
|
||||
|
||||
<h1>Source code for uds.core.services</h1><div class="highlight"><pre>
|
||||
<span class="c"># -*- coding: utf-8 -*-</span>
|
||||
|
||||
<span class="c">#</span>
|
||||
<span class="c"># Copyright (c) 2012 Virtual Cable S.L.</span>
|
||||
<span class="c"># All rights reserved.</span>
|
||||
<span class="c">#</span>
|
||||
<span class="c"># Redistribution and use in source and binary forms, with or without modification,</span>
|
||||
<span class="c"># are permitted provided that the following conditions are met:</span>
|
||||
<span class="c">#</span>
|
||||
<span class="c"># * Redistributions of source code must retain the above copyright notice,</span>
|
||||
<span class="c"># this list of conditions and the following disclaimer.</span>
|
||||
<span class="c"># * Redistributions in binary form must reproduce the above copyright notice,</span>
|
||||
<span class="c"># this list of conditions and the following disclaimer in the documentation</span>
|
||||
<span class="c"># and/or other materials provided with the distribution.</span>
|
||||
<span class="c"># * Neither the name of Virtual Cable S.L. nor the names of its contributors</span>
|
||||
<span class="c"># may be used to endorse or promote products derived from this software</span>
|
||||
<span class="c"># without specific prior written permission.</span>
|
||||
<span class="c">#</span>
|
||||
<span class="c"># THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"</span>
|
||||
<span class="c"># AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE</span>
|
||||
<span class="c"># IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE</span>
|
||||
<span class="c"># DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE</span>
|
||||
<span class="c"># FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL</span>
|
||||
<span class="c"># DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR</span>
|
||||
<span class="c"># SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER</span>
|
||||
<span class="c"># CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,</span>
|
||||
<span class="c"># OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE</span>
|
||||
<span class="c"># OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</span>
|
||||
|
||||
<span class="sd">'''</span>
|
||||
<span class="sd">UDS Service modules interfaces and classes.</span>
|
||||
|
||||
<span class="sd">.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com</span>
|
||||
<span class="sd">'''</span>
|
||||
<span class="kn">from</span> <span class="nn">__future__</span> <span class="kn">import</span> <span class="n">unicode_literals</span>
|
||||
|
||||
<span class="kn">from</span> <span class="nn">BaseServiceProvider</span> <span class="kn">import</span> <span class="n">ServiceProvider</span>
|
||||
<span class="kn">from</span> <span class="nn">BaseService</span> <span class="kn">import</span> <span class="n">Service</span>
|
||||
<span class="kn">from</span> <span class="nn">BasePublication</span> <span class="kn">import</span> <span class="n">Publication</span>
|
||||
<span class="kn">from</span> <span class="nn">BaseDeployed</span> <span class="kn">import</span> <span class="n">UserDeployment</span>
|
||||
|
||||
<span class="kn">from</span> <span class="nn">ClusteredServiceProvider</span> <span class="kn">import</span> <span class="n">ClusteredServiceProvider</span>
|
||||
<span class="kn">from</span> <span class="nn">ClusteredService</span> <span class="kn">import</span> <span class="n">ClusteredService</span>
|
||||
<span class="kn">from</span> <span class="nn">ClusteredPublication</span> <span class="kn">import</span> <span class="n">ClusteredPublication</span>
|
||||
<span class="kn">from</span> <span class="nn">ClusteredUserDeployment</span> <span class="kn">import</span> <span class="n">ClusteredUserDeployment</span>
|
||||
|
||||
<span class="kn">import</span> <span class="nn">Exceptions</span>
|
||||
|
||||
<span class="n">__updated__</span> <span class="o">=</span> <span class="s">'2014-03-22'</span>
|
||||
|
||||
|
||||
<span class="k">def</span> <span class="nf">factory</span><span class="p">():</span>
|
||||
<span class="sd">'''</span>
|
||||
<span class="sd"> Returns factory for register/access to service providers</span>
|
||||
<span class="sd"> '''</span>
|
||||
<span class="kn">from</span> <span class="nn">ServiceProviderFactory</span> <span class="kn">import</span> <span class="n">ServiceProviderFactory</span>
|
||||
<span class="k">return</span> <span class="n">ServiceProviderFactory</span><span class="o">.</span><span class="n">factory</span><span class="p">()</span>
|
||||
</pre></div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearer"></div>
|
||||
</div>
|
||||
<div class="related">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="../../../genindex.html" title="General Index"
|
||||
>index</a></li>
|
||||
<li class="right" >
|
||||
<a href="../../../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li><a href="../../../index.html">UDS 1.0 documentation</a> »</li>
|
||||
<li><a href="../../index.html" >Module code</a> »</li>
|
||||
<li><a href="../core.html" >uds.core</a> »</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="footer">
|
||||
© Copyright 2012, Virtual Cable S.L.U..
|
||||
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2.2.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -1,181 +0,0 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
|
||||
<title>uds.core.services.Exceptions — UDS 1.0 documentation</title>
|
||||
|
||||
<link rel="stylesheet" href="../../../../_static/sphinxdoc.css" type="text/css" />
|
||||
<link rel="stylesheet" href="../../../../_static/pygments.css" type="text/css" />
|
||||
|
||||
<script type="text/javascript">
|
||||
var DOCUMENTATION_OPTIONS = {
|
||||
URL_ROOT: '../../../../',
|
||||
VERSION: '1.0',
|
||||
COLLAPSE_INDEX: false,
|
||||
FILE_SUFFIX: '.html',
|
||||
HAS_SOURCE: true
|
||||
};
|
||||
</script>
|
||||
<script type="text/javascript" src="../../../../_static/jquery.js"></script>
|
||||
<script type="text/javascript" src="../../../../_static/underscore.js"></script>
|
||||
<script type="text/javascript" src="../../../../_static/doctools.js"></script>
|
||||
<script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
|
||||
<link rel="top" title="UDS 1.0 documentation" href="../../../../index.html" />
|
||||
<link rel="up" title="uds.core.services" href="../services.html" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="related">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="../../../../genindex.html" title="General Index"
|
||||
accesskey="I">index</a></li>
|
||||
<li class="right" >
|
||||
<a href="../../../../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li><a href="../../../../index.html">UDS 1.0 documentation</a> »</li>
|
||||
<li><a href="../../../index.html" >Module code</a> »</li>
|
||||
<li><a href="../../core.html" >uds.core</a> »</li>
|
||||
<li><a href="../services.html" accesskey="U">uds.core.services</a> »</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="sphinxsidebar">
|
||||
<div class="sphinxsidebarwrapper">
|
||||
<div id="searchbox" style="display: none">
|
||||
<h3>Quick search</h3>
|
||||
<form class="search" action="../../../../search.html" method="get">
|
||||
<input type="text" name="q" />
|
||||
<input type="submit" value="Go" />
|
||||
<input type="hidden" name="check_keywords" value="yes" />
|
||||
<input type="hidden" name="area" value="default" />
|
||||
</form>
|
||||
<p class="searchtip" style="font-size: 90%">
|
||||
Enter search terms or a module, class or function name.
|
||||
</p>
|
||||
</div>
|
||||
<script type="text/javascript">$('#searchbox').show(0);</script>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="document">
|
||||
<div class="documentwrapper">
|
||||
<div class="bodywrapper">
|
||||
<div class="body">
|
||||
|
||||
<h1>Source code for uds.core.services.Exceptions</h1><div class="highlight"><pre>
|
||||
<span class="c"># -*- coding: utf-8 -*-</span>
|
||||
|
||||
<span class="c">#</span>
|
||||
<span class="c"># Copyright (c) 2012 Virtual Cable S.L.</span>
|
||||
<span class="c"># All rights reserved.</span>
|
||||
<span class="c">#</span>
|
||||
<span class="c"># Redistribution and use in source and binary forms, with or without modification,</span>
|
||||
<span class="c"># are permitted provided that the following conditions are met:</span>
|
||||
<span class="c">#</span>
|
||||
<span class="c"># * Redistributions of source code must retain the above copyright notice,</span>
|
||||
<span class="c"># this list of conditions and the following disclaimer.</span>
|
||||
<span class="c"># * Redistributions in binary form must reproduce the above copyright notice,</span>
|
||||
<span class="c"># this list of conditions and the following disclaimer in the documentation</span>
|
||||
<span class="c"># and/or other materials provided with the distribution.</span>
|
||||
<span class="c"># * Neither the name of Virtual Cable S.L. nor the names of its contributors</span>
|
||||
<span class="c"># may be used to endorse or promote products derived from this software</span>
|
||||
<span class="c"># without specific prior written permission.</span>
|
||||
<span class="c">#</span>
|
||||
<span class="c"># THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"</span>
|
||||
<span class="c"># AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE</span>
|
||||
<span class="c"># IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE</span>
|
||||
<span class="c"># DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE</span>
|
||||
<span class="c"># FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL</span>
|
||||
<span class="c"># DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR</span>
|
||||
<span class="c"># SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER</span>
|
||||
<span class="c"># CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,</span>
|
||||
<span class="c"># OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE</span>
|
||||
<span class="c"># OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</span>
|
||||
|
||||
<span class="sd">'''</span>
|
||||
<span class="sd">.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com</span>
|
||||
<span class="sd">'''</span>
|
||||
<span class="kn">from</span> <span class="nn">__future__</span> <span class="kn">import</span> <span class="n">unicode_literals</span>
|
||||
|
||||
<span class="n">__updated__</span> <span class="o">=</span> <span class="s">'2014-03-22'</span>
|
||||
|
||||
|
||||
<div class="viewcode-block" id="UnsupportedException"><a class="viewcode-back" href="../../../../api/modules/services/Exceptions.html#uds.core.services.Exceptions.UnsupportedException">[docs]</a><span class="k">class</span> <span class="nc">UnsupportedException</span><span class="p">(</span><span class="ne">Exception</span><span class="p">):</span>
|
||||
<span class="sd">'''</span>
|
||||
<span class="sd"> Reflects that we request an operation that is not supported, i.e. Cancel a publication with snapshots</span>
|
||||
<span class="sd"> '''</span>
|
||||
<span class="k">pass</span>
|
||||
|
||||
</div>
|
||||
<div class="viewcode-block" id="OperationException"><a class="viewcode-back" href="../../../../api/modules/services/Exceptions.html#uds.core.services.Exceptions.OperationException">[docs]</a><span class="k">class</span> <span class="nc">OperationException</span><span class="p">(</span><span class="ne">Exception</span><span class="p">):</span>
|
||||
<span class="sd">'''</span>
|
||||
<span class="sd"> Reflects that the operation requested can't be acomplished, i.e. remove an snapshot without snapshot reference, cancel non running operation, etc...</span>
|
||||
<span class="sd"> '''</span>
|
||||
<span class="k">pass</span>
|
||||
|
||||
</div>
|
||||
<div class="viewcode-block" id="PublishException"><a class="viewcode-back" href="../../../../api/modules/services/Exceptions.html#uds.core.services.Exceptions.PublishException">[docs]</a><span class="k">class</span> <span class="nc">PublishException</span><span class="p">(</span><span class="ne">Exception</span><span class="p">):</span>
|
||||
<span class="sd">'''</span>
|
||||
<span class="sd"> Reflects thate the publication can't be done for causes we don't know in advance</span>
|
||||
<span class="sd"> '''</span>
|
||||
<span class="k">pass</span>
|
||||
|
||||
</div>
|
||||
<div class="viewcode-block" id="DeploymentException"><a class="viewcode-back" href="../../../../api/modules/services/Exceptions.html#uds.core.services.Exceptions.DeploymentException">[docs]</a><span class="k">class</span> <span class="nc">DeploymentException</span><span class="p">(</span><span class="ne">Exception</span><span class="p">):</span>
|
||||
<span class="sd">'''</span>
|
||||
<span class="sd"> Reflects that a deployment of a service (at cache, or assigned to user) can't be done for causes we don't know in advance</span>
|
||||
<span class="sd"> '''</span>
|
||||
<span class="k">pass</span>
|
||||
|
||||
</div>
|
||||
<div class="viewcode-block" id="CancelException"><a class="viewcode-back" href="../../../../api/modules/services/Exceptions.html#uds.core.services.Exceptions.CancelException">[docs]</a><span class="k">class</span> <span class="nc">CancelException</span><span class="p">(</span><span class="ne">Exception</span><span class="p">):</span>
|
||||
<span class="sd">'''</span>
|
||||
<span class="sd"> Reflects that a "cancel" operation can't be done for some reason</span>
|
||||
<span class="sd"> '''</span>
|
||||
|
||||
</div>
|
||||
<div class="viewcode-block" id="InvalidServiceException"><a class="viewcode-back" href="../../../../api/modules/services/Exceptions.html#uds.core.services.Exceptions.InvalidServiceException">[docs]</a><span class="k">class</span> <span class="nc">InvalidServiceException</span><span class="p">(</span><span class="ne">Exception</span><span class="p">):</span>
|
||||
<span class="sd">'''</span>
|
||||
<span class="sd"> Invalid service specified. The service is not ready</span>
|
||||
<span class="sd"> '''</span>
|
||||
<span class="k">pass</span>
|
||||
|
||||
</div>
|
||||
<div class="viewcode-block" id="MaxServicesReachedException"><a class="viewcode-back" href="../../../../api/modules/services/Exceptions.html#uds.core.services.Exceptions.MaxServicesReachedException">[docs]</a><span class="k">class</span> <span class="nc">MaxServicesReachedException</span><span class="p">(</span><span class="ne">Exception</span><span class="p">):</span>
|
||||
<span class="sd">'''</span>
|
||||
<span class="sd"> Number of maximum services has been reached, and no more services</span>
|
||||
<span class="sd"> can be created for users.</span>
|
||||
<span class="sd"> '''</span>
|
||||
<span class="k">pass</span></div>
|
||||
</pre></div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearer"></div>
|
||||
</div>
|
||||
<div class="related">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="../../../../genindex.html" title="General Index"
|
||||
>index</a></li>
|
||||
<li class="right" >
|
||||
<a href="../../../../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li><a href="../../../../index.html">UDS 1.0 documentation</a> »</li>
|
||||
<li><a href="../../../index.html" >Module code</a> »</li>
|
||||
<li><a href="../../core.html" >uds.core</a> »</li>
|
||||
<li><a href="../services.html" >uds.core.services</a> »</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="footer">
|
||||
© Copyright 2012, Virtual Cable S.L.U..
|
||||
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2.2.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -1,940 +0,0 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
|
||||
<title>uds.core.ui.UserInterface — UDS 1.0 documentation</title>
|
||||
|
||||
<link rel="stylesheet" href="../../../../_static/sphinxdoc.css" type="text/css" />
|
||||
<link rel="stylesheet" href="../../../../_static/pygments.css" type="text/css" />
|
||||
|
||||
<script type="text/javascript">
|
||||
var DOCUMENTATION_OPTIONS = {
|
||||
URL_ROOT: '../../../../',
|
||||
VERSION: '1.0',
|
||||
COLLAPSE_INDEX: false,
|
||||
FILE_SUFFIX: '.html',
|
||||
HAS_SOURCE: true
|
||||
};
|
||||
</script>
|
||||
<script type="text/javascript" src="../../../../_static/jquery.js"></script>
|
||||
<script type="text/javascript" src="../../../../_static/underscore.js"></script>
|
||||
<script type="text/javascript" src="../../../../_static/doctools.js"></script>
|
||||
<script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
|
||||
<link rel="top" title="UDS 1.0 documentation" href="../../../../index.html" />
|
||||
<link rel="up" title="uds.core" href="../../core.html" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="related">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="../../../../genindex.html" title="General Index"
|
||||
accesskey="I">index</a></li>
|
||||
<li class="right" >
|
||||
<a href="../../../../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li><a href="../../../../index.html">UDS 1.0 documentation</a> »</li>
|
||||
<li><a href="../../../index.html" >Module code</a> »</li>
|
||||
<li><a href="../../core.html" accesskey="U">uds.core</a> »</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="sphinxsidebar">
|
||||
<div class="sphinxsidebarwrapper">
|
||||
<div id="searchbox" style="display: none">
|
||||
<h3>Quick search</h3>
|
||||
<form class="search" action="../../../../search.html" method="get">
|
||||
<input type="text" name="q" />
|
||||
<input type="submit" value="Go" />
|
||||
<input type="hidden" name="check_keywords" value="yes" />
|
||||
<input type="hidden" name="area" value="default" />
|
||||
</form>
|
||||
<p class="searchtip" style="font-size: 90%">
|
||||
Enter search terms or a module, class or function name.
|
||||
</p>
|
||||
</div>
|
||||
<script type="text/javascript">$('#searchbox').show(0);</script>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="document">
|
||||
<div class="documentwrapper">
|
||||
<div class="bodywrapper">
|
||||
<div class="body">
|
||||
|
||||
<h1>Source code for uds.core.ui.UserInterface</h1><div class="highlight"><pre>
|
||||
<span class="c"># -*- coding: utf-8 -*-</span>
|
||||
|
||||
<span class="c">#</span>
|
||||
<span class="c"># Copyright (c) 2012 Virtual Cable S.L.</span>
|
||||
<span class="c"># All rights reserved.</span>
|
||||
<span class="c">#</span>
|
||||
<span class="c"># Redistribution and use in source and binary forms, with or without modification,</span>
|
||||
<span class="c"># are permitted provided that the following conditions are met:</span>
|
||||
<span class="c">#</span>
|
||||
<span class="c"># * Redistributions of source code must retain the above copyright notice,</span>
|
||||
<span class="c"># this list of conditions and the following disclaimer.</span>
|
||||
<span class="c"># * Redistributions in binary form must reproduce the above copyright notice,</span>
|
||||
<span class="c"># this list of conditions and the following disclaimer in the documentation</span>
|
||||
<span class="c"># and/or other materials provided with the distribution.</span>
|
||||
<span class="c"># * Neither the name of Virtual Cable S.L. nor the names of its contributors</span>
|
||||
<span class="c"># may be used to endorse or promote products derived from this software</span>
|
||||
<span class="c"># without specific prior written permission.</span>
|
||||
<span class="c">#</span>
|
||||
<span class="c"># THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"</span>
|
||||
<span class="c"># AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE</span>
|
||||
<span class="c"># IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE</span>
|
||||
<span class="c"># DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE</span>
|
||||
<span class="c"># FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL</span>
|
||||
<span class="c"># DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR</span>
|
||||
<span class="c"># SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER</span>
|
||||
<span class="c"># CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,</span>
|
||||
<span class="c"># OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE</span>
|
||||
<span class="c"># OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</span>
|
||||
|
||||
<span class="sd">'''</span>
|
||||
<span class="sd">.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com</span>
|
||||
<span class="sd">'''</span>
|
||||
<span class="kn">from</span> <span class="nn">__future__</span> <span class="kn">import</span> <span class="n">unicode_literals</span>
|
||||
|
||||
<span class="kn">from</span> <span class="nn">django.utils.translation</span> <span class="kn">import</span> <span class="n">get_language</span><span class="p">,</span> <span class="n">ugettext</span> <span class="k">as</span> <span class="n">_</span>
|
||||
<span class="kn">import</span> <span class="nn">cPickle</span>
|
||||
<span class="kn">import</span> <span class="nn">logging</span>
|
||||
|
||||
<span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="n">__name__</span><span class="p">)</span>
|
||||
|
||||
|
||||
<div class="viewcode-block" id="gui"><a class="viewcode-back" href="../../../../api/modules/FormFields.html#uds.core.ui.UserInterface.gui">[docs]</a><span class="k">class</span> <span class="nc">gui</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
|
||||
<span class="sd">'''</span>
|
||||
<span class="sd"> This class contains the representations of fields needed by UDS modules and</span>
|
||||
<span class="sd"> administation interface.</span>
|
||||
|
||||
<span class="sd"> This contains fields types, that modules uses to make a form and interact</span>
|
||||
<span class="sd"> with users.</span>
|
||||
|
||||
<span class="sd"> The use of this provided fields are as follows:</span>
|
||||
|
||||
<span class="sd"> The Module is descendant of "BaseModule", which also is inherited from this</span>
|
||||
<span class="sd"> class.</span>
|
||||
|
||||
<span class="sd"> At class level, we declare the fields needed to interact with the user, as</span>
|
||||
<span class="sd"> this example:</span>
|
||||
|
||||
<span class="sd"> .. code-block:: python</span>
|
||||
|
||||
<span class="sd"> class AuthModule(Authenticator):</span>
|
||||
<span class="sd"> # ...</span>
|
||||
<span class="sd"> # Other initializations</span>
|
||||
<span class="sd"> # ...</span>
|
||||
<span class="sd"> users = gui.EditableList(label = 'Users', tooltip = 'Select users',</span>
|
||||
<span class="sd"> order = 1, values = ['user1', 'user2', 'user3', 'user4'])</span>
|
||||
<span class="sd"> passw = gui.Password(label='Pass', length=32, tooltip='Password',</span>
|
||||
<span class="sd"> order = 2, required = True, defValue = '12345')</span>
|
||||
<span class="sd"> # ...</span>
|
||||
<span class="sd"> # more fields</span>
|
||||
<span class="sd"> # ...</span>
|
||||
|
||||
<span class="sd"> At class instantiation, this data is extracted and processed, so the admin</span>
|
||||
<span class="sd"> can access this form to let users</span>
|
||||
<span class="sd"> create new instances of this module.</span>
|
||||
<span class="sd"> '''</span>
|
||||
|
||||
<span class="c"># : True string value</span>
|
||||
<span class="n">TRUE</span> <span class="o">=</span> <span class="s">'true'</span>
|
||||
<span class="c"># : False string value</span>
|
||||
<span class="n">FALSE</span> <span class="o">=</span> <span class="s">'false'</span>
|
||||
|
||||
<span class="c"># : Static Callbacks simple registry</span>
|
||||
<span class="n">callbacks</span> <span class="o">=</span> <span class="p">{}</span>
|
||||
|
||||
<span class="c"># Helpers</span>
|
||||
<span class="nd">@staticmethod</span>
|
||||
<span class="k">def</span> <span class="nf">convertToChoices</span><span class="p">(</span><span class="n">vals</span><span class="p">):</span>
|
||||
<span class="sd">'''</span>
|
||||
<span class="sd"> Helper to convert from array of strings to the same dict used in choice,</span>
|
||||
<span class="sd"> multichoice, ..</span>
|
||||
<span class="sd"> The id is set to values in the array (strings), while text is left empty.</span>
|
||||
<span class="sd"> '''</span>
|
||||
<span class="n">res</span> <span class="o">=</span> <span class="p">[]</span>
|
||||
<span class="k">for</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">vals</span><span class="p">:</span>
|
||||
<span class="n">res</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s">'id'</span><span class="p">:</span> <span class="n">v</span><span class="p">,</span> <span class="s">'text'</span><span class="p">:</span> <span class="s">''</span><span class="p">})</span>
|
||||
<span class="k">return</span> <span class="n">res</span>
|
||||
|
||||
<span class="nd">@staticmethod</span>
|
||||
<span class="k">def</span> <span class="nf">convertToList</span><span class="p">(</span><span class="n">vals</span><span class="p">):</span>
|
||||
<span class="k">if</span> <span class="n">vals</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span><span class="p">:</span>
|
||||
<span class="k">return</span> <span class="p">[</span><span class="nb">unicode</span><span class="p">(</span><span class="n">v</span><span class="p">)</span> <span class="k">for</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">vals</span><span class="p">]</span>
|
||||
<span class="k">return</span> <span class="p">[]</span>
|
||||
|
||||
<span class="nd">@staticmethod</span>
|
||||
<span class="k">def</span> <span class="nf">choiceItem</span><span class="p">(</span><span class="n">id_</span><span class="p">,</span> <span class="n">text</span><span class="p">):</span>
|
||||
<span class="sd">'''</span>
|
||||
<span class="sd"> Helper method to create a single choice item.</span>
|
||||
|
||||
<span class="sd"> Args:</span>
|
||||
<span class="sd"> id: Id of the choice to create</span>
|
||||
|
||||
<span class="sd"> text: Text to assign to the choice to create</span>
|
||||
|
||||
<span class="sd"> Returns:</span>
|
||||
<span class="sd"> An dictionary, that is the representation of a single choice item,</span>
|
||||
<span class="sd"> with 2 keys, 'id' and 'text'</span>
|
||||
|
||||
<span class="sd"> :note: Text can be anything, the method converts it first to text before</span>
|
||||
<span class="sd"> assigning to dictionary</span>
|
||||
<span class="sd"> '''</span>
|
||||
<span class="k">return</span> <span class="p">{</span><span class="s">'id'</span><span class="p">:</span> <span class="nb">str</span><span class="p">(</span><span class="n">id_</span><span class="p">),</span> <span class="s">'text'</span><span class="p">:</span> <span class="nb">str</span><span class="p">(</span><span class="n">text</span><span class="p">)}</span>
|
||||
|
||||
<span class="nd">@staticmethod</span>
|
||||
<span class="k">def</span> <span class="nf">strToBool</span><span class="p">(</span><span class="n">str_</span><span class="p">):</span>
|
||||
<span class="sd">'''</span>
|
||||
<span class="sd"> Converts the string "true" (case insensitive) to True (boolean).</span>
|
||||
<span class="sd"> Anything else is converted to false</span>
|
||||
|
||||
<span class="sd"> Args:</span>
|
||||
<span class="sd"> str: Str to convert to boolean</span>
|
||||
|
||||
<span class="sd"> Returns:</span>
|
||||
<span class="sd"> True if the string is "true" (case insensitive), False else.</span>
|
||||
<span class="sd"> '''</span>
|
||||
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">str_</span><span class="p">,</span> <span class="nb">bool</span><span class="p">):</span>
|
||||
<span class="k">return</span> <span class="n">str_</span>
|
||||
<span class="k">if</span> <span class="nb">unicode</span><span class="p">(</span><span class="n">str_</span><span class="p">)</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="o">==</span> <span class="n">gui</span><span class="o">.</span><span class="n">TRUE</span><span class="p">:</span>
|
||||
<span class="k">return</span> <span class="bp">True</span>
|
||||
<span class="k">return</span> <span class="bp">False</span>
|
||||
|
||||
<span class="nd">@staticmethod</span>
|
||||
<span class="k">def</span> <span class="nf">boolToStr</span><span class="p">(</span><span class="n">bol</span><span class="p">):</span>
|
||||
<span class="sd">'''</span>
|
||||
<span class="sd"> Converts a boolean to the string representation. True is converted to</span>
|
||||
<span class="sd"> "true", False to "false".</span>
|
||||
|
||||
<span class="sd"> Args:</span>
|
||||
<span class="sd"> bol: Boolean value (True or false) to convert</span>
|
||||
|
||||
<span class="sd"> Returns:</span>
|
||||
<span class="sd"> "true" if bol evals to True, "false" if don't.</span>
|
||||
<span class="sd"> '''</span>
|
||||
<span class="k">if</span> <span class="n">bol</span><span class="p">:</span>
|
||||
<span class="k">return</span> <span class="n">gui</span><span class="o">.</span><span class="n">TRUE</span>
|
||||
<span class="k">return</span> <span class="n">gui</span><span class="o">.</span><span class="n">FALSE</span>
|
||||
|
||||
<span class="c"># Classes</span>
|
||||
|
||||
<div class="viewcode-block" id="gui.InputField"><a class="viewcode-back" href="../../../../api/modules/FormFields.html#uds.core.ui.UserInterface.gui.InputField">[docs]</a> <span class="k">class</span> <span class="nc">InputField</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
|
||||
<span class="sd">'''</span>
|
||||
<span class="sd"> Class representing an simple input field.</span>
|
||||
<span class="sd"> This class is not directly usable, must be used by any inherited class</span>
|
||||
<span class="sd"> (fields all of them)</span>
|
||||
<span class="sd"> All fields are inherited from this one</span>
|
||||
|
||||
<span class="sd"> The data managed for an input field, and their default values are:</span>
|
||||
<span class="sd"> * length: Max length of the field. Defaults to DEFAULT_LENGTH</span>
|
||||
<span class="sd"> * required: If this field is a MUST. defaults to false</span>
|
||||
<span class="sd"> * label: Label used with this field. Defaults to ''</span>
|
||||
<span class="sd"> * defvalue: Default value for the field. Defaults to '' (this is</span>
|
||||
<span class="sd"> always an string)</span>
|
||||
<span class="sd"> * rdonly: If the field is read only on modification. On creation,</span>
|
||||
<span class="sd"> all fields are "writable". Defaults to False</span>
|
||||
<span class="sd"> * order: order inside the form, defaults to 0 (if two or more fields</span>
|
||||
<span class="sd"> has same order, the output order may be anything)</span>
|
||||
<span class="sd"> * tooltip: Tooltip used in the form, defaults to ''</span>
|
||||
<span class="sd"> * type: type of the input field, defaults to "text box" (TextField)</span>
|
||||
|
||||
<span class="sd"> In every single field, you must at least indicate:</span>
|
||||
<span class="sd"> * if required or not</span>
|
||||
<span class="sd"> * order</span>
|
||||
<span class="sd"> * label</span>
|
||||
<span class="sd"> * tooltip</span>
|
||||
<span class="sd"> * defvalue</span>
|
||||
<span class="sd"> * rdonly if can't be modified once it's created</span>
|
||||
|
||||
<span class="sd"> Any other paremeter needed is indicated in the corresponding field class.</span>
|
||||
|
||||
<span class="sd"> Also a value field is available, so you can get/set the form field value.</span>
|
||||
<span class="sd"> This property expects always an string, no matter what kind of field it is.</span>
|
||||
|
||||
<span class="sd"> Take into account also that "value" has precedence over "defValue",</span>
|
||||
<span class="sd"> so if you use both, the used one will be "value". This is valid for</span>
|
||||
<span class="sd"> all form fields.</span>
|
||||
<span class="sd"> '''</span>
|
||||
<span class="n">TEXT_TYPE</span> <span class="o">=</span> <span class="s">'text'</span>
|
||||
<span class="n">TEXTBOX_TYPE</span> <span class="o">=</span> <span class="s">'textbox'</span>
|
||||
<span class="n">NUMERIC_TYPE</span> <span class="o">=</span> <span class="s">'numeric'</span>
|
||||
<span class="n">PASSWORD_TYPE</span> <span class="o">=</span> <span class="s">'password'</span>
|
||||
<span class="n">HIDDEN_TYPE</span> <span class="o">=</span> <span class="s">'hidden'</span>
|
||||
<span class="n">CHOICE_TYPE</span> <span class="o">=</span> <span class="s">'choice'</span>
|
||||
<span class="n">MULTI_CHOICE_TYPE</span> <span class="o">=</span> <span class="s">'multichoice'</span>
|
||||
<span class="n">EDITABLE_LIST</span> <span class="o">=</span> <span class="s">'editlist'</span>
|
||||
<span class="n">CHECKBOX_TYPE</span> <span class="o">=</span> <span class="s">'checkbox'</span>
|
||||
|
||||
<span class="n">DEFAULT_LENTGH</span> <span class="o">=</span> <span class="mi">32</span> <span class="c"># : If length of some fields are not especified, this value is used as default</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">):</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_data</span> <span class="o">=</span> <span class="p">{</span>
|
||||
<span class="s">'length'</span><span class="p">:</span> <span class="n">options</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'length'</span><span class="p">,</span> <span class="n">gui</span><span class="o">.</span><span class="n">InputField</span><span class="o">.</span><span class="n">DEFAULT_LENTGH</span><span class="p">),</span>
|
||||
<span class="s">'required'</span><span class="p">:</span> <span class="n">options</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'required'</span><span class="p">,</span> <span class="bp">False</span><span class="p">),</span>
|
||||
<span class="s">'label'</span><span class="p">:</span> <span class="n">options</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'label'</span><span class="p">,</span> <span class="s">''</span><span class="p">),</span>
|
||||
<span class="s">'defvalue'</span><span class="p">:</span> <span class="nb">unicode</span><span class="p">(</span><span class="n">options</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'defvalue'</span><span class="p">,</span> <span class="s">''</span><span class="p">)),</span>
|
||||
<span class="s">'rdonly'</span><span class="p">:</span> <span class="n">options</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'rdonly'</span><span class="p">,</span> <span class="bp">False</span><span class="p">),</span> <span class="c"># This property only affects in "modify" operations</span>
|
||||
<span class="s">'order'</span><span class="p">:</span> <span class="n">options</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'order'</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span>
|
||||
<span class="s">'tooltip'</span><span class="p">:</span> <span class="n">options</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'tooltip'</span><span class="p">,</span> <span class="s">''</span><span class="p">),</span>
|
||||
<span class="s">'type'</span><span class="p">:</span> <span class="n">gui</span><span class="o">.</span><span class="n">InputField</span><span class="o">.</span><span class="n">TEXT_TYPE</span><span class="p">,</span>
|
||||
<span class="s">'value'</span><span class="p">:</span> <span class="n">options</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'value'</span><span class="p">,</span> <span class="s">''</span><span class="p">),</span>
|
||||
<span class="p">}</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">_type</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">type_</span><span class="p">):</span>
|
||||
<span class="sd">'''</span>
|
||||
<span class="sd"> Sets the type of this field.</span>
|
||||
|
||||
<span class="sd"> Args:</span>
|
||||
<span class="sd"> type: Type to set (from constants of this class)</span>
|
||||
<span class="sd"> '''</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_data</span><span class="p">[</span><span class="s">'type'</span><span class="p">]</span> <span class="o">=</span> <span class="n">type_</span>
|
||||
|
||||
<div class="viewcode-block" id="gui.InputField.isType"><a class="viewcode-back" href="../../../../api/modules/FormFields.html#uds.core.ui.UserInterface.gui.InputField.isType">[docs]</a> <span class="k">def</span> <span class="nf">isType</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">type_</span><span class="p">):</span>
|
||||
<span class="sd">'''</span>
|
||||
<span class="sd"> Returns true if this field is of specified type</span>
|
||||
<span class="sd"> '''</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_data</span><span class="p">[</span><span class="s">'type'</span><span class="p">]</span> <span class="o">==</span> <span class="n">type_</span>
|
||||
</div>
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">value</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">'''</span>
|
||||
<span class="sd"> Obtains the stored value</span>
|
||||
<span class="sd"> '''</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_data</span><span class="p">[</span><span class="s">'value'</span><span class="p">]</span>
|
||||
|
||||
<span class="nd">@value.setter</span>
|
||||
<div class="viewcode-block" id="gui.InputField.value"><a class="viewcode-back" href="../../../../api/modules/FormFields.html#uds.core.ui.UserInterface.gui.InputField.value">[docs]</a> <span class="k">def</span> <span class="nf">value</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span>
|
||||
<span class="sd">'''</span>
|
||||
<span class="sd"> Stores new value (not the default one)</span>
|
||||
<span class="sd"> '''</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_setValue</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
|
||||
</div>
|
||||
<span class="k">def</span> <span class="nf">_setValue</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span>
|
||||
<span class="sd">'''</span>
|
||||
<span class="sd"> So we can override value setting at descendants</span>
|
||||
<span class="sd"> '''</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_data</span><span class="p">[</span><span class="s">'value'</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span>
|
||||
|
||||
<div class="viewcode-block" id="gui.InputField.guiDescription"><a class="viewcode-back" href="../../../../api/modules/FormFields.html#uds.core.ui.UserInterface.gui.InputField.guiDescription">[docs]</a> <span class="k">def</span> <span class="nf">guiDescription</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">'''</span>
|
||||
<span class="sd"> Returns the dictionary with the description of this item.</span>
|
||||
<span class="sd"> We copy it, cause we need to translate the label and tooltip fields</span>
|
||||
<span class="sd"> and don't want to</span>
|
||||
<span class="sd"> alter original values.</span>
|
||||
<span class="sd"> '''</span>
|
||||
<span class="n">data</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_data</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span>
|
||||
<span class="n">data</span><span class="p">[</span><span class="s">'label'</span><span class="p">]</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="s">'label'</span><span class="p">]</span> <span class="o">!=</span> <span class="s">''</span> <span class="ow">and</span> <span class="n">_</span><span class="p">(</span><span class="n">data</span><span class="p">[</span><span class="s">'label'</span><span class="p">])</span> <span class="ow">or</span> <span class="s">''</span>
|
||||
<span class="n">data</span><span class="p">[</span><span class="s">'tooltip'</span><span class="p">]</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="s">'tooltip'</span><span class="p">]</span> <span class="o">!=</span> <span class="s">''</span> <span class="ow">and</span> <span class="n">_</span><span class="p">(</span><span class="n">data</span><span class="p">[</span><span class="s">'tooltip'</span><span class="p">])</span> <span class="ow">or</span> <span class="s">''</span>
|
||||
<span class="k">return</span> <span class="n">data</span>
|
||||
</div>
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">defValue</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">'''</span>
|
||||
<span class="sd"> Returns the default value for this field</span>
|
||||
<span class="sd"> '''</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_data</span><span class="p">[</span><span class="s">'defvalue'</span><span class="p">]</span>
|
||||
|
||||
<span class="nd">@defValue.setter</span>
|
||||
<div class="viewcode-block" id="gui.InputField.defValue"><a class="viewcode-back" href="../../../../api/modules/FormFields.html#uds.core.ui.UserInterface.gui.InputField.defValue">[docs]</a> <span class="k">def</span> <span class="nf">defValue</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">defValue</span><span class="p">):</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">setDefValue</span><span class="p">(</span><span class="n">defValue</span><span class="p">)</span>
|
||||
</div>
|
||||
<div class="viewcode-block" id="gui.InputField.setDefValue"><a class="viewcode-back" href="../../../../api/modules/FormFields.html#uds.core.ui.UserInterface.gui.InputField.setDefValue">[docs]</a> <span class="k">def</span> <span class="nf">setDefValue</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">defValue</span><span class="p">):</span>
|
||||
<span class="sd">'''</span>
|
||||
<span class="sd"> Sets the default value of the field·</span>
|
||||
|
||||
<span class="sd"> Args:</span>
|
||||
<span class="sd"> defValue: Default value (string)</span>
|
||||
<span class="sd"> '''</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_data</span><span class="p">[</span><span class="s">'defvalue'</span><span class="p">]</span> <span class="o">=</span> <span class="n">defValue</span>
|
||||
</div>
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">label</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_data</span><span class="p">[</span><span class="s">'label'</span><span class="p">]</span>
|
||||
</div>
|
||||
<div class="viewcode-block" id="gui.TextField"><a class="viewcode-back" href="../../../../api/modules/FormFields.html#uds.core.ui.UserInterface.gui.TextField">[docs]</a> <span class="k">class</span> <span class="nc">TextField</span><span class="p">(</span><span class="n">InputField</span><span class="p">):</span>
|
||||
<span class="sd">'''</span>
|
||||
<span class="sd"> This represents a text field.</span>
|
||||
|
||||
<span class="sd"> The values of parameters are inherited from :py:class:`InputField`</span>
|
||||
|
||||
<span class="sd"> Additionally to standard parameters, the length parameter is a</span>
|
||||
<span class="sd"> recommended one for this kind of field.</span>
|
||||
|
||||
<span class="sd"> You can specify that this is a multiline text box with **multiline**</span>
|
||||
<span class="sd"> parameter. If it exists, and is greater than 1, indicates how much</span>
|
||||
<span class="sd"> lines will be used to display field. (Max number is 8)</span>
|
||||
|
||||
<span class="sd"> Example usage:</span>
|
||||
|
||||
<span class="sd"> .. code-block:: python</span>
|
||||
|
||||
<span class="sd"> # Declares an text form field, with label "Host", tooltip</span>
|
||||
<span class="sd"> # "Host name for this module", that is required,</span>
|
||||
<span class="sd"> # with max length of 64 chars and order = 1, and is editable</span>
|
||||
<span class="sd"> # after creation.</span>
|
||||
<span class="sd"> host = gui.TextField(length=64, label = _('Host'), order = 1,</span>
|
||||
<span class="sd"> tooltip = _('Host name for this module'), required = True)</span>
|
||||
|
||||
<span class="sd"> # Declares an text form field, with label "Other",</span>
|
||||
<span class="sd"> # tooltip "Other info", that is not required, that is not</span>
|
||||
<span class="sd"> # required and that is not editable after creation.</span>
|
||||
<span class="sd"> other = gui.TextField(length=64, label = _('Other'), order = 1,</span>
|
||||
<span class="sd"> tooltip = _('Other info'), rdonly = True)</span>
|
||||
|
||||
<span class="sd"> '''</span>
|
||||
<span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">):</span>
|
||||
<span class="nb">super</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">__class__</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">__init__</span><span class="p">(</span><span class="o">**</span><span class="n">options</span><span class="p">)</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_type</span><span class="p">(</span><span class="n">gui</span><span class="o">.</span><span class="n">InputField</span><span class="o">.</span><span class="n">TEXT_TYPE</span><span class="p">)</span>
|
||||
<span class="n">multiline</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">options</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'multiline'</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span>
|
||||
<span class="k">if</span> <span class="n">multiline</span> <span class="o">></span> <span class="mi">8</span><span class="p">:</span>
|
||||
<span class="n">multiline</span> <span class="o">=</span> <span class="mi">8</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_data</span><span class="p">[</span><span class="s">'multiline'</span><span class="p">]</span> <span class="o">=</span> <span class="n">multiline</span>
|
||||
</div>
|
||||
<div class="viewcode-block" id="gui.NumericField"><a class="viewcode-back" href="../../../../api/modules/FormFields.html#uds.core.ui.UserInterface.gui.NumericField">[docs]</a> <span class="k">class</span> <span class="nc">NumericField</span><span class="p">(</span><span class="n">InputField</span><span class="p">):</span>
|
||||
<span class="sd">'''</span>
|
||||
<span class="sd"> This represents a numeric field. It apears with an spin up/down button.</span>
|
||||
|
||||
<span class="sd"> The values of parameres are inherited from :py:class:`InputField`</span>
|
||||
|
||||
<span class="sd"> Additionally to standard parameters, the length parameter indicates the</span>
|
||||
<span class="sd"> max number of digits (0-9 values).</span>
|
||||
|
||||
<span class="sd"> Example usage:</span>
|
||||
|
||||
<span class="sd"> .. code-block:: python</span>
|
||||
|
||||
<span class="sd"> # Declares an numeric form field, with max value of 99999, label</span>
|
||||
<span class="sd"> # "Port", that is required,</span>
|
||||
<span class="sd"> # with tooltip "Port (usually 443)" and order 1</span>
|
||||
<span class="sd"> num = gui.NumericField(length=5, label = _('Port'),</span>
|
||||
<span class="sd"> defvalue = '443', order = 1, tooltip = _('Port (usually 443)'),</span>
|
||||
<span class="sd"> required = True)</span>
|
||||
<span class="sd"> '''</span>
|
||||
<span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">):</span>
|
||||
<span class="nb">super</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">__class__</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">__init__</span><span class="p">(</span><span class="o">**</span><span class="n">options</span><span class="p">)</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_type</span><span class="p">(</span><span class="n">gui</span><span class="o">.</span><span class="n">InputField</span><span class="o">.</span><span class="n">NUMERIC_TYPE</span><span class="p">)</span>
|
||||
|
||||
<div class="viewcode-block" id="gui.NumericField.num"><a class="viewcode-back" href="../../../../api/modules/FormFields.html#uds.core.ui.UserInterface.gui.NumericField.num">[docs]</a> <span class="k">def</span> <span class="nf">num</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">'''</span>
|
||||
<span class="sd"> Return value as integer</span>
|
||||
<span class="sd"> '''</span>
|
||||
<span class="k">return</span> <span class="nb">int</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">value</span><span class="p">)</span>
|
||||
</div></div>
|
||||
<div class="viewcode-block" id="gui.PasswordField"><a class="viewcode-back" href="../../../../api/modules/FormFields.html#uds.core.ui.UserInterface.gui.PasswordField">[docs]</a> <span class="k">class</span> <span class="nc">PasswordField</span><span class="p">(</span><span class="n">InputField</span><span class="p">):</span>
|
||||
<span class="sd">'''</span>
|
||||
<span class="sd"> This represents a password field. It appears with "*" at input, so the contents is not displayed</span>
|
||||
|
||||
<span class="sd"> The values of parameres are inherited from :py:class:`InputField`</span>
|
||||
|
||||
<span class="sd"> Additionally to standard parameters, the length parameter is a recommended one for this kind of field.</span>
|
||||
|
||||
<span class="sd"> Example usage:</span>
|
||||
|
||||
<span class="sd"> .. code-block:: python</span>
|
||||
|
||||
<span class="sd"> # Declares an text form field, with label "Password",</span>
|
||||
<span class="sd"> # tooltip "Password of the user", that is required,</span>
|
||||
<span class="sd"> # with max length of 32 chars and order = 2, and is</span>
|
||||
<span class="sd"> # editable after creation.</span>
|
||||
<span class="sd"> passw = gui.PasswordField(lenth=32, label = _('Password'),</span>
|
||||
<span class="sd"> order = 4, tooltip = _('Password of the user'),</span>
|
||||
<span class="sd"> required = True)</span>
|
||||
|
||||
<span class="sd"> '''</span>
|
||||
<span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">):</span>
|
||||
<span class="nb">super</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">__class__</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">__init__</span><span class="p">(</span><span class="o">**</span><span class="n">options</span><span class="p">)</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_type</span><span class="p">(</span><span class="n">gui</span><span class="o">.</span><span class="n">InputField</span><span class="o">.</span><span class="n">PASSWORD_TYPE</span><span class="p">)</span>
|
||||
</div>
|
||||
<div class="viewcode-block" id="gui.HiddenField"><a class="viewcode-back" href="../../../../api/modules/FormFields.html#uds.core.ui.UserInterface.gui.HiddenField">[docs]</a> <span class="k">class</span> <span class="nc">HiddenField</span><span class="p">(</span><span class="n">InputField</span><span class="p">):</span>
|
||||
<span class="sd">'''</span>
|
||||
<span class="sd"> This represents a hidden field. It is not displayed to the user. It use</span>
|
||||
<span class="sd"> is for keeping info at form needed</span>
|
||||
<span class="sd"> by module, but not editable by user (i.e., one service can keep info</span>
|
||||
<span class="sd"> about the parent provider in hiddens)</span>
|
||||
|
||||
<span class="sd"> The values of parameres are inherited from :py:class:`InputField`</span>
|
||||
|
||||
<span class="sd"> These are almost the same as TextFields, but they do not get displayed</span>
|
||||
<span class="sd"> for user interaction.</span>
|
||||
|
||||
<span class="sd"> Example usage:</span>
|
||||
|
||||
<span class="sd"> .. code-block:: python</span>
|
||||
|
||||
<span class="sd"> # Declares an empty hidden field</span>
|
||||
<span class="sd"> hidden = gui.HiddenField()</span>
|
||||
|
||||
|
||||
<span class="sd"> After that, at initGui method of module, we can store a value inside</span>
|
||||
<span class="sd"> using setDefValue as shown here:</span>
|
||||
|
||||
<span class="sd"> .. code-block:: python</span>
|
||||
|
||||
<span class="sd"> def initGui(self):</span>
|
||||
<span class="sd"> # always set defValue using self, cause we only want to store</span>
|
||||
<span class="sd"> # value for current instance</span>
|
||||
<span class="sd"> self.hidden.setDefValue(self.parent().serialize())</span>
|
||||
|
||||
<span class="sd"> '''</span>
|
||||
<span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">):</span>
|
||||
<span class="nb">super</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">__class__</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">__init__</span><span class="p">(</span><span class="o">**</span><span class="n">options</span><span class="p">)</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_isSerializable</span> <span class="o">=</span> <span class="n">options</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'serializable'</span><span class="p">,</span> <span class="s">''</span><span class="p">)</span> <span class="o">!=</span> <span class="s">''</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_type</span><span class="p">(</span><span class="n">gui</span><span class="o">.</span><span class="n">InputField</span><span class="o">.</span><span class="n">HIDDEN_TYPE</span><span class="p">)</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">isSerializable</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_isSerializable</span>
|
||||
</div>
|
||||
<div class="viewcode-block" id="gui.CheckBoxField"><a class="viewcode-back" href="../../../../api/modules/FormFields.html#uds.core.ui.UserInterface.gui.CheckBoxField">[docs]</a> <span class="k">class</span> <span class="nc">CheckBoxField</span><span class="p">(</span><span class="n">InputField</span><span class="p">):</span>
|
||||
<span class="sd">'''</span>
|
||||
<span class="sd"> This represents a check box field, with values "true" and "false"</span>
|
||||
|
||||
<span class="sd"> The values of parameters are inherited from :py:class:`InputField`</span>
|
||||
|
||||
<span class="sd"> The valid values for this defvalue are: "true" and "false" (as strings)</span>
|
||||
|
||||
<span class="sd"> Example usage:</span>
|
||||
|
||||
<span class="sd"> .. code-block:: python</span>
|
||||
|
||||
<span class="sd"> # Declares an check box field, with label "Use SSL", order 3,</span>
|
||||
<span class="sd"> # tooltip "If checked, will use a ssl connection", default value</span>
|
||||
<span class="sd"> # unchecked (not included, so it's empty, so it's not true :-))</span>
|
||||
<span class="sd"> ssl = gui.CheckBoxField(label = _('Use SSL'), order = 3,</span>
|
||||
<span class="sd"> tooltip = _('If checked, will use a ssl connection'))</span>
|
||||
|
||||
<span class="sd"> '''</span>
|
||||
<span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">):</span>
|
||||
<span class="nb">super</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">__class__</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">__init__</span><span class="p">(</span><span class="o">**</span><span class="n">options</span><span class="p">)</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_type</span><span class="p">(</span><span class="n">gui</span><span class="o">.</span><span class="n">InputField</span><span class="o">.</span><span class="n">CHECKBOX_TYPE</span><span class="p">)</span>
|
||||
|
||||
<div class="viewcode-block" id="gui.CheckBoxField.isTrue"><a class="viewcode-back" href="../../../../api/modules/FormFields.html#uds.core.ui.UserInterface.gui.CheckBoxField.isTrue">[docs]</a> <span class="k">def</span> <span class="nf">isTrue</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">'''</span>
|
||||
<span class="sd"> Checks that the value is true</span>
|
||||
<span class="sd"> '''</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">value</span> <span class="o">==</span> <span class="s">'true'</span>
|
||||
</div></div>
|
||||
<div class="viewcode-block" id="gui.ChoiceField"><a class="viewcode-back" href="../../../../api/modules/FormFields.html#uds.core.ui.UserInterface.gui.ChoiceField">[docs]</a> <span class="k">class</span> <span class="nc">ChoiceField</span><span class="p">(</span><span class="n">InputField</span><span class="p">):</span>
|
||||
<span class="sd">'''</span>
|
||||
<span class="sd"> This represents a simple combo box with single selection.</span>
|
||||
|
||||
<span class="sd"> The values of parameters are inherited from :py:class:`InputField`</span>
|
||||
|
||||
<span class="sd"> ChoiceField needs a function to provide values inside it.</span>
|
||||
|
||||
<span class="sd"> * We specify the values via "values" option this way:</span>
|
||||
|
||||
<span class="sd"> Example:</span>
|
||||
|
||||
<span class="sd"> .. code-block:: python</span>
|
||||
|
||||
<span class="sd"> choices = gui.ChoiceField(label="choices", values = [ {'id':'1',</span>
|
||||
<span class="sd"> 'text':'Text 1'}, {'id':'xxx', 'text':'Text 2'}])</span>
|
||||
|
||||
<span class="sd"> You can specify a multi valuated field via id-values, or a</span>
|
||||
<span class="sd"> single-valued field via id-value</span>
|
||||
|
||||
<span class="sd"> * We can override choice values at UserInterface derived class</span>
|
||||
<span class="sd"> constructor or initGui using setValues</span>
|
||||
|
||||
<span class="sd"> There is an extra option available for this kind of field:</span>
|
||||
|
||||
<span class="sd"> fills: This options is a dictionary that contains this fields:</span>
|
||||
<span class="sd"> * 'callbackName' : Callback name for invocation via the specific</span>
|
||||
<span class="sd"> method xml-rpc. This name is a name we assign to this callback,</span>
|
||||
<span class="sd"> and is used to locate the method when callback is invoked from</span>
|
||||
<span class="sd"> admin interface.</span>
|
||||
<span class="sd"> * 'function' : Function to execute.</span>
|
||||
|
||||
<span class="sd"> This funtion receives one parameter, that is a dictionary with</span>
|
||||
<span class="sd"> all parameters (that, in time, are fields names) that we have</span>
|
||||
<span class="sd"> requested.</span>
|
||||
|
||||
<span class="sd"> The expected return value for this callback is an array of</span>
|
||||
<span class="sd"> dictionaries with fields and values to set, as</span>
|
||||
<span class="sd"> example show below shows.</span>
|
||||
<span class="sd"> * 'parameters' : Array of field names to pass back to server so</span>
|
||||
<span class="sd"> it can obtain the results.</span>
|
||||
|
||||
<span class="sd"> Of course, this fields must be part of the module.</span>
|
||||
|
||||
<span class="sd"> Example:</span>
|
||||
|
||||
<span class="sd"> .. code-block:: python</span>
|
||||
|
||||
<span class="sd"> choice1 = gui.ChoiceField(label="Choice 1", values = ....,</span>
|
||||
<span class="sd"> fills = { 'target': 'choice2', 'callback': fncValues,</span>
|
||||
<span class="sd"> 'parameters': ['choice1', 'name']}</span>
|
||||
<span class="sd"> )</span>
|
||||
<span class="sd"> choice2 = ghui.ChoiceField(label="Choice 2")</span>
|
||||
|
||||
<span class="sd"> Here is a more detailed explanation, using the VC service module as</span>
|
||||
<span class="sd"> sample.</span>
|
||||
|
||||
<span class="sd"> .. code-block:: python</span>
|
||||
|
||||
<span class="sd"> class VCHelpers(object):</span>
|
||||
<span class="sd"> # ...</span>
|
||||
<span class="sd"> # other stuff</span>
|
||||
<span class="sd"> # ...</span>
|
||||
<span class="sd"> @staticmethod</span>
|
||||
<span class="sd"> def getMachines(parameters):</span>
|
||||
<span class="sd"> # ...initialization and other stuff...</span>
|
||||
<span class="sd"> if parameters['resourcePool'] != '':</span>
|
||||
<span class="sd"> # ... do stuff ...</span>
|
||||
<span class="sd"> data = [ { 'name' : 'machine', 'values' : 'xxxxxx' } ]</span>
|
||||
<span class="sd"> return data</span>
|
||||
|
||||
<span class="sd"> class ModuleVC(services.Service)</span>
|
||||
<span class="sd"> # ...</span>
|
||||
<span class="sd"> # stuff</span>
|
||||
<span class="sd"> # ...</span>
|
||||
<span class="sd"> resourcePool = gui.ChoiceField(</span>
|
||||
<span class="sd"> label=_("Resource Pool"), rdonly = False, order = 5,</span>
|
||||
<span class="sd"> fills = {</span>
|
||||
<span class="sd"> 'callbackName' : 'vcFillMachinesFromResource',</span>
|
||||
<span class="sd"> 'function' : VCHelpers.getMachines,</span>
|
||||
<span class="sd"> 'parameters' : ['vc', 'ev', 'resourcePool']</span>
|
||||
<span class="sd"> },</span>
|
||||
<span class="sd"> tooltip = _('Resource Pool containing base machine'),</span>
|
||||
<span class="sd"> required = True</span>
|
||||
<span class="sd"> )</span>
|
||||
|
||||
<span class="sd"> machine = gui.ChoiceField(label = _("Base Machine"), order = 6,</span>
|
||||
<span class="sd"> tooltip = _('Base machine for this service'), required = True )</span>
|
||||
|
||||
<span class="sd"> vc = gui.HiddenField()</span>
|
||||
<span class="sd"> ev = gui.HiddenField() # ....</span>
|
||||
|
||||
<span class="sd"> '''</span>
|
||||
<span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">):</span>
|
||||
<span class="nb">super</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">__class__</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">__init__</span><span class="p">(</span><span class="o">**</span><span class="n">options</span><span class="p">)</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_data</span><span class="p">[</span><span class="s">'values'</span><span class="p">]</span> <span class="o">=</span> <span class="n">options</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'values'</span><span class="p">,</span> <span class="p">[])</span>
|
||||
<span class="k">if</span> <span class="s">'fills'</span> <span class="ow">in</span> <span class="n">options</span><span class="p">:</span>
|
||||
<span class="c"># Save fnc to register as callback</span>
|
||||
<span class="n">fills</span> <span class="o">=</span> <span class="n">options</span><span class="p">[</span><span class="s">'fills'</span><span class="p">]</span>
|
||||
<span class="n">fnc</span> <span class="o">=</span> <span class="n">fills</span><span class="p">[</span><span class="s">'function'</span><span class="p">]</span>
|
||||
<span class="n">fills</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="s">'function'</span><span class="p">)</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_data</span><span class="p">[</span><span class="s">'fills'</span><span class="p">]</span> <span class="o">=</span> <span class="n">fills</span>
|
||||
<span class="n">gui</span><span class="o">.</span><span class="n">callbacks</span><span class="p">[</span><span class="n">fills</span><span class="p">[</span><span class="s">'callbackName'</span><span class="p">]]</span> <span class="o">=</span> <span class="n">fnc</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_type</span><span class="p">(</span><span class="n">gui</span><span class="o">.</span><span class="n">InputField</span><span class="o">.</span><span class="n">CHOICE_TYPE</span><span class="p">)</span>
|
||||
|
||||
<div class="viewcode-block" id="gui.ChoiceField.setValues"><a class="viewcode-back" href="../../../../api/modules/FormFields.html#uds.core.ui.UserInterface.gui.ChoiceField.setValues">[docs]</a> <span class="k">def</span> <span class="nf">setValues</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">values</span><span class="p">):</span>
|
||||
<span class="sd">'''</span>
|
||||
<span class="sd"> Set the values for this choice field</span>
|
||||
<span class="sd"> '''</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_data</span><span class="p">[</span><span class="s">'values'</span><span class="p">]</span> <span class="o">=</span> <span class="n">values</span>
|
||||
</div></div>
|
||||
<div class="viewcode-block" id="gui.MultiChoiceField"><a class="viewcode-back" href="../../../../api/modules/FormFields.html#uds.core.ui.UserInterface.gui.MultiChoiceField">[docs]</a> <span class="k">class</span> <span class="nc">MultiChoiceField</span><span class="p">(</span><span class="n">InputField</span><span class="p">):</span>
|
||||
<span class="sd">'''</span>
|
||||
<span class="sd"> Multichoices are list of items that are multi-selectable.</span>
|
||||
|
||||
<span class="sd"> There is a new parameter here, not covered by InputField:</span>
|
||||
<span class="sd"> * 'rows' to tell gui how many rows to display (the length of the</span>
|
||||
<span class="sd"> displayable list)</span>
|
||||
|
||||
<span class="sd"> "defvalue" is expresed as a comma separated list of ids</span>
|
||||
|
||||
<span class="sd"> This class do not have callback support, as ChoiceField does.</span>
|
||||
|
||||
<span class="sd"> The values is an array of dictionaries, in the form [ { 'id' : 'a',</span>
|
||||
<span class="sd"> 'text': b }, ... ]</span>
|
||||
|
||||
<span class="sd"> Example usage:</span>
|
||||
|
||||
<span class="sd"> .. code-block:: python</span>
|
||||
|
||||
<span class="sd"> # Declares a multiple choices field, with label "Datastores", that</span>
|
||||
<span class="sd"> is editable, with 5 rows for displaying</span>
|
||||
<span class="sd"> # data at most in user interface, 8th in order, that is required</span>
|
||||
<span class="sd"> and has tooltip "Datastores where to put incrementals",</span>
|
||||
<span class="sd"> # this field is required and has 2 selectable items: "datastore0"</span>
|
||||
<span class="sd"> with id "0" and "datastore1" with id "1"</span>
|
||||
<span class="sd"> datastores = gui.MultiChoiceField(label = _("Datastores"),</span>
|
||||
<span class="sd"> rdonly = False, rows = 5, order = 8,</span>
|
||||
<span class="sd"> tooltip = _('Datastores where to put incrementals'),</span>
|
||||
<span class="sd"> required = True,</span>
|
||||
<span class="sd"> values = [ {'id': '0', 'text': 'datastore0' },</span>
|
||||
<span class="sd"> {'id': '1', 'text': 'datastore1' } ]</span>
|
||||
<span class="sd"> )</span>
|
||||
<span class="sd"> '''</span>
|
||||
<span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">):</span>
|
||||
<span class="nb">super</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">__class__</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">__init__</span><span class="p">(</span><span class="o">**</span><span class="n">options</span><span class="p">)</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_data</span><span class="p">[</span><span class="s">'values'</span><span class="p">]</span> <span class="o">=</span> <span class="n">options</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'values'</span><span class="p">,</span> <span class="p">[])</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_data</span><span class="p">[</span><span class="s">'rows'</span><span class="p">]</span> <span class="o">=</span> <span class="n">options</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'rows'</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_type</span><span class="p">(</span><span class="n">gui</span><span class="o">.</span><span class="n">InputField</span><span class="o">.</span><span class="n">MULTI_CHOICE_TYPE</span><span class="p">)</span>
|
||||
|
||||
<div class="viewcode-block" id="gui.MultiChoiceField.setValues"><a class="viewcode-back" href="../../../../api/modules/FormFields.html#uds.core.ui.UserInterface.gui.MultiChoiceField.setValues">[docs]</a> <span class="k">def</span> <span class="nf">setValues</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">values</span><span class="p">):</span>
|
||||
<span class="sd">'''</span>
|
||||
<span class="sd"> Set the values for this multi choice field</span>
|
||||
<span class="sd"> '''</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_data</span><span class="p">[</span><span class="s">'values'</span><span class="p">]</span> <span class="o">=</span> <span class="n">values</span>
|
||||
</div></div>
|
||||
<div class="viewcode-block" id="gui.EditableList"><a class="viewcode-back" href="../../../../api/modules/FormFields.html#uds.core.ui.UserInterface.gui.EditableList">[docs]</a> <span class="k">class</span> <span class="nc">EditableList</span><span class="p">(</span><span class="n">InputField</span><span class="p">):</span>
|
||||
<span class="sd">'''</span>
|
||||
<span class="sd"> Editables list are lists of editable elements (i.e., a list of IPs, macs,</span>
|
||||
<span class="sd"> names, etcc) treated as simple strings with no id</span>
|
||||
|
||||
<span class="sd"> The struct used to pass values is an array of strings, i.e. ['1', '2',</span>
|
||||
<span class="sd"> 'test', 'bebito', ...]</span>
|
||||
|
||||
<span class="sd"> This list don't have "selected" items, so its defvalue field is simply</span>
|
||||
<span class="sd"> ignored.</span>
|
||||
|
||||
<span class="sd"> We only nee to pass in "label" and, maybe, "values" to set default</span>
|
||||
<span class="sd"> content for the list.</span>
|
||||
|
||||
<span class="sd"> Keep in mind that this is an user editable list, so the user can insert</span>
|
||||
<span class="sd"> values and/or import values from files, so</span>
|
||||
<span class="sd"> by default it will probably have no content at all.</span>
|
||||
|
||||
<span class="sd"> Example usage:</span>
|
||||
|
||||
<span class="sd"> .. code-block:: python</span>
|
||||
|
||||
<span class="sd"> #</span>
|
||||
<span class="sd"> ipList = gui.EditableList(label=_('List of IPS'))</span>
|
||||
|
||||
<span class="sd"> '''</span>
|
||||
|
||||
<span class="c"># : Constant for separating values at "value" method</span>
|
||||
<span class="n">SEPARATOR</span> <span class="o">=</span> <span class="s">'</span><span class="se">\001</span><span class="s">'</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">):</span>
|
||||
<span class="nb">super</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">__class__</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">__init__</span><span class="p">(</span><span class="o">**</span><span class="n">options</span><span class="p">)</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_data</span><span class="p">[</span><span class="s">'values'</span><span class="p">]</span> <span class="o">=</span> <span class="n">gui</span><span class="o">.</span><span class="n">convertToList</span><span class="p">(</span><span class="n">options</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'values'</span><span class="p">,</span> <span class="p">[]))</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_type</span><span class="p">(</span><span class="n">gui</span><span class="o">.</span><span class="n">InputField</span><span class="o">.</span><span class="n">EDITABLE_LIST</span><span class="p">)</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">_setValue</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">values</span><span class="p">):</span>
|
||||
<span class="sd">'''</span>
|
||||
<span class="sd"> So we can override value setting at descendants</span>
|
||||
<span class="sd"> '''</span>
|
||||
<span class="nb">super</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">__class__</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">_setValue</span><span class="p">(</span><span class="n">values</span><span class="p">)</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_data</span><span class="p">[</span><span class="s">'values'</span><span class="p">]</span> <span class="o">=</span> <span class="n">gui</span><span class="o">.</span><span class="n">convertToList</span><span class="p">(</span><span class="n">values</span><span class="p">)</span>
|
||||
|
||||
</div></div>
|
||||
<span class="k">class</span> <span class="nc">UserInterfaceType</span><span class="p">(</span><span class="nb">type</span><span class="p">):</span>
|
||||
<span class="sd">'''</span>
|
||||
<span class="sd"> Metaclass definition for moving the user interface descriptions to a usable</span>
|
||||
<span class="sd"> better place</span>
|
||||
<span class="sd"> '''</span>
|
||||
<span class="k">def</span> <span class="nf">__new__</span><span class="p">(</span><span class="n">cls</span><span class="p">,</span> <span class="n">classname</span><span class="p">,</span> <span class="n">bases</span><span class="p">,</span> <span class="n">classDict</span><span class="p">):</span>
|
||||
<span class="n">newClassDict</span> <span class="o">=</span> <span class="p">{}</span>
|
||||
<span class="n">_gui</span> <span class="o">=</span> <span class="p">{}</span>
|
||||
<span class="c"># We will keep a reference to gui elements also at _gui so we can access them easily</span>
|
||||
<span class="k">for</span> <span class="n">attrName</span><span class="p">,</span> <span class="n">attr</span> <span class="ow">in</span> <span class="n">classDict</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
|
||||
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">attr</span><span class="p">,</span> <span class="n">gui</span><span class="o">.</span><span class="n">InputField</span><span class="p">):</span>
|
||||
<span class="n">_gui</span><span class="p">[</span><span class="n">attrName</span><span class="p">]</span> <span class="o">=</span> <span class="n">attr</span>
|
||||
<span class="n">newClassDict</span><span class="p">[</span><span class="n">attrName</span><span class="p">]</span> <span class="o">=</span> <span class="n">attr</span>
|
||||
<span class="n">newClassDict</span><span class="p">[</span><span class="s">'_gui'</span><span class="p">]</span> <span class="o">=</span> <span class="n">_gui</span>
|
||||
<span class="k">return</span> <span class="nb">type</span><span class="o">.</span><span class="n">__new__</span><span class="p">(</span><span class="n">cls</span><span class="p">,</span> <span class="n">classname</span><span class="p">,</span> <span class="n">bases</span><span class="p">,</span> <span class="n">newClassDict</span><span class="p">)</span>
|
||||
|
||||
|
||||
<div class="viewcode-block" id="UserInterface"><a class="viewcode-back" href="../../../../api/modules/BaseModule.html#uds.core.ui.UserInterface.UserInterface">[docs]</a><span class="k">class</span> <span class="nc">UserInterface</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
|
||||
<span class="sd">'''</span>
|
||||
<span class="sd"> This class provides the management for gui descriptions (user forms)</span>
|
||||
|
||||
<span class="sd"> Once a class is derived from this one, that class can contain Field</span>
|
||||
<span class="sd"> Descriptions,</span>
|
||||
<span class="sd"> that will be managed correctly.</span>
|
||||
|
||||
<span class="sd"> By default, the values passed to this class constructor are used to fill</span>
|
||||
<span class="sd"> the gui form fields values.</span>
|
||||
<span class="sd"> '''</span>
|
||||
<span class="n">__metaclass__</span> <span class="o">=</span> <span class="n">UserInterfaceType</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">values</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
|
||||
<span class="kn">import</span> <span class="nn">copy</span>
|
||||
<span class="c"># : If there is an array of elements to initialize, simply try to store values on form fields</span>
|
||||
<span class="c"># Generate a deep copy of inherited Gui, so each User Interface instance has its own "field" set, and do not share the "fielset" with others, what can be really dangerous</span>
|
||||
<span class="c"># Till now, nothing bad happened cause there where being used "serialized", but this do not have to be this way</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_gui</span> <span class="o">=</span> <span class="n">copy</span><span class="o">.</span><span class="n">deepcopy</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_gui</span><span class="p">)</span> <span class="c"># Ensure "gui" is our own instance, deep copied from base</span>
|
||||
<span class="k">for</span> <span class="n">key</span><span class="p">,</span> <span class="n">val</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_gui</span><span class="o">.</span><span class="n">iteritems</span><span class="p">():</span> <span class="c"># And refresg references to them</span>
|
||||
<span class="nb">setattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">key</span><span class="p">,</span> <span class="n">val</span><span class="p">)</span>
|
||||
|
||||
<span class="k">if</span> <span class="n">values</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span><span class="p">:</span>
|
||||
<span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_gui</span><span class="o">.</span><span class="n">iteritems</span><span class="p">():</span>
|
||||
<span class="k">if</span> <span class="n">k</span> <span class="ow">in</span> <span class="n">values</span><span class="p">:</span>
|
||||
<span class="n">v</span><span class="o">.</span><span class="n">value</span> <span class="o">=</span> <span class="n">values</span><span class="p">[</span><span class="n">k</span><span class="p">]</span>
|
||||
|
||||
<div class="viewcode-block" id="UserInterface.initGui"><a class="viewcode-back" href="../../../../api/modules/BaseModule.html#uds.core.ui.UserInterface.UserInterface.initGui">[docs]</a> <span class="k">def</span> <span class="nf">initGui</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">'''</span>
|
||||
<span class="sd"> This method gives the oportunity to initialize gui fields before they</span>
|
||||
<span class="sd"> are send to administartion client.</span>
|
||||
<span class="sd"> We need this because at initialization time we probably don't have the</span>
|
||||
<span class="sd"> data for gui.</span>
|
||||
|
||||
<span class="sd"> :note: This method is used as a "trick" to allow to modify default form</span>
|
||||
<span class="sd"> data for services. Services are child of Service Providers, and</span>
|
||||
<span class="sd"> will probably need data from Provider to fill initial form data.</span>
|
||||
<span class="sd"> The rest of modules will not use this, and this only will be used</span>
|
||||
<span class="sd"> when the user requests a new service or wants to modify existing</span>
|
||||
<span class="sd"> one.</span>
|
||||
<span class="sd"> :note: There is a drawback of this, and it is that there is that this</span>
|
||||
<span class="sd"> method will modify service default data. It will run fast (probably),</span>
|
||||
<span class="sd"> but may happen that two services of same type are requested at same</span>
|
||||
<span class="sd"> time, and returned data will be probable a nonsense. We will take care</span>
|
||||
<span class="sd"> of this posibility in a near version...</span>
|
||||
<span class="sd"> '''</span>
|
||||
<span class="k">pass</span>
|
||||
</div>
|
||||
<div class="viewcode-block" id="UserInterface.valuesDict"><a class="viewcode-back" href="../../../../api/modules/BaseModule.html#uds.core.ui.UserInterface.UserInterface.valuesDict">[docs]</a> <span class="k">def</span> <span class="nf">valuesDict</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">'''</span>
|
||||
<span class="sd"> Returns own data needed for user interaction as a dict of key-names -></span>
|
||||
<span class="sd"> values. The values returned must be strings.</span>
|
||||
|
||||
<span class="sd"> Example:</span>
|
||||
<span class="sd"> we have 2 text field, first named "host" and second named "port",</span>
|
||||
<span class="sd"> we can do something like this:</span>
|
||||
|
||||
<span class="sd"> .. code-block:: python</span>
|
||||
|
||||
<span class="sd"> return { 'host' : self.host, 'port' : self.port }</span>
|
||||
|
||||
<span class="sd"> (Just the reverse of :py:meth:`.__init__`, __init__ receives this</span>
|
||||
<span class="sd"> dict, valuesDict must return the dict)</span>
|
||||
|
||||
<span class="sd"> Names must coincide with fields declared.</span>
|
||||
|
||||
<span class="sd"> Returns:</span>
|
||||
<span class="sd"> Dictionary, associated with declared fields.</span>
|
||||
<span class="sd"> Default implementation returns the values stored at the gui form</span>
|
||||
<span class="sd"> fields declared.</span>
|
||||
|
||||
<span class="sd"> :note: By default, the provided method returns the correct values</span>
|
||||
<span class="sd"> extracted from form fields</span>
|
||||
|
||||
<span class="sd"> '''</span>
|
||||
<span class="n">dic</span> <span class="o">=</span> <span class="p">{}</span>
|
||||
<span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_gui</span><span class="o">.</span><span class="n">iteritems</span><span class="p">():</span>
|
||||
<span class="k">if</span> <span class="n">v</span><span class="o">.</span><span class="n">isType</span><span class="p">(</span><span class="n">gui</span><span class="o">.</span><span class="n">InputField</span><span class="o">.</span><span class="n">EDITABLE_LIST</span><span class="p">):</span>
|
||||
<span class="n">dic</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">=</span> <span class="n">gui</span><span class="o">.</span><span class="n">convertToList</span><span class="p">(</span><span class="n">v</span><span class="o">.</span><span class="n">value</span><span class="p">)</span>
|
||||
<span class="k">elif</span> <span class="n">v</span><span class="o">.</span><span class="n">isType</span><span class="p">(</span><span class="n">gui</span><span class="o">.</span><span class="n">InputField</span><span class="o">.</span><span class="n">MULTI_CHOICE_TYPE</span><span class="p">):</span>
|
||||
<span class="n">dic</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">=</span> <span class="n">gui</span><span class="o">.</span><span class="n">convertToChoices</span><span class="p">(</span><span class="n">v</span><span class="o">.</span><span class="n">value</span><span class="p">)</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">dic</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">=</span> <span class="n">v</span><span class="o">.</span><span class="n">value</span>
|
||||
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s">'Dict: {0}'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">dic</span><span class="p">))</span>
|
||||
<span class="k">return</span> <span class="n">dic</span>
|
||||
</div>
|
||||
<div class="viewcode-block" id="UserInterface.serializeForm"><a class="viewcode-back" href="../../../../api/modules/BaseModule.html#uds.core.ui.UserInterface.UserInterface.serializeForm">[docs]</a> <span class="k">def</span> <span class="nf">serializeForm</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">'''</span>
|
||||
<span class="sd"> All values stored at form fields are serialized and returned as a single</span>
|
||||
<span class="sd"> string</span>
|
||||
<span class="sd"> Separating char is</span>
|
||||
|
||||
<span class="sd"> The returned string is zipped and then converted to base 64</span>
|
||||
|
||||
<span class="sd"> Note: Hidens are not serialized, they are ignored</span>
|
||||
|
||||
<span class="sd"> '''</span>
|
||||
<span class="n">arr</span> <span class="o">=</span> <span class="p">[]</span>
|
||||
<span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_gui</span><span class="o">.</span><span class="n">iteritems</span><span class="p">():</span>
|
||||
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s">'serializing Key: {0}/{1}'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">k</span><span class="p">,</span> <span class="n">v</span><span class="o">.</span><span class="n">value</span><span class="p">))</span>
|
||||
<span class="k">if</span> <span class="n">v</span><span class="o">.</span><span class="n">isType</span><span class="p">(</span><span class="n">gui</span><span class="o">.</span><span class="n">InputField</span><span class="o">.</span><span class="n">HIDDEN_TYPE</span><span class="p">)</span> <span class="ow">and</span> <span class="n">v</span><span class="o">.</span><span class="n">isSerializable</span><span class="p">()</span> <span class="ow">is</span> <span class="bp">False</span><span class="p">:</span>
|
||||
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s">'Field {0} is not serializable'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">k</span><span class="p">))</span>
|
||||
<span class="k">continue</span>
|
||||
<span class="k">if</span> <span class="n">v</span><span class="o">.</span><span class="n">isType</span><span class="p">(</span><span class="n">gui</span><span class="o">.</span><span class="n">InputField</span><span class="o">.</span><span class="n">EDITABLE_LIST</span><span class="p">)</span> <span class="ow">or</span> <span class="n">v</span><span class="o">.</span><span class="n">isType</span><span class="p">(</span><span class="n">gui</span><span class="o">.</span><span class="n">InputField</span><span class="o">.</span><span class="n">MULTI_CHOICE_TYPE</span><span class="p">):</span>
|
||||
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s">'Serializing value {0}'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">v</span><span class="o">.</span><span class="n">value</span><span class="p">))</span>
|
||||
<span class="n">val</span> <span class="o">=</span> <span class="s">'</span><span class="se">\001</span><span class="s">'</span> <span class="o">+</span> <span class="n">cPickle</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">v</span><span class="o">.</span><span class="n">value</span><span class="p">)</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">val</span> <span class="o">=</span> <span class="n">v</span><span class="o">.</span><span class="n">value</span>
|
||||
<span class="k">if</span> <span class="n">val</span> <span class="ow">is</span> <span class="bp">True</span><span class="p">:</span>
|
||||
<span class="n">val</span> <span class="o">=</span> <span class="n">gui</span><span class="o">.</span><span class="n">TRUE</span>
|
||||
<span class="k">elif</span> <span class="n">val</span> <span class="ow">is</span> <span class="bp">False</span><span class="p">:</span>
|
||||
<span class="n">val</span> <span class="o">=</span> <span class="n">gui</span><span class="o">.</span><span class="n">FALSE</span>
|
||||
<span class="n">arr</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">k</span> <span class="o">+</span> <span class="s">'</span><span class="se">\003</span><span class="s">'</span> <span class="o">+</span> <span class="n">val</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="s">'</span><span class="se">\002</span><span class="s">'</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">arr</span><span class="p">)</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s">'zip'</span><span class="p">)</span>
|
||||
</div>
|
||||
<div class="viewcode-block" id="UserInterface.unserializeForm"><a class="viewcode-back" href="../../../../api/modules/BaseModule.html#uds.core.ui.UserInterface.UserInterface.unserializeForm">[docs]</a> <span class="k">def</span> <span class="nf">unserializeForm</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">values</span><span class="p">):</span>
|
||||
<span class="sd">'''</span>
|
||||
<span class="sd"> This method unserializes the values previously obtained using</span>
|
||||
<span class="sd"> :py:meth:`serializeForm`, and stores</span>
|
||||
<span class="sd"> the valid values form form fileds inside its corresponding field</span>
|
||||
<span class="sd"> '''</span>
|
||||
<span class="k">if</span> <span class="n">values</span> <span class="o">==</span> <span class="s">''</span><span class="p">:</span> <span class="c"># Has nothing</span>
|
||||
<span class="k">return</span>
|
||||
|
||||
<span class="k">try</span><span class="p">:</span>
|
||||
<span class="c"># Set all values to defaults ones</span>
|
||||
<span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_gui</span><span class="o">.</span><span class="n">iterkeys</span><span class="p">():</span>
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_gui</span><span class="p">[</span><span class="n">k</span><span class="p">]</span><span class="o">.</span><span class="n">isType</span><span class="p">(</span><span class="n">gui</span><span class="o">.</span><span class="n">InputField</span><span class="o">.</span><span class="n">HIDDEN_TYPE</span><span class="p">)</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">_gui</span><span class="p">[</span><span class="n">k</span><span class="p">]</span><span class="o">.</span><span class="n">isSerializable</span><span class="p">()</span> <span class="ow">is</span> <span class="bp">False</span><span class="p">:</span>
|
||||
<span class="c"># logger.debug('Field {0} is not unserializable'.format(k))</span>
|
||||
<span class="k">continue</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_gui</span><span class="p">[</span><span class="n">k</span><span class="p">]</span><span class="o">.</span><span class="n">value</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_gui</span><span class="p">[</span><span class="n">k</span><span class="p">]</span><span class="o">.</span><span class="n">defValue</span>
|
||||
|
||||
<span class="n">values</span> <span class="o">=</span> <span class="n">values</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s">'zip'</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="n">values</span> <span class="o">==</span> <span class="s">''</span><span class="p">:</span> <span class="c"># Has nothing</span>
|
||||
<span class="k">return</span>
|
||||
|
||||
<span class="k">for</span> <span class="n">txt</span> <span class="ow">in</span> <span class="n">values</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">'</span><span class="se">\002</span><span class="s">'</span><span class="p">):</span>
|
||||
<span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="o">=</span> <span class="n">txt</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">'</span><span class="se">\003</span><span class="s">'</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="n">k</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_gui</span><span class="p">:</span>
|
||||
<span class="k">try</span><span class="p">:</span>
|
||||
<span class="k">if</span> <span class="n">v</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="s">'</span><span class="se">\001</span><span class="s">'</span><span class="p">:</span>
|
||||
<span class="n">val</span> <span class="o">=</span> <span class="n">cPickle</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">v</span><span class="p">[</span><span class="mi">1</span><span class="p">:]</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s">'utf-8'</span><span class="p">))</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">val</span> <span class="o">=</span> <span class="n">v</span>
|
||||
<span class="k">except</span><span class="p">:</span>
|
||||
<span class="n">val</span> <span class="o">=</span> <span class="s">''</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_gui</span><span class="p">[</span><span class="n">k</span><span class="p">]</span><span class="o">.</span><span class="n">value</span> <span class="o">=</span> <span class="n">val</span>
|
||||
<span class="c"># logger.debug('Value for {0}:{1}'.format(k, val))</span>
|
||||
<span class="k">except</span><span class="p">:</span>
|
||||
<span class="c"># Values can contain invalid characters, so we log every single char</span>
|
||||
<span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s">'Invalid serialization data on {0} {1}'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">values</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s">'hex'</span><span class="p">)))</span>
|
||||
</div>
|
||||
<span class="nd">@classmethod</span>
|
||||
<div class="viewcode-block" id="UserInterface.guiDescription"><a class="viewcode-back" href="../../../../api/modules/BaseModule.html#uds.core.ui.UserInterface.UserInterface.guiDescription">[docs]</a> <span class="k">def</span> <span class="nf">guiDescription</span><span class="p">(</span><span class="n">cls</span><span class="p">,</span> <span class="n">obj</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
|
||||
<span class="sd">'''</span>
|
||||
<span class="sd"> This simple method generates the gui description needed by the</span>
|
||||
<span class="sd"> administration client, so it can</span>
|
||||
<span class="sd"> represent it at user interface and manage it.</span>
|
||||
|
||||
<span class="sd"> Args:</span>
|
||||
<span class="sd"> object: If not none, object that will get its "initGui" invoked</span>
|
||||
<span class="sd"> This will only happen (not to be None) in Services.</span>
|
||||
<span class="sd"> '''</span>
|
||||
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s">'Active languaje for gui translation: {0}'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">get_language</span><span class="p">()))</span>
|
||||
<span class="n">gui</span> <span class="o">=</span> <span class="n">cls</span>
|
||||
<span class="k">if</span> <span class="n">obj</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span><span class="p">:</span>
|
||||
<span class="n">obj</span><span class="o">.</span><span class="n">initGui</span><span class="p">()</span> <span class="c"># We give the "oportunity" to fill necesary gui data before providing it to client</span>
|
||||
<span class="n">gui</span> <span class="o">=</span> <span class="n">obj</span>
|
||||
|
||||
<span class="n">res</span> <span class="o">=</span> <span class="p">[]</span>
|
||||
<span class="k">for</span> <span class="n">key</span><span class="p">,</span> <span class="n">val</span> <span class="ow">in</span> <span class="n">gui</span><span class="o">.</span><span class="n">_gui</span><span class="o">.</span><span class="n">iteritems</span><span class="p">():</span>
|
||||
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s">'{0} ### {1}'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">val</span><span class="p">))</span>
|
||||
<span class="n">res</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s">'name'</span><span class="p">:</span> <span class="n">key</span><span class="p">,</span> <span class="s">'gui'</span><span class="p">:</span> <span class="n">val</span><span class="o">.</span><span class="n">guiDescription</span><span class="p">(),</span> <span class="s">'value'</span><span class="p">:</span> <span class="s">''</span><span class="p">})</span>
|
||||
|
||||
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s">'>>>>>>>>>>>> Gui Description: {0} -- {1}'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">res</span><span class="p">))</span>
|
||||
<span class="k">return</span> <span class="n">res</span></div></div>
|
||||
</pre></div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearer"></div>
|
||||
</div>
|
||||
<div class="related">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="../../../../genindex.html" title="General Index"
|
||||
>index</a></li>
|
||||
<li class="right" >
|
||||
<a href="../../../../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li><a href="../../../../index.html">UDS 1.0 documentation</a> »</li>
|
||||
<li><a href="../../../index.html" >Module code</a> »</li>
|
||||
<li><a href="../../core.html" >uds.core</a> »</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="footer">
|
||||
© Copyright 2012, Virtual Cable S.L.U..
|
||||
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2.2.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -1,183 +0,0 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
|
||||
<title>uds.models — UDS 1.0 documentation</title>
|
||||
|
||||
<link rel="stylesheet" href="../../_static/sphinxdoc.css" type="text/css" />
|
||||
<link rel="stylesheet" href="../../_static/pygments.css" type="text/css" />
|
||||
|
||||
<script type="text/javascript">
|
||||
var DOCUMENTATION_OPTIONS = {
|
||||
URL_ROOT: '../../',
|
||||
VERSION: '1.0',
|
||||
COLLAPSE_INDEX: false,
|
||||
FILE_SUFFIX: '.html',
|
||||
HAS_SOURCE: true
|
||||
};
|
||||
</script>
|
||||
<script type="text/javascript" src="../../_static/jquery.js"></script>
|
||||
<script type="text/javascript" src="../../_static/underscore.js"></script>
|
||||
<script type="text/javascript" src="../../_static/doctools.js"></script>
|
||||
<script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
|
||||
<link rel="top" title="UDS 1.0 documentation" href="../../index.html" />
|
||||
<link rel="up" title="Module code" href="../index.html" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="related">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="../../genindex.html" title="General Index"
|
||||
accesskey="I">index</a></li>
|
||||
<li class="right" >
|
||||
<a href="../../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li><a href="../../index.html">UDS 1.0 documentation</a> »</li>
|
||||
<li><a href="../index.html" accesskey="U">Module code</a> »</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="sphinxsidebar">
|
||||
<div class="sphinxsidebarwrapper">
|
||||
<div id="searchbox" style="display: none">
|
||||
<h3>Quick search</h3>
|
||||
<form class="search" action="../../search.html" method="get">
|
||||
<input type="text" name="q" />
|
||||
<input type="submit" value="Go" />
|
||||
<input type="hidden" name="check_keywords" value="yes" />
|
||||
<input type="hidden" name="area" value="default" />
|
||||
</form>
|
||||
<p class="searchtip" style="font-size: 90%">
|
||||
Enter search terms or a module, class or function name.
|
||||
</p>
|
||||
</div>
|
||||
<script type="text/javascript">$('#searchbox').show(0);</script>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="document">
|
||||
<div class="documentwrapper">
|
||||
<div class="bodywrapper">
|
||||
<div class="body">
|
||||
|
||||
<h1>Source code for uds.models</h1><div class="highlight"><pre>
|
||||
<span class="c"># -*- coding: utf-8 -*-</span>
|
||||
|
||||
<span class="c">#</span>
|
||||
<span class="c"># Copyright (c) 2012 Virtual Cable S.L.</span>
|
||||
<span class="c"># All rights reserved.</span>
|
||||
<span class="c">#</span>
|
||||
<span class="c"># Redistribution and use in source and binary forms, with or without modification,</span>
|
||||
<span class="c"># are permitted provided that the following conditions are met:</span>
|
||||
<span class="c">#</span>
|
||||
<span class="c"># * Redistributions of source code must retain the above copyright notice,</span>
|
||||
<span class="c"># this list of conditions and the following disclaimer.</span>
|
||||
<span class="c"># * Redistributions in binary form must reproduce the above copyright notice,</span>
|
||||
<span class="c"># this list of conditions and the following disclaimer in the documentation</span>
|
||||
<span class="c"># and/or other materials provided with the distribution.</span>
|
||||
<span class="c"># * Neither the name of Virtual Cable S.L. nor the names of its contributors</span>
|
||||
<span class="c"># may be used to endorse or promote products derived from this software</span>
|
||||
<span class="c"># without specific prior written permission.</span>
|
||||
<span class="c">#</span>
|
||||
<span class="c"># THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"</span>
|
||||
<span class="c"># AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE</span>
|
||||
<span class="c"># IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE</span>
|
||||
<span class="c"># DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE</span>
|
||||
<span class="c"># FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL</span>
|
||||
<span class="c"># DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR</span>
|
||||
<span class="c"># SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER</span>
|
||||
<span class="c"># CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,</span>
|
||||
<span class="c"># OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE</span>
|
||||
<span class="c"># OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</span>
|
||||
|
||||
<span class="sd">'''</span>
|
||||
<span class="sd">.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com</span>
|
||||
<span class="sd">'''</span>
|
||||
|
||||
<span class="kn">from</span> <span class="nn">__future__</span> <span class="kn">import</span> <span class="n">unicode_literals</span>
|
||||
|
||||
<span class="n">__updated__</span> <span class="o">=</span> <span class="s">'2014-04-24'</span>
|
||||
|
||||
<span class="kn">import</span> <span class="nn">logging</span>
|
||||
|
||||
<span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="n">__name__</span><span class="p">)</span>
|
||||
|
||||
|
||||
<span class="c"># Utility</span>
|
||||
<span class="kn">from</span> <span class="nn">uds.models.Util</span> <span class="kn">import</span> <span class="n">getSqlDatetime</span>
|
||||
<span class="kn">from</span> <span class="nn">uds.models.Util</span> <span class="kn">import</span> <span class="n">optimizeTable</span>
|
||||
<span class="kn">from</span> <span class="nn">uds.models.Util</span> <span class="kn">import</span> <span class="n">NEVER</span>
|
||||
<span class="kn">from</span> <span class="nn">uds.models.Util</span> <span class="kn">import</span> <span class="n">NEVER_UNIX</span>
|
||||
|
||||
<span class="c"># Services</span>
|
||||
<span class="kn">from</span> <span class="nn">uds.models.Provider</span> <span class="kn">import</span> <span class="n">Provider</span>
|
||||
<span class="kn">from</span> <span class="nn">uds.models.Service</span> <span class="kn">import</span> <span class="n">Service</span>
|
||||
|
||||
<span class="c"># Os managers</span>
|
||||
<span class="kn">from</span> <span class="nn">uds.models.OSManager</span> <span class="kn">import</span> <span class="n">OSManager</span>
|
||||
|
||||
<span class="c"># Transports</span>
|
||||
<span class="kn">from</span> <span class="nn">uds.models.Transport</span> <span class="kn">import</span> <span class="n">Transport</span>
|
||||
<span class="kn">from</span> <span class="nn">uds.models.Network</span> <span class="kn">import</span> <span class="n">Network</span>
|
||||
|
||||
|
||||
<span class="c"># Authenticators</span>
|
||||
<span class="kn">from</span> <span class="nn">uds.models.Authenticator</span> <span class="kn">import</span> <span class="n">Authenticator</span>
|
||||
<span class="kn">from</span> <span class="nn">uds.models.User</span> <span class="kn">import</span> <span class="n">User</span>
|
||||
<span class="kn">from</span> <span class="nn">uds.models.UserPreference</span> <span class="kn">import</span> <span class="n">UserPreference</span>
|
||||
<span class="kn">from</span> <span class="nn">uds.models.Group</span> <span class="kn">import</span> <span class="n">Group</span>
|
||||
|
||||
|
||||
<span class="c"># Provisioned services</span>
|
||||
<span class="kn">from</span> <span class="nn">uds.models.ServicesPool</span> <span class="kn">import</span> <span class="n">DeployedService</span>
|
||||
<span class="kn">from</span> <span class="nn">uds.models.ServicesPoolPublication</span> <span class="kn">import</span> <span class="n">DeployedServicePublication</span>
|
||||
<span class="kn">from</span> <span class="nn">uds.models.UserService</span> <span class="kn">import</span> <span class="n">UserService</span>
|
||||
|
||||
<span class="c"># Especific log information for an user service</span>
|
||||
<span class="kn">from</span> <span class="nn">uds.models.Log</span> <span class="kn">import</span> <span class="n">Log</span>
|
||||
|
||||
<span class="c"># Stats</span>
|
||||
<span class="kn">from</span> <span class="nn">uds.models.StatsCounters</span> <span class="kn">import</span> <span class="n">StatsCounters</span>
|
||||
<span class="kn">from</span> <span class="nn">uds.models.StatsEvents</span> <span class="kn">import</span> <span class="n">StatsEvents</span>
|
||||
|
||||
|
||||
<span class="c"># General utility models, such as a database cache (for caching remote content of slow connections to external services providers for example)</span>
|
||||
<span class="c"># We could use django cache (and maybe we do it in a near future), but we need to clean up things when objecs owning them are deleted</span>
|
||||
<span class="kn">from</span> <span class="nn">uds.models.Cache</span> <span class="kn">import</span> <span class="n">Cache</span>
|
||||
<span class="kn">from</span> <span class="nn">uds.models.Config</span> <span class="kn">import</span> <span class="n">Config</span>
|
||||
<span class="kn">from</span> <span class="nn">uds.models.Storage</span> <span class="kn">import</span> <span class="n">Storage</span>
|
||||
<span class="kn">from</span> <span class="nn">uds.models.UniqueId</span> <span class="kn">import</span> <span class="n">UniqueId</span>
|
||||
|
||||
<span class="c"># Workers/Schedulers related</span>
|
||||
<span class="kn">from</span> <span class="nn">uds.models.Scheduler</span> <span class="kn">import</span> <span class="n">Scheduler</span>
|
||||
<span class="kn">from</span> <span class="nn">uds.models.DelayedTask</span> <span class="kn">import</span> <span class="n">DelayedTask</span>
|
||||
</pre></div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearer"></div>
|
||||
</div>
|
||||
<div class="related">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="../../genindex.html" title="General Index"
|
||||
>index</a></li>
|
||||
<li class="right" >
|
||||
<a href="../../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li><a href="../../index.html">UDS 1.0 documentation</a> »</li>
|
||||
<li><a href="../index.html" >Module code</a> »</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="footer">
|
||||
© Copyright 2012, Virtual Cable S.L.U..
|
||||
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2.2.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -1,9 +0,0 @@
|
||||
==============
|
||||
UDS's core API
|
||||
==============
|
||||
|
||||
.. toctree::
|
||||
|
||||
models
|
||||
modules
|
||||
/development/samples/samples
|
@ -1,24 +0,0 @@
|
||||
===================
|
||||
UDS Database Models
|
||||
===================
|
||||
|
||||
This section describes de models used in UDS.
|
||||
|
||||
The models described here are implemented using Django models, so you can get more
|
||||
info about Django models functionalty at `Django project website <http://www.djangoproject.com/>`_
|
||||
|
||||
The function of the models inside UDS is to provide the persistence needed by
|
||||
the core and by other utility classes that are provided, such as a Cache, Storage
|
||||
or unique IDs.
|
||||
|
||||
Right now the models are used all over UDS, but with time we will limit the use
|
||||
of this models to be done through managers or utility clases designed for that
|
||||
purpose.
|
||||
|
||||
.. toctree::
|
||||
|
||||
models/services
|
||||
models/authentication
|
||||
models/transport
|
||||
models/other
|
||||
|
@ -1,25 +0,0 @@
|
||||
=============================
|
||||
Authentication Related models
|
||||
=============================
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
.. module:: uds.models
|
||||
|
||||
.. autoclass:: Authenticator
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
.. autoclass:: User
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
.. autoclass:: Group
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
.. autoclass:: UserPreference
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
|
@ -1,41 +0,0 @@
|
||||
============
|
||||
Other models
|
||||
============
|
||||
|
||||
Environment related
|
||||
-------------------
|
||||
|
||||
.. module:: uds.models
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
.. autoclass:: Cache
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
.. autoclass:: Storage
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
.. autoclass:: UniqueId
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Module related
|
||||
--------------
|
||||
|
||||
.. autoclass:: Config
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Scheduling and background workers related
|
||||
-----------------------------------------
|
||||
|
||||
.. autoclass:: Scheduler
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
.. autoclass:: DelayedTask
|
||||
:members:
|
||||
:show-inheritance:
|
@ -1,33 +0,0 @@
|
||||
======================
|
||||
Service Related models
|
||||
======================
|
||||
|
||||
This models takes cares of persistence of the Services and its associated elements.
|
||||
|
||||
DESCRIBE HIEARARCHY HERE
|
||||
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
.. module:: uds.models
|
||||
|
||||
.. autoclass:: Provider
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
.. autoclass:: Service
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
.. autoclass:: DeployedService
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
.. autoclass:: DeployedServicePublication
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
.. autoclass:: UserService
|
||||
:members:
|
||||
:show-inheritance:
|
@ -1,18 +0,0 @@
|
||||
========================
|
||||
Transport Related models
|
||||
========================
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
.. module:: uds.models
|
||||
|
||||
.. autoclass:: Transport
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
.. autoclass:: Network
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
|
||||
|
@ -1,18 +0,0 @@
|
||||
===========
|
||||
UDS Modules
|
||||
===========
|
||||
|
||||
|
||||
Modules are the basic component of plugin architecture of UDS.
|
||||
|
||||
As so, they are spreadly covered here, and with
|
||||
:doc:`samples </development/samples/samples>` must give enough information for
|
||||
allowing anyone to develop their own modules.
|
||||
|
||||
.. toctree::
|
||||
|
||||
modules/BaseModule
|
||||
modules/FormFields
|
||||
modules/ServiceModules
|
||||
modules/AuthenticatorModule
|
||||
|
@ -1,27 +0,0 @@
|
||||
=====================
|
||||
Authenticator Modules
|
||||
=====================
|
||||
|
||||
Authenticator modules are responsible of providing the user authentication
|
||||
part inside UDS.
|
||||
|
||||
They are composed of a package where it is provided and, at least, the following
|
||||
elements:
|
||||
|
||||
* One icon for administration interface representation. Icon is png file of
|
||||
16x16.
|
||||
* One class, derived from uds.core.auths.Authenticator, providing the needed
|
||||
logic for that authenticator.
|
||||
* Registration of the class inside uds at package's __init__.
|
||||
|
||||
All packages included inside uds.auths will automatically be imported, but
|
||||
the authenticators needs to register as valid authenticators, and the best place
|
||||
to do that is at the authenticator's package __init__.
|
||||
|
||||
The best way to understand what you need to create your own authenticator,
|
||||
is to look at :doc:`modules samples </development/samples/samples>`
|
||||
|
||||
|
||||
.. toctree::
|
||||
|
||||
auths/Authenticator
|
@ -1,53 +0,0 @@
|
||||
===========
|
||||
Base Module
|
||||
===========
|
||||
|
||||
The Base module is the base class used for all modules of UDS.
|
||||
|
||||
In order to deveplop an UDS Module, there is a number of basic methods that you must provide.
|
||||
|
||||
There are the clases that are base of BaseModule, that are:
|
||||
* BaseModule_
|
||||
* Environmentable_
|
||||
* Serializable_
|
||||
* UserInterface_
|
||||
|
||||
.. toctree::
|
||||
|
||||
BaseModule
|
||||
----------
|
||||
|
||||
.. module:: uds.core
|
||||
|
||||
.. autoclass:: Module
|
||||
:members:
|
||||
|
||||
Environmentable
|
||||
---------------
|
||||
|
||||
.. autoclass:: Environmentable
|
||||
:members:
|
||||
|
||||
|
||||
Serializable
|
||||
------------
|
||||
|
||||
.. autoclass:: Serializable
|
||||
:members:
|
||||
|
||||
|
||||
UserInterface
|
||||
-------------
|
||||
|
||||
UserInterface is the class responsible for managing the Field Descriptions of modules.
|
||||
|
||||
This fields descriptions are intended for allowing an easy exposition of configuration form via the
|
||||
administration interface.
|
||||
|
||||
You can obtain more information about user interface fields at :doc:`User interface fields types <FormFields>`.
|
||||
|
||||
.. module:: uds.core.ui.UserInterface
|
||||
|
||||
.. autoclass:: UserInterface
|
||||
:members:
|
||||
|
@ -1,33 +0,0 @@
|
||||
Form Fields
|
||||
===========
|
||||
|
||||
Form Fields are utility clases provided for allowing easy communication of modules
|
||||
and administration interface.
|
||||
|
||||
It helps to define the administration level forms that will be used to manage
|
||||
different modules (service providers, services, authenticators, transports, ...)
|
||||
|
||||
All modules that needs to be presented to admin users, use UserInterface as one
|
||||
of their base class.
|
||||
|
||||
Think that not all interfaces needed by different modules need a direct representation
|
||||
at administration interface level, (for example, UserDeployment do not need to be
|
||||
managed by administrators, nor publications, both corresponding to service modules).
|
||||
|
||||
.. module:: uds.core.ui.UserInterface
|
||||
|
||||
.. toctree::
|
||||
|
||||
|
||||
The types of fields provided are:
|
||||
* :py:class:`gui.TextField`
|
||||
* :py:class:`gui.NumericField`
|
||||
* :py:class:`gui.PasswordField`
|
||||
* :py:class:`gui.HiddenField`
|
||||
* :py:class:`gui.CheckBoxField`
|
||||
* :py:class:`gui.ChoiceField`
|
||||
* :py:class:`gui.MultiChoiceField`
|
||||
* :py:class:`gui.EditableList`
|
||||
|
||||
.. autoclass:: gui
|
||||
:members: InputField, TextField, NumericField, PasswordField, HiddenField, CheckBoxField, ChoiceField, MultiChoiceField, EditableList
|
@ -1,53 +0,0 @@
|
||||
===============
|
||||
Service Modules
|
||||
===============
|
||||
|
||||
Service modules are responsible for giving the user consumable ip services for
|
||||
users.
|
||||
|
||||
They are composed of a package where it is provided, at least, the following
|
||||
elements:
|
||||
|
||||
* One icon for administration interface representation. Icon is png file of
|
||||
16x16.
|
||||
* A Full tree of classes, derived from interfaces (descrived below)
|
||||
* Registration of the class inside UDS at package's __init__.
|
||||
|
||||
All packages included inside uds.services will automatically be imported, but
|
||||
the service providers (root of service trees) needs to register as valid
|
||||
providers, and the best place to do that is at the authenticator's package __init__.
|
||||
|
||||
the Full tree of classes needed by the service modules are:
|
||||
|
||||
* **Provider**: This is the root tree of any service. It represents an agrupation
|
||||
of services under the same root. As sample, a service provider can be an
|
||||
Open nebula server, an VC, or whataver is a common root for a number of services.
|
||||
* **Service**: This is the representation of what a service will give to an user.
|
||||
As such, this is not what the user will consume, but this is more the definition
|
||||
of what the user will consume. Before assigning a service to an user, the admin
|
||||
will need to declare a "Deployed Service", that is a definition, using this service
|
||||
an a number of other modules, of what the user will consume. Inside this service
|
||||
we need to provide the information needed for deploying an user consumable item,
|
||||
such as if it needs to be "prepared", if it supports cache, if it must be assigned
|
||||
to an user "manually", and all the custom data that the user deployments and publications
|
||||
will need.
|
||||
* **Publication**. Some services, before being assigned to users, needs some kind of
|
||||
preparation. This process of preparation is called here "publication". The service
|
||||
itself will declare if it needs a publication and, if needed, who is responsible of
|
||||
that. Services with needed publication will use this kind of class to provide
|
||||
such preparation.
|
||||
* **User Deployment**. This is what will provide the final user consumable service.
|
||||
The user deployment is the last responsible for, using the provided service
|
||||
and provided publication (if needed), to create the elements that the user will
|
||||
consume.
|
||||
|
||||
The best way to understand what you need to create your own services,
|
||||
is to look at :doc:`modules samples </development/samples/samples>`
|
||||
|
||||
.. toctree::
|
||||
|
||||
services/Provider
|
||||
services/Service
|
||||
services/Publication
|
||||
services/UserDeployment
|
||||
services/Exceptions
|
@ -1,15 +0,0 @@
|
||||
=======================
|
||||
Authenticator Interface
|
||||
=======================
|
||||
|
||||
The authenticator class is in fact an interface. UDS authenticators must derive
|
||||
from this, and must provide the logic so UDS can manage the users and groups that
|
||||
an authenticator provides.
|
||||
|
||||
|
||||
.. toctree::
|
||||
|
||||
.. module:: uds.core.auths
|
||||
|
||||
.. autoclass:: Authenticator
|
||||
:members:
|
@ -1,9 +0,0 @@
|
||||
==================
|
||||
Service Exceptions
|
||||
==================
|
||||
|
||||
.. toctree::
|
||||
|
||||
.. automodule:: uds.core.services.Exceptions
|
||||
:members:
|
||||
|
@ -1,27 +0,0 @@
|
||||
==================
|
||||
Provider interface
|
||||
==================
|
||||
|
||||
The provider class is the root class of the module. It keeps the common information
|
||||
needed by all services provided by this "provider".
|
||||
|
||||
Think about a provider as the class that will declare all stuff neded by core and
|
||||
child services to provide and administrator user a way to create services to be
|
||||
consumed by users.
|
||||
|
||||
One good example is a Virtualization server. Here we keep information about that
|
||||
server (ip address, protocol, ....) and services provided by that "provider" will
|
||||
make use of that information to make the administrator not provide it once an again
|
||||
for every service we put on that virtualization server.
|
||||
|
||||
.. toctree::
|
||||
|
||||
.. module:: uds.core.services
|
||||
|
||||
For a detailed example of a service provider, you can see the provided
|
||||
:doc:`provider sample </development/samples/services/Provider>`
|
||||
|
||||
.. autoclass:: ServiceProvider
|
||||
:members:
|
||||
|
||||
|
@ -1,30 +0,0 @@
|
||||
=====================
|
||||
Publication interface
|
||||
=====================
|
||||
|
||||
The publication class is in fact an interface. It represents, in those case that
|
||||
a service needs the preparation, the logic for that preparation.
|
||||
|
||||
So the publication class is responsible of doing whatever is needed to get the
|
||||
deployed service (that is the compound of a service, an os manager, transports
|
||||
and authenticators) ready for deploying user consumables.
|
||||
|
||||
Note that not all services needs to implement this class, only in those case
|
||||
where that service declares that a publication is needed.
|
||||
|
||||
|
||||
As functional sample of a publication, imagine that we want to assing KVM COW
|
||||
machines to users. The publication class can make a clone of the base machine
|
||||
(that the service itself has taken note of which one is), and then the COWs will
|
||||
be created from this cloned machine.
|
||||
|
||||
.. toctree::
|
||||
|
||||
.. module:: uds.core.services
|
||||
|
||||
For a detailed example of a service provider, you can see the provided
|
||||
:doc:`publication sample </development/samples/services/Publication>`
|
||||
|
||||
.. autoclass:: Publication
|
||||
:members:
|
||||
|
@ -1,25 +0,0 @@
|
||||
=================
|
||||
Service interface
|
||||
=================
|
||||
|
||||
The service class is in fact an interface. It represents the base for all user
|
||||
deployments (that is, consumable user services) that will be provided.
|
||||
|
||||
As such, the service is responsible for keeping the information that, at deployments,
|
||||
will be neded by provided user consumable services.
|
||||
|
||||
A good sample of a service can be a KVM machine that will be copied COW and that COWs
|
||||
will be assigned to users. In that case, we will collect which machine will be copied,
|
||||
where it is to be copied, an a few more params that the user deployments will need.
|
||||
|
||||
.. toctree::
|
||||
|
||||
.. module:: uds.core.services
|
||||
|
||||
For a detailed example of a service provider, you can see the provided
|
||||
:doc:`service sample </development/samples/services/Service>`
|
||||
|
||||
.. autoclass:: Service
|
||||
:members:
|
||||
|
||||
|
@ -1,23 +0,0 @@
|
||||
========================
|
||||
UserDeployment interface
|
||||
========================
|
||||
|
||||
The user deployment class is in fact an interface. It represents the final consumable
|
||||
that will be assigned to an user, and, as such, it must provide some mechanisms to
|
||||
allow core to manage those consumables.
|
||||
|
||||
A good sample of an user deployment can be a KVM Virtual Machine, cloned COW from
|
||||
another, and assigned to an user.
|
||||
|
||||
.. toctree::
|
||||
|
||||
.. module:: uds.core.services
|
||||
|
||||
For detailed examples of a couple of user deployments, you can see the provided
|
||||
:doc:`service sample </development/samples/services/DeployedServiceOne>` and
|
||||
:doc:`service sample </development/samples/services/DeployedServiceTwo>`
|
||||
|
||||
.. autoclass:: UserDeployment
|
||||
:members:
|
||||
|
||||
|
@ -1,36 +0,0 @@
|
||||
==================
|
||||
UDS's architecture
|
||||
==================
|
||||
|
||||
This section covers the current UDS Arquiceture & diagrams.
|
||||
|
||||
UDS is built on the Django web framework, which itself is
|
||||
built on Python, thus MyTARDIS follows the architectural model
|
||||
of Django.
|
||||
|
||||
Component Architecture
|
||||
----------------------
|
||||
|
||||
This diagram shows the major components of UDS.
|
||||
|
||||
* Core components
|
||||
* `Apache Http <http://projects.apache.org/projects/http_server.html>`_
|
||||
* `WSGI <http://code.google.com/p/modwsgi/>`_
|
||||
* `Django <http://www.djangoproject.com/>`_
|
||||
* `Python <http://docs.python.org/>`_.
|
||||
|
||||
* RDBMS
|
||||
UDS is currently being developed/testing on Mysql 5 Database.
|
||||
May other databases will work also, but no one else has been tested.
|
||||
|
||||
Functional Architecture
|
||||
-----------------------
|
||||
|
||||
UDS is build using Django as base support for Web acess and Database access.
|
||||
|
||||
Over this, UDS uses the following diagram:
|
||||
|
||||
DIAGRAM
|
||||
|
||||
Core
|
||||
Basic core funcionality.
|
@ -1,3 +0,0 @@
|
||||
===================
|
||||
Contributing to UDS
|
||||
===================
|
@ -1,3 +0,0 @@
|
||||
==============
|
||||
UDS Repository
|
||||
==============
|
@ -1,15 +0,0 @@
|
||||
====================
|
||||
Sample Authenticator
|
||||
====================
|
||||
|
||||
The authenticator is the responsible of providing the needed mechanisms to UDS for
|
||||
user authentication.
|
||||
|
||||
As thatm this must provide a number of methods, that will allow UDS to manage
|
||||
things the way it needs to. (Access users, groups, check credentials, etc...)
|
||||
|
||||
Here you can :download:`Download sample </_downloads/samples/auths/SampleAuth.py>`
|
||||
|
||||
|
||||
.. literalinclude:: /_downloads/samples/auths/SampleAuth.py
|
||||
:linenos:
|
@ -1,100 +0,0 @@
|
||||
===================
|
||||
UDS Modules Samples
|
||||
===================
|
||||
|
||||
In this section we cover basic samples of the different kind of mudules supported
|
||||
by UDS.
|
||||
|
||||
UDS is designed in a modular way, meaning this that it has a core that allows
|
||||
a number of modules to get plugged inside the whole system.
|
||||
|
||||
This modules are:
|
||||
|
||||
* Services, including all stuff around them.
|
||||
* Transports
|
||||
* OS Managers
|
||||
* Authenticators
|
||||
|
||||
This secion will try to give sample of every module, what it must do and how this
|
||||
must be done.
|
||||
|
||||
Service Sample
|
||||
--------------
|
||||
|
||||
A service is composed of several classes. This classes depends on how the service works.
|
||||
|
||||
This are:
|
||||
|
||||
* *Provider*, that is simply the "root" where services
|
||||
descent, so we can configure just one part of the service parameters and rest
|
||||
of them at service level.
|
||||
|
||||
One sample of provider is a virtualization server, such as oVirt, Open Nebula, or
|
||||
others like it. We can keep info about server at provider level, and info about
|
||||
what we need in an specific service at service level.
|
||||
|
||||
* *Service*, that is a service definition, that must be deployed at a later stage
|
||||
to offer something to the users.
|
||||
|
||||
Following our previous sample, if provider was an oVirt server, a service can
|
||||
be a Virtual Machine cloned COW.
|
||||
|
||||
* *Publication*, This class is optional. If service declares that needs a
|
||||
publication for deployment of user instance, this class implements exactly
|
||||
that, the publication for that service. Publications are in fact a way of
|
||||
allowing services to prepare something in a stage prior to creating the
|
||||
user consumable services.
|
||||
|
||||
Following our previous sample, if provider was an oVirt Server and the service
|
||||
was a Virtual Machine cloned for Cow, the poblication can be a full clone of
|
||||
the service machine for making COWS from this one.
|
||||
|
||||
* *DeployedService*, This class is the user consumed service itself. After a
|
||||
service is created, it must be deployed, and deploy will mean that there will
|
||||
be "instances" of that service (User Deployments) that will be consumed by
|
||||
users.
|
||||
|
||||
Following our previous sample, if the publication was a full copy machine,
|
||||
an deployed service can be a machine in COW format using as base that
|
||||
machine.
|
||||
|
||||
|
||||
From theese, the only not really needed is Publication. Publication will only be
|
||||
needed whenever a service needs a "preparation" before creating the user consumable
|
||||
deployed services. For a service to be usable, we will need the full tree, meaning
|
||||
this that we will provide all controllers (Provider, service or services, publication
|
||||
or publications, deployed service or deployed services.).
|
||||
|
||||
All class belonging to a service must be grouped under the same package, and we
|
||||
well need to register this package for the system to recognize it as service.
|
||||
|
||||
For this, we must register the Provider, that has references to rest of items.
|
||||
|
||||
Provider declares which services it provides. Services declares which publication
|
||||
and deployed service it needs. Provider can declare multiples services it offers,
|
||||
but services has at most one publication and exatly one deployed service.
|
||||
|
||||
So, by registering the Provider, we register the whole tree provided by de package.
|
||||
|
||||
Here you can find samples of every class needed for creating a new package of
|
||||
services.
|
||||
|
||||
.. toctree::
|
||||
|
||||
services/whatisneeded
|
||||
services/Provider
|
||||
services/Service
|
||||
services/Publication
|
||||
services/DeployedServiceOne
|
||||
services/DeployedServiceTwo
|
||||
|
||||
|
||||
Authenticator Sample
|
||||
--------------------
|
||||
|
||||
An authenticator is composed of a single class, derived from :py:class:`uds.core.auths.Authenticator`.
|
||||
|
||||
Here you can find a sample of an authenticator.
|
||||
|
||||
.. toctree::
|
||||
auths/Authenticator
|
@ -1,20 +0,0 @@
|
||||
==========================
|
||||
Sample User Deployment One
|
||||
==========================
|
||||
|
||||
User deployments are the class that are responsible for creating the ultimate consumable
|
||||
user service, that is, for managing that whenever the core requests a new service for
|
||||
an user, this classes will take responsibility to provide it.
|
||||
|
||||
Here we cover SampleUserDeploymentOne that is for SampleServiceOne, do not needs to be
|
||||
published and do not uses cache.
|
||||
|
||||
You can easily follow the code to see what it does, and what you have to do if you
|
||||
want to provide a new one.
|
||||
|
||||
:download:`Download sample </_downloads/samples/services/SampleUserDeploymentOne.py>`
|
||||
|
||||
|
||||
.. literalinclude:: /_downloads/samples/services/SampleUserDeploymentOne.py
|
||||
:linenos:
|
||||
|
@ -1,20 +0,0 @@
|
||||
==========================
|
||||
Sample User Deployment Two
|
||||
==========================
|
||||
|
||||
User deployments are the class that are responsible for creating the ultimate consumable
|
||||
user service, that is, for managing that whenever the core requests a new service for
|
||||
an user, this classes will take responsibility to provide it.
|
||||
|
||||
Here we cover SampleUserDeploymentTwo that is for SampleServiceTwo, needs to be
|
||||
published and has L1 and L2 cache items.
|
||||
|
||||
You can easily follow the code to see what it does, and what you have to do if you
|
||||
want to provide a new one.
|
||||
|
||||
:download:`Download sample </_downloads/samples/services/SampleUserDeploymentTwo.py>`
|
||||
|
||||
|
||||
.. literalinclude:: /_downloads/samples/services/SampleUserDeploymentTwo.py
|
||||
:linenos:
|
||||
|
@ -1,19 +0,0 @@
|
||||
=======================
|
||||
Sample Service Provider
|
||||
=======================
|
||||
|
||||
The service provider is the top of the tree of services needed clases.
|
||||
It main function is to provide a base for services, where this services contains
|
||||
a common parent that is, for example, a server, a range of IPs, etc...
|
||||
|
||||
This sample covers a simple service provider, explains also a bit about FormFields
|
||||
and shows what tasks must be done by a service provider.
|
||||
|
||||
You can easily follow the code to see what it does, and what you have to do if you
|
||||
want to provide a new one.
|
||||
|
||||
:download:`Download sample </_downloads/samples/services/SampleProvider.py>`
|
||||
|
||||
|
||||
.. literalinclude:: /_downloads/samples/services/SampleProvider.py
|
||||
:linenos:
|
@ -1,23 +0,0 @@
|
||||
==================
|
||||
Sample publication
|
||||
==================
|
||||
|
||||
A publication is a class responsible for making a service defined available to be
|
||||
consumed by users.
|
||||
|
||||
Not all services needs publications as you have already seen if you are following
|
||||
the samples. Publications are only needed for services that needs some kind of
|
||||
preparation, as, for example, with Virtual Machines, clone the base virtual machine
|
||||
so we can create COW copies from this clone. This kind of behavior needs a preparation
|
||||
step, that is efectively to clone the virtual base, and that will be the task of a
|
||||
publication for that kind of services.
|
||||
|
||||
You can easily follow the code to see what it does, and what you have to do if you
|
||||
want to provide a new one.
|
||||
|
||||
:download:`Download sample </_downloads/samples/services/SamplePublication.py>`
|
||||
|
||||
|
||||
.. literalinclude:: /_downloads/samples/services/SamplePublication.py
|
||||
:linenos:
|
||||
|
@ -1,15 +0,0 @@
|
||||
==============
|
||||
Sample service
|
||||
==============
|
||||
|
||||
Here we cover two services. ServiceOne, that do not needs publication and
|
||||
ServiceTwo, that needs publication.
|
||||
|
||||
This sample should be enought to guide you through the creation of a new service.
|
||||
|
||||
:download:`Download sample </_downloads/samples/services/SampleService.py>`
|
||||
|
||||
|
||||
.. literalinclude:: /_downloads/samples/services/SampleService.py
|
||||
:linenos:
|
||||
|
@ -1,32 +0,0 @@
|
||||
Needs for a service package
|
||||
---------------------------
|
||||
|
||||
For a new package of services, you will need:
|
||||
|
||||
|
||||
* One package (python package), of course :-).
|
||||
* One icon for the provider, in png format an 16x16 size. Colours is left
|
||||
to your election. This icon will be informed at Provider class.
|
||||
* One icon for every service that the provider will expose. Same as provider
|
||||
icons. These icons will be informed at Service class. Every single class
|
||||
must provide its own icon.
|
||||
* Registering the provider. For the samples show here, this will be at
|
||||
__init__ of the package.
|
||||
|
||||
The contents of the sample package __init__ file is:
|
||||
|
||||
.. literalinclude:: /_downloads/samples/services/__init__.py
|
||||
:linenos:
|
||||
|
||||
:download:`Download sample </_downloads/samples/services/__init__.py>`
|
||||
|
||||
* Put the package under the apropiate uds package. In the case of
|
||||
services, this is under "uds.core".
|
||||
|
||||
Core will look for all packages under "uds.services" and import them at
|
||||
initialization of the server, so every package under this will get their
|
||||
__init__ called, where we register the provider.
|
||||
|
||||
* Follow the samples provided here as base
|
||||
|
||||
|
@ -1,71 +0,0 @@
|
||||
.. _index:
|
||||
|
||||
===================
|
||||
UDS's documentation
|
||||
===================
|
||||
|
||||
This documentation is provided so we can understand (hopefully) UDS, its internals,
|
||||
and everything about it.
|
||||
|
||||
Right now the documentation is not too ritch, but we are working on it so it will
|
||||
get the needed level for this kind of project.
|
||||
|
||||
|
||||
First Steps
|
||||
===========
|
||||
|
||||
* **From scratch:**
|
||||
:doc:`Overview <intro/overview>` |
|
||||
:doc:`Installation <intro/install>`
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
|
||||
intro/overview
|
||||
intro/install
|
||||
|
||||
The internals of uds
|
||||
====================
|
||||
|
||||
.. toctree::
|
||||
|
||||
development/architecture
|
||||
development/development
|
||||
api/index
|
||||
|
||||
UDS Open source project
|
||||
=======================
|
||||
|
||||
* **Community:**
|
||||
:doc:`How to get involved <development/contributing>` |
|
||||
:doc:`The UDS source code repository <development/repository>`
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
|
||||
development/contributing
|
||||
development/repository
|
||||
|
||||
|
||||
Acknowledgements
|
||||
================
|
||||
|
||||
We want to thaks all the people that has contributed to de project, an also
|
||||
other Open Source project used to improve this one.
|
||||
|
||||
List of other software used to build UDS:
|
||||
|
||||
* `Django <http://www.djangoproject.com/>`_
|
||||
* `XML-RPC.NET Copyright (c) 2006 Charles Cook <http://www.xml-rpc.net/>`_
|
||||
* `Darkglass reworked graphics <http://kde-look.org/content/show.php/Dark-Glass+reviewed?content=67902>`_
|
||||
* `Crystal project <http://kde-look.org/content/show.php/Crystal+Project?content=60475>`_
|
||||
* `South <http://south.aeracode.org/>`_
|
||||
* `Jsch <http://www.jcraft.com/jsch/>`_
|
||||
* `JQuery <http://jquery.org/>`_
|
||||
* `Plugin detect library <http://www.pinlady.net/PluginDetect/>`_
|
||||
* `JQuery UI <http://jqueryui.com/>`_
|
||||
|
||||
I hope to do nor forget anythinh here, if i do, please, report it so we can credit
|
||||
to every project that UDS makes use of.
|
||||
|
||||
|
@ -1,46 +0,0 @@
|
||||
==============
|
||||
Installing UDS
|
||||
==============
|
||||
|
||||
In order to run UDS, you will need:
|
||||
|
||||
* Django Server 1.4
|
||||
* South module for Django
|
||||
* Mysql libraries for python
|
||||
* Mysql Database
|
||||
* Ldap Libraries for python
|
||||
* Criptographic package for python
|
||||
|
||||
Default transports are compiled in binary form, and keeped inside UDS repository,
|
||||
so you won't need Java to put UDS to work.
|
||||
|
||||
Once you have all of this, you will have to follow these steps:
|
||||
|
||||
* Obtain UDS from repository, you can see how to do this from
|
||||
:doc:`repository access documentation </development/repository>`
|
||||
* Configure a database for use with UDS. To do this, simple create a database
|
||||
inside your Mysql server, and a user with all permissions in this database.
|
||||
* Configure UDS settings.
|
||||
Inside "server" folder, you will find "settings.py". This file contains the
|
||||
configuration of UDS (if it runs in debug mode, ..). The most important part
|
||||
here is the DATABASES section, where you will set up the database that UDS
|
||||
will use. Simply change "host", "port", "udsername", "password" and "name"
|
||||
to match your database settings.
|
||||
Here, we have to take care that, if we left UDS in debug mode, Django will keep
|
||||
track of all petitions to UDS, so memory will grow constantly. Do not get scared
|
||||
if you see that UDS starts to waste too much memory. Simply restart it or, if it's
|
||||
intended to be running for a while, set DEBUG variable to "False".
|
||||
Important sections are:
|
||||
|
||||
* Create initial database tables.
|
||||
Inside UDS folder, where you downloaded it, you will see a "manage.py".
|
||||
This python application is the responsible for managing UDS, from database creation,
|
||||
migrations, backend start & stop, web server (testing web server btw), ...
|
||||
To create initial databases, we will do:
|
||||
|
||||
python manage.py sync
|
||||
python manage.py migrate
|
||||
|
||||
Now we have all databases and everything that UDS needs for starting up ready... :-)
|
||||
|
||||
|
@ -1,32 +0,0 @@
|
||||
===============
|
||||
UDS at a glance
|
||||
===============
|
||||
|
||||
UDS has been developed to make a single open source server that allows the access
|
||||
to the growing ip services catalog.
|
||||
|
||||
For this, we have try to make a framework that allows the use of any ip service,
|
||||
focusing initially at VDI because it's the mayor need for the people we have
|
||||
contacted initially .
|
||||
|
||||
Also, first version of UDS has been developed "fast" (very fast indeed), so now
|
||||
we need to make a revision an adapt de code of the framework so it's more
|
||||
'pythonic'. (Think that i start learning python one day like this, and less than
|
||||
a week later i started this proyect). So think that, althouth UDS is fully
|
||||
functional, has been tested and is stable enought for any production environment,
|
||||
there is a lot of work to do.
|
||||
|
||||
As so, UDS not only provides default modules for a lot of things (virtualization
|
||||
provider, authentication providers, protocols, ...), but also provides the core
|
||||
itself to allow anyone who wants or needs something, incorporate it to the
|
||||
catalog of UDS in an easy and fast way.
|
||||
|
||||
* In order to use UDS, you must simply :doc:`Follow the installation guide <install>`.
|
||||
|
||||
* In order to design and implement your own modules, you must:
|
||||
|
||||
* :doc:`Understand the architecture </development/architecture>`
|
||||
* :doc:`See some module samples </development/samples/samples>`
|
||||
|
||||
* In order to contribute, you must install UDS, understand it, an read the
|
||||
:doc:`contributing guide </development/contributing>`
|
Before Width: | Height: | Size: 673 B |
@ -1,537 +0,0 @@
|
||||
/*
|
||||
* basic.css
|
||||
* ~~~~~~~~~
|
||||
*
|
||||
* Sphinx stylesheet -- basic theme.
|
||||
*
|
||||
* :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
* :license: BSD, see LICENSE for details.
|
||||
*
|
||||
*/
|
||||
|
||||
/* -- main layout ----------------------------------------------------------- */
|
||||
|
||||
div.clearer {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
/* -- relbar ---------------------------------------------------------------- */
|
||||
|
||||
div.related {
|
||||
width: 100%;
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
div.related h3 {
|
||||
display: none;
|
||||
}
|
||||
|
||||
div.related ul {
|
||||
margin: 0;
|
||||
padding: 0 0 0 10px;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
div.related li {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
div.related li.right {
|
||||
float: right;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
/* -- sidebar --------------------------------------------------------------- */
|
||||
|
||||
div.sphinxsidebarwrapper {
|
||||
padding: 10px 5px 0 10px;
|
||||
}
|
||||
|
||||
div.sphinxsidebar {
|
||||
float: left;
|
||||
width: 230px;
|
||||
margin-left: -100%;
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
div.sphinxsidebar ul {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
div.sphinxsidebar ul ul,
|
||||
div.sphinxsidebar ul.want-points {
|
||||
margin-left: 20px;
|
||||
list-style: square;
|
||||
}
|
||||
|
||||
div.sphinxsidebar ul ul {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
div.sphinxsidebar form {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
div.sphinxsidebar input {
|
||||
border: 1px solid #98dbcc;
|
||||
font-family: sans-serif;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
div.sphinxsidebar #searchbox input[type="text"] {
|
||||
width: 170px;
|
||||
}
|
||||
|
||||
div.sphinxsidebar #searchbox input[type="submit"] {
|
||||
width: 30px;
|
||||
}
|
||||
|
||||
img {
|
||||
border: 0;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
/* -- search page ----------------------------------------------------------- */
|
||||
|
||||
ul.search {
|
||||
margin: 10px 0 0 20px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
ul.search li {
|
||||
padding: 5px 0 5px 20px;
|
||||
background-image: url(file.png);
|
||||
background-repeat: no-repeat;
|
||||
background-position: 0 7px;
|
||||
}
|
||||
|
||||
ul.search li a {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
ul.search li div.context {
|
||||
color: #888;
|
||||
margin: 2px 0 0 30px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
ul.keywordmatches li.goodmatch a {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* -- index page ------------------------------------------------------------ */
|
||||
|
||||
table.contentstable {
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
table.contentstable p.biglink {
|
||||
line-height: 150%;
|
||||
}
|
||||
|
||||
a.biglink {
|
||||
font-size: 1.3em;
|
||||
}
|
||||
|
||||
span.linkdescr {
|
||||
font-style: italic;
|
||||
padding-top: 5px;
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
/* -- general index --------------------------------------------------------- */
|
||||
|
||||
table.indextable {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
table.indextable td {
|
||||
text-align: left;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
table.indextable dl, table.indextable dd {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
table.indextable tr.pcap {
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
table.indextable tr.cap {
|
||||
margin-top: 10px;
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
|
||||
img.toggler {
|
||||
margin-right: 3px;
|
||||
margin-top: 3px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
div.modindex-jumpbox {
|
||||
border-top: 1px solid #ddd;
|
||||
border-bottom: 1px solid #ddd;
|
||||
margin: 1em 0 1em 0;
|
||||
padding: 0.4em;
|
||||
}
|
||||
|
||||
div.genindex-jumpbox {
|
||||
border-top: 1px solid #ddd;
|
||||
border-bottom: 1px solid #ddd;
|
||||
margin: 1em 0 1em 0;
|
||||
padding: 0.4em;
|
||||
}
|
||||
|
||||
/* -- general body styles --------------------------------------------------- */
|
||||
|
||||
a.headerlink {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
h1:hover > a.headerlink,
|
||||
h2:hover > a.headerlink,
|
||||
h3:hover > a.headerlink,
|
||||
h4:hover > a.headerlink,
|
||||
h5:hover > a.headerlink,
|
||||
h6:hover > a.headerlink,
|
||||
dt:hover > a.headerlink {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
div.body p.caption {
|
||||
text-align: inherit;
|
||||
}
|
||||
|
||||
div.body td {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.field-list ul {
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
.first {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
|
||||
p.rubric {
|
||||
margin-top: 30px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
img.align-left, .figure.align-left, object.align-left {
|
||||
clear: left;
|
||||
float: left;
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
img.align-right, .figure.align-right, object.align-right {
|
||||
clear: right;
|
||||
float: right;
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
img.align-center, .figure.align-center, object.align-center {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.align-left {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.align-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.align-right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* -- sidebars -------------------------------------------------------------- */
|
||||
|
||||
div.sidebar {
|
||||
margin: 0 0 0.5em 1em;
|
||||
border: 1px solid #ddb;
|
||||
padding: 7px 7px 0 7px;
|
||||
background-color: #ffe;
|
||||
width: 40%;
|
||||
float: right;
|
||||
}
|
||||
|
||||
p.sidebar-title {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* -- topics ---------------------------------------------------------------- */
|
||||
|
||||
div.topic {
|
||||
border: 1px solid #ccc;
|
||||
padding: 7px 7px 0 7px;
|
||||
margin: 10px 0 10px 0;
|
||||
}
|
||||
|
||||
p.topic-title {
|
||||
font-size: 1.1em;
|
||||
font-weight: bold;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
/* -- admonitions ----------------------------------------------------------- */
|
||||
|
||||
div.admonition {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
padding: 7px;
|
||||
}
|
||||
|
||||
div.admonition dt {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
div.admonition dl {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
p.admonition-title {
|
||||
margin: 0px 10px 5px 0px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
div.body p.centered {
|
||||
text-align: center;
|
||||
margin-top: 25px;
|
||||
}
|
||||
|
||||
/* -- tables ---------------------------------------------------------------- */
|
||||
|
||||
table.docutils {
|
||||
border: 0;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
table.docutils td, table.docutils th {
|
||||
padding: 1px 8px 1px 5px;
|
||||
border-top: 0;
|
||||
border-left: 0;
|
||||
border-right: 0;
|
||||
border-bottom: 1px solid #aaa;
|
||||
}
|
||||
|
||||
table.field-list td, table.field-list th {
|
||||
border: 0 !important;
|
||||
}
|
||||
|
||||
table.footnote td, table.footnote th {
|
||||
border: 0 !important;
|
||||
}
|
||||
|
||||
th {
|
||||
text-align: left;
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
table.citation {
|
||||
border-left: solid 1px gray;
|
||||
margin-left: 1px;
|
||||
}
|
||||
|
||||
table.citation td {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
/* -- other body styles ----------------------------------------------------- */
|
||||
|
||||
ol.arabic {
|
||||
list-style: decimal;
|
||||
}
|
||||
|
||||
ol.loweralpha {
|
||||
list-style: lower-alpha;
|
||||
}
|
||||
|
||||
ol.upperalpha {
|
||||
list-style: upper-alpha;
|
||||
}
|
||||
|
||||
ol.lowerroman {
|
||||
list-style: lower-roman;
|
||||
}
|
||||
|
||||
ol.upperroman {
|
||||
list-style: upper-roman;
|
||||
}
|
||||
|
||||
dl {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
dd p {
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
dd ul, dd table {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
dd {
|
||||
margin-top: 3px;
|
||||
margin-bottom: 10px;
|
||||
margin-left: 30px;
|
||||
}
|
||||
|
||||
dt:target, .highlighted {
|
||||
background-color: #fbe54e;
|
||||
}
|
||||
|
||||
dl.glossary dt {
|
||||
font-weight: bold;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
.field-list ul {
|
||||
margin: 0;
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
.field-list p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.optional {
|
||||
font-size: 1.3em;
|
||||
}
|
||||
|
||||
.versionmodified {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.system-message {
|
||||
background-color: #fda;
|
||||
padding: 5px;
|
||||
border: 3px solid red;
|
||||
}
|
||||
|
||||
.footnote:target {
|
||||
background-color: #ffa;
|
||||
}
|
||||
|
||||
.line-block {
|
||||
display: block;
|
||||
margin-top: 1em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.line-block .line-block {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
margin-left: 1.5em;
|
||||
}
|
||||
|
||||
.guilabel, .menuselection {
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
.accelerator {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.classifier {
|
||||
font-style: oblique;
|
||||
}
|
||||
|
||||
abbr, acronym {
|
||||
border-bottom: dotted 1px;
|
||||
cursor: help;
|
||||
}
|
||||
|
||||
/* -- code displays --------------------------------------------------------- */
|
||||
|
||||
pre {
|
||||
overflow: auto;
|
||||
overflow-y: hidden; /* fixes display issues on Chrome browsers */
|
||||
}
|
||||
|
||||
td.linenos pre {
|
||||
padding: 5px 0px;
|
||||
border: 0;
|
||||
background-color: transparent;
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
table.highlighttable {
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
|
||||
table.highlighttable td {
|
||||
padding: 0 0.5em 0 0.5em;
|
||||
}
|
||||
|
||||
tt.descname {
|
||||
background-color: transparent;
|
||||
font-weight: bold;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
tt.descclassname {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
tt.xref, a tt {
|
||||
background-color: transparent;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.viewcode-link {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.viewcode-back {
|
||||
float: right;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
div.viewcode-block:target {
|
||||
margin: -1px -10px;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
/* -- math display ---------------------------------------------------------- */
|
||||
|
||||
img.math {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
div.body div.math p {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
span.eqno {
|
||||
float: right;
|
||||
}
|
||||
|
||||
/* -- printout stylesheet --------------------------------------------------- */
|
||||
|
||||
@media print {
|
||||
div.document,
|
||||
div.documentwrapper,
|
||||
div.bodywrapper {
|
||||
margin: 0 !important;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
div.sphinxsidebar,
|
||||
div.related,
|
||||
div.footer,
|
||||
#top-link {
|
||||
display: none;
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 202 B |
@ -1,238 +0,0 @@
|
||||
/*
|
||||
* doctools.js
|
||||
* ~~~~~~~~~~~
|
||||
*
|
||||
* Sphinx JavaScript utilities for all documentation.
|
||||
*
|
||||
* :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
* :license: BSD, see LICENSE for details.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* select a different prefix for underscore
|
||||
*/
|
||||
$u = _.noConflict();
|
||||
|
||||
/**
|
||||
* make the code below compatible with browsers without
|
||||
* an installed firebug like debugger
|
||||
if (!window.console || !console.firebug) {
|
||||
var names = ["log", "debug", "info", "warn", "error", "assert", "dir",
|
||||
"dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace",
|
||||
"profile", "profileEnd"];
|
||||
window.console = {};
|
||||
for (var i = 0; i < names.length; ++i)
|
||||
window.console[names[i]] = function() {};
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* small helper function to urldecode strings
|
||||
*/
|
||||
jQuery.urldecode = function(x) {
|
||||
return decodeURIComponent(x).replace(/\+/g, ' ');
|
||||
};
|
||||
|
||||
/**
|
||||
* small helper function to urlencode strings
|
||||
*/
|
||||
jQuery.urlencode = encodeURIComponent;
|
||||
|
||||
/**
|
||||
* This function returns the parsed url parameters of the
|
||||
* current request. Multiple values per key are supported,
|
||||
* it will always return arrays of strings for the value parts.
|
||||
*/
|
||||
jQuery.getQueryParameters = function(s) {
|
||||
if (typeof s == 'undefined')
|
||||
s = document.location.search;
|
||||
var parts = s.substr(s.indexOf('?') + 1).split('&');
|
||||
var result = {};
|
||||
for (var i = 0; i < parts.length; i++) {
|
||||
var tmp = parts[i].split('=', 2);
|
||||
var key = jQuery.urldecode(tmp[0]);
|
||||
var value = jQuery.urldecode(tmp[1]);
|
||||
if (key in result)
|
||||
result[key].push(value);
|
||||
else
|
||||
result[key] = [value];
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* highlight a given string on a jquery object by wrapping it in
|
||||
* span elements with the given class name.
|
||||
*/
|
||||
jQuery.fn.highlightText = function(text, className) {
|
||||
function highlight(node) {
|
||||
if (node.nodeType == 3) {
|
||||
var val = node.nodeValue;
|
||||
var pos = val.toLowerCase().indexOf(text);
|
||||
if (pos >= 0 && !jQuery(node.parentNode).hasClass(className)) {
|
||||
var span = document.createElement("span");
|
||||
span.className = className;
|
||||
span.appendChild(document.createTextNode(val.substr(pos, text.length)));
|
||||
node.parentNode.insertBefore(span, node.parentNode.insertBefore(
|
||||
document.createTextNode(val.substr(pos + text.length)),
|
||||
node.nextSibling));
|
||||
node.nodeValue = val.substr(0, pos);
|
||||
}
|
||||
}
|
||||
else if (!jQuery(node).is("button, select, textarea")) {
|
||||
jQuery.each(node.childNodes, function() {
|
||||
highlight(this);
|
||||
});
|
||||
}
|
||||
}
|
||||
return this.each(function() {
|
||||
highlight(this);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Small JavaScript module for the documentation.
|
||||
*/
|
||||
var Documentation = {
|
||||
|
||||
init : function() {
|
||||
this.fixFirefoxAnchorBug();
|
||||
this.highlightSearchWords();
|
||||
this.initIndexTable();
|
||||
},
|
||||
|
||||
/**
|
||||
* i18n support
|
||||
*/
|
||||
TRANSLATIONS : {},
|
||||
PLURAL_EXPR : function(n) { return n == 1 ? 0 : 1; },
|
||||
LOCALE : 'unknown',
|
||||
|
||||
// gettext and ngettext don't access this so that the functions
|
||||
// can safely bound to a different name (_ = Documentation.gettext)
|
||||
gettext : function(string) {
|
||||
var translated = Documentation.TRANSLATIONS[string];
|
||||
if (typeof translated == 'undefined')
|
||||
return string;
|
||||
return (typeof translated == 'string') ? translated : translated[0];
|
||||
},
|
||||
|
||||
ngettext : function(singular, plural, n) {
|
||||
var translated = Documentation.TRANSLATIONS[singular];
|
||||
if (typeof translated == 'undefined')
|
||||
return (n == 1) ? singular : plural;
|
||||
return translated[Documentation.PLURALEXPR(n)];
|
||||
},
|
||||
|
||||
addTranslations : function(catalog) {
|
||||
for (var key in catalog.messages)
|
||||
this.TRANSLATIONS[key] = catalog.messages[key];
|
||||
this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')');
|
||||
this.LOCALE = catalog.locale;
|
||||
},
|
||||
|
||||
/**
|
||||
* add context elements like header anchor links
|
||||
*/
|
||||
addContextElements : function() {
|
||||
$('div[id] > :header:first').each(function() {
|
||||
$('<a class="headerlink">\u00B6</a>').
|
||||
attr('href', '#' + this.id).
|
||||
attr('title', _('Permalink to this headline')).
|
||||
appendTo(this);
|
||||
});
|
||||
$('dt[id]').each(function() {
|
||||
$('<a class="headerlink">\u00B6</a>').
|
||||
attr('href', '#' + this.id).
|
||||
attr('title', _('Permalink to this definition')).
|
||||
appendTo(this);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* workaround a firefox stupidity
|
||||
*/
|
||||
fixFirefoxAnchorBug : function() {
|
||||
if (document.location.hash && $.browser.mozilla)
|
||||
window.setTimeout(function() {
|
||||
document.location.href += '';
|
||||
}, 10);
|
||||
},
|
||||
|
||||
/**
|
||||
* highlight the search words provided in the url in the text
|
||||
*/
|
||||
highlightSearchWords : function() {
|
||||
var params = $.getQueryParameters();
|
||||
var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : [];
|
||||
if (terms.length) {
|
||||
var body = $('div.body');
|
||||
if (!body.length) {
|
||||
body = $('body');
|
||||
}
|
||||
window.setTimeout(function() {
|
||||
$.each(terms, function() {
|
||||
body.highlightText(this.toLowerCase(), 'highlighted');
|
||||
});
|
||||
}, 10);
|
||||
$('<p class="highlight-link"><a href="javascript:Documentation.' +
|
||||
'hideSearchWords()">' + _('Hide Search Matches') + '</a></p>')
|
||||
.appendTo($('#searchbox'));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* init the domain index toggle buttons
|
||||
*/
|
||||
initIndexTable : function() {
|
||||
var togglers = $('img.toggler').click(function() {
|
||||
var src = $(this).attr('src');
|
||||
var idnum = $(this).attr('id').substr(7);
|
||||
$('tr.cg-' + idnum).toggle();
|
||||
if (src.substr(-9) == 'minus.png')
|
||||
$(this).attr('src', src.substr(0, src.length-9) + 'plus.png');
|
||||
else
|
||||
$(this).attr('src', src.substr(0, src.length-8) + 'minus.png');
|
||||
}).css('display', '');
|
||||
if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) {
|
||||
togglers.click();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* helper function to hide the search marks again
|
||||
*/
|
||||
hideSearchWords : function() {
|
||||
$('#searchbox .highlight-link').fadeOut(300);
|
||||
$('span.highlighted').removeClass('highlighted');
|
||||
},
|
||||
|
||||
/**
|
||||
* make the url absolute
|
||||
*/
|
||||
makeURL : function(relativeURL) {
|
||||
return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL;
|
||||
},
|
||||
|
||||
/**
|
||||
* get the current relative url
|
||||
*/
|
||||
getCurrentURL : function() {
|
||||
var path = document.location.pathname;
|
||||
var parts = path.split(/\//);
|
||||
$.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() {
|
||||
if (this == '..')
|
||||
parts.pop();
|
||||
});
|
||||
var url = parts.join('/');
|
||||
return path.substring(url.lastIndexOf('/') + 1, path.length - 1);
|
||||
}
|
||||
};
|
||||
|
||||
// quick alias for translations
|
||||
_ = Documentation.gettext;
|
||||
|
||||
$(document).ready(function() {
|
||||
Documentation.init();
|
||||
});
|
Before Width: | Height: | Size: 368 B |
Before Width: | Height: | Size: 363 B |
Before Width: | Height: | Size: 392 B |
9404
server/documentation/_build/html/_static/jquery.js
vendored
Before Width: | Height: | Size: 199 B |
Before Width: | Height: | Size: 218 B |
Before Width: | Height: | Size: 199 B |
@ -1,62 +0,0 @@
|
||||
.highlight .hll { background-color: #ffffcc }
|
||||
.highlight { background: #eeffcc; }
|
||||
.highlight .c { color: #408090; font-style: italic } /* Comment */
|
||||
.highlight .err { border: 1px solid #FF0000 } /* Error */
|
||||
.highlight .k { color: #007020; font-weight: bold } /* Keyword */
|
||||
.highlight .o { color: #666666 } /* Operator */
|
||||
.highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */
|
||||
.highlight .cp { color: #007020 } /* Comment.Preproc */
|
||||
.highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */
|
||||
.highlight .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */
|
||||
.highlight .gd { color: #A00000 } /* Generic.Deleted */
|
||||
.highlight .ge { font-style: italic } /* Generic.Emph */
|
||||
.highlight .gr { color: #FF0000 } /* Generic.Error */
|
||||
.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
|
||||
.highlight .gi { color: #00A000 } /* Generic.Inserted */
|
||||
.highlight .go { color: #333333 } /* Generic.Output */
|
||||
.highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */
|
||||
.highlight .gs { font-weight: bold } /* Generic.Strong */
|
||||
.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
|
||||
.highlight .gt { color: #0044DD } /* Generic.Traceback */
|
||||
.highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */
|
||||
.highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */
|
||||
.highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */
|
||||
.highlight .kp { color: #007020 } /* Keyword.Pseudo */
|
||||
.highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */
|
||||
.highlight .kt { color: #902000 } /* Keyword.Type */
|
||||
.highlight .m { color: #208050 } /* Literal.Number */
|
||||
.highlight .s { color: #4070a0 } /* Literal.String */
|
||||
.highlight .na { color: #4070a0 } /* Name.Attribute */
|
||||
.highlight .nb { color: #007020 } /* Name.Builtin */
|
||||
.highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */
|
||||
.highlight .no { color: #60add5 } /* Name.Constant */
|
||||
.highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */
|
||||
.highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */
|
||||
.highlight .ne { color: #007020 } /* Name.Exception */
|
||||
.highlight .nf { color: #06287e } /* Name.Function */
|
||||
.highlight .nl { color: #002070; font-weight: bold } /* Name.Label */
|
||||
.highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */
|
||||
.highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */
|
||||
.highlight .nv { color: #bb60d5 } /* Name.Variable */
|
||||
.highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */
|
||||
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
|
||||
.highlight .mf { color: #208050 } /* Literal.Number.Float */
|
||||
.highlight .mh { color: #208050 } /* Literal.Number.Hex */
|
||||
.highlight .mi { color: #208050 } /* Literal.Number.Integer */
|
||||
.highlight .mo { color: #208050 } /* Literal.Number.Oct */
|
||||
.highlight .sb { color: #4070a0 } /* Literal.String.Backtick */
|
||||
.highlight .sc { color: #4070a0 } /* Literal.String.Char */
|
||||
.highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */
|
||||
.highlight .s2 { color: #4070a0 } /* Literal.String.Double */
|
||||
.highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */
|
||||
.highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */
|
||||
.highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */
|
||||
.highlight .sx { color: #c65d09 } /* Literal.String.Other */
|
||||
.highlight .sr { color: #235388 } /* Literal.String.Regex */
|
||||
.highlight .s1 { color: #4070a0 } /* Literal.String.Single */
|
||||
.highlight .ss { color: #517918 } /* Literal.String.Symbol */
|
||||
.highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */
|
||||
.highlight .vc { color: #bb60d5 } /* Name.Variable.Class */
|
||||
.highlight .vg { color: #bb60d5 } /* Name.Variable.Global */
|
||||
.highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */
|
||||
.highlight .il { color: #208050 } /* Literal.Number.Integer.Long */
|
@ -1,622 +0,0 @@
|
||||
/*
|
||||
* searchtools.js_t
|
||||
* ~~~~~~~~~~~~~~~~
|
||||
*
|
||||
* Sphinx JavaScript utilties for the full-text search.
|
||||
*
|
||||
* :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
* :license: BSD, see LICENSE for details.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Porter Stemmer
|
||||
*/
|
||||
var Stemmer = function() {
|
||||
|
||||
var step2list = {
|
||||
ational: 'ate',
|
||||
tional: 'tion',
|
||||
enci: 'ence',
|
||||
anci: 'ance',
|
||||
izer: 'ize',
|
||||
bli: 'ble',
|
||||
alli: 'al',
|
||||
entli: 'ent',
|
||||
eli: 'e',
|
||||
ousli: 'ous',
|
||||
ization: 'ize',
|
||||
ation: 'ate',
|
||||
ator: 'ate',
|
||||
alism: 'al',
|
||||
iveness: 'ive',
|
||||
fulness: 'ful',
|
||||
ousness: 'ous',
|
||||
aliti: 'al',
|
||||
iviti: 'ive',
|
||||
biliti: 'ble',
|
||||
logi: 'log'
|
||||
};
|
||||
|
||||
var step3list = {
|
||||
icate: 'ic',
|
||||
ative: '',
|
||||
alize: 'al',
|
||||
iciti: 'ic',
|
||||
ical: 'ic',
|
||||
ful: '',
|
||||
ness: ''
|
||||
};
|
||||
|
||||
var c = "[^aeiou]"; // consonant
|
||||
var v = "[aeiouy]"; // vowel
|
||||
var C = c + "[^aeiouy]*"; // consonant sequence
|
||||
var V = v + "[aeiou]*"; // vowel sequence
|
||||
|
||||
var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0
|
||||
var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1
|
||||
var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1
|
||||
var s_v = "^(" + C + ")?" + v; // vowel in stem
|
||||
|
||||
this.stemWord = function (w) {
|
||||
var stem;
|
||||
var suffix;
|
||||
var firstch;
|
||||
var origword = w;
|
||||
|
||||
if (w.length < 3)
|
||||
return w;
|
||||
|
||||
var re;
|
||||
var re2;
|
||||
var re3;
|
||||
var re4;
|
||||
|
||||
firstch = w.substr(0,1);
|
||||
if (firstch == "y")
|
||||
w = firstch.toUpperCase() + w.substr(1);
|
||||
|
||||
// Step 1a
|
||||
re = /^(.+?)(ss|i)es$/;
|
||||
re2 = /^(.+?)([^s])s$/;
|
||||
|
||||
if (re.test(w))
|
||||
w = w.replace(re,"$1$2");
|
||||
else if (re2.test(w))
|
||||
w = w.replace(re2,"$1$2");
|
||||
|
||||
// Step 1b
|
||||
re = /^(.+?)eed$/;
|
||||
re2 = /^(.+?)(ed|ing)$/;
|
||||
if (re.test(w)) {
|
||||
var fp = re.exec(w);
|
||||
re = new RegExp(mgr0);
|
||||
if (re.test(fp[1])) {
|
||||
re = /.$/;
|
||||
w = w.replace(re,"");
|
||||
}
|
||||
}
|
||||
else if (re2.test(w)) {
|
||||
var fp = re2.exec(w);
|
||||
stem = fp[1];
|
||||
re2 = new RegExp(s_v);
|
||||
if (re2.test(stem)) {
|
||||
w = stem;
|
||||
re2 = /(at|bl|iz)$/;
|
||||
re3 = new RegExp("([^aeiouylsz])\\1$");
|
||||
re4 = new RegExp("^" + C + v + "[^aeiouwxy]$");
|
||||
if (re2.test(w))
|
||||
w = w + "e";
|
||||
else if (re3.test(w)) {
|
||||
re = /.$/;
|
||||
w = w.replace(re,"");
|
||||
}
|
||||
else if (re4.test(w))
|
||||
w = w + "e";
|
||||
}
|
||||
}
|
||||
|
||||
// Step 1c
|
||||
re = /^(.+?)y$/;
|
||||
if (re.test(w)) {
|
||||
var fp = re.exec(w);
|
||||
stem = fp[1];
|
||||
re = new RegExp(s_v);
|
||||
if (re.test(stem))
|
||||
w = stem + "i";
|
||||
}
|
||||
|
||||
// Step 2
|
||||
re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/;
|
||||
if (re.test(w)) {
|
||||
var fp = re.exec(w);
|
||||
stem = fp[1];
|
||||
suffix = fp[2];
|
||||
re = new RegExp(mgr0);
|
||||
if (re.test(stem))
|
||||
w = stem + step2list[suffix];
|
||||
}
|
||||
|
||||
// Step 3
|
||||
re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/;
|
||||
if (re.test(w)) {
|
||||
var fp = re.exec(w);
|
||||
stem = fp[1];
|
||||
suffix = fp[2];
|
||||
re = new RegExp(mgr0);
|
||||
if (re.test(stem))
|
||||
w = stem + step3list[suffix];
|
||||
}
|
||||
|
||||
// Step 4
|
||||
re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/;
|
||||
re2 = /^(.+?)(s|t)(ion)$/;
|
||||
if (re.test(w)) {
|
||||
var fp = re.exec(w);
|
||||
stem = fp[1];
|
||||
re = new RegExp(mgr1);
|
||||
if (re.test(stem))
|
||||
w = stem;
|
||||
}
|
||||
else if (re2.test(w)) {
|
||||
var fp = re2.exec(w);
|
||||
stem = fp[1] + fp[2];
|
||||
re2 = new RegExp(mgr1);
|
||||
if (re2.test(stem))
|
||||
w = stem;
|
||||
}
|
||||
|
||||
// Step 5
|
||||
re = /^(.+?)e$/;
|
||||
if (re.test(w)) {
|
||||
var fp = re.exec(w);
|
||||
stem = fp[1];
|
||||
re = new RegExp(mgr1);
|
||||
re2 = new RegExp(meq1);
|
||||
re3 = new RegExp("^" + C + v + "[^aeiouwxy]$");
|
||||
if (re.test(stem) || (re2.test(stem) && !(re3.test(stem))))
|
||||
w = stem;
|
||||
}
|
||||
re = /ll$/;
|
||||
re2 = new RegExp(mgr1);
|
||||
if (re.test(w) && re2.test(w)) {
|
||||
re = /.$/;
|
||||
w = w.replace(re,"");
|
||||
}
|
||||
|
||||
// and turn initial Y back to y
|
||||
if (firstch == "y")
|
||||
w = firstch.toLowerCase() + w.substr(1);
|
||||
return w;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Simple result scoring code.
|
||||
*/
|
||||
var Scorer = {
|
||||
// Implement the following function to further tweak the score for each result
|
||||
// The function takes a result array [filename, title, anchor, descr, score]
|
||||
// and returns the new score.
|
||||
/*
|
||||
score: function(result) {
|
||||
return result[4];
|
||||
},
|
||||
*/
|
||||
|
||||
// query matches the full name of an object
|
||||
objNameMatch: 11,
|
||||
// or matches in the last dotted part of the object name
|
||||
objPartialMatch: 6,
|
||||
// Additive scores depending on the priority of the object
|
||||
objPrio: {0: 15, // used to be importantResults
|
||||
1: 5, // used to be objectResults
|
||||
2: -5}, // used to be unimportantResults
|
||||
// Used when the priority is not in the mapping.
|
||||
objPrioDefault: 0,
|
||||
|
||||
// query found in title
|
||||
title: 15,
|
||||
// query found in terms
|
||||
term: 5
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Search Module
|
||||
*/
|
||||
var Search = {
|
||||
|
||||
_index : null,
|
||||
_queued_query : null,
|
||||
_pulse_status : -1,
|
||||
|
||||
init : function() {
|
||||
var params = $.getQueryParameters();
|
||||
if (params.q) {
|
||||
var query = params.q[0];
|
||||
$('input[name="q"]')[0].value = query;
|
||||
this.performSearch(query);
|
||||
}
|
||||
},
|
||||
|
||||
loadIndex : function(url) {
|
||||
$.ajax({type: "GET", url: url, data: null,
|
||||
dataType: "script", cache: true,
|
||||
complete: function(jqxhr, textstatus) {
|
||||
if (textstatus != "success") {
|
||||
document.getElementById("searchindexloader").src = url;
|
||||
}
|
||||
}});
|
||||
},
|
||||
|
||||
setIndex : function(index) {
|
||||
var q;
|
||||
this._index = index;
|
||||
if ((q = this._queued_query) !== null) {
|
||||
this._queued_query = null;
|
||||
Search.query(q);
|
||||
}
|
||||
},
|
||||
|
||||
hasIndex : function() {
|
||||
return this._index !== null;
|
||||
},
|
||||
|
||||
deferQuery : function(query) {
|
||||
this._queued_query = query;
|
||||
},
|
||||
|
||||
stopPulse : function() {
|
||||
this._pulse_status = 0;
|
||||
},
|
||||
|
||||
startPulse : function() {
|
||||
if (this._pulse_status >= 0)
|
||||
return;
|
||||
function pulse() {
|
||||
var i;
|
||||
Search._pulse_status = (Search._pulse_status + 1) % 4;
|
||||
var dotString = '';
|
||||
for (i = 0; i < Search._pulse_status; i++)
|
||||
dotString += '.';
|
||||
Search.dots.text(dotString);
|
||||
if (Search._pulse_status > -1)
|
||||
window.setTimeout(pulse, 500);
|
||||
}
|
||||
pulse();
|
||||
},
|
||||
|
||||
/**
|
||||
* perform a search for something (or wait until index is loaded)
|
||||
*/
|
||||
performSearch : function(query) {
|
||||
// create the required interface elements
|
||||
this.out = $('#search-results');
|
||||
this.title = $('<h2>' + _('Searching') + '</h2>').appendTo(this.out);
|
||||
this.dots = $('<span></span>').appendTo(this.title);
|
||||
this.status = $('<p style="display: none"></p>').appendTo(this.out);
|
||||
this.output = $('<ul class="search"/>').appendTo(this.out);
|
||||
|
||||
$('#search-progress').text(_('Preparing search...'));
|
||||
this.startPulse();
|
||||
|
||||
// index already loaded, the browser was quick!
|
||||
if (this.hasIndex())
|
||||
this.query(query);
|
||||
else
|
||||
this.deferQuery(query);
|
||||
},
|
||||
|
||||
/**
|
||||
* execute search (requires search index to be loaded)
|
||||
*/
|
||||
query : function(query) {
|
||||
var i;
|
||||
var stopwords = ["a","and","are","as","at","be","but","by","for","if","in","into","is","it","near","no","not","of","on","or","such","that","the","their","then","there","these","they","this","to","was","will","with"];
|
||||
|
||||
// stem the searchterms and add them to the correct list
|
||||
var stemmer = new Stemmer();
|
||||
var searchterms = [];
|
||||
var excluded = [];
|
||||
var hlterms = [];
|
||||
var tmp = query.split(/\s+/);
|
||||
var objectterms = [];
|
||||
for (i = 0; i < tmp.length; i++) {
|
||||
if (tmp[i] !== "") {
|
||||
objectterms.push(tmp[i].toLowerCase());
|
||||
}
|
||||
|
||||
if ($u.indexOf(stopwords, tmp[i].toLowerCase()) != -1 || tmp[i].match(/^\d+$/) ||
|
||||
tmp[i] === "") {
|
||||
// skip this "word"
|
||||
continue;
|
||||
}
|
||||
// stem the word
|
||||
var word = stemmer.stemWord(tmp[i].toLowerCase());
|
||||
var toAppend;
|
||||
// select the correct list
|
||||
if (word[0] == '-') {
|
||||
toAppend = excluded;
|
||||
word = word.substr(1);
|
||||
}
|
||||
else {
|
||||
toAppend = searchterms;
|
||||
hlterms.push(tmp[i].toLowerCase());
|
||||
}
|
||||
// only add if not already in the list
|
||||
if (!$u.contains(toAppend, word))
|
||||
toAppend.push(word);
|
||||
}
|
||||
var highlightstring = '?highlight=' + $.urlencode(hlterms.join(" "));
|
||||
|
||||
// console.debug('SEARCH: searching for:');
|
||||
// console.info('required: ', searchterms);
|
||||
// console.info('excluded: ', excluded);
|
||||
|
||||
// prepare search
|
||||
var terms = this._index.terms;
|
||||
var titleterms = this._index.titleterms;
|
||||
|
||||
// array of [filename, title, anchor, descr, score]
|
||||
var results = [];
|
||||
$('#search-progress').empty();
|
||||
|
||||
// lookup as object
|
||||
for (i = 0; i < objectterms.length; i++) {
|
||||
var others = [].concat(objectterms.slice(0, i),
|
||||
objectterms.slice(i+1, objectterms.length));
|
||||
results = results.concat(this.performObjectSearch(objectterms[i], others));
|
||||
}
|
||||
|
||||
// lookup as search terms in fulltext
|
||||
results = results.concat(this.performTermsSearch(searchterms, excluded, terms, Scorer.term))
|
||||
.concat(this.performTermsSearch(searchterms, excluded, titleterms, Scorer.title));
|
||||
|
||||
// let the scorer override scores with a custom scoring function
|
||||
if (Scorer.score) {
|
||||
for (i = 0; i < results.length; i++)
|
||||
results[i][4] = Scorer.score(results[i]);
|
||||
}
|
||||
|
||||
// now sort the results by score (in opposite order of appearance, since the
|
||||
// display function below uses pop() to retrieve items) and then
|
||||
// alphabetically
|
||||
results.sort(function(a, b) {
|
||||
var left = a[4];
|
||||
var right = b[4];
|
||||
if (left > right) {
|
||||
return 1;
|
||||
} else if (left < right) {
|
||||
return -1;
|
||||
} else {
|
||||
// same score: sort alphabetically
|
||||
left = a[1].toLowerCase();
|
||||
right = b[1].toLowerCase();
|
||||
return (left > right) ? -1 : ((left < right) ? 1 : 0);
|
||||
}
|
||||
});
|
||||
|
||||
// for debugging
|
||||
//Search.lastresults = results.slice(); // a copy
|
||||
//console.info('search results:', Search.lastresults);
|
||||
|
||||
// print the results
|
||||
var resultCount = results.length;
|
||||
function displayNextItem() {
|
||||
// results left, load the summary and display it
|
||||
if (results.length) {
|
||||
var item = results.pop();
|
||||
var listItem = $('<li style="display:none"></li>');
|
||||
if (DOCUMENTATION_OPTIONS.FILE_SUFFIX === '') {
|
||||
// dirhtml builder
|
||||
var dirname = item[0] + '/';
|
||||
if (dirname.match(/\/index\/$/)) {
|
||||
dirname = dirname.substring(0, dirname.length-6);
|
||||
} else if (dirname == 'index/') {
|
||||
dirname = '';
|
||||
}
|
||||
listItem.append($('<a/>').attr('href',
|
||||
DOCUMENTATION_OPTIONS.URL_ROOT + dirname +
|
||||
highlightstring + item[2]).html(item[1]));
|
||||
} else {
|
||||
// normal html builders
|
||||
listItem.append($('<a/>').attr('href',
|
||||
item[0] + DOCUMENTATION_OPTIONS.FILE_SUFFIX +
|
||||
highlightstring + item[2]).html(item[1]));
|
||||
}
|
||||
if (item[3]) {
|
||||
listItem.append($('<span> (' + item[3] + ')</span>'));
|
||||
Search.output.append(listItem);
|
||||
listItem.slideDown(5, function() {
|
||||
displayNextItem();
|
||||
});
|
||||
} else if (DOCUMENTATION_OPTIONS.HAS_SOURCE) {
|
||||
$.ajax({url: DOCUMENTATION_OPTIONS.URL_ROOT + '_sources/' + item[0] + '.txt',
|
||||
dataType: "text",
|
||||
complete: function(jqxhr, textstatus) {
|
||||
var data = jqxhr.responseText;
|
||||
if (data !== '') {
|
||||
listItem.append(Search.makeSearchSummary(data, searchterms, hlterms));
|
||||
}
|
||||
Search.output.append(listItem);
|
||||
listItem.slideDown(5, function() {
|
||||
displayNextItem();
|
||||
});
|
||||
}});
|
||||
} else {
|
||||
// no source available, just display title
|
||||
Search.output.append(listItem);
|
||||
listItem.slideDown(5, function() {
|
||||
displayNextItem();
|
||||
});
|
||||
}
|
||||
}
|
||||
// search finished, update title and status message
|
||||
else {
|
||||
Search.stopPulse();
|
||||
Search.title.text(_('Search Results'));
|
||||
if (!resultCount)
|
||||
Search.status.text(_('Your search did not match any documents. Please make sure that all words are spelled correctly and that you\'ve selected enough categories.'));
|
||||
else
|
||||
Search.status.text(_('Search finished, found %s page(s) matching the search query.').replace('%s', resultCount));
|
||||
Search.status.fadeIn(500);
|
||||
}
|
||||
}
|
||||
displayNextItem();
|
||||
},
|
||||
|
||||
/**
|
||||
* search for object names
|
||||
*/
|
||||
performObjectSearch : function(object, otherterms) {
|
||||
var filenames = this._index.filenames;
|
||||
var objects = this._index.objects;
|
||||
var objnames = this._index.objnames;
|
||||
var titles = this._index.titles;
|
||||
|
||||
var i;
|
||||
var results = [];
|
||||
|
||||
for (var prefix in objects) {
|
||||
for (var name in objects[prefix]) {
|
||||
var fullname = (prefix ? prefix + '.' : '') + name;
|
||||
if (fullname.toLowerCase().indexOf(object) > -1) {
|
||||
var score = 0;
|
||||
var parts = fullname.split('.');
|
||||
// check for different match types: exact matches of full name or
|
||||
// "last name" (i.e. last dotted part)
|
||||
if (fullname == object || parts[parts.length - 1] == object) {
|
||||
score += Scorer.objNameMatch;
|
||||
// matches in last name
|
||||
} else if (parts[parts.length - 1].indexOf(object) > -1) {
|
||||
score += Scorer.objPartialMatch;
|
||||
}
|
||||
var match = objects[prefix][name];
|
||||
var objname = objnames[match[1]][2];
|
||||
var title = titles[match[0]];
|
||||
// If more than one term searched for, we require other words to be
|
||||
// found in the name/title/description
|
||||
if (otherterms.length > 0) {
|
||||
var haystack = (prefix + ' ' + name + ' ' +
|
||||
objname + ' ' + title).toLowerCase();
|
||||
var allfound = true;
|
||||
for (i = 0; i < otherterms.length; i++) {
|
||||
if (haystack.indexOf(otherterms[i]) == -1) {
|
||||
allfound = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!allfound) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
var descr = objname + _(', in ') + title;
|
||||
|
||||
var anchor = match[3];
|
||||
if (anchor === '')
|
||||
anchor = fullname;
|
||||
else if (anchor == '-')
|
||||
anchor = objnames[match[1]][1] + '-' + fullname;
|
||||
// add custom score for some objects according to scorer
|
||||
if (Scorer.objPrio.hasOwnProperty(match[2])) {
|
||||
score += Scorer.objPrio[match[2]];
|
||||
} else {
|
||||
score += Scorer.objPrioDefault;
|
||||
}
|
||||
results.push([filenames[match[0]], fullname, '#'+anchor, descr, score]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
},
|
||||
|
||||
/**
|
||||
* search for full-text terms in the index
|
||||
*/
|
||||
performTermsSearch : function(searchterms, excluded, terms, score) {
|
||||
var filenames = this._index.filenames;
|
||||
var titles = this._index.titles;
|
||||
|
||||
var i, j, file, files;
|
||||
var fileMap = {};
|
||||
var results = [];
|
||||
|
||||
// perform the search on the required terms
|
||||
for (i = 0; i < searchterms.length; i++) {
|
||||
var word = searchterms[i];
|
||||
// no match but word was a required one
|
||||
if ((files = terms[word]) === undefined)
|
||||
break;
|
||||
if (files.length === undefined) {
|
||||
files = [files];
|
||||
}
|
||||
// create the mapping
|
||||
for (j = 0; j < files.length; j++) {
|
||||
file = files[j];
|
||||
if (file in fileMap)
|
||||
fileMap[file].push(word);
|
||||
else
|
||||
fileMap[file] = [word];
|
||||
}
|
||||
}
|
||||
|
||||
// now check if the files don't contain excluded terms
|
||||
for (file in fileMap) {
|
||||
var valid = true;
|
||||
|
||||
// check if all requirements are matched
|
||||
if (fileMap[file].length != searchterms.length)
|
||||
continue;
|
||||
|
||||
// ensure that none of the excluded terms is in the search result
|
||||
for (i = 0; i < excluded.length; i++) {
|
||||
if (terms[excluded[i]] == file ||
|
||||
$u.contains(terms[excluded[i]] || [], file)) {
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if we have still a valid result we can add it to the result list
|
||||
if (valid) {
|
||||
results.push([filenames[file], titles[file], '', null, score]);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
},
|
||||
|
||||
/**
|
||||
* helper function to return a node containing the
|
||||
* search summary for a given text. keywords is a list
|
||||
* of stemmed words, hlwords is the list of normal, unstemmed
|
||||
* words. the first one is used to find the occurance, the
|
||||
* latter for highlighting it.
|
||||
*/
|
||||
makeSearchSummary : function(text, keywords, hlwords) {
|
||||
var textLower = text.toLowerCase();
|
||||
var start = 0;
|
||||
$.each(keywords, function() {
|
||||
var i = textLower.indexOf(this.toLowerCase());
|
||||
if (i > -1)
|
||||
start = i;
|
||||
});
|
||||
start = Math.max(start - 120, 0);
|
||||
var excerpt = ((start > 0) ? '...' : '') +
|
||||
$.trim(text.substr(start, 240)) +
|
||||
((start + 240 - text.length) ? '...' : '');
|
||||
var rv = $('<div class="context"></div>').text(excerpt);
|
||||
$.each(hlwords, function() {
|
||||
rv = rv.highlightText(this, 'highlighted');
|
||||
});
|
||||
return rv;
|
||||
}
|
||||
};
|
||||
|
||||
$(document).ready(function() {
|
||||
Search.init();
|
||||
});
|
@ -1,339 +0,0 @@
|
||||
/*
|
||||
* sphinxdoc.css_t
|
||||
* ~~~~~~~~~~~~~~~
|
||||
*
|
||||
* Sphinx stylesheet -- sphinxdoc theme. Originally created by
|
||||
* Armin Ronacher for Werkzeug.
|
||||
*
|
||||
* :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
* :license: BSD, see LICENSE for details.
|
||||
*
|
||||
*/
|
||||
|
||||
@import url("basic.css");
|
||||
|
||||
/* -- page layout ----------------------------------------------------------- */
|
||||
|
||||
body {
|
||||
font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva',
|
||||
'Verdana', sans-serif;
|
||||
font-size: 14px;
|
||||
letter-spacing: -0.01em;
|
||||
line-height: 150%;
|
||||
text-align: center;
|
||||
background-color: #BFD1D4;
|
||||
color: black;
|
||||
padding: 0;
|
||||
border: 1px solid #aaa;
|
||||
|
||||
margin: 0px 80px 0px 80px;
|
||||
min-width: 740px;
|
||||
}
|
||||
|
||||
div.document {
|
||||
background-color: white;
|
||||
text-align: left;
|
||||
background-image: url(contents.png);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
|
||||
div.bodywrapper {
|
||||
margin: 0 240px 0 0;
|
||||
border-right: 1px solid #ccc;
|
||||
}
|
||||
|
||||
div.body {
|
||||
margin: 0;
|
||||
padding: 0.5em 20px 20px 20px;
|
||||
}
|
||||
|
||||
div.related {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
div.related ul {
|
||||
background-image: url(navigation.png);
|
||||
height: 2em;
|
||||
border-top: 1px solid #ddd;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
div.related ul li {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 2em;
|
||||
float: left;
|
||||
}
|
||||
|
||||
div.related ul li.right {
|
||||
float: right;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
div.related ul li a {
|
||||
margin: 0;
|
||||
padding: 0 5px 0 5px;
|
||||
line-height: 1.75em;
|
||||
color: #EE9816;
|
||||
}
|
||||
|
||||
div.related ul li a:hover {
|
||||
color: #3CA8E7;
|
||||
}
|
||||
|
||||
div.sphinxsidebarwrapper {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
div.sphinxsidebar {
|
||||
margin: 0;
|
||||
padding: 0.5em 15px 15px 0;
|
||||
width: 210px;
|
||||
float: right;
|
||||
font-size: 1em;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
div.sphinxsidebar h3, div.sphinxsidebar h4 {
|
||||
margin: 1em 0 0.5em 0;
|
||||
font-size: 1em;
|
||||
padding: 0.1em 0 0.1em 0.5em;
|
||||
color: white;
|
||||
border: 1px solid #86989B;
|
||||
background-color: #AFC1C4;
|
||||
}
|
||||
|
||||
div.sphinxsidebar h3 a {
|
||||
color: white;
|
||||
}
|
||||
|
||||
div.sphinxsidebar ul {
|
||||
padding-left: 1.5em;
|
||||
margin-top: 7px;
|
||||
padding: 0;
|
||||
line-height: 130%;
|
||||
}
|
||||
|
||||
div.sphinxsidebar ul ul {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
div.footer {
|
||||
background-color: #E3EFF1;
|
||||
color: #86989B;
|
||||
padding: 3px 8px 3px 0;
|
||||
clear: both;
|
||||
font-size: 0.8em;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
div.footer a {
|
||||
color: #86989B;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* -- body styles ----------------------------------------------------------- */
|
||||
|
||||
p {
|
||||
margin: 0.8em 0 0.5em 0;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #CA7900;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #2491CF;
|
||||
}
|
||||
|
||||
div.body a {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin: 0;
|
||||
padding: 0.7em 0 0.3em 0;
|
||||
font-size: 1.5em;
|
||||
color: #11557C;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin: 1.3em 0 0.2em 0;
|
||||
font-size: 1.35em;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin: 1em 0 -0.3em 0;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
div.body h1 a, div.body h2 a, div.body h3 a, div.body h4 a, div.body h5 a, div.body h6 a {
|
||||
color: black!important;
|
||||
}
|
||||
|
||||
h1 a.anchor, h2 a.anchor, h3 a.anchor, h4 a.anchor, h5 a.anchor, h6 a.anchor {
|
||||
display: none;
|
||||
margin: 0 0 0 0.3em;
|
||||
padding: 0 0.2em 0 0.2em;
|
||||
color: #aaa!important;
|
||||
}
|
||||
|
||||
h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor,
|
||||
h5:hover a.anchor, h6:hover a.anchor {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
h1 a.anchor:hover, h2 a.anchor:hover, h3 a.anchor:hover, h4 a.anchor:hover,
|
||||
h5 a.anchor:hover, h6 a.anchor:hover {
|
||||
color: #777;
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
a.headerlink {
|
||||
color: #c60f0f!important;
|
||||
font-size: 1em;
|
||||
margin-left: 6px;
|
||||
padding: 0 4px 0 4px;
|
||||
text-decoration: none!important;
|
||||
}
|
||||
|
||||
a.headerlink:hover {
|
||||
background-color: #ccc;
|
||||
color: white!important;
|
||||
}
|
||||
|
||||
cite, code, tt {
|
||||
font-family: 'Consolas', 'Deja Vu Sans Mono',
|
||||
'Bitstream Vera Sans Mono', monospace;
|
||||
font-size: 0.95em;
|
||||
letter-spacing: 0.01em;
|
||||
}
|
||||
|
||||
tt {
|
||||
background-color: #f2f2f2;
|
||||
border-bottom: 1px solid #ddd;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
tt.descname, tt.descclassname, tt.xref {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: 1px solid #abc;
|
||||
margin: 2em;
|
||||
}
|
||||
|
||||
a tt {
|
||||
border: 0;
|
||||
color: #CA7900;
|
||||
}
|
||||
|
||||
a tt:hover {
|
||||
color: #2491CF;
|
||||
}
|
||||
|
||||
pre {
|
||||
font-family: 'Consolas', 'Deja Vu Sans Mono',
|
||||
'Bitstream Vera Sans Mono', monospace;
|
||||
font-size: 0.95em;
|
||||
letter-spacing: 0.015em;
|
||||
line-height: 120%;
|
||||
padding: 0.5em;
|
||||
border: 1px solid #ccc;
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
|
||||
pre a {
|
||||
color: inherit;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
td.linenos pre {
|
||||
padding: 0.5em 0;
|
||||
}
|
||||
|
||||
div.quotebar {
|
||||
background-color: #f8f8f8;
|
||||
max-width: 250px;
|
||||
float: right;
|
||||
padding: 2px 7px;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
|
||||
div.topic {
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
margin: 0 -0.5em 0 -0.5em;
|
||||
}
|
||||
|
||||
table td, table th {
|
||||
padding: 0.2em 0.5em 0.2em 0.5em;
|
||||
}
|
||||
|
||||
div.admonition, div.warning {
|
||||
font-size: 0.9em;
|
||||
margin: 1em 0 1em 0;
|
||||
border: 1px solid #86989B;
|
||||
background-color: #f7f7f7;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
div.admonition p, div.warning p {
|
||||
margin: 0.5em 1em 0.5em 1em;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
div.admonition pre, div.warning pre {
|
||||
margin: 0.4em 1em 0.4em 1em;
|
||||
}
|
||||
|
||||
div.admonition p.admonition-title,
|
||||
div.warning p.admonition-title {
|
||||
margin: 0;
|
||||
padding: 0.1em 0 0.1em 0.5em;
|
||||
color: white;
|
||||
border-bottom: 1px solid #86989B;
|
||||
font-weight: bold;
|
||||
background-color: #AFC1C4;
|
||||
}
|
||||
|
||||
div.warning {
|
||||
border: 1px solid #940000;
|
||||
}
|
||||
|
||||
div.warning p.admonition-title {
|
||||
background-color: #CF0000;
|
||||
border-bottom-color: #940000;
|
||||
}
|
||||
|
||||
div.admonition ul, div.admonition ol,
|
||||
div.warning ul, div.warning ol {
|
||||
margin: 0.1em 0.5em 0.5em 3em;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
div.versioninfo {
|
||||
margin: 1em 0 0 0;
|
||||
border: 1px solid #ccc;
|
||||
background-color: #DDEAF0;
|
||||
padding: 8px;
|
||||
line-height: 1.3em;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.viewcode-back {
|
||||
font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva',
|
||||
'Verdana', sans-serif;
|
||||
}
|
||||
|
||||
div.viewcode-block:target {
|
||||
background-color: #f4debf;
|
||||
border-top: 1px solid #ac9;
|
||||
border-bottom: 1px solid #ac9;
|
||||
}
|
Before Width: | Height: | Size: 372 B |
Before Width: | Height: | Size: 363 B |
@ -1,808 +0,0 @@
|
||||
/*
|
||||
* websupport.js
|
||||
* ~~~~~~~~~~~~~
|
||||
*
|
||||
* sphinx.websupport utilties for all documentation.
|
||||
*
|
||||
* :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
* :license: BSD, see LICENSE for details.
|
||||
*
|
||||
*/
|
||||
|
||||
(function($) {
|
||||
$.fn.autogrow = function() {
|
||||
return this.each(function() {
|
||||
var textarea = this;
|
||||
|
||||
$.fn.autogrow.resize(textarea);
|
||||
|
||||
$(textarea)
|
||||
.focus(function() {
|
||||
textarea.interval = setInterval(function() {
|
||||
$.fn.autogrow.resize(textarea);
|
||||
}, 500);
|
||||
})
|
||||
.blur(function() {
|
||||
clearInterval(textarea.interval);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
$.fn.autogrow.resize = function(textarea) {
|
||||
var lineHeight = parseInt($(textarea).css('line-height'), 10);
|
||||
var lines = textarea.value.split('\n');
|
||||
var columns = textarea.cols;
|
||||
var lineCount = 0;
|
||||
$.each(lines, function() {
|
||||
lineCount += Math.ceil(this.length / columns) || 1;
|
||||
});
|
||||
var height = lineHeight * (lineCount + 1);
|
||||
$(textarea).css('height', height);
|
||||
};
|
||||
})(jQuery);
|
||||
|
||||
(function($) {
|
||||
var comp, by;
|
||||
|
||||
function init() {
|
||||
initEvents();
|
||||
initComparator();
|
||||
}
|
||||
|
||||
function initEvents() {
|
||||
$('a.comment-close').live("click", function(event) {
|
||||
event.preventDefault();
|
||||
hide($(this).attr('id').substring(2));
|
||||
});
|
||||
$('a.vote').live("click", function(event) {
|
||||
event.preventDefault();
|
||||
handleVote($(this));
|
||||
});
|
||||
$('a.reply').live("click", function(event) {
|
||||
event.preventDefault();
|
||||
openReply($(this).attr('id').substring(2));
|
||||
});
|
||||
$('a.close-reply').live("click", function(event) {
|
||||
event.preventDefault();
|
||||
closeReply($(this).attr('id').substring(2));
|
||||
});
|
||||
$('a.sort-option').live("click", function(event) {
|
||||
event.preventDefault();
|
||||
handleReSort($(this));
|
||||
});
|
||||
$('a.show-proposal').live("click", function(event) {
|
||||
event.preventDefault();
|
||||
showProposal($(this).attr('id').substring(2));
|
||||
});
|
||||
$('a.hide-proposal').live("click", function(event) {
|
||||
event.preventDefault();
|
||||
hideProposal($(this).attr('id').substring(2));
|
||||
});
|
||||
$('a.show-propose-change').live("click", function(event) {
|
||||
event.preventDefault();
|
||||
showProposeChange($(this).attr('id').substring(2));
|
||||
});
|
||||
$('a.hide-propose-change').live("click", function(event) {
|
||||
event.preventDefault();
|
||||
hideProposeChange($(this).attr('id').substring(2));
|
||||
});
|
||||
$('a.accept-comment').live("click", function(event) {
|
||||
event.preventDefault();
|
||||
acceptComment($(this).attr('id').substring(2));
|
||||
});
|
||||
$('a.delete-comment').live("click", function(event) {
|
||||
event.preventDefault();
|
||||
deleteComment($(this).attr('id').substring(2));
|
||||
});
|
||||
$('a.comment-markup').live("click", function(event) {
|
||||
event.preventDefault();
|
||||
toggleCommentMarkupBox($(this).attr('id').substring(2));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Set comp, which is a comparator function used for sorting and
|
||||
* inserting comments into the list.
|
||||
*/
|
||||
function setComparator() {
|
||||
// If the first three letters are "asc", sort in ascending order
|
||||
// and remove the prefix.
|
||||
if (by.substring(0,3) == 'asc') {
|
||||
var i = by.substring(3);
|
||||
comp = function(a, b) { return a[i] - b[i]; };
|
||||
} else {
|
||||
// Otherwise sort in descending order.
|
||||
comp = function(a, b) { return b[by] - a[by]; };
|
||||
}
|
||||
|
||||
// Reset link styles and format the selected sort option.
|
||||
$('a.sel').attr('href', '#').removeClass('sel');
|
||||
$('a.by' + by).removeAttr('href').addClass('sel');
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a comp function. If the user has preferences stored in
|
||||
* the sortBy cookie, use those, otherwise use the default.
|
||||
*/
|
||||
function initComparator() {
|
||||
by = 'rating'; // Default to sort by rating.
|
||||
// If the sortBy cookie is set, use that instead.
|
||||
if (document.cookie.length > 0) {
|
||||
var start = document.cookie.indexOf('sortBy=');
|
||||
if (start != -1) {
|
||||
start = start + 7;
|
||||
var end = document.cookie.indexOf(";", start);
|
||||
if (end == -1) {
|
||||
end = document.cookie.length;
|
||||
by = unescape(document.cookie.substring(start, end));
|
||||
}
|
||||
}
|
||||
}
|
||||
setComparator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a comment div.
|
||||
*/
|
||||
function show(id) {
|
||||
$('#ao' + id).hide();
|
||||
$('#ah' + id).show();
|
||||
var context = $.extend({id: id}, opts);
|
||||
var popup = $(renderTemplate(popupTemplate, context)).hide();
|
||||
popup.find('textarea[name="proposal"]').hide();
|
||||
popup.find('a.by' + by).addClass('sel');
|
||||
var form = popup.find('#cf' + id);
|
||||
form.submit(function(event) {
|
||||
event.preventDefault();
|
||||
addComment(form);
|
||||
});
|
||||
$('#s' + id).after(popup);
|
||||
popup.slideDown('fast', function() {
|
||||
getComments(id);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide a comment div.
|
||||
*/
|
||||
function hide(id) {
|
||||
$('#ah' + id).hide();
|
||||
$('#ao' + id).show();
|
||||
var div = $('#sc' + id);
|
||||
div.slideUp('fast', function() {
|
||||
div.remove();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform an ajax request to get comments for a node
|
||||
* and insert the comments into the comments tree.
|
||||
*/
|
||||
function getComments(id) {
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
url: opts.getCommentsURL,
|
||||
data: {node: id},
|
||||
success: function(data, textStatus, request) {
|
||||
var ul = $('#cl' + id);
|
||||
var speed = 100;
|
||||
$('#cf' + id)
|
||||
.find('textarea[name="proposal"]')
|
||||
.data('source', data.source);
|
||||
|
||||
if (data.comments.length === 0) {
|
||||
ul.html('<li>No comments yet.</li>');
|
||||
ul.data('empty', true);
|
||||
} else {
|
||||
// If there are comments, sort them and put them in the list.
|
||||
var comments = sortComments(data.comments);
|
||||
speed = data.comments.length * 100;
|
||||
appendComments(comments, ul);
|
||||
ul.data('empty', false);
|
||||
}
|
||||
$('#cn' + id).slideUp(speed + 200);
|
||||
ul.slideDown(speed);
|
||||
},
|
||||
error: function(request, textStatus, error) {
|
||||
showError('Oops, there was a problem retrieving the comments.');
|
||||
},
|
||||
dataType: 'json'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a comment via ajax and insert the comment into the comment tree.
|
||||
*/
|
||||
function addComment(form) {
|
||||
var node_id = form.find('input[name="node"]').val();
|
||||
var parent_id = form.find('input[name="parent"]').val();
|
||||
var text = form.find('textarea[name="comment"]').val();
|
||||
var proposal = form.find('textarea[name="proposal"]').val();
|
||||
|
||||
if (text == '') {
|
||||
showError('Please enter a comment.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Disable the form that is being submitted.
|
||||
form.find('textarea,input').attr('disabled', 'disabled');
|
||||
|
||||
// Send the comment to the server.
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: opts.addCommentURL,
|
||||
dataType: 'json',
|
||||
data: {
|
||||
node: node_id,
|
||||
parent: parent_id,
|
||||
text: text,
|
||||
proposal: proposal
|
||||
},
|
||||
success: function(data, textStatus, error) {
|
||||
// Reset the form.
|
||||
if (node_id) {
|
||||
hideProposeChange(node_id);
|
||||
}
|
||||
form.find('textarea')
|
||||
.val('')
|
||||
.add(form.find('input'))
|
||||
.removeAttr('disabled');
|
||||
var ul = $('#cl' + (node_id || parent_id));
|
||||
if (ul.data('empty')) {
|
||||
$(ul).empty();
|
||||
ul.data('empty', false);
|
||||
}
|
||||
insertComment(data.comment);
|
||||
var ao = $('#ao' + node_id);
|
||||
ao.find('img').attr({'src': opts.commentBrightImage});
|
||||
if (node_id) {
|
||||
// if this was a "root" comment, remove the commenting box
|
||||
// (the user can get it back by reopening the comment popup)
|
||||
$('#ca' + node_id).slideUp();
|
||||
}
|
||||
},
|
||||
error: function(request, textStatus, error) {
|
||||
form.find('textarea,input').removeAttr('disabled');
|
||||
showError('Oops, there was a problem adding the comment.');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively append comments to the main comment list and children
|
||||
* lists, creating the comment tree.
|
||||
*/
|
||||
function appendComments(comments, ul) {
|
||||
$.each(comments, function() {
|
||||
var div = createCommentDiv(this);
|
||||
ul.append($(document.createElement('li')).html(div));
|
||||
appendComments(this.children, div.find('ul.comment-children'));
|
||||
// To avoid stagnating data, don't store the comments children in data.
|
||||
this.children = null;
|
||||
div.data('comment', this);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* After adding a new comment, it must be inserted in the correct
|
||||
* location in the comment tree.
|
||||
*/
|
||||
function insertComment(comment) {
|
||||
var div = createCommentDiv(comment);
|
||||
|
||||
// To avoid stagnating data, don't store the comments children in data.
|
||||
comment.children = null;
|
||||
div.data('comment', comment);
|
||||
|
||||
var ul = $('#cl' + (comment.node || comment.parent));
|
||||
var siblings = getChildren(ul);
|
||||
|
||||
var li = $(document.createElement('li'));
|
||||
li.hide();
|
||||
|
||||
// Determine where in the parents children list to insert this comment.
|
||||
for(i=0; i < siblings.length; i++) {
|
||||
if (comp(comment, siblings[i]) <= 0) {
|
||||
$('#cd' + siblings[i].id)
|
||||
.parent()
|
||||
.before(li.html(div));
|
||||
li.slideDown('fast');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If we get here, this comment rates lower than all the others,
|
||||
// or it is the only comment in the list.
|
||||
ul.append(li.html(div));
|
||||
li.slideDown('fast');
|
||||
}
|
||||
|
||||
function acceptComment(id) {
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: opts.acceptCommentURL,
|
||||
data: {id: id},
|
||||
success: function(data, textStatus, request) {
|
||||
$('#cm' + id).fadeOut('fast');
|
||||
$('#cd' + id).removeClass('moderate');
|
||||
},
|
||||
error: function(request, textStatus, error) {
|
||||
showError('Oops, there was a problem accepting the comment.');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function deleteComment(id) {
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: opts.deleteCommentURL,
|
||||
data: {id: id},
|
||||
success: function(data, textStatus, request) {
|
||||
var div = $('#cd' + id);
|
||||
if (data == 'delete') {
|
||||
// Moderator mode: remove the comment and all children immediately
|
||||
div.slideUp('fast', function() {
|
||||
div.remove();
|
||||
});
|
||||
return;
|
||||
}
|
||||
// User mode: only mark the comment as deleted
|
||||
div
|
||||
.find('span.user-id:first')
|
||||
.text('[deleted]').end()
|
||||
.find('div.comment-text:first')
|
||||
.text('[deleted]').end()
|
||||
.find('#cm' + id + ', #dc' + id + ', #ac' + id + ', #rc' + id +
|
||||
', #sp' + id + ', #hp' + id + ', #cr' + id + ', #rl' + id)
|
||||
.remove();
|
||||
var comment = div.data('comment');
|
||||
comment.username = '[deleted]';
|
||||
comment.text = '[deleted]';
|
||||
div.data('comment', comment);
|
||||
},
|
||||
error: function(request, textStatus, error) {
|
||||
showError('Oops, there was a problem deleting the comment.');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function showProposal(id) {
|
||||
$('#sp' + id).hide();
|
||||
$('#hp' + id).show();
|
||||
$('#pr' + id).slideDown('fast');
|
||||
}
|
||||
|
||||
function hideProposal(id) {
|
||||
$('#hp' + id).hide();
|
||||
$('#sp' + id).show();
|
||||
$('#pr' + id).slideUp('fast');
|
||||
}
|
||||
|
||||
function showProposeChange(id) {
|
||||
$('#pc' + id).hide();
|
||||
$('#hc' + id).show();
|
||||
var textarea = $('#pt' + id);
|
||||
textarea.val(textarea.data('source'));
|
||||
$.fn.autogrow.resize(textarea[0]);
|
||||
textarea.slideDown('fast');
|
||||
}
|
||||
|
||||
function hideProposeChange(id) {
|
||||
$('#hc' + id).hide();
|
||||
$('#pc' + id).show();
|
||||
var textarea = $('#pt' + id);
|
||||
textarea.val('').removeAttr('disabled');
|
||||
textarea.slideUp('fast');
|
||||
}
|
||||
|
||||
function toggleCommentMarkupBox(id) {
|
||||
$('#mb' + id).toggle();
|
||||
}
|
||||
|
||||
/** Handle when the user clicks on a sort by link. */
|
||||
function handleReSort(link) {
|
||||
var classes = link.attr('class').split(/\s+/);
|
||||
for (var i=0; i<classes.length; i++) {
|
||||
if (classes[i] != 'sort-option') {
|
||||
by = classes[i].substring(2);
|
||||
}
|
||||
}
|
||||
setComparator();
|
||||
// Save/update the sortBy cookie.
|
||||
var expiration = new Date();
|
||||
expiration.setDate(expiration.getDate() + 365);
|
||||
document.cookie= 'sortBy=' + escape(by) +
|
||||
';expires=' + expiration.toUTCString();
|
||||
$('ul.comment-ul').each(function(index, ul) {
|
||||
var comments = getChildren($(ul), true);
|
||||
comments = sortComments(comments);
|
||||
appendComments(comments, $(ul).empty());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to process a vote when a user clicks an arrow.
|
||||
*/
|
||||
function handleVote(link) {
|
||||
if (!opts.voting) {
|
||||
showError("You'll need to login to vote.");
|
||||
return;
|
||||
}
|
||||
|
||||
var id = link.attr('id');
|
||||
if (!id) {
|
||||
// Didn't click on one of the voting arrows.
|
||||
return;
|
||||
}
|
||||
// If it is an unvote, the new vote value is 0,
|
||||
// Otherwise it's 1 for an upvote, or -1 for a downvote.
|
||||
var value = 0;
|
||||
if (id.charAt(1) != 'u') {
|
||||
value = id.charAt(0) == 'u' ? 1 : -1;
|
||||
}
|
||||
// The data to be sent to the server.
|
||||
var d = {
|
||||
comment_id: id.substring(2),
|
||||
value: value
|
||||
};
|
||||
|
||||
// Swap the vote and unvote links.
|
||||
link.hide();
|
||||
$('#' + id.charAt(0) + (id.charAt(1) == 'u' ? 'v' : 'u') + d.comment_id)
|
||||
.show();
|
||||
|
||||
// The div the comment is displayed in.
|
||||
var div = $('div#cd' + d.comment_id);
|
||||
var data = div.data('comment');
|
||||
|
||||
// If this is not an unvote, and the other vote arrow has
|
||||
// already been pressed, unpress it.
|
||||
if ((d.value !== 0) && (data.vote === d.value * -1)) {
|
||||
$('#' + (d.value == 1 ? 'd' : 'u') + 'u' + d.comment_id).hide();
|
||||
$('#' + (d.value == 1 ? 'd' : 'u') + 'v' + d.comment_id).show();
|
||||
}
|
||||
|
||||
// Update the comments rating in the local data.
|
||||
data.rating += (data.vote === 0) ? d.value : (d.value - data.vote);
|
||||
data.vote = d.value;
|
||||
div.data('comment', data);
|
||||
|
||||
// Change the rating text.
|
||||
div.find('.rating:first')
|
||||
.text(data.rating + ' point' + (data.rating == 1 ? '' : 's'));
|
||||
|
||||
// Send the vote information to the server.
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: opts.processVoteURL,
|
||||
data: d,
|
||||
error: function(request, textStatus, error) {
|
||||
showError('Oops, there was a problem casting that vote.');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a reply form used to reply to an existing comment.
|
||||
*/
|
||||
function openReply(id) {
|
||||
// Swap out the reply link for the hide link
|
||||
$('#rl' + id).hide();
|
||||
$('#cr' + id).show();
|
||||
|
||||
// Add the reply li to the children ul.
|
||||
var div = $(renderTemplate(replyTemplate, {id: id})).hide();
|
||||
$('#cl' + id)
|
||||
.prepend(div)
|
||||
// Setup the submit handler for the reply form.
|
||||
.find('#rf' + id)
|
||||
.submit(function(event) {
|
||||
event.preventDefault();
|
||||
addComment($('#rf' + id));
|
||||
closeReply(id);
|
||||
})
|
||||
.find('input[type=button]')
|
||||
.click(function() {
|
||||
closeReply(id);
|
||||
});
|
||||
div.slideDown('fast', function() {
|
||||
$('#rf' + id).find('textarea').focus();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the reply form opened with openReply.
|
||||
*/
|
||||
function closeReply(id) {
|
||||
// Remove the reply div from the DOM.
|
||||
$('#rd' + id).slideUp('fast', function() {
|
||||
$(this).remove();
|
||||
});
|
||||
|
||||
// Swap out the hide link for the reply link
|
||||
$('#cr' + id).hide();
|
||||
$('#rl' + id).show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively sort a tree of comments using the comp comparator.
|
||||
*/
|
||||
function sortComments(comments) {
|
||||
comments.sort(comp);
|
||||
$.each(comments, function() {
|
||||
this.children = sortComments(this.children);
|
||||
});
|
||||
return comments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the children comments from a ul. If recursive is true,
|
||||
* recursively include childrens' children.
|
||||
*/
|
||||
function getChildren(ul, recursive) {
|
||||
var children = [];
|
||||
ul.children().children("[id^='cd']")
|
||||
.each(function() {
|
||||
var comment = $(this).data('comment');
|
||||
if (recursive)
|
||||
comment.children = getChildren($(this).find('#cl' + comment.id), true);
|
||||
children.push(comment);
|
||||
});
|
||||
return children;
|
||||
}
|
||||
|
||||
/** Create a div to display a comment in. */
|
||||
function createCommentDiv(comment) {
|
||||
if (!comment.displayed && !opts.moderator) {
|
||||
return $('<div class="moderate">Thank you! Your comment will show up '
|
||||
+ 'once it is has been approved by a moderator.</div>');
|
||||
}
|
||||
// Prettify the comment rating.
|
||||
comment.pretty_rating = comment.rating + ' point' +
|
||||
(comment.rating == 1 ? '' : 's');
|
||||
// Make a class (for displaying not yet moderated comments differently)
|
||||
comment.css_class = comment.displayed ? '' : ' moderate';
|
||||
// Create a div for this comment.
|
||||
var context = $.extend({}, opts, comment);
|
||||
var div = $(renderTemplate(commentTemplate, context));
|
||||
|
||||
// If the user has voted on this comment, highlight the correct arrow.
|
||||
if (comment.vote) {
|
||||
var direction = (comment.vote == 1) ? 'u' : 'd';
|
||||
div.find('#' + direction + 'v' + comment.id).hide();
|
||||
div.find('#' + direction + 'u' + comment.id).show();
|
||||
}
|
||||
|
||||
if (opts.moderator || comment.text != '[deleted]') {
|
||||
div.find('a.reply').show();
|
||||
if (comment.proposal_diff)
|
||||
div.find('#sp' + comment.id).show();
|
||||
if (opts.moderator && !comment.displayed)
|
||||
div.find('#cm' + comment.id).show();
|
||||
if (opts.moderator || (opts.username == comment.username))
|
||||
div.find('#dc' + comment.id).show();
|
||||
}
|
||||
return div;
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple template renderer. Placeholders such as <%id%> are replaced
|
||||
* by context['id'] with items being escaped. Placeholders such as <#id#>
|
||||
* are not escaped.
|
||||
*/
|
||||
function renderTemplate(template, context) {
|
||||
var esc = $(document.createElement('div'));
|
||||
|
||||
function handle(ph, escape) {
|
||||
var cur = context;
|
||||
$.each(ph.split('.'), function() {
|
||||
cur = cur[this];
|
||||
});
|
||||
return escape ? esc.text(cur || "").html() : cur;
|
||||
}
|
||||
|
||||
return template.replace(/<([%#])([\w\.]*)\1>/g, function() {
|
||||
return handle(arguments[2], arguments[1] == '%' ? true : false);
|
||||
});
|
||||
}
|
||||
|
||||
/** Flash an error message briefly. */
|
||||
function showError(message) {
|
||||
$(document.createElement('div')).attr({'class': 'popup-error'})
|
||||
.append($(document.createElement('div'))
|
||||
.attr({'class': 'error-message'}).text(message))
|
||||
.appendTo('body')
|
||||
.fadeIn("slow")
|
||||
.delay(2000)
|
||||
.fadeOut("slow");
|
||||
}
|
||||
|
||||
/** Add a link the user uses to open the comments popup. */
|
||||
$.fn.comment = function() {
|
||||
return this.each(function() {
|
||||
var id = $(this).attr('id').substring(1);
|
||||
var count = COMMENT_METADATA[id];
|
||||
var title = count + ' comment' + (count == 1 ? '' : 's');
|
||||
var image = count > 0 ? opts.commentBrightImage : opts.commentImage;
|
||||
var addcls = count == 0 ? ' nocomment' : '';
|
||||
$(this)
|
||||
.append(
|
||||
$(document.createElement('a')).attr({
|
||||
href: '#',
|
||||
'class': 'sphinx-comment-open' + addcls,
|
||||
id: 'ao' + id
|
||||
})
|
||||
.append($(document.createElement('img')).attr({
|
||||
src: image,
|
||||
alt: 'comment',
|
||||
title: title
|
||||
}))
|
||||
.click(function(event) {
|
||||
event.preventDefault();
|
||||
show($(this).attr('id').substring(2));
|
||||
})
|
||||
)
|
||||
.append(
|
||||
$(document.createElement('a')).attr({
|
||||
href: '#',
|
||||
'class': 'sphinx-comment-close hidden',
|
||||
id: 'ah' + id
|
||||
})
|
||||
.append($(document.createElement('img')).attr({
|
||||
src: opts.closeCommentImage,
|
||||
alt: 'close',
|
||||
title: 'close'
|
||||
}))
|
||||
.click(function(event) {
|
||||
event.preventDefault();
|
||||
hide($(this).attr('id').substring(2));
|
||||
})
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
var opts = {
|
||||
processVoteURL: '/_process_vote',
|
||||
addCommentURL: '/_add_comment',
|
||||
getCommentsURL: '/_get_comments',
|
||||
acceptCommentURL: '/_accept_comment',
|
||||
deleteCommentURL: '/_delete_comment',
|
||||
commentImage: '/static/_static/comment.png',
|
||||
closeCommentImage: '/static/_static/comment-close.png',
|
||||
loadingImage: '/static/_static/ajax-loader.gif',
|
||||
commentBrightImage: '/static/_static/comment-bright.png',
|
||||
upArrow: '/static/_static/up.png',
|
||||
downArrow: '/static/_static/down.png',
|
||||
upArrowPressed: '/static/_static/up-pressed.png',
|
||||
downArrowPressed: '/static/_static/down-pressed.png',
|
||||
voting: false,
|
||||
moderator: false
|
||||
};
|
||||
|
||||
if (typeof COMMENT_OPTIONS != "undefined") {
|
||||
opts = jQuery.extend(opts, COMMENT_OPTIONS);
|
||||
}
|
||||
|
||||
var popupTemplate = '\
|
||||
<div class="sphinx-comments" id="sc<%id%>">\
|
||||
<p class="sort-options">\
|
||||
Sort by:\
|
||||
<a href="#" class="sort-option byrating">best rated</a>\
|
||||
<a href="#" class="sort-option byascage">newest</a>\
|
||||
<a href="#" class="sort-option byage">oldest</a>\
|
||||
</p>\
|
||||
<div class="comment-header">Comments</div>\
|
||||
<div class="comment-loading" id="cn<%id%>">\
|
||||
loading comments... <img src="<%loadingImage%>" alt="" /></div>\
|
||||
<ul id="cl<%id%>" class="comment-ul"></ul>\
|
||||
<div id="ca<%id%>">\
|
||||
<p class="add-a-comment">Add a comment\
|
||||
(<a href="#" class="comment-markup" id="ab<%id%>">markup</a>):</p>\
|
||||
<div class="comment-markup-box" id="mb<%id%>">\
|
||||
reStructured text markup: <i>*emph*</i>, <b>**strong**</b>, \
|
||||
<tt>``code``</tt>, \
|
||||
code blocks: <tt>::</tt> and an indented block after blank line</div>\
|
||||
<form method="post" id="cf<%id%>" class="comment-form" action="">\
|
||||
<textarea name="comment" cols="80"></textarea>\
|
||||
<p class="propose-button">\
|
||||
<a href="#" id="pc<%id%>" class="show-propose-change">\
|
||||
Propose a change ▹\
|
||||
</a>\
|
||||
<a href="#" id="hc<%id%>" class="hide-propose-change">\
|
||||
Propose a change ▿\
|
||||
</a>\
|
||||
</p>\
|
||||
<textarea name="proposal" id="pt<%id%>" cols="80"\
|
||||
spellcheck="false"></textarea>\
|
||||
<input type="submit" value="Add comment" />\
|
||||
<input type="hidden" name="node" value="<%id%>" />\
|
||||
<input type="hidden" name="parent" value="" />\
|
||||
</form>\
|
||||
</div>\
|
||||
</div>';
|
||||
|
||||
var commentTemplate = '\
|
||||
<div id="cd<%id%>" class="sphinx-comment<%css_class%>">\
|
||||
<div class="vote">\
|
||||
<div class="arrow">\
|
||||
<a href="#" id="uv<%id%>" class="vote" title="vote up">\
|
||||
<img src="<%upArrow%>" />\
|
||||
</a>\
|
||||
<a href="#" id="uu<%id%>" class="un vote" title="vote up">\
|
||||
<img src="<%upArrowPressed%>" />\
|
||||
</a>\
|
||||
</div>\
|
||||
<div class="arrow">\
|
||||
<a href="#" id="dv<%id%>" class="vote" title="vote down">\
|
||||
<img src="<%downArrow%>" id="da<%id%>" />\
|
||||
</a>\
|
||||
<a href="#" id="du<%id%>" class="un vote" title="vote down">\
|
||||
<img src="<%downArrowPressed%>" />\
|
||||
</a>\
|
||||
</div>\
|
||||
</div>\
|
||||
<div class="comment-content">\
|
||||
<p class="tagline comment">\
|
||||
<span class="user-id"><%username%></span>\
|
||||
<span class="rating"><%pretty_rating%></span>\
|
||||
<span class="delta"><%time.delta%></span>\
|
||||
</p>\
|
||||
<div class="comment-text comment"><#text#></div>\
|
||||
<p class="comment-opts comment">\
|
||||
<a href="#" class="reply hidden" id="rl<%id%>">reply ▹</a>\
|
||||
<a href="#" class="close-reply" id="cr<%id%>">reply ▿</a>\
|
||||
<a href="#" id="sp<%id%>" class="show-proposal">proposal ▹</a>\
|
||||
<a href="#" id="hp<%id%>" class="hide-proposal">proposal ▿</a>\
|
||||
<a href="#" id="dc<%id%>" class="delete-comment hidden">delete</a>\
|
||||
<span id="cm<%id%>" class="moderation hidden">\
|
||||
<a href="#" id="ac<%id%>" class="accept-comment">accept</a>\
|
||||
</span>\
|
||||
</p>\
|
||||
<pre class="proposal" id="pr<%id%>">\
|
||||
<#proposal_diff#>\
|
||||
</pre>\
|
||||
<ul class="comment-children" id="cl<%id%>"></ul>\
|
||||
</div>\
|
||||
<div class="clearleft"></div>\
|
||||
</div>\
|
||||
</div>';
|
||||
|
||||
var replyTemplate = '\
|
||||
<li>\
|
||||
<div class="reply-div" id="rd<%id%>">\
|
||||
<form id="rf<%id%>">\
|
||||
<textarea name="comment" cols="80"></textarea>\
|
||||
<input type="submit" value="Add reply" />\
|
||||
<input type="button" value="Cancel" />\
|
||||
<input type="hidden" name="parent" value="<%id%>" />\
|
||||
<input type="hidden" name="node" value="" />\
|
||||
</form>\
|
||||
</div>\
|
||||
</li>';
|
||||
|
||||
$(document).ready(function() {
|
||||
init();
|
||||
});
|
||||
})(jQuery);
|
||||
|
||||
$(document).ready(function() {
|
||||
// add comment anchors for all paragraphs that are commentable
|
||||
$('.sphinx-has-comment').comment();
|
||||
|
||||
// highlight search words in search results
|
||||
$("div.context").each(function() {
|
||||
var params = $.getQueryParameters();
|
||||
var terms = (params.q) ? params.q[0].split(/\s+/) : [];
|
||||
var result = $(this);
|
||||
$.each(terms, function() {
|
||||
result.highlightText(this.toLowerCase(), 'highlighted');
|
||||
});
|
||||
});
|
||||
|
||||
// directly open comment window if requested
|
||||
var anchor = document.location.hash;
|
||||
if (anchor.substring(0, 9) == '#comment-') {
|
||||
$('#ao' + anchor.substring(9)).click();
|
||||
document.location.hash = '#s' + anchor.substring(9);
|
||||
}
|
||||
});
|