initial commit : Brie avec lecture LDAP
This commit is contained in:
commit
3e95b9a9d6
6
.hgignore
Normal file
6
.hgignore
Normal file
@ -0,0 +1,6 @@
|
||||
syntax: glob
|
||||
|
||||
Brie/data/sessions/*
|
||||
*.pyc
|
||||
*.swp
|
||||
*.swo
|
10
Brie/Brie.egg-info/PKG-INFO
Normal file
10
Brie/Brie.egg-info/PKG-INFO
Normal file
@ -0,0 +1,10 @@
|
||||
Metadata-Version: 1.0
|
||||
Name: Brie
|
||||
Version: 0.1dev
|
||||
Summary: UNKNOWN
|
||||
Home-page: UNKNOWN
|
||||
Author: UNKNOWN
|
||||
Author-email: UNKNOWN
|
||||
License: UNKNOWN
|
||||
Description: UNKNOWN
|
||||
Platform: UNKNOWN
|
68
Brie/Brie.egg-info/SOURCES.txt
Normal file
68
Brie/Brie.egg-info/SOURCES.txt
Normal file
@ -0,0 +1,68 @@
|
||||
MANIFEST.in
|
||||
README.txt
|
||||
setup.cfg
|
||||
setup.py
|
||||
Brie.egg-info/PKG-INFO
|
||||
Brie.egg-info/SOURCES.txt
|
||||
Brie.egg-info/dependency_links.txt
|
||||
Brie.egg-info/entry_points.txt
|
||||
Brie.egg-info/paster_plugins.txt
|
||||
Brie.egg-info/requires.txt
|
||||
Brie.egg-info/top_level.txt
|
||||
brie/__init__.py
|
||||
brie/websetup.py
|
||||
brie/config/__init__.py
|
||||
brie/config/app_cfg.py
|
||||
brie/config/environment.py
|
||||
brie/config/middleware.py
|
||||
brie/controllers/__init__.py
|
||||
brie/controllers/error.py
|
||||
brie/controllers/root.py
|
||||
brie/controllers/secure.py
|
||||
brie/controllers/template.py
|
||||
brie/i18n/ru/LC_MESSAGES/brie.po
|
||||
brie/lib/__init__.py
|
||||
brie/lib/app_globals.py
|
||||
brie/lib/base.py
|
||||
brie/lib/helpers.py
|
||||
brie/model/__init__.py
|
||||
brie/model/auth.py
|
||||
brie/public/favicon.ico
|
||||
brie/public/css/style.css
|
||||
brie/public/images/contentbg.png
|
||||
brie/public/images/error.png
|
||||
brie/public/images/header_inner2.png
|
||||
brie/public/images/headerbg.png
|
||||
brie/public/images/info.png
|
||||
brie/public/images/inputbg.png
|
||||
brie/public/images/loginbg.png
|
||||
brie/public/images/loginbottombg.png
|
||||
brie/public/images/loginheader-left.png
|
||||
brie/public/images/loginheader-right.png
|
||||
brie/public/images/menu-item-actibg-first.png
|
||||
brie/public/images/menu-item-actibg.png
|
||||
brie/public/images/menu-item-border.png
|
||||
brie/public/images/menubg.png
|
||||
brie/public/images/ok.png
|
||||
brie/public/images/pagebg.png
|
||||
brie/public/images/star.png
|
||||
brie/public/images/strype2.png
|
||||
brie/public/images/under_the_hood_blue.png
|
||||
brie/public/images/warning.png
|
||||
brie/templates/__init__.py
|
||||
brie/templates/about.html
|
||||
brie/templates/authentication.html
|
||||
brie/templates/debug.html
|
||||
brie/templates/error.html
|
||||
brie/templates/footer.html
|
||||
brie/templates/header.html
|
||||
brie/templates/index.html
|
||||
brie/templates/login.html
|
||||
brie/templates/master.html
|
||||
brie/templates/sidebars.html
|
||||
brie/tests/__init__.py
|
||||
brie/tests/functional/__init__.py
|
||||
brie/tests/functional/test_authentication.py
|
||||
brie/tests/functional/test_root.py
|
||||
brie/tests/models/__init__.py
|
||||
brie/tests/models/test_auth.py
|
1
Brie/Brie.egg-info/dependency_links.txt
Normal file
1
Brie/Brie.egg-info/dependency_links.txt
Normal file
@ -0,0 +1 @@
|
||||
|
7
Brie/Brie.egg-info/entry_points.txt
Normal file
7
Brie/Brie.egg-info/entry_points.txt
Normal file
@ -0,0 +1,7 @@
|
||||
|
||||
[paste.app_factory]
|
||||
main = brie.config.middleware:make_app
|
||||
|
||||
[paste.app_install]
|
||||
main = pylons.util:PylonsInstaller
|
||||
|
4
Brie/Brie.egg-info/paster_plugins.txt
Normal file
4
Brie/Brie.egg-info/paster_plugins.txt
Normal file
@ -0,0 +1,4 @@
|
||||
PasteScript
|
||||
Pylons
|
||||
TurboGears2
|
||||
tg.devtools
|
7
Brie/Brie.egg-info/requires.txt
Normal file
7
Brie/Brie.egg-info/requires.txt
Normal file
@ -0,0 +1,7 @@
|
||||
TurboGears2 >= 2.0b7
|
||||
Catwalk >= 2.0.2
|
||||
Babel >=0.9.4
|
||||
toscawidgets >= 0.9.7.1
|
||||
zope.sqlalchemy >= 0.4
|
||||
repoze.tm2 >= 1.0a4
|
||||
repoze.what-quickstart >= 1.0
|
1
Brie/Brie.egg-info/top_level.txt
Normal file
1
Brie/Brie.egg-info/top_level.txt
Normal file
@ -0,0 +1 @@
|
||||
brie
|
4
Brie/MANIFEST.in
Normal file
4
Brie/MANIFEST.in
Normal file
@ -0,0 +1,4 @@
|
||||
recursive-include brie/public *
|
||||
include brie/public/favicon.ico
|
||||
recursive-include brie/i18n *
|
||||
recursive-include brie/templates *
|
24
Brie/README.txt
Normal file
24
Brie/README.txt
Normal file
@ -0,0 +1,24 @@
|
||||
This file is for you to describe the Brie application. Typically
|
||||
you would include information such as the information below:
|
||||
|
||||
Installation and Setup
|
||||
======================
|
||||
|
||||
Install ``Brie`` using the setup.py script::
|
||||
|
||||
$ cd Brie
|
||||
$ python setup.py install
|
||||
|
||||
Create the project database for any model classes defined::
|
||||
|
||||
$ paster setup-app development.ini
|
||||
|
||||
Start the paste http server::
|
||||
|
||||
$ paster serve development.ini
|
||||
|
||||
While developing you may want the server to reload after changes in package files (or its dependencies) are saved. This can be achieved easily by adding the --reload option::
|
||||
|
||||
$ paster serve --reload development.ini
|
||||
|
||||
Then you are ready to go.
|
1
Brie/REAME
Normal file
1
Brie/REAME
Normal file
@ -0,0 +1 @@
|
||||
migrate_* sont des scripts temporaires d'entre deux
|
0
Brie/__init__.py
Normal file
0
Brie/__init__.py
Normal file
2
Brie/brie/__init__.py
Normal file
2
Brie/brie/__init__.py
Normal file
@ -0,0 +1,2 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""The Brie package"""
|
2
Brie/brie/config/__init__.py
Normal file
2
Brie/brie/config/__init__.py
Normal file
@ -0,0 +1,2 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
65
Brie/brie/config/app_cfg.py
Normal file
65
Brie/brie/config/app_cfg.py
Normal file
@ -0,0 +1,65 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Global configuration file for TG2-specific settings in Brie.
|
||||
|
||||
This file complements development/deployment.ini.
|
||||
|
||||
Please note that **all the argument values are strings**. If you want to
|
||||
convert them into boolean, for example, you should use the
|
||||
:func:`paste.deploy.converters.asbool` function, as in::
|
||||
|
||||
from paste.deploy.converters import asbool
|
||||
setting = asbool(global_conf.get('the_setting'))
|
||||
|
||||
"""
|
||||
|
||||
from tg.configuration import AppConfig
|
||||
|
||||
import brie
|
||||
from brie import model
|
||||
from brie.lib import app_globals, helpers
|
||||
|
||||
base_config = AppConfig()
|
||||
base_config.renderers = []
|
||||
|
||||
base_config.package = brie
|
||||
|
||||
#Set the default renderer
|
||||
base_config.default_renderer = 'genshi'
|
||||
base_config.renderers.append('genshi')
|
||||
# if you want raw speed and have installed chameleon.genshi
|
||||
# you should try to use this renderer instead.
|
||||
# warning: for the moment chameleon does not handle i18n translations
|
||||
#base_config.renderers.append('chameleon_genshi')
|
||||
|
||||
#Configure the base SQLALchemy Setup
|
||||
base_config.use_sqlalchemy = True
|
||||
base_config.model = brie.model
|
||||
base_config.DBSession = brie.model.DBSession
|
||||
|
||||
|
||||
# YOU MUST CHANGE THIS VALUE IN PRODUCTION TO SECURE YOUR APP
|
||||
base_config.sa_auth.cookie_secret = "ChangeME"
|
||||
|
||||
# Configure the authentication backend
|
||||
base_config.auth_backend = 'sqlalchemy'
|
||||
base_config.sa_auth.dbsession = model.DBSession
|
||||
# what is the class you want to use to search for users in the database
|
||||
base_config.sa_auth.user_class = model.User
|
||||
# what is the class you want to use to search for groups in the database
|
||||
base_config.sa_auth.group_class = model.Group
|
||||
# what is the class you want to use to search for permissions in the database
|
||||
base_config.sa_auth.permission_class = model.Permission
|
||||
|
||||
|
||||
# override this if you would like to provide a different who plugin for
|
||||
# managing login and logout of your application
|
||||
base_config.sa_auth.form_plugin = None
|
||||
|
||||
# You may optionally define a page where you want users to be redirected to
|
||||
# on login:
|
||||
base_config.sa_auth.post_login_url = '/post_login'
|
||||
|
||||
# You may optionally define a page where you want users to be redirected to
|
||||
# on logout:
|
||||
base_config.sa_auth.post_logout_url = '/post_logout'
|
95
Brie/brie/config/deployment.ini_tmpl
Normal file
95
Brie/brie/config/deployment.ini_tmpl
Normal file
@ -0,0 +1,95 @@
|
||||
#
|
||||
# Brie - TurboGears configuration
|
||||
#
|
||||
# The %(here)s variable will be replaced with the parent directory of this file
|
||||
#
|
||||
[DEFAULT]
|
||||
# WARGING == If debug is not set to false, you'll get the interactive
|
||||
# debugger on production, which is a huge security hole.
|
||||
|
||||
debug = false
|
||||
email_to = you@yourdomain.com
|
||||
smtp_server = localhost
|
||||
error_email_from = paste@localhost
|
||||
|
||||
[server:main]
|
||||
use = egg:Paste#http
|
||||
host = 0.0.0.0
|
||||
port = 8080
|
||||
|
||||
[app:main]
|
||||
use = egg:Brie
|
||||
full_stack = true
|
||||
cache_dir = %(here)s/data
|
||||
beaker.session.key = brie
|
||||
beaker.session.secret = ${app_instance_secret}
|
||||
app_instance_uuid = ${app_instance_uuid}
|
||||
|
||||
# If you'd like to fine-tune the individual locations of the cache data dirs
|
||||
# for the Cache data, or the Session saves, un-comment the desired settings
|
||||
# here:
|
||||
#beaker.cache.data_dir = %(here)s/data/cache
|
||||
#beaker.session.data_dir = %(here)s/data/sessions
|
||||
# Specify the database for SQLAlchemy to use via
|
||||
# turbogears.database
|
||||
# %(here) may include a ':' character on Windows environments; this can
|
||||
# invalidate the URI when specifying a SQLite db via path name
|
||||
sqlalchemy.url = sqlite:///%(here)s/somedb.db
|
||||
sqlalchemy.echo = False
|
||||
|
||||
# WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT*
|
||||
# Debug mode will enable the interactive debugging tool, allowing ANYONE to
|
||||
# execute malicious code after an exception is raised.
|
||||
#set debug = false
|
||||
|
||||
# Logging configuration
|
||||
# Add additional loggers, handlers, formatters here
|
||||
# Uses python's logging config file format
|
||||
# http://docs.python.org/lib/logging-config-fileformat.html
|
||||
|
||||
[loggers]
|
||||
keys = root, brie, sqlalchemy, auth
|
||||
|
||||
[handlers]
|
||||
keys = console
|
||||
|
||||
[formatters]
|
||||
keys = generic
|
||||
|
||||
# If you create additional loggers, add them as a key to [loggers]
|
||||
[logger_root]
|
||||
level = INFO
|
||||
handlers = console
|
||||
|
||||
[logger_brie]
|
||||
level = INFO
|
||||
handlers =
|
||||
qualname = brie
|
||||
|
||||
[logger_sqlalchemy]
|
||||
level = WARN
|
||||
handlers =
|
||||
qualname = sqlalchemy.engine
|
||||
# "level = INFO" logs SQL queries.
|
||||
# "level = DEBUG" logs SQL queries and results.
|
||||
# "level = WARN" logs neither. (Recommended for production systems.)
|
||||
|
||||
|
||||
# A logger for authentication, identification and authorization -- this is
|
||||
# repoze.who and repoze.what:
|
||||
[logger_auth]
|
||||
level = WARN
|
||||
handlers =
|
||||
qualname = auth
|
||||
|
||||
# If you create additional handlers, add them as a key to [handlers]
|
||||
[handler_console]
|
||||
class = StreamHandler
|
||||
args = (sys.stderr,)
|
||||
level = NOTSET
|
||||
formatter = generic
|
||||
|
||||
# If you create additional formatters, add them as a key to [formatters]
|
||||
[formatter_generic]
|
||||
format = %(asctime)s,%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
|
||||
datefmt = %H:%M:%S
|
9
Brie/brie/config/environment.py
Normal file
9
Brie/brie/config/environment.py
Normal file
@ -0,0 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""WSGI environment setup for Brie."""
|
||||
|
||||
from brie.config.app_cfg import base_config
|
||||
|
||||
__all__ = ['load_environment']
|
||||
|
||||
#Use base_config to setup the environment loader function
|
||||
load_environment = base_config.make_load_environment()
|
12
Brie/brie/config/ldap_config.py
Normal file
12
Brie/brie/config/ldap_config.py
Normal file
@ -0,0 +1,12 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
uri = "ldaps://ldap.pacaterie.u-psud.fr"
|
||||
|
||||
base_dn = "dc=pacaterie,dc=u-psud,dc=fr"
|
||||
|
||||
username_base_dn = "ou=membres," + base_dn
|
||||
|
||||
room_base_dn = "ou=chambres," + base_dn
|
||||
area_filter = "(objectClass=pacateriearea)"
|
||||
floor_filter = "(objectClass=pacateriefloor)"
|
||||
room_filter = "(objectClass=pacaterieRoom)"
|
39
Brie/brie/config/middleware.py
Normal file
39
Brie/brie/config/middleware.py
Normal file
@ -0,0 +1,39 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""WSGI middleware initialization for the Brie application."""
|
||||
|
||||
from brie.config.app_cfg import base_config
|
||||
from brie.config.environment import load_environment
|
||||
|
||||
|
||||
__all__ = ['make_app']
|
||||
|
||||
# Use base_config to setup the necessary PasteDeploy application factory.
|
||||
# make_base_app will wrap the TG2 app with all the middleware it needs.
|
||||
make_base_app = base_config.setup_tg_wsgi_app(load_environment)
|
||||
|
||||
|
||||
def make_app(global_conf, full_stack=True, **app_conf):
|
||||
"""
|
||||
Set Brie up with the settings found in the PasteDeploy configuration
|
||||
file used.
|
||||
|
||||
:param global_conf: The global settings for Brie (those
|
||||
defined under the ``[DEFAULT]`` section).
|
||||
:type global_conf: dict
|
||||
:param full_stack: Should the whole TG2 stack be set up?
|
||||
:type full_stack: str or bool
|
||||
:return: The Brie application with all the relevant middleware
|
||||
loaded.
|
||||
|
||||
This is the PasteDeploy factory for the Brie application.
|
||||
|
||||
``app_conf`` contains all the application-specific settings (those defined
|
||||
under ``[app:main]``.
|
||||
|
||||
|
||||
"""
|
||||
app = make_base_app(global_conf, full_stack=True, **app_conf)
|
||||
|
||||
# Wrap your base TurboGears 2 application with custom middleware here
|
||||
|
||||
return app
|
2
Brie/brie/controllers/__init__.py
Normal file
2
Brie/brie/controllers/__init__.py
Normal file
@ -0,0 +1,2 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Controllers for the Brie application."""
|
142
Brie/brie/controllers/auth.py
Normal file
142
Brie/brie/controllers/auth.py
Normal file
@ -0,0 +1,142 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from tg import session
|
||||
from tg.controllers import RestController, redirect
|
||||
from tg.decorators import expose, validate
|
||||
|
||||
from brie.lib.base import BaseController
|
||||
from brie.config import ldap_config
|
||||
from brie.lib.ldap_helper import *
|
||||
|
||||
class User(object):
|
||||
ldap_bind = None
|
||||
attrs = None
|
||||
|
||||
def __init__(self, ldap_bind, attrs):
|
||||
self.ldap_bind = ldap_bind
|
||||
self.attrs = attrs
|
||||
#end def
|
||||
#end class
|
||||
|
||||
class AuthHandler(object):
|
||||
__users = dict()
|
||||
__user_session_name = "user"
|
||||
__anon_bind = None
|
||||
|
||||
def get_anon_bind(self):
|
||||
if self.__anon_bind is not None:
|
||||
return self.__anon_bind
|
||||
else:
|
||||
self.__anon_bind = Ldap.connect("", "")
|
||||
return self.__anon_bind
|
||||
#end if
|
||||
#end def
|
||||
|
||||
def login(self, username, password):
|
||||
if self.get_anon_bind() is None:
|
||||
return False
|
||||
|
||||
actual_user = self.get_anon_bind().search_first(ldap_config.username_base_dn, "(uid=" + username + ")")
|
||||
|
||||
if actual_user is None:
|
||||
return False
|
||||
|
||||
username_dn = actual_user.dn
|
||||
bind = Ldap.connect(username_dn, password)
|
||||
|
||||
if bind is None:
|
||||
return False
|
||||
|
||||
attributes = bind.search_first(username_dn, "(uid=" + username + ")")
|
||||
|
||||
user = User(bind, attributes)
|
||||
|
||||
AuthHandler.__users[username] = user
|
||||
|
||||
session[AuthHandler.__user_session_name] = username
|
||||
session.save()
|
||||
|
||||
return True
|
||||
#end def
|
||||
|
||||
def logout(self):
|
||||
user = session[AuthHandler.__user_session_name]
|
||||
if user in AuthHandler.__users:
|
||||
stored_user = AuthHandler.__users[user]
|
||||
stored_user.ldap_bind.close()
|
||||
del AuthHandler.__users[user]
|
||||
#end if
|
||||
session[AuthHandler.__user_session_name] = None
|
||||
session.save()
|
||||
#end def
|
||||
|
||||
def get_user(self):
|
||||
if not AuthHandler.__user_session_name in session:
|
||||
return None
|
||||
|
||||
user = session[AuthHandler.__user_session_name]
|
||||
if user in AuthHandler.__users:
|
||||
return AuthHandler.__users[user]
|
||||
|
||||
return None
|
||||
#end def
|
||||
|
||||
def get_user_or_redirect(self):
|
||||
maybe_user = self.get_user()
|
||||
if maybe_user is None:
|
||||
redirect("/auth/login/") # TODO from config
|
||||
#end if
|
||||
|
||||
return maybe_user
|
||||
#end def
|
||||
|
||||
#end class
|
||||
|
||||
class AuthenticatedRestController(RestController):
|
||||
user = None
|
||||
|
||||
def __before__(self, *args, **kwargs):
|
||||
self.user = current.get_user_or_redirect()
|
||||
#end def
|
||||
#end def
|
||||
|
||||
class AuthenticatedBaseController(BaseController):
|
||||
user = None
|
||||
|
||||
def __before__(self, *args, **kwargs):
|
||||
self.user = current.get_user_or_redirect()
|
||||
#end def
|
||||
#end def
|
||||
|
||||
current = AuthHandler()
|
||||
|
||||
class LoginRestController(RestController):
|
||||
|
||||
@expose("brie.templates.auth.login")
|
||||
def get(self):
|
||||
return dict(login = "", error = "")
|
||||
|
||||
@expose("brie.templates.auth.login")
|
||||
def post(self, username, password):
|
||||
success = current.login(username, password)
|
||||
|
||||
if success:
|
||||
redirect("/")
|
||||
#end if
|
||||
|
||||
return dict(login = username, error = "erreur de connexion")
|
||||
#end def
|
||||
|
||||
|
||||
class AuthRestController(BaseController):
|
||||
login = LoginRestController()
|
||||
|
||||
@expose()
|
||||
def logout(self):
|
||||
current.logout()
|
||||
redirect("/")
|
||||
#end class
|
||||
|
||||
|
||||
|
||||
|
23
Brie/brie/controllers/controller.template
Normal file
23
Brie/brie/controllers/controller.template
Normal file
@ -0,0 +1,23 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Sample controller module"""
|
||||
|
||||
# turbogears imports
|
||||
from tg import expose
|
||||
#from tg import redirect, validate, flash
|
||||
|
||||
# third party imports
|
||||
#from pylons.i18n import ugettext as _
|
||||
#from repoze.what import predicates
|
||||
|
||||
# project specific imports
|
||||
from brie.lib.base import BaseController
|
||||
#from brie.model import DBSession, metadata
|
||||
|
||||
|
||||
class SampleController(BaseController):
|
||||
#Uncomment this line if your controller requires an authenticated user
|
||||
#allow_only = authorize.not_anonymous()
|
||||
|
||||
@expose('brie.templates.index')
|
||||
def index(self):
|
||||
return dict(page='index')
|
83
Brie/brie/controllers/edit.py
Normal file
83
Brie/brie/controllers/edit.py
Normal file
@ -0,0 +1,83 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from tg import session
|
||||
from tg.controllers import redirect
|
||||
from tg.decorators import expose, validate
|
||||
|
||||
from brie.lib.camembert_helpers import *
|
||||
|
||||
from brie.config import ldap_config
|
||||
from brie.lib.ldap_helper import *
|
||||
from brie.model import DBSession
|
||||
from brie.model.ldap import *
|
||||
|
||||
from brie.controllers import auth
|
||||
from brie.controllers.auth import AuthenticatedBaseController, AuthenticatedRestController
|
||||
|
||||
from operator import itemgetter
|
||||
|
||||
|
||||
#root = tg.config['application_root_module'].RootController
|
||||
|
||||
""" Controller d'affichage de details de membres, chambres et interfaces """
|
||||
class EditController(AuthenticatedBaseController):
|
||||
show = None
|
||||
wifi = None
|
||||
|
||||
def __init__(self, new_show):
|
||||
self.show = new_show
|
||||
self.wifi = WifiRestController(new_show)
|
||||
|
||||
""" Affiche les détails du membre, de la chambre et de l'interface """
|
||||
@expose("brie.templates.edit.member")
|
||||
def member(self, uid):
|
||||
return self.show.member(uid)
|
||||
#end def
|
||||
|
||||
@expose("brie.templates.edit.room")
|
||||
def room(self, room_number):
|
||||
return self.show.room(room_number)
|
||||
#end def
|
||||
|
||||
@expose("brie.templates.edit.interface")
|
||||
def interface(self, interface_id):
|
||||
return self.show.interface(interface_id)
|
||||
#end def
|
||||
#end class
|
||||
|
||||
class WifiRestController(AuthenticatedRestController):
|
||||
show = None
|
||||
|
||||
def __init__(self, new_show):
|
||||
self.show = new_show
|
||||
|
||||
@expose("brie.templates.edit.wifi")
|
||||
def get(self, uid):
|
||||
member = Member.get_by_uid(self.user, uid)
|
||||
|
||||
if member is None:
|
||||
self.show.error_no_entry()
|
||||
|
||||
|
||||
def post(self, uid, password):
|
||||
member = Member.get_by_uid(self.user, uid)
|
||||
|
||||
if member is None:
|
||||
self.show.error_no_entry()
|
||||
|
||||
wifi = Wifi.get_by_dn(self.user, member.dn)
|
||||
|
||||
if wifi is None:
|
||||
wifi_dn = "cn=wifi," + member.dn
|
||||
self.user.ldap_bind.add_entry(wifi_dn, Wifi.entry_attr(password))
|
||||
else:
|
||||
attr = {
|
||||
"userPassword" : password
|
||||
}
|
||||
self.user.ldap_bind.replace_attr(wifi.dn, attr)
|
||||
#end if
|
||||
|
||||
redirect("/show/member/" + uid)
|
||||
#end def
|
||||
#end class
|
||||
|
111
Brie/brie/controllers/rooms.py
Normal file
111
Brie/brie/controllers/rooms.py
Normal file
@ -0,0 +1,111 @@
|
||||
from tg import session
|
||||
from tg.controllers import redirect
|
||||
from tg.decorators import expose, validate
|
||||
from brie.lib.base import BaseController
|
||||
|
||||
from brie.lib.camembert_helpers import *
|
||||
|
||||
from brie.config import ldap_config
|
||||
from brie.lib.ldap_helper import *
|
||||
from brie.model import DBSession
|
||||
from brie.model.camembert import *
|
||||
from brie.model.ldap import *
|
||||
|
||||
from brie.controllers import auth
|
||||
from brie.controllers.auth import AuthenticatedBaseController, AuthenticatedRestController
|
||||
|
||||
from operator import itemgetter
|
||||
|
||||
|
||||
class RoomsController(AuthenticatedBaseController):
|
||||
__default_color = "ok_color"
|
||||
__error_colors = {
|
||||
"PAS PAYE" : "non_paye_color",
|
||||
"CERTIF" : "non_certif_color",
|
||||
"VIDE" : "vide_color"
|
||||
}
|
||||
|
||||
|
||||
def color_picker(self, description):
|
||||
for color in self.__error_colors.iteritems():
|
||||
if color[0] in description:
|
||||
return color[1]
|
||||
#end if
|
||||
#end for
|
||||
|
||||
return self.__default_color
|
||||
#end def
|
||||
|
||||
def reverse_sort_name(self, name_items):
|
||||
return sorted(name_items, key=itemgetter(0), reverse=True)
|
||||
|
||||
def sort_name(self, name_items):
|
||||
return sorted(name_items, key=itemgetter(0))
|
||||
|
||||
@expose("brie.templates.rooms.index")
|
||||
def index(self):
|
||||
result = DBSession.query(Interface)
|
||||
|
||||
interfaces_dict = dict()
|
||||
for interface in result:
|
||||
interfaces_dict[str(interface.idinterface)] = interface
|
||||
|
||||
stats = dict()
|
||||
areas = dict()
|
||||
|
||||
rooms = self.user.ldap_bind.search(ldap_config.room_base_dn, ldap_config.room_filter)
|
||||
|
||||
rooms = sorted(rooms, key = lambda a: a.cn.first())
|
||||
for room in rooms:
|
||||
interface = interfaces_dict[room.get("x-switchInterface").first()]
|
||||
|
||||
color = self.color_picker(interface.ifdescription)
|
||||
if color in stats:
|
||||
stats[color] = stats[color] + 1
|
||||
else:
|
||||
stats[color] = 0
|
||||
#end if
|
||||
|
||||
room_id = int(room.uid.first())
|
||||
floor = Translations.floor_of_room(room_id)
|
||||
area = Translations.area_of_room(room_id)
|
||||
|
||||
if area not in areas:
|
||||
areas[area] = dict()
|
||||
#end if
|
||||
|
||||
if floor not in areas[area]:
|
||||
areas[area][floor] = []
|
||||
#end if
|
||||
|
||||
areas[area][floor].append((room, interface))
|
||||
#end for
|
||||
|
||||
return { "areas" : areas, "color_picker" : self.color_picker, "reverse_sorted_name" : self.reverse_sort_name, "sorted_name" : self.sort_name, "stats" : stats}
|
||||
#end def
|
||||
|
||||
@expose("brie.templates.rooms.index")
|
||||
def preview(self, number):
|
||||
if not number.isdigit(): redirect("/rooms/")
|
||||
|
||||
index_result = self.index()
|
||||
|
||||
room = Room.get_by_uid(self.user, number)
|
||||
|
||||
|
||||
member = None
|
||||
if room.has("x-memberIn"):
|
||||
member = Member.get_by_dn(self.user, room.get("x-memberIn").first())
|
||||
|
||||
|
||||
interface = (
|
||||
DBSession.query(Interface)
|
||||
.filter(Interface.idinterface == room.get("x-switchInterface").first())
|
||||
.first()
|
||||
)
|
||||
|
||||
preview = member, room, interface
|
||||
index_result["preview"] = preview
|
||||
|
||||
return index_result
|
||||
#end def
|
62
Brie/brie/controllers/root.py
Normal file
62
Brie/brie/controllers/root.py
Normal file
@ -0,0 +1,62 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Main Controller"""
|
||||
|
||||
from tg import expose, flash, require, url, request, redirect
|
||||
from pylons.i18n import ugettext as _, lazy_ugettext as l_
|
||||
from catwalk.tg2 import Catwalk
|
||||
from repoze.what import predicates
|
||||
|
||||
from brie.lib.base import BaseController
|
||||
from brie.model import DBSession, metadata
|
||||
from brie import model
|
||||
#from brie.controllers.secure import SecureController
|
||||
import brie.controllers.auth as auth_handler
|
||||
from brie.controllers.auth import AuthRestController
|
||||
from brie.controllers.rooms import RoomsController
|
||||
from brie.controllers.show import ShowController
|
||||
from brie.controllers.edit import EditController
|
||||
|
||||
from brie.model.camembert import Materiel
|
||||
|
||||
__all__ = ['RootController']
|
||||
|
||||
|
||||
class RootController(BaseController):
|
||||
"""
|
||||
The root controller for the Brie application.
|
||||
|
||||
All the other controllers and WSGI applications should be mounted on this
|
||||
controller. For example::
|
||||
|
||||
panel = ControlPanelController()
|
||||
another_app = AnotherWSGIApplication()
|
||||
|
||||
Keep in mind that WSGI applications shouldn't be mounted directly: They
|
||||
must be wrapped around with :class:`tg.controllers.WSGIAppController`.
|
||||
|
||||
"""
|
||||
# admin = Catwalk(model, DBSession)
|
||||
|
||||
auth = AuthRestController()
|
||||
rooms = RoomsController()
|
||||
show = ShowController()
|
||||
edit = EditController(show)
|
||||
|
||||
@expose('brie.templates.index')
|
||||
def index(self):
|
||||
"""Handle the front-page."""
|
||||
materiel = DBSession.query(Materiel)
|
||||
user = auth_handler.current.get_user()
|
||||
|
||||
return { "user" : user, "materiel" : materiel }
|
||||
|
||||
@expose()
|
||||
def foobar(self):
|
||||
redirect("http://172.17.22.10:9000/toto")
|
||||
#end def
|
||||
|
||||
# @expose('brie.templates.index')
|
||||
# @require(predicates.has_permission('manage', msg=l_('Only for managers')))
|
||||
# def manage_permission_only(self, **kw):
|
||||
# """Illustrate how a page for managers only works."""
|
||||
# return dict(page='managers stuff')
|
81
Brie/brie/controllers/show.py
Normal file
81
Brie/brie/controllers/show.py
Normal file
@ -0,0 +1,81 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from tg import session
|
||||
from tg.controllers import redirect
|
||||
from tg.decorators import expose, validate
|
||||
|
||||
from brie.lib.camembert_helpers import *
|
||||
|
||||
from brie.config import ldap_config
|
||||
from brie.lib.ldap_helper import *
|
||||
from brie.model import DBSession
|
||||
from brie.model.camembert import Interface
|
||||
from brie.model.ldap import *
|
||||
|
||||
from brie.controllers import auth
|
||||
from brie.controllers.auth import AuthenticatedBaseController, AuthenticatedRestController
|
||||
|
||||
from operator import itemgetter
|
||||
|
||||
""" Controller d'affichage de details de membres, chambres et interfaces """
|
||||
class ShowController(AuthenticatedBaseController):
|
||||
|
||||
@expose("brie.templates.show.error")
|
||||
def error_no_entry(self):
|
||||
return { "error" : "Entrée non existante" }
|
||||
|
||||
""" Affiche les détails du membre, de la chambre et de l'interface """
|
||||
@expose("brie.templates.show.member")
|
||||
def member(self, uid):
|
||||
member = Member.get_by_uid(self.user, uid)
|
||||
|
||||
if member is None:
|
||||
return self.error_no_entry()
|
||||
|
||||
room = Room.get_by_member_dn(self.user, member.dn)
|
||||
interface = (
|
||||
DBSession.query(Interface)
|
||||
.filter(Interface.idinterface == room.get("x-switchInterface").first())
|
||||
.first()
|
||||
)
|
||||
|
||||
return { "member_ldap" : member, "interface" : interface, "room_ldap" : room }
|
||||
#end def
|
||||
|
||||
@expose("brie.templates.show.room")
|
||||
def room(self, room_id):
|
||||
room = Room.get_by_uid(self.user, room_id)
|
||||
|
||||
if room is None:
|
||||
return self.error_no_entry()
|
||||
|
||||
interface = (
|
||||
DBSession.query(Interface)
|
||||
.filter(Interface.idinterface == room.get("x-switchInterface").first())
|
||||
.first()
|
||||
)
|
||||
|
||||
member = None
|
||||
if room.has("x-memberIn"):
|
||||
member = Member.get_by_dn(self.user, room.get("x-memberIn").first())
|
||||
|
||||
return { "interface" : interface, "room_ldap" : room, "member_ldap" : member }
|
||||
#end def
|
||||
|
||||
@expose("brie.templates.show.interface")
|
||||
def interface(self, interface_id):
|
||||
interface = (
|
||||
DBSession.query(Interface)
|
||||
.filter(Interface.idinterface == interface_id)
|
||||
.first()
|
||||
)
|
||||
|
||||
if interface is None:
|
||||
return self.error_no_entry()
|
||||
|
||||
room = Room.get_by_interface(self.user, interface.idinterface)
|
||||
|
||||
return { "interface" : interface, "room_ldap" : room }
|
||||
#end def
|
||||
#end class
|
||||
|
35
Brie/brie/controllers/template.py
Normal file
35
Brie/brie/controllers/template.py
Normal file
@ -0,0 +1,35 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Fallback controller."""
|
||||
|
||||
from brie.lib.base import BaseController
|
||||
|
||||
__all__ = ['TemplateController']
|
||||
|
||||
|
||||
class TemplateController(BaseController):
|
||||
"""
|
||||
The fallback controller for Brie.
|
||||
|
||||
By default, the final controller tried to fulfill the request
|
||||
when no other routes match. It may be used to display a template
|
||||
when all else fails, e.g.::
|
||||
|
||||
def view(self, url):
|
||||
return render('/%s' % url)
|
||||
|
||||
Or if you're using Mako and want to explicitly send a 404 (Not
|
||||
Found) response code when the requested template doesn't exist::
|
||||
|
||||
import mako.exceptions
|
||||
|
||||
def view(self, url):
|
||||
try:
|
||||
return render('/%s' % url)
|
||||
except mako.exceptions.TopLevelLookupException:
|
||||
abort(404)
|
||||
|
||||
"""
|
||||
|
||||
def view(self, url):
|
||||
"""Abort the request with a 404 HTTP status code."""
|
||||
abort(404)
|
24
Brie/brie/i18n/ru/LC_MESSAGES/brie.po
Normal file
24
Brie/brie/i18n/ru/LC_MESSAGES/brie.po
Normal file
@ -0,0 +1,24 @@
|
||||
# Russian translations for ${package}.
|
||||
# Copyright (C) 2008 ORGANIZATION
|
||||
# This file is distributed under the same license as the ${package} project.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2008.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: ${package} 0.0.0\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2008-01-13 14:00+0200\n"
|
||||
"PO-Revision-Date: 2008-01-13 14:00+0200\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: ru <LL@li.org>\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
|
||||
"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: Babel 0.9.1\n"
|
||||
|
||||
#: ${package}/controllers/root.py:13
|
||||
msgid "Your application is now running"
|
||||
msgstr "Ваши приложение успешно запущено"
|
||||
|
2
Brie/brie/lib/__init__.py
Normal file
2
Brie/brie/lib/__init__.py
Normal file
@ -0,0 +1,2 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
18
Brie/brie/lib/app_globals.py
Normal file
18
Brie/brie/lib/app_globals.py
Normal file
@ -0,0 +1,18 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""The application's Globals object"""
|
||||
|
||||
__all__ = ['Globals']
|
||||
|
||||
|
||||
class Globals(object):
|
||||
"""Container for objects available throughout the life of the application.
|
||||
|
||||
One instance of Globals is created during application initialization and
|
||||
is available during requests via the 'app_globals' variable.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
"""Do nothing, by default."""
|
||||
pass
|
32
Brie/brie/lib/base.py
Normal file
32
Brie/brie/lib/base.py
Normal file
@ -0,0 +1,32 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""The base Controller API."""
|
||||
|
||||
from tg import TGController, tmpl_context
|
||||
from tg.render import render
|
||||
from tg import request
|
||||
from pylons.i18n import _, ungettext, N_
|
||||
from tw.api import WidgetBunch
|
||||
import brie.model as model
|
||||
|
||||
__all__ = ['Controller', 'BaseController']
|
||||
|
||||
|
||||
class BaseController(TGController):
|
||||
"""
|
||||
Base class for the controllers in the application.
|
||||
|
||||
Your web application should have one of these. The root of
|
||||
your application is used to compute URLs used by your app.
|
||||
|
||||
"""
|
||||
|
||||
def __call__(self, environ, start_response):
|
||||
"""Invoke the Controller"""
|
||||
# TGController.__call__ dispatches to the Controller method
|
||||
# the request is routed to. This routing information is
|
||||
# available in environ['pylons.routes_dict']
|
||||
|
||||
request.identity = request.environ.get('repoze.who.identity')
|
||||
tmpl_context.identity = request.identity
|
||||
return TGController.__call__(self, environ, start_response)
|
42
Brie/brie/lib/camembert_helpers.py
Normal file
42
Brie/brie/lib/camembert_helpers.py
Normal file
@ -0,0 +1,42 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import unicodedata
|
||||
|
||||
|
||||
class Translations(object):
|
||||
|
||||
@staticmethod
|
||||
def to_uid(name, surname):
|
||||
clean_name = Translations.strip_accents(name.replace(" ", "")).lower()[:15]
|
||||
clean_surname = Translations.strip_accents(surname.replace(" ", "")).lower()[:15]
|
||||
|
||||
return clean_name + "." + clean_surname
|
||||
#end def
|
||||
|
||||
@staticmethod
|
||||
def floor_of_room(room):
|
||||
return room / 100
|
||||
#end def
|
||||
|
||||
@staticmethod
|
||||
def area_of_room(room):
|
||||
if Translations.floor_of_room(room) == 5:
|
||||
return "crous"
|
||||
|
||||
floor_number = room % 100
|
||||
|
||||
if floor_number <= 33:
|
||||
return "sud"
|
||||
else:
|
||||
return "nord"
|
||||
#end if
|
||||
#end def
|
||||
|
||||
#end class
|
||||
|
||||
|
||||
|
||||
# http://stackoverflow.com/questions/517923/what-is-the-best-way-to-remove-accents-in-a-python-unicode-string
|
||||
@staticmethod
|
||||
def strip_accents(s):
|
||||
return ''.join((c for c in unicodedata.normalize('NFD', s) if unicodedata.category(c) != 'Mn'))
|
||||
#end def
|
5
Brie/brie/lib/helpers.py
Normal file
5
Brie/brie/lib/helpers.py
Normal file
@ -0,0 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""WebHelpers used in Brie."""
|
||||
|
||||
from webhelpers import date, feedgenerator, html, number, misc, text
|
180
Brie/brie/lib/ldap_helper.py
Normal file
180
Brie/brie/lib/ldap_helper.py
Normal file
@ -0,0 +1,180 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import ldap
|
||||
#import ldap.modlist as modlist
|
||||
|
||||
from brie.config import ldap_config
|
||||
|
||||
class Ldap(object):
|
||||
__connection = None
|
||||
|
||||
def __init__(self, connection):
|
||||
self.__connection = connection
|
||||
#end def
|
||||
|
||||
@staticmethod
|
||||
def connect(dn, password):
|
||||
connection = None
|
||||
try:
|
||||
connection = ldap.initialize(ldap_config.uri)
|
||||
connection.simple_bind_s(dn, password)
|
||||
except:
|
||||
return None
|
||||
#end try
|
||||
|
||||
if connection is not None:
|
||||
return Ldap(connection)
|
||||
#end
|
||||
|
||||
return None
|
||||
#end def
|
||||
|
||||
def search(self, dn, filter, scope = ldap.SCOPE_SUBTREE):
|
||||
try:
|
||||
results = self.__connection.search_s(dn, scope, filter)
|
||||
except:
|
||||
return None
|
||||
#end try
|
||||
|
||||
ldap_results = []
|
||||
|
||||
for result in results:
|
||||
result_dn = result[0]
|
||||
attributes = result[1]
|
||||
val_dict = dict()
|
||||
|
||||
for attribute in attributes.iteritems():
|
||||
name = attribute[0]
|
||||
values = attribute[1]
|
||||
ldap_value = LdapValue(name, values)
|
||||
val_dict[name] = ldap_value
|
||||
#end for
|
||||
|
||||
ldap_result = LdapResult(result_dn, val_dict)
|
||||
ldap_results.append(ldap_result)
|
||||
#end for
|
||||
|
||||
return ldap_results
|
||||
#end def
|
||||
|
||||
def search_first(self, dn, filter, scope = ldap.SCOPE_SUBTREE):
|
||||
results = self.search(dn, filter, scope)
|
||||
if results is None: return None
|
||||
|
||||
for result in results:
|
||||
return result
|
||||
#end for
|
||||
|
||||
return None
|
||||
#end def
|
||||
|
||||
def search_dn(self, dn):
|
||||
return self.search_first(dn, "(objectClass=*)", ldap.SCOPE_BASE)
|
||||
|
||||
def replace_attr(self, dn, attributes):
|
||||
modlist = []
|
||||
for attribute in attributes.iteritems():
|
||||
modlist.append((ldap.MOD_REPLACE, attribute[0], attribute[1]))
|
||||
#end for
|
||||
self.__connection.modify_s(dn, modlist)
|
||||
#end def
|
||||
|
||||
def add_attr(self, dn, attributes):
|
||||
modlist = []
|
||||
for attribute in attributes.iteritems():
|
||||
modlist.append((ldap.MOD_ADD, attribute[0], attribute[1]))
|
||||
#end for
|
||||
try:
|
||||
self.__connection.modify_s(dn, modlist)
|
||||
except ldap.TYPE_OR_VALUE_EXISTS:
|
||||
pass
|
||||
#end def
|
||||
|
||||
def delete_attr(self, dn, attributes):
|
||||
modlist = []
|
||||
for attribute in attributes.iteritems():
|
||||
modlist.append((ldap.MOD_DELETE, attribute[0], attribute[1]))
|
||||
#end for
|
||||
#try:
|
||||
self.__connection.modify_s(dn, modlist)
|
||||
#except:
|
||||
# pass
|
||||
#end def
|
||||
|
||||
def add_entry(self, dn, attributes):
|
||||
modlist = []
|
||||
for attribute in attributes.iteritems():
|
||||
modlist.append((attribute[0], attribute[1]))
|
||||
#end for
|
||||
|
||||
##try:
|
||||
self.__connection.add_s(dn, modlist)
|
||||
##except:
|
||||
## pass
|
||||
#end def
|
||||
|
||||
def delete_entry(self, dn):
|
||||
#try:
|
||||
self.__connection.delete_s(dn)
|
||||
#except:
|
||||
# pass
|
||||
#end def
|
||||
|
||||
def delete_entry_subtree(self, dn):
|
||||
entries = self.search(dn, "(objectClass=*)")
|
||||
for entry in reversed(entries):
|
||||
self.delete_entry(entry.dn)
|
||||
#end for
|
||||
#end def
|
||||
|
||||
def rename_entry(self, dn, newdn, superior):
|
||||
self.__connection.rename_s(dn, newdn, newsuperior= superior)
|
||||
|
||||
def close(self):
|
||||
self.__connection.unbind()
|
||||
|
||||
#end class
|
||||
|
||||
class LdapResult(object):
|
||||
dn = None
|
||||
|
||||
def __init__(self, dn, var_dict):
|
||||
self.__dict__ = var_dict
|
||||
self.dn = dn
|
||||
#end def
|
||||
|
||||
def has(self, attribute_name):
|
||||
return attribute_name in self.__dict__
|
||||
#end def
|
||||
|
||||
def get(self, name):
|
||||
if name in self.__dict__:
|
||||
return self.__dict__[name]
|
||||
else:
|
||||
return self.__getattr__(name)
|
||||
#end if
|
||||
#end def
|
||||
|
||||
def __getattr__(self, name):
|
||||
return None
|
||||
#end def
|
||||
|
||||
#end class
|
||||
|
||||
class LdapValue(object):
|
||||
name = None
|
||||
values = []
|
||||
|
||||
def __init__(self, name, values):
|
||||
self.values = [value.decode("utf-8") for value in values]
|
||||
self.name = name
|
||||
#end def
|
||||
|
||||
def first(self, default = None):
|
||||
for value in self.values:
|
||||
return value
|
||||
#end for
|
||||
|
||||
return default
|
||||
#end def
|
||||
#end class
|
||||
|
62
Brie/brie/model/__init__.py
Normal file
62
Brie/brie/model/__init__.py
Normal file
@ -0,0 +1,62 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""The application's model objects"""
|
||||
|
||||
from zope.sqlalchemy import ZopeTransactionExtension
|
||||
from sqlalchemy.orm import scoped_session, sessionmaker
|
||||
#from sqlalchemy import MetaData
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
|
||||
# Global session manager: DBSession() returns the Thread-local
|
||||
# session object appropriate for the current web request.
|
||||
maker = sessionmaker(autoflush=True, autocommit=False,
|
||||
extension=ZopeTransactionExtension())
|
||||
DBSession = scoped_session(maker)
|
||||
|
||||
# Base class for all of our model classes: By default, the data model is
|
||||
# defined with SQLAlchemy's declarative extension, but if you need more
|
||||
# control, you can switch to the traditional method.
|
||||
DeclarativeBase = declarative_base()
|
||||
|
||||
# There are two convenient ways for you to spare some typing.
|
||||
# You can have a query property on all your model classes by doing this:
|
||||
# DeclarativeBase.query = DBSession.query_property()
|
||||
# Or you can use a session-aware mapper as it was used in TurboGears 1:
|
||||
# DeclarativeBase = declarative_base(mapper=DBSession.mapper)
|
||||
|
||||
# Global metadata.
|
||||
# The default metadata is the one from the declarative base.
|
||||
metadata = DeclarativeBase.metadata
|
||||
|
||||
# If you have multiple databases with overlapping table names, you'll need a
|
||||
# metadata for each database. Feel free to rename 'metadata2'.
|
||||
#metadata2 = MetaData()
|
||||
|
||||
#####
|
||||
# Generally you will not want to define your table's mappers, and data objects
|
||||
# here in __init__ but will want to create modules them in the model directory
|
||||
# and import them at the bottom of this file.
|
||||
#
|
||||
######
|
||||
|
||||
def init_model(engine):
|
||||
"""Call me before using any of the tables or classes in the model."""
|
||||
|
||||
DBSession.configure(bind=engine)
|
||||
# If you are using reflection to introspect your database and create
|
||||
# table objects for you, your tables must be defined and mapped inside
|
||||
# the init_model function, so that the engine is available if you
|
||||
# use the model outside tg2, you need to make sure this is called before
|
||||
# you use the model.
|
||||
|
||||
#
|
||||
# See the following example:
|
||||
|
||||
#global t_reflected
|
||||
|
||||
#t_reflected = Table("Reflected", metadata,
|
||||
# autoload=True, autoload_with=engine)
|
||||
|
||||
#mapper(Reflected, t_reflected)
|
||||
|
||||
# Import your model modules here.
|
||||
from brie.model.auth import User, Group, Permission
|
232
Brie/brie/model/auth.py
Normal file
232
Brie/brie/model/auth.py
Normal file
@ -0,0 +1,232 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Auth* related model.
|
||||
|
||||
This is where the models used by :mod:`repoze.who` and :mod:`repoze.what` are
|
||||
defined.
|
||||
|
||||
It's perfectly fine to re-use this definition in the Brie application,
|
||||
though.
|
||||
|
||||
"""
|
||||
import os
|
||||
from datetime import datetime
|
||||
import sys
|
||||
try:
|
||||
from hashlib import sha1
|
||||
except ImportError:
|
||||
sys.exit('ImportError: No module named hashlib\n'
|
||||
'If you are on python2.4 this library is not part of python. '
|
||||
'Please install it. Example: easy_install hashlib')
|
||||
|
||||
from sqlalchemy import Table, ForeignKey, Column
|
||||
from sqlalchemy.types import Unicode, Integer, DateTime
|
||||
from sqlalchemy.orm import relation, synonym
|
||||
|
||||
from brie.model import DeclarativeBase, metadata, DBSession
|
||||
|
||||
__all__ = ['User', 'Group', 'Permission']
|
||||
|
||||
|
||||
#{ Association tables
|
||||
|
||||
|
||||
# This is the association table for the many-to-many relationship between
|
||||
# groups and permissions. This is required by repoze.what.
|
||||
group_permission_table = Table('tg_group_permission', metadata,
|
||||
Column('group_id', Integer, ForeignKey('tg_group.group_id',
|
||||
onupdate="CASCADE", ondelete="CASCADE")),
|
||||
Column('permission_id', Integer, ForeignKey('tg_permission.permission_id',
|
||||
onupdate="CASCADE", ondelete="CASCADE"))
|
||||
)
|
||||
|
||||
# This is the association table for the many-to-many relationship between
|
||||
# groups and members - this is, the memberships. It's required by repoze.what.
|
||||
user_group_table = Table('tg_user_group', metadata,
|
||||
Column('user_id', Integer, ForeignKey('tg_user.user_id',
|
||||
onupdate="CASCADE", ondelete="CASCADE")),
|
||||
Column('group_id', Integer, ForeignKey('tg_group.group_id',
|
||||
onupdate="CASCADE", ondelete="CASCADE"))
|
||||
)
|
||||
|
||||
|
||||
#{ The auth* model itself
|
||||
|
||||
|
||||
class Group(DeclarativeBase):
|
||||
"""
|
||||
Group definition for :mod:`repoze.what`.
|
||||
|
||||
Only the ``group_name`` column is required by :mod:`repoze.what`.
|
||||
|
||||
"""
|
||||
|
||||
__tablename__ = 'tg_group'
|
||||
|
||||
#{ Columns
|
||||
|
||||
group_id = Column(Integer, autoincrement=True, primary_key=True)
|
||||
|
||||
group_name = Column(Unicode(16), unique=True, nullable=False)
|
||||
|
||||
display_name = Column(Unicode(255))
|
||||
|
||||
created = Column(DateTime, default=datetime.now)
|
||||
|
||||
#{ Relations
|
||||
|
||||
users = relation('User', secondary=user_group_table, backref='groups')
|
||||
|
||||
#{ Special methods
|
||||
|
||||
def __repr__(self):
|
||||
return '<Group: name=%s>' % self.group_name
|
||||
|
||||
def __unicode__(self):
|
||||
return self.group_name
|
||||
|
||||
#}
|
||||
|
||||
|
||||
# The 'info' argument we're passing to the email_address and password columns
|
||||
# contain metadata that Rum (http://python-rum.org/) can use generate an
|
||||
# admin interface for your models.
|
||||
class User(DeclarativeBase):
|
||||
"""
|
||||
User definition.
|
||||
|
||||
This is the user definition used by :mod:`repoze.who`, which requires at
|
||||
least the ``user_name`` column.
|
||||
|
||||
"""
|
||||
__tablename__ = 'tg_user'
|
||||
|
||||
#{ Columns
|
||||
|
||||
user_id = Column(Integer, autoincrement=True, primary_key=True)
|
||||
|
||||
user_name = Column(Unicode(16), unique=True, nullable=False)
|
||||
|
||||
email_address = Column(Unicode(255), unique=True, nullable=False,
|
||||
info={'rum': {'field':'Email'}})
|
||||
|
||||
display_name = Column(Unicode(255))
|
||||
|
||||
_password = Column('password', Unicode(80),
|
||||
info={'rum': {'field':'Password'}})
|
||||
|
||||
created = Column(DateTime, default=datetime.now)
|
||||
|
||||
#{ Special methods
|
||||
|
||||
def __repr__(self):
|
||||
return '<User: email="%s", display name="%s">' % (
|
||||
self.email_address, self.display_name)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.display_name or self.user_name
|
||||
|
||||
#{ Getters and setters
|
||||
|
||||
@property
|
||||
def permissions(self):
|
||||
"""Return a set of strings for the permissions granted."""
|
||||
perms = set()
|
||||
for g in self.groups:
|
||||
perms = perms | set(g.permissions)
|
||||
return perms
|
||||
|
||||
@classmethod
|
||||
def by_email_address(cls, email):
|
||||
"""Return the user object whose email address is ``email``."""
|
||||
return DBSession.query(cls).filter(cls.email_address==email).first()
|
||||
|
||||
@classmethod
|
||||
def by_user_name(cls, username):
|
||||
"""Return the user object whose user name is ``username``."""
|
||||
return DBSession.query(cls).filter(cls.user_name==username).first()
|
||||
|
||||
def _set_password(self, password):
|
||||
"""Hash ``password`` on the fly and store its hashed version."""
|
||||
hashed_password = password
|
||||
|
||||
if isinstance(password, unicode):
|
||||
password_8bit = password.encode('UTF-8')
|
||||
else:
|
||||
password_8bit = password
|
||||
|
||||
salt = sha1()
|
||||
salt.update(os.urandom(60))
|
||||
hash = sha1()
|
||||
hash.update(password_8bit + salt.hexdigest())
|
||||
hashed_password = salt.hexdigest() + hash.hexdigest()
|
||||
|
||||
# Make sure the hashed password is an UTF-8 object at the end of the
|
||||
# process because SQLAlchemy _wants_ a unicode object for Unicode
|
||||
# columns
|
||||
if not isinstance(hashed_password, unicode):
|
||||
hashed_password = hashed_password.decode('UTF-8')
|
||||
|
||||
self._password = hashed_password
|
||||
|
||||
def _get_password(self):
|
||||
"""Return the hashed version of the password."""
|
||||
return self._password
|
||||
|
||||
password = synonym('_password', descriptor=property(_get_password,
|
||||
_set_password))
|
||||
|
||||
#}
|
||||
|
||||
def validate_password(self, password):
|
||||
"""
|
||||
Check the password against existing credentials.
|
||||
|
||||
:param password: the password that was provided by the user to
|
||||
try and authenticate. This is the clear text version that we will
|
||||
need to match against the hashed one in the database.
|
||||
:type password: unicode object.
|
||||
:return: Whether the password is valid.
|
||||
:rtype: bool
|
||||
|
||||
"""
|
||||
hashed_pass = sha1()
|
||||
hashed_pass.update(password + self.password[:40])
|
||||
return self.password[40:] == hashed_pass.hexdigest()
|
||||
|
||||
|
||||
class Permission(DeclarativeBase):
|
||||
"""
|
||||
Permission definition for :mod:`repoze.what`.
|
||||
|
||||
Only the ``permission_name`` column is required by :mod:`repoze.what`.
|
||||
|
||||
"""
|
||||
|
||||
__tablename__ = 'tg_permission'
|
||||
|
||||
#{ Columns
|
||||
|
||||
permission_id = Column(Integer, autoincrement=True, primary_key=True)
|
||||
|
||||
permission_name = Column(Unicode(16), unique=True, nullable=False)
|
||||
|
||||
description = Column(Unicode(255))
|
||||
|
||||
#{ Relations
|
||||
|
||||
groups = relation(Group, secondary=group_permission_table,
|
||||
backref='permissions')
|
||||
|
||||
#{ Special methods
|
||||
|
||||
def __repr__(self):
|
||||
return '<Permission: name=%s>' % self.permission_name
|
||||
|
||||
def __unicode__(self):
|
||||
return self.permission_name
|
||||
|
||||
#}
|
||||
|
||||
|
||||
#}
|
144
Brie/brie/model/camembert.py
Normal file
144
Brie/brie/model/camembert.py
Normal file
@ -0,0 +1,144 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Sample model module."""
|
||||
|
||||
from sqlalchemy import *
|
||||
from sqlalchemy.orm import mapper, relation
|
||||
from sqlalchemy import Table, ForeignKey, Column
|
||||
from sqlalchemy.types import Integer, Unicode
|
||||
from sqlalchemy.dialects.postgresql import MACADDR, INET, BOOLEAN, DATE
|
||||
#from sqlalchemy.orm import relation, backref
|
||||
|
||||
from brie.model import DeclarativeBase, metadata, DBSession
|
||||
|
||||
|
||||
class Materiel(DeclarativeBase):
|
||||
__tablename__ = 'materiel'
|
||||
|
||||
#{ Columns
|
||||
|
||||
idmateriel = Column(Integer, primary_key=True)
|
||||
|
||||
hostname = Column(Unicode(64))
|
||||
manageable = Column(Integer)
|
||||
snmpversion = Column(Integer)
|
||||
type = Column(Unicode(64))
|
||||
ostype = Column(Unicode(512))
|
||||
capabilities = Column(Integer)
|
||||
datecreation = Column(Integer)
|
||||
datelast = Column(Integer)
|
||||
|
||||
#}
|
||||
|
||||
class Room(DeclarativeBase):
|
||||
__tablename__ = "room"
|
||||
|
||||
idroom = Column(Integer, primary_key=True)
|
||||
|
||||
idinterface = Column(Integer)
|
||||
name = Column(Unicode(32))
|
||||
|
||||
class Computer(DeclarativeBase):
|
||||
__tablename__ = "computer"
|
||||
|
||||
idcomp = Column(Integer, primary_key = True)
|
||||
|
||||
name = Column(Unicode(32), nullable = False)
|
||||
mac = Column(MACADDR, nullable = False)
|
||||
iduser = Column(Integer)
|
||||
ip = Column(INET)
|
||||
#end class
|
||||
|
||||
class UserPacaterie(DeclarativeBase):
|
||||
__tablename__ = "user_pac"
|
||||
|
||||
iduser = Column(Integer, primary_key = True)
|
||||
|
||||
nom = Column(Unicode(64), nullable = False)
|
||||
prenom = Column(Unicode(64), nullable = False)
|
||||
datedeco = Column(DATE, nullable = False)
|
||||
mail = Column(Unicode(64))
|
||||
certif = Column(BOOLEAN, nullable = False)
|
||||
idroom = Column(Integer)
|
||||
special_case = Column(BOOLEAN)
|
||||
comment = Column(Unicode(64))
|
||||
#end class
|
||||
|
||||
class Ip(DeclarativeBase):
|
||||
__tablename__ = "ip"
|
||||
|
||||
ip = Column(INET, primary_key = True)
|
||||
idmateriel = Column(Integer, primary_key = True)
|
||||
main = Column(BOOLEAN)
|
||||
datecreation = Column(Integer)
|
||||
datelast = Column(Integer)
|
||||
#end class
|
||||
|
||||
class IpUser(DeclarativeBase):
|
||||
__tablename__ = "ip_user"
|
||||
|
||||
ip = Column(INET, primary_key = True)
|
||||
free = Column(BOOLEAN)
|
||||
#end class
|
||||
|
||||
class Fdb(DeclarativeBase):
|
||||
__tablename__ = "fdb"
|
||||
|
||||
idinterface = Column(Integer, primary_key = True)
|
||||
vlan = Column(Integer, primary_key = True)
|
||||
mac = Column(MACADDR, primary_key = True)
|
||||
datefirst = Column(Integer)
|
||||
datelast = Column(Integer)
|
||||
type = Column(Integer)
|
||||
#end class
|
||||
|
||||
class Action(DeclarativeBase):
|
||||
__tablename__ = "action"
|
||||
|
||||
idaction = Column(Integer, primary_key = True)
|
||||
idinterface = Column(Integer)
|
||||
numaction = Column(Integer, nullable = False)
|
||||
option = Column(Unicode(256))
|
||||
#end class
|
||||
|
||||
class ActionLog(DeclarativeBase):
|
||||
__tablename__ = "action_log"
|
||||
|
||||
idlog = Column(Integer, primary_key = True)
|
||||
loggeduser = Column(Unicode(64), nullable = False)
|
||||
logdate = Column(Integer, nullable = False)
|
||||
idinterface = Column(Integer)
|
||||
numaction = Column(Integer, nullable = False)
|
||||
oldoption = Column(Unicode(256))
|
||||
newoption = Column(Unicode(256))
|
||||
iduser = Column(Integer)
|
||||
amount = Column(Unicode(64))
|
||||
#end class
|
||||
|
||||
class Interface(DeclarativeBase):
|
||||
__tablename__ = "interface"
|
||||
|
||||
idinterface = Column(Integer, primary_key = True)
|
||||
idmateriel = Column(Integer, nullable = False)
|
||||
ifnumber = Column(Integer, nullable = False)
|
||||
ifname = Column(Unicode(64))
|
||||
ifdescription = Column(Unicode(256))
|
||||
ifaddress = Column(MACADDR)
|
||||
ifspeed = Column(Integer)
|
||||
ifadminstatus = Column(Integer)
|
||||
ifoperstatus = Column(Integer)
|
||||
iftype = Column(Integer)
|
||||
ifvlan = Column(Integer)
|
||||
ifvoicevlan = Column(Integer)
|
||||
ifnativevlan = Column(Integer)
|
||||
ifmodule = Column(Integer)
|
||||
ifport = Column(Integer)
|
||||
portdot1d = Column(Integer)
|
||||
portfast = Column(BOOLEAN)
|
||||
portsecenable = Column(BOOLEAN)
|
||||
portsecstatus = Column(Integer)
|
||||
portsecmaxmac = Column(Integer)
|
||||
portseccurrmac = Column(Integer)
|
||||
portsecviolation = Column(Integer)
|
||||
portseclastsrcaddr = Column(MACADDR)
|
||||
portsecsticky = Column(BOOLEAN)
|
||||
#end class
|
59
Brie/brie/model/ldap.py
Normal file
59
Brie/brie/model/ldap.py
Normal file
@ -0,0 +1,59 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from brie.config import ldap_config
|
||||
|
||||
class Member(object):
|
||||
|
||||
@staticmethod
|
||||
def get_by_dn(user_session, dn):
|
||||
return user_session.ldap_bind.search_dn(dn)
|
||||
#end def
|
||||
|
||||
@staticmethod
|
||||
def get_by_uid(user_session, uid):
|
||||
return user_session.ldap_bind.search_first(ldap_config.username_base_dn, "(uid=" + uid + ")")
|
||||
#end def
|
||||
|
||||
#end class
|
||||
|
||||
class Room(object):
|
||||
|
||||
@staticmethod
|
||||
def get_by_name(user_session, name):
|
||||
return user_session.ldap_bind.search_first(ldap_config.room_base_dn, "(&" + ldap_config.room_filter + "(cn=" + name + "))")
|
||||
#end def
|
||||
|
||||
@staticmethod
|
||||
def get_by_uid(user_session, uid):
|
||||
return user_session.ldap_bind.search_first(ldap_config.room_base_dn, "(&" + ldap_config.room_filter + "(uid=" + uid + "))")
|
||||
#end def
|
||||
|
||||
@staticmethod
|
||||
def get_by_member_dn(user_session, dn):
|
||||
return user_session.ldap_bind.search_first(ldap_config.room_base_dn, "(&" + ldap_config.room_filter + "(x-memberIn=" + dn + "))")
|
||||
#end def
|
||||
|
||||
@staticmethod
|
||||
def get_by_interface(user_session, interface_id):
|
||||
return user_session.ldap_bind.search_first(ldap_config.room_base_dn, "(&" + ldap_config.room_filter + "(x-switchInterface=" + str(interface_id) + "))")
|
||||
|
||||
#end class
|
||||
|
||||
|
||||
class Wifi(object):
|
||||
|
||||
@staticmethod
|
||||
def entry_attr(password):
|
||||
return {
|
||||
"objectClass" : ["top", "organizationalRole", "simpleSecurityObject"],
|
||||
"cn" : "wifi",
|
||||
"userPassword" : password
|
||||
}
|
||||
#end def
|
||||
|
||||
@staticmethod
|
||||
def get_by_dn(user_session, dn):
|
||||
return user_session.ldap_bind.search_first("cn=wifi," + dn)
|
||||
#end def
|
||||
|
||||
#end class
|
22
Brie/brie/model/model.template
Normal file
22
Brie/brie/model/model.template
Normal file
@ -0,0 +1,22 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Sample model module."""
|
||||
|
||||
from sqlalchemy import *
|
||||
from sqlalchemy.orm import mapper, relation
|
||||
from sqlalchemy import Table, ForeignKey, Column
|
||||
from sqlalchemy.types import Integer, Unicode
|
||||
#from sqlalchemy.orm import relation, backref
|
||||
|
||||
from brie.model import DeclarativeBase, metadata, DBSession
|
||||
|
||||
|
||||
class SampleModel(DeclarativeBase):
|
||||
__tablename__ = 'sample_model'
|
||||
|
||||
#{ Columns
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
|
||||
data = Column(Unicode(255), nullable=False)
|
||||
|
||||
#}
|
31
Brie/brie/public/css/common.css
Normal file
31
Brie/brie/public/css/common.css
Normal file
@ -0,0 +1,31 @@
|
||||
html {
|
||||
font-family: sans-serif;
|
||||
color: #444444;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #444444;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: white;
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
.section {
|
||||
font-family: sans-serif;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.section_name, .section_name_no_caps {
|
||||
color: grey;
|
||||
font-weight: bold;
|
||||
margin-bottom: 6px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.section_name {
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
68
Brie/brie/public/css/rooms.css
Normal file
68
Brie/brie/public/css/rooms.css
Normal file
@ -0,0 +1,68 @@
|
||||
html {
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #444444;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: white;
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.floor_name {
|
||||
color: lightgrey;
|
||||
}
|
||||
|
||||
.room_number, .interface_status {
|
||||
display: inline-block;
|
||||
color: #444444;
|
||||
font-weight: bold;
|
||||
padding: 3px;
|
||||
margin: 2px;
|
||||
}
|
||||
|
||||
.area {
|
||||
width: 1300px
|
||||
}
|
||||
|
||||
.preview_part {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.preview_name {
|
||||
color: #444444;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.ok_color {
|
||||
background-color: #D1F2C4
|
||||
}
|
||||
|
||||
.vide_color {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.non_certif_color {
|
||||
background-color: #F2E1C4;
|
||||
}
|
||||
|
||||
.non_paye_color {
|
||||
background-color: #F2C4C4;
|
||||
}
|
||||
|
||||
.shut_color {
|
||||
background-color: lightgray;
|
||||
}
|
||||
|
||||
.violation_color {
|
||||
background-color: #F2C4C4;
|
||||
}
|
||||
|
||||
.rooms_legend {
|
||||
float: right;
|
||||
}
|
12
Brie/brie/public/css/show.css
Normal file
12
Brie/brie/public/css/show.css
Normal file
@ -0,0 +1,12 @@
|
||||
.show_section_name {
|
||||
margin-left: 200px;
|
||||
}
|
||||
|
||||
.item_name {
|
||||
width: 196px;
|
||||
color: #A0A0A0;
|
||||
display: inline-block;
|
||||
height: 22px;
|
||||
text-align: right;
|
||||
padding-right: 4px;
|
||||
}
|
303
Brie/brie/public/css/style.css
Normal file
303
Brie/brie/public/css/style.css
Normal file
@ -0,0 +1,303 @@
|
||||
html {
|
||||
background: #555555 url('../images/pagebg.png') top left repeat-x;
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
text-align: left;
|
||||
width: 960px;
|
||||
margin: 0 auto;
|
||||
padding: 0;
|
||||
font-size: 12px;
|
||||
font-family:"Lucida Grande","Lucida Sans Unicode",geneva,verdana,sans-serif;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #286571;
|
||||
}
|
||||
|
||||
#header {
|
||||
height: 132px;
|
||||
margin: 10px 10px 0 10px;
|
||||
background: url('../images/headerbg.png') top left no-repeat;
|
||||
}
|
||||
|
||||
#header h1 {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
padding-top: 30px;
|
||||
padding-left: 180px;
|
||||
color: #fff;
|
||||
position: relative;
|
||||
font-size: 36px;
|
||||
}
|
||||
|
||||
#header h1 .subtitle {
|
||||
font-size: 60%;
|
||||
position: absolute;
|
||||
left: 240px;
|
||||
top: 70px;
|
||||
}
|
||||
|
||||
ul#mainmenu {
|
||||
margin: 0;
|
||||
padding: 0 10px;
|
||||
background: url('../images/menubg.png') top left no-repeat;
|
||||
height: 38px;
|
||||
}
|
||||
|
||||
ul#mainmenu li {
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
display: inline;
|
||||
float: left;
|
||||
}
|
||||
|
||||
ul#mainmenu li a {
|
||||
color: #fff;
|
||||
float: left;
|
||||
height: 31px;
|
||||
display: block;
|
||||
line-height: 30px;
|
||||
vertical-align: middle;
|
||||
padding: 0 10px;
|
||||
font-size: 12px;
|
||||
text-decoration: none;
|
||||
background: url('../images/menu-item-border.png') left top no-repeat;
|
||||
}
|
||||
|
||||
ul#mainmenu li a:hover, ul#mainmenu li a.active {
|
||||
background: url('../images/menu-item-actibg.png') left top no-repeat;
|
||||
}
|
||||
|
||||
ul#mainmenu li.first a {
|
||||
background: none;
|
||||
}
|
||||
|
||||
ul#mainmenu li.first a:hover, ul#mainmenu li.first a.active {
|
||||
background: url('../images/menu-item-actibg-first.png') left top no-repeat;
|
||||
}
|
||||
|
||||
ul#mainmenu li.loginlogout
|
||||
{
|
||||
float: right;
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
ul#mainmenu li.loginlogout a:hover
|
||||
{
|
||||
background: url('../images/menu-item-border.png') left top no-repeat;
|
||||
}
|
||||
|
||||
#content {
|
||||
background: #fff url('../images/contentbg.png') left bottom no-repeat;
|
||||
margin : 0 10px 10px 10px;
|
||||
padding: 0 10px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#content .currentpage {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
/* Login form*/
|
||||
|
||||
#loginform
|
||||
{
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
form.loginfields
|
||||
{
|
||||
text-align: left;
|
||||
width: 270px;
|
||||
background: url('../images/loginbg.png') top left no-repeat;
|
||||
padding: 0;
|
||||
margin: 0 auto;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
form.loginfields h2
|
||||
{
|
||||
font-size: 16px;
|
||||
float: left;
|
||||
padding: 0;
|
||||
margin: 5px;
|
||||
margin-top: 0;
|
||||
background: url('../images/loginheader-left.png') top left no-repeat;
|
||||
}
|
||||
|
||||
* html form.loginfields h2
|
||||
{
|
||||
margin-left: 3px;
|
||||
width: 80px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
form.loginfields h2 span
|
||||
{
|
||||
background: url('../images/loginheader-right.png') right top no-repeat;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
display: block;
|
||||
font-size: 100%;
|
||||
font-weight: normal;
|
||||
color: #fff;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
*+html form.loginfields h2 span
|
||||
{
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
form.loginfields label
|
||||
{
|
||||
clear: left;
|
||||
float: left;
|
||||
margin-top: 5px;
|
||||
margin-left: 10px;
|
||||
width: 65px;
|
||||
line-height: 31px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
form.loginfields input.text
|
||||
{
|
||||
float: left;
|
||||
margin-left: 10px;
|
||||
margin-top: 5px;
|
||||
width: 165px;
|
||||
height: 21px;
|
||||
padding: 5px;
|
||||
border: 0;
|
||||
background: url('../images/inputbg.png') top left no-repeat;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
form.loginfields input#submit
|
||||
{
|
||||
background: url('../images/loginbottombg.png') bottom left no-repeat;
|
||||
width: 270px;
|
||||
height: 61px;
|
||||
border: 0;
|
||||
margin-top: 10px;
|
||||
color: #fff;
|
||||
padding: 10px 140px 20px 10px;
|
||||
}
|
||||
|
||||
* html form.loginfields input#submit
|
||||
{
|
||||
clear: both;
|
||||
margin-left: -10px;
|
||||
}
|
||||
|
||||
/* Sidebar */
|
||||
.sidebar {
|
||||
border: 1px solid #cce;
|
||||
background-color: #eee;
|
||||
margin: 0.5em;
|
||||
margin-left: 1.5em;
|
||||
padding: 1em;
|
||||
float: right;
|
||||
width: 200px;
|
||||
font-size: 88%;
|
||||
}
|
||||
|
||||
.sidebar h2 {
|
||||
margin-top: 0;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.sidebar ul {
|
||||
margin-left: 1.5em;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#sb_top {
|
||||
clear: right;
|
||||
}
|
||||
|
||||
#sb_bottom {
|
||||
clear: right;
|
||||
}
|
||||
|
||||
#getting_started {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
#getting_started_steps a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#getting_started_steps a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
#getting_started_steps li {
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
/* Other and footer */
|
||||
#footer {
|
||||
background: #fff;
|
||||
padding: 10px;
|
||||
color:#888888;
|
||||
font-size:90%;
|
||||
}
|
||||
.flogo {
|
||||
float:left;
|
||||
margin-bottom:0px;
|
||||
padding-left:20px;
|
||||
padding-right:20px;
|
||||
padding-top:0px;
|
||||
}
|
||||
.foottext p {
|
||||
margin: 0; padding: 0;
|
||||
}
|
||||
.code {
|
||||
font-family:monospace;
|
||||
font-size:127%;
|
||||
}
|
||||
span.code {
|
||||
background:#EEEEEE none repeat scroll 0% 0%;
|
||||
font-weight:bold;
|
||||
}
|
||||
#flash, .notice {
|
||||
font-size:120%;
|
||||
font-weight:bolder;
|
||||
margin:0pt auto 0.5em;
|
||||
width:680px;
|
||||
}
|
||||
#flash div, .notice {
|
||||
padding:20px 15px 20px 65px;
|
||||
}
|
||||
#flash .ok {
|
||||
background:#d8ecd8 url(../images/ok.png) no-repeat scroll 10px center;
|
||||
}
|
||||
#flash .warning {
|
||||
background:#fff483 url(../images/warning.png) no-repeat scroll 10px center;
|
||||
}
|
||||
#flash .error {
|
||||
background:#f9c5c1 url(../images/error.png) no-repeat scroll 10px center;
|
||||
}
|
||||
#flash .alert,
|
||||
#flash .info {
|
||||
background:#EEEEFF url(../images/info.png) no-repeat scroll 10px center;
|
||||
}
|
||||
.notice {
|
||||
background:#EEEEFF url(../images/info.png) no-repeat scroll 10px center;
|
||||
}
|
||||
.fielderror {
|
||||
color:red;
|
||||
font-weight:bold;
|
||||
}
|
||||
div.clearingdiv {
|
||||
clear:both;
|
||||
}
|
BIN
Brie/brie/public/favicon.ico
Normal file
BIN
Brie/brie/public/favicon.ico
Normal file
Binary file not shown.
2
Brie/brie/templates/__init__.py
Normal file
2
Brie/brie/templates/__init__.py
Normal file
@ -0,0 +1,2 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Templates package for the application."""
|
0
Brie/brie/templates/auth/__init__.py
Normal file
0
Brie/brie/templates/auth/__init__.py
Normal file
16
Brie/brie/templates/auth/login.html
Normal file
16
Brie/brie/templates/auth/login.html
Normal file
@ -0,0 +1,16 @@
|
||||
<html>
|
||||
<body>
|
||||
<form action="/auth/login" method="post">
|
||||
<p class="error">${error}</p>
|
||||
<div>
|
||||
<span>Nom d'utilisateur</span>
|
||||
<input name="username" type="text" value="${login}" />
|
||||
</div>
|
||||
<div>
|
||||
<span>Nom d'utilisateur</span>
|
||||
<input name="password" type="password" />
|
||||
</div>
|
||||
<input type="submit" value="connexion"/>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
0
Brie/brie/templates/edit/__init__.py
Normal file
0
Brie/brie/templates/edit/__init__.py
Normal file
6
Brie/brie/templates/edit/error.html
Normal file
6
Brie/brie/templates/edit/error.html
Normal file
@ -0,0 +1,6 @@
|
||||
<html
|
||||
xmlns:py="http://genshi.edgewall.org/"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
>
|
||||
<span class="section_name">${error}</span>
|
||||
</html>
|
23
Brie/brie/templates/edit/member.html
Normal file
23
Brie/brie/templates/edit/member.html
Normal file
@ -0,0 +1,23 @@
|
||||
<html
|
||||
xmlns:py="http://genshi.edgewall.org/"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
<xi:include href="member_room_interface_edit_views.html" />
|
||||
<head>
|
||||
<link type="text/css" rel="Stylesheet" href="/css/common.css" />
|
||||
<link type="text/css" rel="Stylesheet" href="/css/show.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div py:choose="member_ldap">
|
||||
<span class="section_name" py:when="None">Entrée inexistante</span>
|
||||
<div py:otherwise="">${member_view(member_ldap)}</div>
|
||||
</div>
|
||||
<div py:choose="room">
|
||||
<span class="section_name" py:when="None">Pas de chambre associée</span>
|
||||
<div py:otherwise="">${room_view(room)}</div>
|
||||
</div>
|
||||
<div py:choose="interface">
|
||||
<span class="section_name" py:when="None">Pas d'interface associée</span>
|
||||
<div py:otherwise="">${interface_view(interface)}</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
133
Brie/brie/templates/edit/member_room_interface_edit_views.html
Normal file
133
Brie/brie/templates/edit/member_room_interface_edit_views.html
Normal file
@ -0,0 +1,133 @@
|
||||
<html
|
||||
xmlns:py="http://genshi.edgewall.org/"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
py:strip="">
|
||||
<py:def function="member_view(member_ldap)">
|
||||
<div class="section">
|
||||
<span class="section_name show_section_name">${member_ldap.cn.first()}</span>
|
||||
<div>
|
||||
<div>
|
||||
<span class="item_name">Fin de connexion</span>
|
||||
<span py:choose="member_ldap.get('x-connectionEnd')">
|
||||
<span py:when="None">Pas de fin de connexion</span>
|
||||
<span py:otherwise="">${member_ldap.get("x-connectionEnd").first()}</span>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="item_name">E-mail</span>
|
||||
<input type="text" value="${member_ldap.mail.first('')}" />
|
||||
</div>
|
||||
<div>
|
||||
<span class="item_name">Certificat</span>
|
||||
<py:with vars="certif = member_ldap.get('x-certificatGiven')">
|
||||
<span py:choose="">
|
||||
<span py:when="certif is not None and certif.first() == 'TRUE'">oui</span>
|
||||
<span py:otherwise="">non</span>
|
||||
</span>
|
||||
</py:with>
|
||||
</div>
|
||||
<div>
|
||||
<span class="item_name">Commentaire</span>
|
||||
<span py:choose="member_ldap.get('x-comment')">
|
||||
<span py:when="None"></span>
|
||||
<span py:otherwise="">${member_ldap.get("x-comment").first()}</span>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="item_name">Cas spécial</span>
|
||||
<py:with vars="cas_spec = member_ldap.get('x-specialCase')">
|
||||
<span py:choose="">
|
||||
<span py:when="cas_spec is not None and cas_spec.first() == 'TRUE'">oui</span>
|
||||
<span py:otherwise="">non</span>
|
||||
</span>
|
||||
</py:with>
|
||||
</div>
|
||||
<div>
|
||||
<span class="item_name">Wifi</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</py:def>
|
||||
|
||||
<py:def function="room_view(room, member_in = None)">
|
||||
<div class="section">
|
||||
<span class="section_name show_section_name">CHAMBRE ${room.cn.first()}</span>
|
||||
<div>
|
||||
<div py:if="member_in is not None">
|
||||
<span class="item_name">Membre</span>
|
||||
<span>
|
||||
<a href="/show/member/${member_in.uid.first()}">${member_in.cn.first()}</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</py:def>
|
||||
|
||||
<py:def function="interface_view(interface, room_attached = None)">
|
||||
<div class="section">
|
||||
<span class="section_name show_section_name">INFOS INTERFACE</span>
|
||||
<div>
|
||||
<div>
|
||||
<span class="item_name">Nombre de mac max</span>
|
||||
<span>${interface.portsecmaxmac}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="item_name">Violation</span>
|
||||
<span>${interface.portsecviolation}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section">
|
||||
<span class="section_name show_section_name">INFOS AVANCÉES</span>
|
||||
<div>
|
||||
<div>
|
||||
<span class="item_name">ifNumber</span>
|
||||
<span>${interface.ifnumber}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="item_name">ifAddress</span>
|
||||
<span>${interface.ifaddress}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="item_name">ifType</span>
|
||||
<span>${interface.iftype}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="item_name">Description</span>
|
||||
<span>${interface.ifdescription}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="item_name">Etat</span>
|
||||
<span py:choose="interface.ifoperstatus">
|
||||
<span py:when="1">Up</span>
|
||||
<span py:when="0">Down</span>
|
||||
<span py:when="2">Error</span>
|
||||
<span py:otherwise="">Inconnu</span>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="item_name">Vitesse</span>
|
||||
<span py:choose="interface.ifspeed">
|
||||
<span py:when="10000000">10 Mb/s</span>
|
||||
<span py:when="100000000">100 Mb/s</span>
|
||||
<span py:when="1000000000">1 Gb/s</span>
|
||||
<span py:otherwise="">interface.ifspeed</span>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="item_name">Vlan</span>
|
||||
<span>${interface.ifvlan}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="item_name">Native Vlan</span>
|
||||
<span>${interface.ifnativevlan}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="item_name">SpanningTree Portfast</span>
|
||||
<span>${interface.portfast}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</py:def>
|
||||
</html>
|
||||
|
19
Brie/brie/templates/edit/room.html
Normal file
19
Brie/brie/templates/edit/room.html
Normal file
@ -0,0 +1,19 @@
|
||||
<html
|
||||
xmlns:py="http://genshi.edgewall.org/"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
<xi:include href="member_room_interface_views.html" />
|
||||
<head>
|
||||
<link type="text/css" rel="Stylesheet" href="/css/common.css" />
|
||||
<link type="text/css" rel="Stylesheet" href="/css/show.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div py:choose="room">
|
||||
<span class="section_name" py:when="None">Pas de chambre associée</span>
|
||||
<div py:otherwise="">${room_view(room, member_ldap)}</div>
|
||||
</div>
|
||||
<div py:choose="interface">
|
||||
<span class="section_name" py:when="None">Pas d'interface associée</span>
|
||||
<div py:otherwise="">${interface_view(interface)}</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
10
Brie/brie/templates/index.html
Normal file
10
Brie/brie/templates/index.html
Normal file
@ -0,0 +1,10 @@
|
||||
<html xmlns:py="http://genshi.edgewall.org/" xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
<xi:include href="login_widget.html" />
|
||||
<body>
|
||||
<div>${login_widget(user)}</div>
|
||||
<h1>Test</h1>
|
||||
<div py:for="item in materiel">
|
||||
<span>${item.hostname}</span>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
17
Brie/brie/templates/login_widget.html
Normal file
17
Brie/brie/templates/login_widget.html
Normal file
@ -0,0 +1,17 @@
|
||||
<html
|
||||
xmlns:py="http://genshi.edgewall.org/"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
py:strip=""
|
||||
>
|
||||
<py:def function="login_widget(user)">
|
||||
<div py:choose="">
|
||||
<div py:when="user is None">
|
||||
<a href="${tg.url('/auth/login')}">Connection</a>
|
||||
</div>
|
||||
<div py:otherwise="">
|
||||
<span>${user.attrs.cn.first()}</span>
|
||||
<a href="${tg.url('/auth/logout')}">Deconnection</a>
|
||||
</div>
|
||||
</div>
|
||||
</py:def>
|
||||
</html>
|
2
Brie/brie/templates/models/__init__.py
Normal file
2
Brie/brie/templates/models/__init__.py
Normal file
@ -0,0 +1,2 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Templates package for the application."""
|
132
Brie/brie/templates/models/about.html
Normal file
132
Brie/brie/templates/models/about.html
Normal file
@ -0,0 +1,132 @@
|
||||
<!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"
|
||||
xmlns:py="http://genshi.edgewall.org/"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
|
||||
<xi:include href="master.html" />
|
||||
|
||||
<head>
|
||||
<meta content="text/html; charset=UTF-8" http-equiv="content-type" py:replace="''"/>
|
||||
<title>Learning TurboGears 2.0: Quick guide to the Quickstart pages.</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
${sidebar_top()}
|
||||
${sidebar_bottom()}
|
||||
<div id="getting_started">
|
||||
<h2>Architectural basics of a quickstart TG2 site.</h2>
|
||||
<p>The TG2 quickstart command produces this basic TG site. Here's how it works.</p>
|
||||
<ol id="getting_started_steps">
|
||||
<li class="getting_started">
|
||||
<h3>Code my data model</h3>
|
||||
<p> When you want a model for storing favorite links or wiki content,
|
||||
the <strong>/model</strong> folder in your site is ready to go.</p>
|
||||
<p> You can build a dynamic site without any data model at all. There
|
||||
still be a default data-model template for you if you didn't enable
|
||||
authentication and authorization in quickstart. If you enabled
|
||||
it, you got auth data-model made for you.</p>
|
||||
</li>
|
||||
<li class="getting_started">
|
||||
<h3>Design my URL structure</h3>
|
||||
<p> The "<span class="code">root.py</span>" file under the
|
||||
<strong>/controllers</strong> folder has your URLs. When you
|
||||
called this url (<span class="code"><a href="${tg.url('/about')}">about</a></span>),
|
||||
the command went through the RootController class to the
|
||||
<span class="code">about</span><span class="code">()</span> method.</p>
|
||||
<p> Those Python methods are responsible to create the dictionary of
|
||||
variables that will be used in your web views (template).</p>
|
||||
</li>
|
||||
<li class="getting_started">
|
||||
<h3>Reuse the web page elements</h3>
|
||||
<p> A web page viewed by user could be constructed by single or
|
||||
several reusable templates under <strong>/templates</strong>.
|
||||
Take 'about' page for example, each reusable templates generating
|
||||
a part of the page. We'll cover them in the order of where they are
|
||||
found, listed near the top of the about.html template</p>
|
||||
<p> <strong><span class="code">header.html</span></strong> - The
|
||||
"header.html" template contains the HTML code to display the
|
||||
'header': The blue gradient, TG2 logo, and some site text at the
|
||||
top of every page it is included on. When the "about.html" template
|
||||
is called, it includes this "header.html" template (and the others)
|
||||
with a <span class="code"><xi:include /></span> tag, part of
|
||||
the Genshi templating system. The "header.html" template is not a
|
||||
completely static HTML -- it also dynamically displays the current
|
||||
page name with a Genshi template method called "replace" with the
|
||||
code: <span class="code"><span py:replace="page"/></span>.
|
||||
It means replace this <span class="code"><span /></span>
|
||||
region with the contents found in the variable 'page' that has
|
||||
been sent in the dictionary to this "about.html" template, and is
|
||||
available through that namespace for use by this "header.html"
|
||||
template. That's how it changes in the header depending on what
|
||||
page you are visiting.
|
||||
</p>
|
||||
<p> <strong><span class="code">sidebars.html</span></strong> - The
|
||||
sidebars (navigation areas on the right side of the page) are
|
||||
generated as two separate <span class="code">py:def</span> blocks
|
||||
in the "sidebars.html" template. The <span class="code">py:def</span>
|
||||
construct is best thought of as a "macro" code... a simple way to
|
||||
separate and reuse common code snippets. All it takes to include
|
||||
these on the "about.html" page template is to write
|
||||
<span class="code">
|
||||
<br/><br/>
|
||||
$${sidebar_top()}
|
||||
<br/>
|
||||
$${sidebar_bottom()}
|
||||
<br/><br/>
|
||||
</span> in the page where they are wanted. CSS styling (in
|
||||
"/public/css/style.css") floats them off to the right side. You can
|
||||
remove a sidebar or add more of them, and the CSS will place them one
|
||||
atop the other.</p>
|
||||
<p>This is, of course, also exactly how the header and footer
|
||||
templates are also displayed in their proper places, but we'll
|
||||
cover that in the "master.html" template below.</p>
|
||||
<p>Oh, and in sidebar_top we've added a dynamic menu that shows the
|
||||
link to this page at the top when you're at the "index" page, and
|
||||
shows a link to the Home (index) page when you're here. Study the
|
||||
"sidebars.html" template to see how we used
|
||||
<span class="code">py:choose</span> for that.</p>
|
||||
<p> <strong><span class="code">footer.html</span></strong> - The
|
||||
"footer.html" block is simple, but also utilizes a special
|
||||
"replace" method to set the current YEAR in the footer copyright
|
||||
message. The code is:
|
||||
<span class="code"><span py:replace="now.strftime('%Y')">
|
||||
</span> and it uses the variable "now" that was passed
|
||||
in with the dictionary of variables. But because "now" is a
|
||||
datetime object, we can use the Python
|
||||
<span class="code">"strftime()"</span> method with the "replace"
|
||||
call to say "Just Display The Year Here". Simple, elegant; we
|
||||
format the date display in the template (the View in the
|
||||
Model/View/Controller architecture) rather than formatting it in
|
||||
the Controller method and sending it to the template as a string
|
||||
variable.</p>
|
||||
<p> <strong><span class="code">master.html</span></strong> - The
|
||||
"master.html" template is called last, by design. The "master.html"
|
||||
template controls the overall design of the page we're looking at,
|
||||
calling first the "header" py:def macro, then the putting everything
|
||||
from this "about.html" template into the "content" div, and
|
||||
then calling the "footer" macro at the end. Thus the "master.html"
|
||||
template provides the overall architecture for each page in this
|
||||
site.</p>
|
||||
<p>But why then shouldn't we call it first? Isn't it the most
|
||||
important? Perhaps, but that's precisely why we call it LAST.
|
||||
The "master.html" template needs to know where to find everything
|
||||
else, everything that it will use in py:def macros to build the
|
||||
page. So that means we call the other templates first, and then
|
||||
call "master.html". </p>
|
||||
<p>There's more to the "master.html" template... study it to see how
|
||||
the <title> tags and static JS and CSS files are brought into
|
||||
the page. Templating with Genshi is a powerful tool and we've only
|
||||
scratched the surface. There are also a few little CSS tricks
|
||||
hidden in these pages, like the use of a "clearingdiv" to make
|
||||
sure that your footer stays below the sidebars and always looks
|
||||
right. That's not TG2 at work, just CSS. You'll need all your
|
||||
skills to build a fine web app, but TG2 will make the hard parts
|
||||
easier so that you can concentrate more on good design and content
|
||||
rather than struggling with mechanics.</p>
|
||||
</li>
|
||||
</ol>
|
||||
<p>Good luck with TurboGears 2!</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
67
Brie/brie/templates/models/authentication.html
Normal file
67
Brie/brie/templates/models/authentication.html
Normal file
@ -0,0 +1,67 @@
|
||||
<!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"
|
||||
xmlns:py="http://genshi.edgewall.org/"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
|
||||
<xi:include href="master.html" />
|
||||
|
||||
<head>
|
||||
<meta content="text/html; charset=UTF-8" http-equiv="content-type" py:replace="''"/>
|
||||
<title>Learning TurboGears 2.0: Quick guide to authentication.</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
${sidebar_top()}
|
||||
${sidebar_bottom()}
|
||||
<div id="getting_started">
|
||||
<h2>Authentication & Authorization in a TG2 site.</h2>
|
||||
<p>If you have access to this page, this means you have enabled authentication and authorization
|
||||
in the quickstart to create your project.</p>
|
||||
<p>
|
||||
The paster command will have created a few specific controllers for you. But before you
|
||||
go to play with those controllers you'll need to make sure your application has been
|
||||
properly bootstapped.
|
||||
This is dead easy, here is how to do this:
|
||||
</p>
|
||||
|
||||
<span class="code">
|
||||
paster setup-app development.ini
|
||||
</span>
|
||||
|
||||
<p>
|
||||
inside your application's folder and you'll get a database setup (using the preferences you have
|
||||
set in your development.ini file). This database will also have been prepopulated with some
|
||||
default logins/passwords so that you can test the secured controllers and methods.
|
||||
</p>
|
||||
<p>
|
||||
To change the comportement of this setup-app command you just need to edit the <span class="code">websetup.py</span> file.
|
||||
</p>
|
||||
<p>
|
||||
Now try to visiting the <a href="${tg.url('/manage_permission_only')}">manage_permission_only</a> URL. You will be challenged with a login/password form.
|
||||
</p>
|
||||
<p>
|
||||
Only managers are authorized to visit this method. You will need to log-in using:
|
||||
<p>
|
||||
<span class="code">
|
||||
login: manager
|
||||
</span>
|
||||
</p>
|
||||
<p>
|
||||
<span class="code">
|
||||
password: managepass
|
||||
</span>
|
||||
</p>
|
||||
</p>
|
||||
<p>
|
||||
Another protected resource is <a href="${tg.url('/editor_user_only')}">editor_user_only</a>. This one is protected by a different set of permissions.
|
||||
You will need to be <span class="code">editor</span> with a password of <span class="code">editpass</span> to be able to access it.
|
||||
</p>
|
||||
<p>
|
||||
The last kind of protected resource in this quickstarted app is a full so called <a href="${tg.url('/secc')}">secure controller</a>. This controller is protected globally.
|
||||
Instead of having a @require decorator on each method, we have set an allow_only attribute at the class level. All the methods in this controller will
|
||||
require the same level of access. You need to be manager to access <a href="${tg.url('/secc')}">secc</a> or <a href="${tg.url('/secc/some_where')}">secc/some_where</a>.
|
||||
</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
20
Brie/brie/templates/models/debug.html
Normal file
20
Brie/brie/templates/models/debug.html
Normal file
@ -0,0 +1,20 @@
|
||||
<!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"
|
||||
xmlns:py="http://genshi.edgewall.org/"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
|
||||
<xi:include href="master.html" />
|
||||
|
||||
<head>
|
||||
<meta content="text/html; charset=UTF-8" http-equiv="content-type" py:replace="''"/>
|
||||
<title>Sample Template, for looking at template locals</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>All objects from locals():</h1>
|
||||
|
||||
<div py:for="item in sorted(locals()['data'].keys())">
|
||||
${item}: ${repr(locals()['data'][item])}</div>
|
||||
</body>
|
||||
</html>
|
19
Brie/brie/templates/models/error.html
Normal file
19
Brie/brie/templates/models/error.html
Normal file
@ -0,0 +1,19 @@
|
||||
<!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"
|
||||
xmlns:py="http://genshi.edgewall.org/"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
|
||||
<xi:include href="master.html" />
|
||||
|
||||
<head>
|
||||
<meta content="text/html; charset=UTF-8" http-equiv="content-type" py:replace="''"/>
|
||||
<title>A ${code} Error has Occurred </title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Error ${code}</h1>
|
||||
|
||||
<div>${XML(message)}</div>
|
||||
</body>
|
||||
</html>
|
17
Brie/brie/templates/models/footer.html
Normal file
17
Brie/brie/templates/models/footer.html
Normal file
@ -0,0 +1,17 @@
|
||||
<html xmlns:py="http://genshi.edgewall.org/"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
py:strip="">
|
||||
<py:def function="footer">
|
||||
<div id="footer">
|
||||
<div class="flogo">
|
||||
<img src="${tg.url('/images/under_the_hood_blue.png')}" alt="TurboGears" />
|
||||
<p><a href="http://www.turbogears.org/2.0/">Powered by TurboGears 2</a></p>
|
||||
</div>
|
||||
<div class="foottext">
|
||||
<p>TurboGears is a open source front-to-back web development
|
||||
framework written in Python. Copyright (c) 2005-2008 </p>
|
||||
</div>
|
||||
<div class="clearingdiv"></div>
|
||||
</div>
|
||||
</py:def>
|
||||
</html>
|
12
Brie/brie/templates/models/header.html
Normal file
12
Brie/brie/templates/models/header.html
Normal file
@ -0,0 +1,12 @@
|
||||
<html xmlns:py="http://genshi.edgewall.org/"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
py:strip="">
|
||||
<py:def function="header">
|
||||
<div id="header">
|
||||
<h1>
|
||||
Welcome to TurboGears 2
|
||||
<span class="subtitle">The Python web metaframework</span>
|
||||
</h1>
|
||||
</div>
|
||||
</py:def>
|
||||
</html>
|
40
Brie/brie/templates/models/index.html
Normal file
40
Brie/brie/templates/models/index.html
Normal file
@ -0,0 +1,40 @@
|
||||
<!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"
|
||||
xmlns:py="http://genshi.edgewall.org/"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
|
||||
<xi:include href="master.html" />
|
||||
|
||||
<head>
|
||||
<meta content="text/html; charset=UTF-8" http-equiv="content-type" py:replace="''"/>
|
||||
<title>Welcome to TurboGears 2.0, standing on the
|
||||
shoulders of giants, since 2007</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
${sidebar_top()}
|
||||
<div id="getting_started">
|
||||
<h2>Presentation</h2>
|
||||
<p>TurboGears 2 is rapid web application development toolkit designed to make your life easier.</p>
|
||||
<ol id="getting_started_steps">
|
||||
<li class="getting_started">
|
||||
<h3>Code your data model</h3>
|
||||
<p> Design your data model, Create the database, and Add some bootstrap data.</p>
|
||||
</li>
|
||||
<li class="getting_started">
|
||||
<h3>Design your URL architecture</h3>
|
||||
<p> Decide your URLs, Program your controller methods, Design your
|
||||
templates, and place some static files (CSS and/or JavaScript). </p>
|
||||
</li>
|
||||
<li class="getting_started">
|
||||
<h3>Distribute your app</h3>
|
||||
<p> Test your source, Generate project documents, Build a distribution.</p>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
<div class="clearingdiv" />
|
||||
<div class="notice"> Thank you for choosing TurboGears.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
24
Brie/brie/templates/models/login.html
Normal file
24
Brie/brie/templates/models/login.html
Normal file
@ -0,0 +1,24 @@
|
||||
<!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"
|
||||
xmlns:py="http://genshi.edgewall.org/"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
|
||||
<xi:include href="master.html" />
|
||||
|
||||
<head>
|
||||
<meta content="text/html; charset=UTF-8" http-equiv="content-type" py:replace="''"/>
|
||||
<title>Login Form</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="loginform">
|
||||
<form action="${tg.url('/login_handler', came_from = came_from.encode('utf-8'), __logins = login_counter.encode('utf-8'))}" method="POST" class="loginfields">
|
||||
<h2><span>Login</span></h2>
|
||||
<label for="login">Username:</label><input type="text" id="login" name="login" class="text"></input><br/>
|
||||
<label for="password">Password:</label><input type="password" id="password" name="password" class="text"></input>
|
||||
<input type="submit" id="submit" value="Login" />
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
44
Brie/brie/templates/models/master.html
Normal file
44
Brie/brie/templates/models/master.html
Normal file
@ -0,0 +1,44 @@
|
||||
<!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"
|
||||
xmlns:py="http://genshi.edgewall.org/"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
py:strip="">
|
||||
<xi:include href="header.html" />
|
||||
<xi:include href="sidebars.html" />
|
||||
<xi:include href="footer.html" />
|
||||
<head py:match="head" py:attrs="select('@*')">
|
||||
<meta content="text/html; charset=UTF-8" http-equiv="content-type" py:replace="''"/>
|
||||
<title py:replace="''">Your title goes here</title>
|
||||
<meta py:replace="select('*')"/>
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="${tg.url('/css/style.css')}" />
|
||||
</head>
|
||||
|
||||
<body py:match="body" py:attrs="select('@*')">
|
||||
${header()}
|
||||
<ul id="mainmenu">
|
||||
<li class="first"><a href="${tg.url('/')}" class="${('', 'active')[defined('page') and page==page=='index']}">Welcome</a></li>
|
||||
<li><a href="${tg.url('/about')}" class="${('', 'active')[defined('page') and page==page=='about']}">About</a></li>
|
||||
<li py:if="tg.auth_stack_enabled"><a href="${tg.url('/auth')}" class="${('', 'active')[defined('page') and page==page=='auth']}">Authentication</a></li>
|
||||
<li><a href="http://groups.google.com/group/turbogears">Contact</a></li>
|
||||
<span py:if="tg.auth_stack_enabled" py:strip="True">
|
||||
<li py:if="not request.identity" id="login" class="loginlogout"><a href="${tg.url('/login')}">Login</a></li>
|
||||
<li py:if="request.identity" id="login" class="loginlogout"><a href="${tg.url('/logout_handler')}">Logout</a></li>
|
||||
<li py:if="request.identity" id="admin" class="loginlogout"><a href="${tg.url('/admin')}">Admin</a></li>
|
||||
</span>
|
||||
</ul>
|
||||
<div id="content">
|
||||
<py:if test="defined('page')">
|
||||
<div class="currentpage">
|
||||
Now Viewing: <span py:replace="page"/>
|
||||
</div>
|
||||
</py:if>
|
||||
<py:with vars="flash=tg.flash_obj.render('flash', use_js=False)">
|
||||
<div py:if="flash" py:content="XML(flash)" />
|
||||
</py:with>
|
||||
<div py:replace="select('*|text()')"/>
|
||||
<!-- End of content -->
|
||||
${footer()}
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
38
Brie/brie/templates/models/sidebars.html
Normal file
38
Brie/brie/templates/models/sidebars.html
Normal file
@ -0,0 +1,38 @@
|
||||
<html xmlns:py="http://genshi.edgewall.org/"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
py:strip="">
|
||||
|
||||
<py:def function="sidebar_top">
|
||||
<div id="sb_top" class="sidebar">
|
||||
<h2>Get Started with TG2</h2>
|
||||
<ul class="links">
|
||||
<li py:choose="">
|
||||
<span py:when="defined('page') and page=='index'">
|
||||
<a href="${tg.url('/about')}">About this page</a>
|
||||
A quick guide to this TG2 site
|
||||
</span>
|
||||
<span py:otherwise=""><a href="${tg.url('/')}">Home</a> Back to your Quickstart Home page </span>
|
||||
</li>
|
||||
<li><a href="http://www.turbogears.org/2.0/docs/">TG2 Documents</a> - Read everything in the Getting Started section</li>
|
||||
<li><a href="http://docs.turbogears.org/1.0">TG1 docs</a> (still useful, although a lot has changed for TG2) </li>
|
||||
<li><a href="http://groups.google.com/group/turbogears"> Join the TG Mail List</a> for general TG use/topics </li>
|
||||
</ul>
|
||||
</div>
|
||||
</py:def>
|
||||
|
||||
<py:def function="sidebar_bottom">
|
||||
<div id="sb_bottom" class="sidebar">
|
||||
<h2>Developing TG2</h2>
|
||||
<ul class="links">
|
||||
<li><a href="http://docs.turbogears.org/2.0/RoughDocs/">More TG2 Documents</a> in progress</li>
|
||||
<li><a href="http://trac.turbogears.org/query?status=new&status=assigned&status=reopened&group=type&milestone=2.0&order=priority">TG2 Trac tickets</a> What's happening now in TG2 development</li>
|
||||
<li><a href="http://trac.turbogears.org/timeline">TG Dev timeline</a> (recent ticket updates, svn checkins, wiki changes)</li>
|
||||
<li><a href="http://svn.turbogears.org/trunk">TG2 SVN repository</a> For checking out a copy</li>
|
||||
<li><a href="http://turbogears.org/2.0/docs/main/Contributing.html#installing-the-development-version-of-turbogears-2-from-source">Follow these instructions</a> For installing your copy</li>
|
||||
<li><a href="http://trac.turbogears.org/browser/trunk">TG2 Trac's svn view</a> In case you need a quick look</li>
|
||||
<li><a href="http://groups.google.com/group/turbogears-trunk"> Join the TG-Trunk Mail List</a> for TG2 discuss/dev </li>
|
||||
</ul>
|
||||
</div>
|
||||
</py:def>
|
||||
|
||||
</html>
|
0
Brie/brie/templates/rooms/__init__.py
Normal file
0
Brie/brie/templates/rooms/__init__.py
Normal file
61
Brie/brie/templates/rooms/index.html
Normal file
61
Brie/brie/templates/rooms/index.html
Normal file
@ -0,0 +1,61 @@
|
||||
<html
|
||||
xmlns:py="http://genshi.edgewall.org/"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
>
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="/css/rooms.css" />
|
||||
<link rel="stylesheet" type="text/css" href="/css/common.css" />
|
||||
</head>
|
||||
<div class="rooms_legend">
|
||||
<py:def function="display_stat(name)">
|
||||
<div class="room_number ${name}">${"%03d" % stats[name]}</div>
|
||||
</py:def>
|
||||
<div>
|
||||
${display_stat("ok_color")}
|
||||
<span>ordinateurs connectés</span>
|
||||
</div>
|
||||
<div>
|
||||
${display_stat("non_certif_color")}
|
||||
<span>certifs manquants</span>
|
||||
</div>
|
||||
<div>
|
||||
${display_stat("non_paye_color")}
|
||||
<span>fins de connexions passées</span>
|
||||
</div>
|
||||
<div>
|
||||
${display_stat("vide_color")}
|
||||
<span>chambres vides</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="area section">
|
||||
<span class="section_name">PREVIEW</span>
|
||||
<div py:if="defined('preview')">
|
||||
<py:with vars="member_ldap, room_preview, interface_preview = preview">
|
||||
<div class="room_number ${color_picker(interface_preview.ifdescription)}">
|
||||
<span><a href="/show/room/${room_preview.uid.first()}">${room_preview.cn.first()}</a></span>
|
||||
</div>
|
||||
<div class="preview_part preview_name" py:choose="member_ldap is not None">
|
||||
<span py:when="True"><a href="/show/member/${member_ldap.uid.first()}">${member_ldap.cn.first()}</a></span>
|
||||
<span py:otherwise=""><a href="/show/room/${room_preview.uid.first()}">Chambre Vide</a></span>
|
||||
</div>
|
||||
<div class="preview_part" py:choose="">
|
||||
<span py:when="interface_preview.ifoperstatus == 1" class="interface_status ok_color">Ordinateur branché</span>
|
||||
<span py:when="interface_preview.portsecviolation == 1" class="interface_status violation_color">Violation mac</span>
|
||||
<span py:when="interface_preview.ifoperstatus == 0" class="interface_status shut_color">Ordinateur débranché</span>
|
||||
<span py:when="interface_preview.portsecstatus == 3" class="interface_status violation_color">Inteface éteinte</span>
|
||||
</div>
|
||||
</py:with>
|
||||
</div>
|
||||
</div>
|
||||
<div py:for="area_name, floors in sorted_name(areas.iteritems())" class="area section">
|
||||
<div>
|
||||
<span class="section_name">${("Aile " + area_name).upper()}</span>
|
||||
<div py:for="floor_name, rooms in reverse_sorted_name(floors.iteritems())" class="floor">
|
||||
<span class="floor_name">étage ${floor_name}</span>
|
||||
<div py:for="room, interface in rooms" class="room_number ${color_picker(interface.ifdescription)}">
|
||||
<a href="/rooms/preview/${room.uid.first()}"><span>${room.cn.first()}</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</html>
|
0
Brie/brie/templates/show/__init__.py
Normal file
0
Brie/brie/templates/show/__init__.py
Normal file
6
Brie/brie/templates/show/error.html
Normal file
6
Brie/brie/templates/show/error.html
Normal file
@ -0,0 +1,6 @@
|
||||
<html
|
||||
xmlns:py="http://genshi.edgewall.org/"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
>
|
||||
<span class="section_name">${error}</span>
|
||||
</html>
|
23
Brie/brie/templates/show/member.html
Normal file
23
Brie/brie/templates/show/member.html
Normal file
@ -0,0 +1,23 @@
|
||||
<html
|
||||
xmlns:py="http://genshi.edgewall.org/"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
<xi:include href="member_room_interface_views.html" />
|
||||
<head>
|
||||
<link type="text/css" rel="Stylesheet" href="/css/common.css" />
|
||||
<link type="text/css" rel="Stylesheet" href="/css/show.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div py:choose="member_ldap">
|
||||
<span class="section_name" py:when="None">Entrée inexistante</span>
|
||||
<div py:otherwise="">${member_view(member_ldap)}</div>
|
||||
</div>
|
||||
<div py:choose="room_ldap">
|
||||
<span class="section_name" py:when="None">Pas de chambre associée</span>
|
||||
<div py:otherwise="">${room_view(room_ldap)}</div>
|
||||
</div>
|
||||
<div py:choose="interface">
|
||||
<span class="section_name" py:when="None">Pas d'interface associée</span>
|
||||
<div py:otherwise="">${interface_view(interface)}</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
133
Brie/brie/templates/show/member_room_interface_views.html
Normal file
133
Brie/brie/templates/show/member_room_interface_views.html
Normal file
@ -0,0 +1,133 @@
|
||||
<html
|
||||
xmlns:py="http://genshi.edgewall.org/"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
py:strip="">
|
||||
<py:def function="member_view(member_ldap)">
|
||||
<div class="section">
|
||||
<span class="section_name show_section_name">${member_ldap.cn.first()}</span>
|
||||
<div>
|
||||
<div>
|
||||
<span class="item_name">Fin de connexion</span>
|
||||
<span py:choose="member_ldap.get('x-connectionEnd')">
|
||||
<span py:when="None">Pas de fin de connexion</span>
|
||||
<span py:otherwise="">${member_ldap.get("x-connectionEnd").first()}</span>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="item_name">E-mail</span>
|
||||
<span>${member_ldap.mail.first('')}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="item_name">Certificat</span>
|
||||
<py:with vars="certif = member_ldap.get('x-certificatGiven')">
|
||||
<span py:choose="">
|
||||
<span py:when="certif is not None and certif.first() == 'TRUE'">oui</span>
|
||||
<span py:otherwise="">non</span>
|
||||
</span>
|
||||
</py:with>
|
||||
</div>
|
||||
<div>
|
||||
<span class="item_name">Commentaire</span>
|
||||
<span py:choose="member_ldap.get('x-comment')">
|
||||
<span py:when="None"></span>
|
||||
<span py:otherwise="">${member_ldap.get("x-comment").first()}</span>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="item_name">Cas spécial</span>
|
||||
<py:with vars="cas_spec = member_ldap.get('x-specialCase')">
|
||||
<span py:choose="">
|
||||
<span py:when="cas_spec is not None and cas_spec.first() == 'TRUE'">oui</span>
|
||||
<span py:otherwise="">non</span>
|
||||
</span>
|
||||
</py:with>
|
||||
</div>
|
||||
<div>
|
||||
<span class="item_name">Wifi</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</py:def>
|
||||
|
||||
<py:def function="room_view(room, member_in = None)">
|
||||
<div class="section">
|
||||
<span class="section_name show_section_name">CHAMBRE ${room.cn.first()}</span>
|
||||
<div>
|
||||
<div py:if="member_in is not None">
|
||||
<span class="item_name">Membre</span>
|
||||
<span>
|
||||
<a href="/show/member/${member_in.uid.first()}">${member_in.cn.first()}</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</py:def>
|
||||
|
||||
<py:def function="interface_view(interface, room_attached = None)">
|
||||
<div class="section">
|
||||
<span class="section_name show_section_name">INFOS INTERFACE</span>
|
||||
<div>
|
||||
<div>
|
||||
<span class="item_name">Nombre de mac max</span>
|
||||
<span>${interface.portsecmaxmac}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="item_name">Violation</span>
|
||||
<span>${interface.portsecviolation}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section">
|
||||
<span class="section_name show_section_name">INFOS AVANCÉES</span>
|
||||
<div>
|
||||
<div>
|
||||
<span class="item_name">ifNumber</span>
|
||||
<span>${interface.ifnumber}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="item_name">ifAddress</span>
|
||||
<span>${interface.ifaddress}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="item_name">ifType</span>
|
||||
<span>${interface.iftype}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="item_name">Description</span>
|
||||
<span>${interface.ifdescription}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="item_name">Etat</span>
|
||||
<span py:choose="interface.ifoperstatus">
|
||||
<span py:when="1">Up</span>
|
||||
<span py:when="0">Down</span>
|
||||
<span py:when="2">Error</span>
|
||||
<span py:otherwise="">Inconnu</span>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="item_name">Vitesse</span>
|
||||
<span py:choose="interface.ifspeed">
|
||||
<span py:when="10000000">10 Mb/s</span>
|
||||
<span py:when="100000000">100 Mb/s</span>
|
||||
<span py:when="1000000000">1 Gb/s</span>
|
||||
<span py:otherwise="">interface.ifspeed</span>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="item_name">Vlan</span>
|
||||
<span>${interface.ifvlan}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="item_name">Native Vlan</span>
|
||||
<span>${interface.ifnativevlan}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="item_name">SpanningTree Portfast</span>
|
||||
<span>${interface.portfast}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</py:def>
|
||||
</html>
|
||||
|
19
Brie/brie/templates/show/room.html
Normal file
19
Brie/brie/templates/show/room.html
Normal file
@ -0,0 +1,19 @@
|
||||
<html
|
||||
xmlns:py="http://genshi.edgewall.org/"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
<xi:include href="member_room_interface_views.html" />
|
||||
<head>
|
||||
<link type="text/css" rel="Stylesheet" href="/css/common.css" />
|
||||
<link type="text/css" rel="Stylesheet" href="/css/show.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div py:choose="room_ldap">
|
||||
<span class="section_name" py:when="None">Pas de chambre associée</span>
|
||||
<div py:otherwise="">${room_view(room_ldap, member_ldap)}</div>
|
||||
</div>
|
||||
<div py:choose="interface">
|
||||
<span class="section_name" py:when="None">Pas d'interface associée</span>
|
||||
<div py:otherwise="">${interface_view(interface)}</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
64
Brie/brie/tests/__init__.py
Normal file
64
Brie/brie/tests/__init__.py
Normal file
@ -0,0 +1,64 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Unit and functional test suite for Brie."""
|
||||
|
||||
from os import path
|
||||
import sys
|
||||
|
||||
from tg import config
|
||||
from paste.deploy import loadapp
|
||||
from paste.script.appinstall import SetupCommand
|
||||
from routes import url_for
|
||||
from webtest import TestApp
|
||||
from nose.tools import eq_
|
||||
|
||||
from brie import model
|
||||
|
||||
__all__ = ['setup_db', 'teardown_db', 'TestController', 'url_for']
|
||||
|
||||
def setup_db():
|
||||
"""Method used to build a database"""
|
||||
engine = config['pylons.app_globals'].sa_engine
|
||||
model.init_model(engine)
|
||||
model.metadata.create_all(engine)
|
||||
|
||||
def teardown_db():
|
||||
"""Method used to destroy a database"""
|
||||
engine = config['pylons.app_globals'].sa_engine
|
||||
model.metadata.drop_all(engine)
|
||||
|
||||
|
||||
class TestController(object):
|
||||
"""
|
||||
Base functional test case for the controllers.
|
||||
|
||||
The Brie application instance (``self.app``) set up in this test
|
||||
case (and descendants) has authentication disabled, so that developers can
|
||||
test the protected areas independently of the :mod:`repoze.who` plugins
|
||||
used initially. This way, authentication can be tested once and separately.
|
||||
|
||||
Check brie.tests.functional.test_authentication for the repoze.who
|
||||
integration tests.
|
||||
|
||||
This is the officially supported way to test protected areas with
|
||||
repoze.who-testutil (http://code.gustavonarea.net/repoze.who-testutil/).
|
||||
|
||||
"""
|
||||
|
||||
application_under_test = 'main_without_authn'
|
||||
|
||||
def setUp(self):
|
||||
"""Method called by nose before running each test"""
|
||||
# Loading the application:
|
||||
conf_dir = config.here
|
||||
wsgiapp = loadapp('config:test.ini#%s' % self.application_under_test,
|
||||
relative_to=conf_dir)
|
||||
self.app = TestApp(wsgiapp)
|
||||
# Setting it up:
|
||||
test_file = path.join(conf_dir, 'test.ini')
|
||||
cmd = SetupCommand('setup-app')
|
||||
cmd.run([test_file])
|
||||
|
||||
def tearDown(self):
|
||||
"""Method called by nose after running each test"""
|
||||
# Cleaning up the database:
|
||||
teardown_db()
|
2
Brie/brie/tests/functional/__init__.py
Normal file
2
Brie/brie/tests/functional/__init__.py
Normal file
@ -0,0 +1,2 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Functional test suite for the controllers of the application."""
|
86
Brie/brie/tests/functional/test_authentication.py
Normal file
86
Brie/brie/tests/functional/test_authentication.py
Normal file
@ -0,0 +1,86 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Integration tests for the :mod:`repoze.who`-powered authentication sub-system.
|
||||
|
||||
As Brie grows and the authentication method changes, only these tests
|
||||
should be updated.
|
||||
|
||||
"""
|
||||
|
||||
from brie.tests import TestController
|
||||
|
||||
|
||||
class TestAuthentication(TestController):
|
||||
"""
|
||||
Tests for the default authentication setup.
|
||||
|
||||
By default in TurboGears 2, :mod:`repoze.who` is configured with the same
|
||||
plugins specified by repoze.what-quickstart (which are listed in
|
||||
http://code.gustavonarea.net/repoze.what-quickstart/#repoze.what.plugins.quickstart.setup_sql_auth).
|
||||
|
||||
As the settings for those plugins change, or the plugins are replaced,
|
||||
these tests should be updated.
|
||||
|
||||
"""
|
||||
|
||||
application_under_test = 'main'
|
||||
|
||||
def test_forced_login(self):
|
||||
"""
|
||||
Anonymous users must be redirected to the login form when authorization
|
||||
is denied.
|
||||
|
||||
Next, upon successful login they should be redirected to the initially
|
||||
requested page.
|
||||
|
||||
"""
|
||||
# Requesting a protected area
|
||||
resp = self.app.get('/secc/', status=302)
|
||||
assert resp.location.startswith('http://localhost/login')
|
||||
# Getting the login form:
|
||||
resp = resp.follow(status=200)
|
||||
form = resp.form
|
||||
# Submitting the login form:
|
||||
form['login'] = u'manager'
|
||||
form['password'] = 'managepass'
|
||||
post_login = form.submit(status=302)
|
||||
# Being redirected to the initially requested page:
|
||||
assert post_login.location.startswith('http://localhost/post_login')
|
||||
initial_page = post_login.follow(status=302)
|
||||
assert 'authtkt' in initial_page.request.cookies, \
|
||||
"Session cookie wasn't defined: %s" % initial_page.request.cookies
|
||||
assert initial_page.location.startswith('http://localhost/secc/'), \
|
||||
initial_page.location
|
||||
|
||||
def test_voluntary_login(self):
|
||||
"""Voluntary logins must work correctly"""
|
||||
# Going to the login form voluntarily:
|
||||
resp = self.app.get('/login', status=200)
|
||||
form = resp.form
|
||||
# Submitting the login form:
|
||||
form['login'] = u'manager'
|
||||
form['password'] = 'managepass'
|
||||
post_login = form.submit(status=302)
|
||||
# Being redirected to the home page:
|
||||
assert post_login.location.startswith('http://localhost/post_login')
|
||||
home_page = post_login.follow(status=302)
|
||||
assert 'authtkt' in home_page.request.cookies, \
|
||||
'Session cookie was not defined: %s' % home_page.request.cookies
|
||||
assert home_page.location == 'http://localhost/'
|
||||
|
||||
def test_logout(self):
|
||||
"""Logouts must work correctly"""
|
||||
# Logging in voluntarily the quick way:
|
||||
resp = self.app.get('/login_handler?login=manager&password=managepass',
|
||||
status=302)
|
||||
resp = resp.follow(status=302)
|
||||
assert 'authtkt' in resp.request.cookies, \
|
||||
'Session cookie was not defined: %s' % resp.request.cookies
|
||||
# Logging out:
|
||||
resp = self.app.get('/logout_handler', status=302)
|
||||
assert resp.location.startswith('http://localhost/post_logout')
|
||||
# Finally, redirected to the home page:
|
||||
home_page = resp.follow(status=302)
|
||||
assert home_page.request.cookies.get('authtkt') == '', \
|
||||
'Session cookie was not deleted: %s' % home_page.request.cookies
|
||||
assert home_page.location == 'http://localhost/', home_page.location
|
49
Brie/brie/tests/functional/test_root.py
Normal file
49
Brie/brie/tests/functional/test_root.py
Normal file
@ -0,0 +1,49 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Functional test suite for the root controller.
|
||||
|
||||
This is an example of how functional tests can be written for controllers.
|
||||
|
||||
As opposed to a unit-test, which test a small unit of functionality,
|
||||
functional tests exercise the whole application and its WSGI stack.
|
||||
|
||||
Please read http://pythonpaste.org/webtest/ for more information.
|
||||
|
||||
"""
|
||||
from nose.tools import assert_true
|
||||
|
||||
from brie.tests import TestController
|
||||
|
||||
|
||||
class TestRootController(TestController):
|
||||
def test_index(self):
|
||||
response = self.app.get('/')
|
||||
msg = 'TurboGears 2 is rapid web application development toolkit '\
|
||||
'designed to make your life easier.'
|
||||
# You can look for specific strings:
|
||||
assert_true(msg in response)
|
||||
|
||||
# You can also access a BeautifulSoup'ed response in your tests
|
||||
# (First run $ easy_install BeautifulSoup
|
||||
# and then uncomment the next two lines)
|
||||
|
||||
#links = response.html.findAll('a')
|
||||
#print links
|
||||
#assert_true(links, "Mummy, there are no links here!")
|
||||
def test_secc_with_manager(self):
|
||||
"""Only the manager can access the secure controller"""
|
||||
# Note how authentication is forged:
|
||||
environ = {'REMOTE_USER': 'manager'}
|
||||
resp = self.app.get('/secc', extra_environ=environ, status=200)
|
||||
assert 'Secure Controller here' in resp.body, resp.body
|
||||
|
||||
def test_secc_with_editor(self):
|
||||
"""The editor shouldn't access the secure controller"""
|
||||
environ = {'REMOTE_USER': 'editor'}
|
||||
self.app.get('/secc', extra_environ=environ, status=403)
|
||||
# It's enough to know that authorization was denied with a 403 status
|
||||
|
||||
def test_secc_with_anonymous(self):
|
||||
"""Anonymous users must not access the secure controller"""
|
||||
self.app.get('/secc', status=401)
|
||||
# It's enough to know that authorization was denied with a 401 status
|
52
Brie/brie/tests/models/__init__.py
Normal file
52
Brie/brie/tests/models/__init__.py
Normal file
@ -0,0 +1,52 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Unit test suite for the models of the application."""
|
||||
from nose.tools import assert_equals
|
||||
|
||||
from brie.model import DBSession
|
||||
from brie.tests import setup_db, teardown_db
|
||||
|
||||
__all__ = ['ModelTest']
|
||||
|
||||
#Create an empty database before we start our tests for this module
|
||||
def setup():
|
||||
"""Function called by nose on module load"""
|
||||
setup_db()
|
||||
|
||||
#Teardown that database
|
||||
def teardown():
|
||||
"""Function called by nose after all tests in this module ran"""
|
||||
teardown_db()
|
||||
|
||||
class ModelTest(object):
|
||||
"""Base unit test case for the models."""
|
||||
|
||||
klass = None
|
||||
attrs = {}
|
||||
|
||||
def setup(self):
|
||||
try:
|
||||
new_attrs = {}
|
||||
new_attrs.update(self.attrs)
|
||||
new_attrs.update(self.do_get_dependencies())
|
||||
self.obj = self.klass(**new_attrs)
|
||||
DBSession.add(self.obj)
|
||||
DBSession.flush()
|
||||
return self.obj
|
||||
except:
|
||||
DBSession.rollback()
|
||||
raise
|
||||
|
||||
def tearDown(self):
|
||||
DBSession.rollback()
|
||||
|
||||
def do_get_dependencies(self):
|
||||
"""Use this method to pull in other objects that need to be created for this object to be build properly"""
|
||||
return {}
|
||||
|
||||
def test_create_obj(self):
|
||||
pass
|
||||
|
||||
def test_query_obj(self):
|
||||
obj = DBSession.query(self.klass).one()
|
||||
for key, value in self.attrs.iteritems():
|
||||
assert_equals(getattr(obj, key), value)
|
51
Brie/brie/tests/models/test_auth.py
Normal file
51
Brie/brie/tests/models/test_auth.py
Normal file
@ -0,0 +1,51 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Test suite for the TG app's models"""
|
||||
from nose.tools import eq_
|
||||
|
||||
from brie import model
|
||||
from brie.tests.models import ModelTest
|
||||
|
||||
class TestGroup(ModelTest):
|
||||
"""Unit test case for the ``Group`` model."""
|
||||
klass = model.Group
|
||||
attrs = dict(
|
||||
group_name = u"test_group",
|
||||
display_name = u"Test Group"
|
||||
)
|
||||
|
||||
|
||||
class TestUser(ModelTest):
|
||||
"""Unit test case for the ``User`` model."""
|
||||
|
||||
klass = model.User
|
||||
attrs = dict(
|
||||
user_name = u"ignucius",
|
||||
email_address = u"ignucius@example.org"
|
||||
)
|
||||
|
||||
def test_obj_creation_username(self):
|
||||
"""The obj constructor must set the user name right"""
|
||||
eq_(self.obj.user_name, u"ignucius")
|
||||
|
||||
def test_obj_creation_email(self):
|
||||
"""The obj constructor must set the email right"""
|
||||
eq_(self.obj.email_address, u"ignucius@example.org")
|
||||
|
||||
def test_no_permissions_by_default(self):
|
||||
"""User objects should have no permission by default."""
|
||||
eq_(len(self.obj.permissions), 0)
|
||||
|
||||
def test_getting_by_email(self):
|
||||
"""Users should be fetcheable by their email addresses"""
|
||||
him = model.User.by_email_address(u"ignucius@example.org")
|
||||
eq_(him, self.obj)
|
||||
|
||||
|
||||
class TestPermission(ModelTest):
|
||||
"""Unit test case for the ``Permission`` model."""
|
||||
|
||||
klass = model.Permission
|
||||
attrs = dict(
|
||||
permission_name = u"test_permission",
|
||||
description = u"This is a test Description"
|
||||
)
|
57
Brie/brie/websetup.py
Normal file
57
Brie/brie/websetup.py
Normal file
@ -0,0 +1,57 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Setup the Brie application"""
|
||||
|
||||
import logging
|
||||
|
||||
import transaction
|
||||
from tg import config
|
||||
|
||||
from brie.config.environment import load_environment
|
||||
|
||||
__all__ = ['setup_app']
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def setup_app(command, conf, vars):
|
||||
"""Place any commands to setup brie here"""
|
||||
load_environment(conf.global_conf, conf.local_conf)
|
||||
# Load the models
|
||||
from brie import model
|
||||
print "Creating tables"
|
||||
model.metadata.create_all(bind=config['pylons.app_globals'].sa_engine)
|
||||
|
||||
manager = model.User()
|
||||
manager.user_name = u'manager'
|
||||
manager.display_name = u'Example manager'
|
||||
manager.email_address = u'manager@somedomain.com'
|
||||
manager.password = u'managepass'
|
||||
|
||||
model.DBSession.add(manager)
|
||||
|
||||
group = model.Group()
|
||||
group.group_name = u'managers'
|
||||
group.display_name = u'Managers Group'
|
||||
|
||||
group.users.append(manager)
|
||||
|
||||
model.DBSession.add(group)
|
||||
|
||||
permission = model.Permission()
|
||||
permission.permission_name = u'manage'
|
||||
permission.description = u'This permission give an administrative right to the bearer'
|
||||
permission.groups.append(group)
|
||||
|
||||
model.DBSession.add(permission)
|
||||
|
||||
editor = model.User()
|
||||
editor.user_name = u'editor'
|
||||
editor.display_name = u'Example editor'
|
||||
editor.email_address = u'editor@somedomain.com'
|
||||
editor.password = u'editpass'
|
||||
|
||||
model.DBSession.add(editor)
|
||||
model.DBSession.flush()
|
||||
|
||||
transaction.commit()
|
||||
print "Successfully setup"
|
63
Brie/check_mac_interface.py
Normal file
63
Brie/check_mac_interface.py
Normal file
@ -0,0 +1,63 @@
|
||||
#from paste.deploy import appconfig
|
||||
#from pylons import config
|
||||
|
||||
#from brie.config.environment import load_environment
|
||||
|
||||
#conf = appconfig('config:development.ini', relative_to='.')
|
||||
#load_environment(conf.global_conf, conf.local_conf)
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
from brie.config import ldap_config
|
||||
from brie.lib.ldap_helper import *
|
||||
from brie.lib.camembert_helpers import *
|
||||
|
||||
from brie.model import DBSession
|
||||
from brie.model.camembert import *
|
||||
|
||||
#interface_name = os.environ["NAS_PORT_ID"]
|
||||
#switch_ip = os.environ["NAS_IP_ADDRESS"]
|
||||
#mac = os.environ["USERNAME"]
|
||||
|
||||
#bind = Ldap.connect("uid=roven.gabriel," + ldap_config.username_base_dn, "foobar")
|
||||
bind = Ldap.connect("uid=admin,ou=Administrators,ou=TopologyManagement,o=netscaperoot", "t734DSSL61")
|
||||
|
||||
rooms_base_dn = "ou=chambres,dc=pacaterie,dc=u-psud,dc=fr"
|
||||
|
||||
interface_name = "FastEthernet0/43"
|
||||
switch_ip = "172.17.24.2"
|
||||
mac = "000f1f867189"
|
||||
|
||||
rooms = bind.search(rooms_base_dn, "(&(&(objectClass=pacaterieRoom)(x-switchInterface=" + interface_name + ")(x-switch=" + switch_ip + ")))")
|
||||
|
||||
|
||||
def roomOrNone(member):
|
||||
if member.has("roomNumber"):
|
||||
return member.roomNumber.first()
|
||||
return None
|
||||
#end def
|
||||
|
||||
|
||||
def isOk():
|
||||
for room in rooms:
|
||||
print room.get("x-switchInterface").first()
|
||||
if room.has("x-memberIn"):
|
||||
print room.get("x-memberIn").first()
|
||||
associated_member_machine = bind.search_first(room.get("x-memberIn").first(), "(uid=" + mac + ")")
|
||||
print associated_member_machine.uid.first()
|
||||
return associated_member_machine is not None
|
||||
#end if
|
||||
#end for
|
||||
|
||||
return False
|
||||
#end def
|
||||
|
||||
ok = isOk()
|
||||
|
||||
if ok:
|
||||
sys.exit(0)
|
||||
else:
|
||||
sys.exit(1)
|
||||
|
||||
|
0
Brie/devdata.db
Normal file
0
Brie/devdata.db
Normal file
129
Brie/development.ini
Normal file
129
Brie/development.ini
Normal file
@ -0,0 +1,129 @@
|
||||
#
|
||||
# Brie - Pylons development environment configuration
|
||||
#
|
||||
# The %(here)s variable will be replaced with the parent directory of this file
|
||||
#
|
||||
# This file is for deployment specific config options -- other configuration
|
||||
# that is always required for the app is done in the config directory,
|
||||
# and generally should not be modified by end users.
|
||||
|
||||
[DEFAULT]
|
||||
debug = true
|
||||
# Uncomment and replace with the address which should receive any error reports
|
||||
#email_to = you@yourdomain.com
|
||||
smtp_server = localhost
|
||||
error_email_from = paste@localhost
|
||||
|
||||
[server:main]
|
||||
use = egg:Paste#http
|
||||
host = 0.0.0.0
|
||||
port = 9000
|
||||
|
||||
[app:main]
|
||||
use = egg:Brie
|
||||
full_stack = true
|
||||
#lang = ru
|
||||
cache_dir = %(here)s/data
|
||||
beaker.session.key = brie
|
||||
beaker.session.secret = somesecret
|
||||
|
||||
# If you'd like to fine-tune the individual locations of the cache data dirs
|
||||
# for the Cache data, or the Session saves, un-comment the desired settings
|
||||
# here:
|
||||
#beaker.cache.data_dir = %(here)s/data/cache
|
||||
#beaker.session.data_dir = %(here)s/data/sessions
|
||||
|
||||
# pick the form for your database
|
||||
# %(here) may include a ':' character on Windows environments; this can
|
||||
# invalidate the URI when specifying a SQLite db via path name
|
||||
sqlalchemy.url=postgresql://camembert:CamembertDB%40Pacat@archange.pacaterie.u-psud.fr:5432/camembert
|
||||
# sqlalchemy.url=mysql://username:password@hostname:port/databasename
|
||||
|
||||
|
||||
# If you have sqlite, here's a simple default to get you started
|
||||
# in development
|
||||
|
||||
#sqlalchemy.url = sqlite:///%(here)s/devdata.db
|
||||
#echo shouldn't be used together with the logging module.
|
||||
#sqlalchemy.echo = false
|
||||
#sqlalchemy.echo_pool = false
|
||||
#sqlalchemy.pool_recycle = 3600
|
||||
|
||||
# if you are using Mako and want to be able to reload
|
||||
# the mako template from disk during the development phase
|
||||
# you should say 'true' here
|
||||
# This option is only used for mako templating engine
|
||||
# WARNING: if you want to deploy your application using a zipped egg
|
||||
# (ie: if your application's setup.py defines zip-safe=True, then you
|
||||
# MUST put "false" for the production environment because there will
|
||||
# be no disk and real files to compare time with.
|
||||
# On the contrary if your application defines zip-safe=False and is
|
||||
# deployed in an unzipped manner, then you can leave this option to true
|
||||
templating.mako.reloadfromdisk = true
|
||||
|
||||
# the compiled template dir is a directory that must be readable by your
|
||||
# webserver. It will be used to store the resulting templates once compiled
|
||||
# by the TemplateLookup system.
|
||||
# During development you generally don't need this option since paste's HTTP
|
||||
# server will have access to you development directories, but in production
|
||||
# you'll most certainly want to have apache or nginx to write in a directory
|
||||
# that does not contain any source code in any form for obvious security reasons.
|
||||
#
|
||||
#templating.mako.compiled_templates_dir = /some/dir/where/webserver/has/access
|
||||
|
||||
# WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT*
|
||||
# Debug mode will enable the interactive debugging tool, allowing ANYONE to
|
||||
# execute malicious code after an exception is raised.
|
||||
#set debug = false
|
||||
|
||||
# Logging configuration
|
||||
# Add additional loggers, handlers, formatters here
|
||||
# Uses python's logging config file format
|
||||
# http://docs.python.org/lib/logging-config-fileformat.html
|
||||
|
||||
[loggers]
|
||||
keys = root, brie, sqlalchemy, auth
|
||||
|
||||
[handlers]
|
||||
keys = console
|
||||
|
||||
[formatters]
|
||||
keys = generic
|
||||
|
||||
# If you create additional loggers, add them as a key to [loggers]
|
||||
[logger_root]
|
||||
level = INFO
|
||||
handlers = console
|
||||
|
||||
[logger_brie]
|
||||
level = DEBUG
|
||||
handlers =
|
||||
qualname = brie
|
||||
|
||||
[logger_sqlalchemy]
|
||||
level = INFO
|
||||
handlers =
|
||||
qualname = sqlalchemy.engine
|
||||
# "level = INFO" logs SQL queries.
|
||||
# "level = DEBUG" logs SQL queries and results.
|
||||
# "level = WARN" logs neither. (Recommended for production systems.)
|
||||
|
||||
|
||||
# A logger for authentication, identification and authorization -- this is
|
||||
# repoze.who and repoze.what:
|
||||
[logger_auth]
|
||||
level = WARN
|
||||
handlers =
|
||||
qualname = auth
|
||||
|
||||
# If you create additional handlers, add them as a key to [handlers]
|
||||
[handler_console]
|
||||
class = StreamHandler
|
||||
args = (sys.stderr,)
|
||||
level = NOTSET
|
||||
formatter = generic
|
||||
|
||||
# If you create additional formatters, add them as a key to [formatters]
|
||||
[formatter_generic]
|
||||
format = %(asctime)s,%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
|
||||
datefmt = %H:%M:%S
|
14
Brie/ez_setup/README.txt
Normal file
14
Brie/ez_setup/README.txt
Normal file
@ -0,0 +1,14 @@
|
||||
This directory exists so that Subversion-based projects can share a single
|
||||
copy of the ``ez_setup`` bootstrap module for ``setuptools``, and have it
|
||||
automatically updated in their projects when ``setuptools`` is updated.
|
||||
|
||||
For your convenience, you may use the following svn:externals definition::
|
||||
|
||||
ez_setup svn://svn.eby-sarna.com/svnroot/ez_setup
|
||||
|
||||
You can set this by executing this command in your project directory::
|
||||
|
||||
svn propedit svn:externals .
|
||||
|
||||
And then adding the line shown above to the file that comes up for editing.
|
||||
Then, whenever you update your project, ``ez_setup`` will be updated as well.
|
229
Brie/ez_setup/__init__.py
Normal file
229
Brie/ez_setup/__init__.py
Normal file
@ -0,0 +1,229 @@
|
||||
#!/usr/bin/python
|
||||
"""Bootstrap setuptools installation
|
||||
|
||||
If you want to use setuptools in your package's setup.py, just include this
|
||||
file in the same directory with it, and add this to the top of your setup.py::
|
||||
|
||||
from ez_setup import use_setuptools
|
||||
use_setuptools()
|
||||
|
||||
If you want to require a specific version of setuptools, set a download
|
||||
mirror, or use an alternate download directory, you can do so by supplying
|
||||
the appropriate options to ``use_setuptools()``.
|
||||
|
||||
This file can also be run as a script to install or upgrade setuptools.
|
||||
"""
|
||||
import sys
|
||||
DEFAULT_VERSION = "0.6c7"
|
||||
DEFAULT_URL = "http://pypi.python.org/packages/%s/s/setuptools/" % sys.version[:3]
|
||||
|
||||
md5_data = {
|
||||
'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca',
|
||||
'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb',
|
||||
'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b',
|
||||
'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a',
|
||||
'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618',
|
||||
'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac',
|
||||
'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5',
|
||||
'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4',
|
||||
'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c',
|
||||
'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b',
|
||||
'setuptools-0.6c2-py2.3.egg': 'f0064bf6aa2b7d0f3ba0b43f20817c27',
|
||||
'setuptools-0.6c2-py2.4.egg': '616192eec35f47e8ea16cd6a122b7277',
|
||||
'setuptools-0.6c3-py2.3.egg': 'f181fa125dfe85a259c9cd6f1d7b78fa',
|
||||
'setuptools-0.6c3-py2.4.egg': 'e0ed74682c998bfb73bf803a50e7b71e',
|
||||
'setuptools-0.6c3-py2.5.egg': 'abef16fdd61955514841c7c6bd98965e',
|
||||
'setuptools-0.6c4-py2.3.egg': 'b0b9131acab32022bfac7f44c5d7971f',
|
||||
'setuptools-0.6c4-py2.4.egg': '2a1f9656d4fbf3c97bf946c0a124e6e2',
|
||||
'setuptools-0.6c4-py2.5.egg': '8f5a052e32cdb9c72bcf4b5526f28afc',
|
||||
'setuptools-0.6c5-py2.3.egg': 'ee9fd80965da04f2f3e6b3576e9d8167',
|
||||
'setuptools-0.6c5-py2.4.egg': 'afe2adf1c01701ee841761f5bcd8aa64',
|
||||
'setuptools-0.6c5-py2.5.egg': 'a8d3f61494ccaa8714dfed37bccd3d5d',
|
||||
'setuptools-0.6c6-py2.3.egg': '35686b78116a668847237b69d549ec20',
|
||||
'setuptools-0.6c6-py2.4.egg': '3c56af57be3225019260a644430065ab',
|
||||
'setuptools-0.6c6-py2.5.egg': 'b2f8a7520709a5b34f80946de5f02f53',
|
||||
'setuptools-0.6c7-py2.3.egg': '209fdf9adc3a615e5115b725658e13e2',
|
||||
'setuptools-0.6c7-py2.4.egg': '5a8f954807d46a0fb67cf1f26c55a82e',
|
||||
'setuptools-0.6c7-py2.5.egg': '45d2ad28f9750e7434111fde831e8372',
|
||||
}
|
||||
|
||||
import sys, os
|
||||
|
||||
def _validate_md5(egg_name, data):
|
||||
if egg_name in md5_data:
|
||||
from md5 import md5
|
||||
digest = md5(data).hexdigest()
|
||||
if digest != md5_data[egg_name]:
|
||||
print >>sys.stderr, (
|
||||
"md5 validation of %s failed! (Possible download problem?)"
|
||||
% egg_name
|
||||
)
|
||||
sys.exit(2)
|
||||
return data
|
||||
|
||||
|
||||
def use_setuptools(
|
||||
version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
|
||||
download_delay=15
|
||||
):
|
||||
"""Automatically find/download setuptools and make it available on sys.path
|
||||
|
||||
`version` should be a valid setuptools version number that is available
|
||||
as an egg for download under the `download_base` URL (which should end with
|
||||
a '/'). `to_dir` is the directory where setuptools will be downloaded, if
|
||||
it is not already available. If `download_delay` is specified, it should
|
||||
be the number of seconds that will be paused before initiating a download,
|
||||
should one be required. If an older version of setuptools is installed,
|
||||
this routine will print a message to ``sys.stderr`` and raise SystemExit in
|
||||
an attempt to abort the calling script.
|
||||
"""
|
||||
try:
|
||||
import setuptools
|
||||
if setuptools.__version__ == '0.0.1':
|
||||
print >>sys.stderr, (
|
||||
"You have an obsolete version of setuptools installed. Please\n"
|
||||
"remove it from your system entirely before rerunning this script."
|
||||
)
|
||||
sys.exit(2)
|
||||
except ImportError:
|
||||
egg = download_setuptools(version, download_base, to_dir, download_delay)
|
||||
sys.path.insert(0, egg)
|
||||
import setuptools; setuptools.bootstrap_install_from = egg
|
||||
|
||||
import pkg_resources
|
||||
try:
|
||||
pkg_resources.require("setuptools>="+version)
|
||||
|
||||
except pkg_resources.VersionConflict, e:
|
||||
# XXX could we install in a subprocess here?
|
||||
print >>sys.stderr, (
|
||||
"The required version of setuptools (>=%s) is not available, and\n"
|
||||
"can't be installed while this script is running. Please install\n"
|
||||
" a more recent version first.\n\n(Currently using %r)"
|
||||
) % (version, e.args[0])
|
||||
sys.exit(2)
|
||||
|
||||
def download_setuptools(
|
||||
version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
|
||||
delay = 15
|
||||
):
|
||||
"""Download setuptools from a specified location and return its filename
|
||||
|
||||
`version` should be a valid setuptools version number that is available
|
||||
as an egg for download under the `download_base` URL (which should end
|
||||
with a '/'). `to_dir` is the directory where the egg will be downloaded.
|
||||
`delay` is the number of seconds to pause before an actual download attempt.
|
||||
"""
|
||||
import urllib2, shutil
|
||||
egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3])
|
||||
url = download_base + egg_name
|
||||
saveto = os.path.join(to_dir, egg_name)
|
||||
src = dst = None
|
||||
if not os.path.exists(saveto): # Avoid repeated downloads
|
||||
try:
|
||||
from distutils import log
|
||||
if delay:
|
||||
log.warn("""
|
||||
---------------------------------------------------------------------------
|
||||
This script requires setuptools version %s to run (even to display
|
||||
help). I will attempt to download it for you (from
|
||||
%s), but
|
||||
you may need to enable firewall access for this script first.
|
||||
I will start the download in %d seconds.
|
||||
|
||||
(Note: if this machine does not have network access, please obtain the file
|
||||
|
||||
%s
|
||||
|
||||
and place it in this directory before rerunning this script.)
|
||||
---------------------------------------------------------------------------""",
|
||||
version, download_base, delay, url
|
||||
); from time import sleep; sleep(delay)
|
||||
log.warn("Downloading %s", url)
|
||||
src = urllib2.urlopen(url)
|
||||
# Read/write all in one block, so we don't create a corrupt file
|
||||
# if the download is interrupted.
|
||||
data = _validate_md5(egg_name, src.read())
|
||||
dst = open(saveto,"wb"); dst.write(data)
|
||||
finally:
|
||||
if src: src.close()
|
||||
if dst: dst.close()
|
||||
return os.path.realpath(saveto)
|
||||
|
||||
def main(argv, version=DEFAULT_VERSION):
|
||||
"""Install or upgrade setuptools and EasyInstall"""
|
||||
|
||||
try:
|
||||
import setuptools
|
||||
except ImportError:
|
||||
egg = None
|
||||
try:
|
||||
egg = download_setuptools(version, delay=0)
|
||||
sys.path.insert(0,egg)
|
||||
from setuptools.command.easy_install import main
|
||||
return main(list(argv)+[egg]) # we're done here
|
||||
finally:
|
||||
if egg and os.path.exists(egg):
|
||||
os.unlink(egg)
|
||||
else:
|
||||
if setuptools.__version__ == '0.0.1':
|
||||
# tell the user to uninstall obsolete version
|
||||
use_setuptools(version)
|
||||
|
||||
req = "setuptools>="+version
|
||||
import pkg_resources
|
||||
try:
|
||||
pkg_resources.require(req)
|
||||
except pkg_resources.VersionConflict:
|
||||
try:
|
||||
from setuptools.command.easy_install import main
|
||||
except ImportError:
|
||||
from easy_install import main
|
||||
main(list(argv)+[download_setuptools(delay=0)])
|
||||
sys.exit(0) # try to force an exit
|
||||
else:
|
||||
if argv:
|
||||
from setuptools.command.easy_install import main
|
||||
main(argv)
|
||||
else:
|
||||
print "Setuptools version",version,"or greater has been installed."
|
||||
print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)'
|
||||
|
||||
|
||||
|
||||
def update_md5(filenames):
|
||||
"""Update our built-in md5 registry"""
|
||||
|
||||
import re
|
||||
from md5 import md5
|
||||
|
||||
for name in filenames:
|
||||
base = os.path.basename(name)
|
||||
f = open(name,'rb')
|
||||
md5_data[base] = md5(f.read()).hexdigest()
|
||||
f.close()
|
||||
|
||||
data = [" %r: %r,\n" % it for it in md5_data.items()]
|
||||
data.sort()
|
||||
repl = "".join(data)
|
||||
|
||||
import inspect
|
||||
srcfile = inspect.getsourcefile(sys.modules[__name__])
|
||||
f = open(srcfile, 'rb'); src = f.read(); f.close()
|
||||
|
||||
match = re.search("\nmd5_data = {\n([^}]+)}", src)
|
||||
if not match:
|
||||
print >>sys.stderr, "Internal error!"
|
||||
sys.exit(2)
|
||||
|
||||
src = src[:match.start(1)] + repl + src[match.end(1):]
|
||||
f = open(srcfile,'w')
|
||||
f.write(src)
|
||||
f.close()
|
||||
|
||||
|
||||
if __name__=='__main__':
|
||||
if len(sys.argv)>2 and sys.argv[1]=='--md5update':
|
||||
update_md5(sys.argv[2:])
|
||||
else:
|
||||
main(sys.argv[1:])
|
32
Brie/foo
Normal file
32
Brie/foo
Normal file
@ -0,0 +1,32 @@
|
||||
Boubakar OUATTARA
|
||||
boubakar.ouattara
|
||||
chambre 456 etage 4 aile nord
|
||||
Boubakar OUATTARA
|
||||
Tocha ZAABAY
|
||||
tocha.zaabay
|
||||
chambre 465 etage 4 aile nord
|
||||
Tocha ZAABAY
|
||||
Claude ALGOURDIN
|
||||
claude.algourdin
|
||||
chambre 418 etage 4 aile sud
|
||||
Claude ALGOURDIN
|
||||
Rachid CHEDRA
|
||||
rachid.chedra
|
||||
chambre 217 etage 2 aile sud
|
||||
Rachid CHEDRA
|
||||
Guillaume LETOUPIN
|
||||
guillaume.letoupin
|
||||
chambre 232 etage 2 aile sud
|
||||
Guillaume LETOUPIN
|
||||
erica MINUZ
|
||||
erica.minuz
|
||||
chambre 374 etage 3 aile nord
|
||||
Erica MINUZ
|
||||
FLAVIA MACHADO DOMINGUES
|
||||
flavia.machadodomingue
|
||||
chambre 452 etage 4 aile nord
|
||||
flavia.machadodomingue not found
|
||||
SOPHIA ID SALAH
|
||||
sophia.idsalah
|
||||
chambre 360 etage 3 aile nord
|
||||
Sophia ID SALAH
|
130
Brie/migrate_machines.py
Normal file
130
Brie/migrate_machines.py
Normal file
@ -0,0 +1,130 @@
|
||||
from paste.deploy import appconfig
|
||||
from pylons import config
|
||||
|
||||
from brie.config.environment import load_environment
|
||||
|
||||
conf = appconfig('config:development.ini', relative_to='.')
|
||||
load_environment(conf.global_conf, conf.local_conf)
|
||||
|
||||
from brie.config import ldap_config
|
||||
from brie.lib.ldap_helper import *
|
||||
from brie.lib.camembert_helpers import *
|
||||
|
||||
from brie.model import DBSession
|
||||
from brie.model.camembert import *
|
||||
|
||||
#bind = Ldap.connect("uid=roven.gabriel," + ldap_config.username_base_dn, "foobar")
|
||||
bind = Ldap.connect("uid=admin,ou=Administrators,ou=TopologyManagement,o=netscaperoot", "t734DSSL61")
|
||||
|
||||
members = bind.search(ldap_config.username_base_dn, "(objectClass=pacatnetMember)")
|
||||
|
||||
def roomOrNone(member):
|
||||
if member.has("roomNumber"):
|
||||
return member.roomNumber.first()
|
||||
return None
|
||||
#end def
|
||||
|
||||
def first(items):
|
||||
for item in items:
|
||||
return item
|
||||
|
||||
return None
|
||||
#end def
|
||||
|
||||
nextuid = 30000
|
||||
|
||||
|
||||
base_chambres_dn = "ou=chambres," + ldap_config.base_dn
|
||||
|
||||
|
||||
results = DBSession.query(UserPacaterie)
|
||||
|
||||
for user in results:
|
||||
uid = Translations.to_uid(user.prenom, user.nom)
|
||||
print uid
|
||||
|
||||
member = bind.search_first(ldap_config.username_base_dn, "(uid=" + uid + ")")
|
||||
|
||||
|
||||
print member.dn
|
||||
|
||||
machines = DBSession.query(Computer).filter(Computer.iduser == user.iduser)
|
||||
|
||||
machine_id = 1
|
||||
|
||||
for machine in machines:
|
||||
print machine_id
|
||||
print machine.name
|
||||
print machine.mac
|
||||
print machine.ip
|
||||
|
||||
machine_dn = "cn=" + str(machine_id) + "," + member.dn
|
||||
|
||||
existant = bind.search_first(machine_dn, "(objectClass=*)")
|
||||
|
||||
if existant is not None:
|
||||
bind.delete_entry_subtree(existant.dn)
|
||||
print "deleted : " + existant.dn
|
||||
|
||||
print machine_dn
|
||||
|
||||
machine_attributes = {
|
||||
"objectClass" : ["top", "organizationalRole"],
|
||||
"cn" : str(machine_id)
|
||||
}
|
||||
|
||||
bind.add_entry(machine_dn, machine_attributes)
|
||||
|
||||
dhcp_dn = "cn=" + str(machine.name) + "," + machine_dn
|
||||
|
||||
print dhcp_dn
|
||||
|
||||
dhcp_attributes = {
|
||||
"objectClass" : ["top", "uidObject", "dhcpHost"],
|
||||
"cn" : str(machine.name),
|
||||
"uid" : "machine_membre",
|
||||
"dhcpHWAddress" : str("ethernet " + machine.mac),
|
||||
"dhcpStatements" : str("fixed-address " + machine.name)
|
||||
}
|
||||
|
||||
bind.add_entry(dhcp_dn, dhcp_attributes)
|
||||
|
||||
mac_auth_dn = "cn=mac," + machine_dn
|
||||
|
||||
print mac_auth_dn
|
||||
|
||||
flat_mac = str(machine.mac).replace(":", "")
|
||||
|
||||
print flat_mac
|
||||
|
||||
mac_auth_attributes = {
|
||||
"objectClass" : ["top", "organizationalRole", "simpleSecurityObject", "uidObject"],
|
||||
"cn" : "mac",
|
||||
"uid" : flat_mac,
|
||||
"userPassword" : flat_mac
|
||||
}
|
||||
|
||||
bind.add_entry(mac_auth_dn, mac_auth_attributes)
|
||||
|
||||
dns_dn = "dlzHostName=" + machine.name + "," + machine_dn
|
||||
|
||||
print dns_dn
|
||||
|
||||
dns_attributes = {
|
||||
"objectClass" : ["top", "dlzAbstractRecord", "dlzGenericRecord"],
|
||||
"dlzData" : str(machine.ip),
|
||||
"dlzHostName" : str(machine.name),
|
||||
"dlzRecordId" : "1",
|
||||
"dlzTTL" : "3600",
|
||||
"dlzType" : "A"
|
||||
}
|
||||
|
||||
bind.add_entry(dns_dn, dns_attributes)
|
||||
|
||||
machine_id = 1 + machine_id
|
||||
|
||||
#end for machine
|
||||
|
||||
|
||||
|
||||
#end for
|
107
Brie/migrate_names_values.py
Normal file
107
Brie/migrate_names_values.py
Normal file
@ -0,0 +1,107 @@
|
||||
from paste.deploy import appconfig
|
||||
from pylons import config
|
||||
|
||||
from brie.config.environment import load_environment
|
||||
|
||||
conf = appconfig('config:development.ini', relative_to='.')
|
||||
load_environment(conf.global_conf, conf.local_conf)
|
||||
|
||||
from brie.config import ldap_config
|
||||
from brie.lib.ldap_helper import *
|
||||
from brie.lib.camembert_helpers import *
|
||||
|
||||
from brie.model import DBSession
|
||||
from brie.model.camembert import *
|
||||
|
||||
#bind = Ldap.connect("uid=roven.gabriel," + ldap_config.username_base_dn, "foobar")
|
||||
bind = Ldap.connect("uid=admin,ou=Administrators,ou=TopologyManagement,o=netscaperoot", "t734DSSL61")
|
||||
|
||||
members = bind.search(ldap_config.username_base_dn, "(objectClass=pacatnetMember)")
|
||||
|
||||
def roomOrNone(member):
|
||||
if member.has("roomNumber"):
|
||||
return member.roomNumber.first()
|
||||
return None
|
||||
#end def
|
||||
|
||||
def first(items):
|
||||
for item in items:
|
||||
return item
|
||||
|
||||
return None
|
||||
#end def
|
||||
|
||||
nextuid = 30000
|
||||
|
||||
|
||||
base_chambres_dn = "ou=chambres," + ldap_config.base_dn
|
||||
|
||||
|
||||
results = DBSession.query(Room)
|
||||
|
||||
for room in results:
|
||||
ldap_room = bind.search_first(base_chambres_dn, "(cn=" + room.name + ")")
|
||||
member_of = {
|
||||
"x-memberIn" : None
|
||||
}
|
||||
|
||||
try:
|
||||
bind.delete_attr(ldap_room.dn, member_of)
|
||||
print "deleted " + ldap_room.dn
|
||||
except:
|
||||
pass
|
||||
#end try
|
||||
|
||||
#end for
|
||||
|
||||
|
||||
results = DBSession.query(UserPacaterie, Room).filter(UserPacaterie.idroom == Room.idroom)
|
||||
|
||||
for (user, room) in results:
|
||||
uid = Translations.to_uid(user.prenom, user.nom)
|
||||
print uid
|
||||
|
||||
member = bind.search_first(ldap_config.username_base_dn, "(uid=" + uid + ")")
|
||||
|
||||
print room.name
|
||||
|
||||
member_dn = ""
|
||||
|
||||
if member is None:
|
||||
member_dn = "uid=" + uid + ",ou=2012," + ldap_config.username_base_dn
|
||||
|
||||
mail = user.mail
|
||||
if mail is None:
|
||||
mail = ""
|
||||
attributes = {
|
||||
"objectClass" : ["top", "person", "organizationalPerson", "inetOrgPerson", "pacatnetMember", "pykotaAccount", "posixAccount"],
|
||||
"uid" :(uid).encode("utf-8"),
|
||||
"cn" : (user.prenom + " " + user.nom.upper()).encode("utf-8"),
|
||||
"sn" : (user.nom.upper()).encode("utf-8"),
|
||||
"givenName" : (user.prenom).encode("utf-8"),
|
||||
"uidNumber" : str(-1),
|
||||
"gidNumber" : "10000",
|
||||
"homeDirectory" : ("/net/home/" + uid).encode("utf-8"),
|
||||
"mail" : (mail).encode("utf-8"),
|
||||
"loginShell" : "/usr/bin/zsh".encode("utf-8")
|
||||
}
|
||||
|
||||
bind.add_entry(member_dn, attributes)
|
||||
|
||||
else:
|
||||
member_dn = member.dn
|
||||
#end if
|
||||
|
||||
|
||||
|
||||
ldap_room = bind.search_first(base_chambres_dn, "(cn=" + room.name + ")")
|
||||
|
||||
print ldap_room.dn
|
||||
print member_dn
|
||||
|
||||
new_member_of = {
|
||||
"x-memberIn" : str(member_dn)
|
||||
}
|
||||
|
||||
bind.replace_attr(ldap_room.dn, new_member_of)
|
||||
#end for
|
70
Brie/migrate_remove_useless_values.py
Normal file
70
Brie/migrate_remove_useless_values.py
Normal file
@ -0,0 +1,70 @@
|
||||
from paste.deploy import appconfig
|
||||
from pylons import config
|
||||
|
||||
from brie.config.environment import load_environment
|
||||
|
||||
conf = appconfig('config:development.ini', relative_to='.')
|
||||
load_environment(conf.global_conf, conf.local_conf)
|
||||
|
||||
from brie.config import ldap_config
|
||||
from brie.lib.ldap_helper import *
|
||||
from brie.lib.camembert_helpers import *
|
||||
|
||||
from brie.model import DBSession
|
||||
from brie.model.camembert import *
|
||||
|
||||
#bind = Ldap.connect("uid=roven.gabriel,ou=2011," + ldap_config.username_base_dn, "foobar")
|
||||
bind = Ldap.connect("uid=admin,ou=Administrators,ou=TopologyManagement,o=netscaperoot", "t734DSSL61")
|
||||
|
||||
members = bind.search(ldap_config.username_base_dn, "(&(ou:dn:=2011)(objectClass=pacatnetMember))")
|
||||
|
||||
def roomOrNone(member):
|
||||
if member.has("roomNumber"):
|
||||
return member.roomNumber.first()
|
||||
return None
|
||||
#end def
|
||||
|
||||
def first(items):
|
||||
for item in items:
|
||||
return item
|
||||
|
||||
return None
|
||||
#end def
|
||||
|
||||
nextuid = 30000
|
||||
|
||||
def add(uid, user, room_dn, nextuid):
|
||||
user_dn = "uid=" + uid + "," + ldap_config.username_base_dn
|
||||
mail = user.mail
|
||||
if mail is None:
|
||||
mail = ""
|
||||
attributes = {
|
||||
"objectClass" : ["top", "person", "organizationalPerson", "inetOrgPerson", "pacatnetMember", "pykotaAccount", "posixAccount"],
|
||||
"uid" :(uid).encode("utf-8"),
|
||||
"cn" : (user.prenom + " " + user.nom.upper()).encode("utf-8"),
|
||||
"sn" : (user.nom.upper()).encode("utf-8"),
|
||||
"givenName" : (user.prenom).encode("utf-8"),
|
||||
"uidNumber" : str(nextuid),
|
||||
"gidNumber" : "10000",
|
||||
"homeDirectory" : ("/net/home/" + uid).encode("utf-8"),
|
||||
"mail" : (mail).encode("utf-8"),
|
||||
"x-room" : (room_dn).encode("utf-8"),
|
||||
"loginShell" : "/usr/bin/zsh".encode("utf-8")
|
||||
}
|
||||
|
||||
bind.add_entry(user_dn, attributes)
|
||||
|
||||
#end def
|
||||
|
||||
filestream = open("people_to_change.txt", "r")
|
||||
|
||||
for line in filestream:
|
||||
uid = line.strip()
|
||||
print "++" + uid + "++"
|
||||
print "ou=2010," + ldap_config.username_base_dn
|
||||
result = bind.search_first(ldap_config.username_base_dn, "(uid=" + uid + ")")
|
||||
bind.rename_entry(result.dn, "uid=" + result.uid.first(), "ou=2010," + ldap_config.username_base_dn)
|
||||
|
||||
#end for
|
||||
|
||||
|
80
Brie/migrate_rooms.py
Normal file
80
Brie/migrate_rooms.py
Normal file
@ -0,0 +1,80 @@
|
||||
from paste.deploy import appconfig
|
||||
from pylons import config
|
||||
|
||||
from brie.config.environment import load_environment
|
||||
|
||||
conf = appconfig('config:development.ini', relative_to='.')
|
||||
load_environment(conf.global_conf, conf.local_conf)
|
||||
|
||||
from brie.config import ldap_config
|
||||
from brie.lib.ldap_helper import *
|
||||
|
||||
from brie.model import DBSession
|
||||
from brie.model.camembert import *
|
||||
|
||||
import socket
|
||||
|
||||
#bind = Ldap.connect("uid=roven.gabriel,ou=2010," + ldap_config.username_base_dn, "foobar")
|
||||
bind = Ldap.connect("uid=admin,ou=Administrators,ou=TopologyManagement,o=netscaperoot", "t734DSSL61")
|
||||
|
||||
members = bind.search(ldap_config.username_base_dn, "(objectClass=pacatnetMember)")
|
||||
|
||||
def roomOrNone(member):
|
||||
if member.has("roomNumber"):
|
||||
return member.roomNumber.first()
|
||||
return None
|
||||
#end def
|
||||
|
||||
def first(items):
|
||||
for item in items:
|
||||
return item
|
||||
|
||||
return None
|
||||
#end def
|
||||
|
||||
def area(room_number):
|
||||
floor_number = room_number % 100
|
||||
|
||||
if floor_number <= 33:
|
||||
return "sud"
|
||||
else:
|
||||
return "nord"
|
||||
#end if
|
||||
#end def
|
||||
|
||||
results = DBSession.query(Room, Materiel, Interface).filter(Room.idinterface == Interface.idinterface).filter(Interface.idmateriel == Materiel.idmateriel)
|
||||
|
||||
for room, materiel, interface in results:
|
||||
aile = area(room.idroom)
|
||||
etage = str(room.idroom / 100)
|
||||
|
||||
base_chambres_dn = "ou=chambres," + ldap_config.base_dn
|
||||
|
||||
other_dn = "cn=" + etage + ",cn=" + aile + "," + base_chambres_dn
|
||||
|
||||
full_dn = "cn=" + room.name + "," + other_dn
|
||||
|
||||
print room
|
||||
|
||||
switch_ip = socket.gethostbyname(str(materiel.hostname))
|
||||
|
||||
|
||||
attributes = {
|
||||
"objectClass" : "pacaterieRoom",
|
||||
"cn" : str(room.name),
|
||||
"x-switch" : str(switch_ip),
|
||||
"x-switchInterface" : str(interface.ifname)
|
||||
}
|
||||
|
||||
|
||||
print str(room.idinterface)
|
||||
|
||||
print full_dn
|
||||
try:
|
||||
bind.replace_attr(full_dn, attributes)
|
||||
except ldap.NO_SUCH_OBJECT:
|
||||
bind.add_entry(full_dn, attributes)
|
||||
# print attributes
|
||||
#end for
|
||||
|
||||
|
59
Brie/migrate_switch.py
Normal file
59
Brie/migrate_switch.py
Normal file
@ -0,0 +1,59 @@
|
||||
from paste.deploy import appconfig
|
||||
from pylons import config
|
||||
|
||||
from brie.config.environment import load_environment
|
||||
|
||||
conf = appconfig('config:development.ini', relative_to='.')
|
||||
load_environment(conf.global_conf, conf.local_conf)
|
||||
|
||||
from brie.config import ldap_config
|
||||
from brie.lib.ldap_helper import *
|
||||
from brie.lib.camembert_helpers import *
|
||||
|
||||
from brie.model import DBSession
|
||||
from brie.model.camembert import *
|
||||
|
||||
#bind = Ldap.connect("uid=roven.gabriel," + ldap_config.username_base_dn, "foobar")
|
||||
bind = Ldap.connect("uid=admin,ou=Administrators,ou=TopologyManagement,o=netscaperoot", "t734DSSL61")
|
||||
|
||||
members = bind.search(ldap_config.username_base_dn, "(objectClass=pacatnetMember)")
|
||||
|
||||
def roomOrNone(member):
|
||||
if member.has("roomNumber"):
|
||||
return member.roomNumber.first()
|
||||
return None
|
||||
#end def
|
||||
|
||||
def first(items):
|
||||
for item in items:
|
||||
return item
|
||||
|
||||
return None
|
||||
#end def
|
||||
|
||||
nextuid = 30000
|
||||
|
||||
|
||||
base_chambres_dn = "ou=chambres," + ldap_config.base_dn
|
||||
|
||||
|
||||
results = DBSession.query(Room, Interface).filter(Room.idinterface == Interface.idinterface).order_by(Room.name)
|
||||
|
||||
for (room, interface) in results:
|
||||
ldap_room = bind.search_first(base_chambres_dn, "(cn=" + room.name + ")")
|
||||
print ldap_room.dn
|
||||
|
||||
switch_id = {
|
||||
"x-switchInterface" : str(interface.idinterface)
|
||||
}
|
||||
|
||||
bind.replace_attr(ldap_room.dn, switch_id)
|
||||
|
||||
uid_attr = {
|
||||
"objectClass" : "uidObject",
|
||||
"uid" : str(room.idroom)
|
||||
}
|
||||
|
||||
bind.add_attr(ldap_room.dn, uid_attr)
|
||||
|
||||
#end for
|
32
Brie/setup.cfg
Normal file
32
Brie/setup.cfg
Normal file
@ -0,0 +1,32 @@
|
||||
[egg_info]
|
||||
tag_build = dev
|
||||
tag_svn_revision = true
|
||||
|
||||
[easy_install]
|
||||
find_links = http://www.pylonshq.com/download/
|
||||
|
||||
[nosetests]
|
||||
with-pylons=test.ini
|
||||
|
||||
# Babel configuration
|
||||
[compile_catalog]
|
||||
domain = brie
|
||||
directory = brie/i18n
|
||||
statistics = true
|
||||
|
||||
[extract_messages]
|
||||
add_comments = TRANSLATORS:
|
||||
output_file = brie/i18n/brie.pot
|
||||
width = 80
|
||||
keywords = l_
|
||||
|
||||
[init_catalog]
|
||||
domain = brie
|
||||
input_file = brie/i18n/brie.pot
|
||||
output_dir = brie/i18n
|
||||
|
||||
[update_catalog]
|
||||
domain = brie
|
||||
input_file = brie/i18n/brie.pot
|
||||
output_dir = brie/i18n
|
||||
previous = true
|
49
Brie/setup.py
Normal file
49
Brie/setup.py
Normal file
@ -0,0 +1,49 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
try:
|
||||
from setuptools import setup, find_packages
|
||||
except ImportError:
|
||||
from ez_setup import use_setuptools
|
||||
use_setuptools()
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
setup(
|
||||
name='Brie',
|
||||
version='0.1',
|
||||
description='',
|
||||
author='',
|
||||
author_email='',
|
||||
#url='',
|
||||
install_requires=[
|
||||
"TurboGears2 >= 2.0b7",
|
||||
"Catwalk >= 2.0.2",
|
||||
"Babel >=0.9.4",
|
||||
#can be removed iif use_toscawidgets = False
|
||||
"toscawidgets >= 0.9.7.1",
|
||||
"zope.sqlalchemy >= 0.4 ",
|
||||
"repoze.tm2 >= 1.0a4",
|
||||
|
||||
"repoze.what-quickstart >= 1.0",
|
||||
],
|
||||
setup_requires=["PasteScript >= 1.7"],
|
||||
paster_plugins=['PasteScript', 'Pylons', 'TurboGears2', 'tg.devtools'],
|
||||
packages=find_packages(exclude=['ez_setup']),
|
||||
include_package_data=True,
|
||||
test_suite='nose.collector',
|
||||
tests_require=['WebTest', 'BeautifulSoup'],
|
||||
package_data={'brie': ['i18n/*/LC_MESSAGES/*.mo',
|
||||
'templates/*/*',
|
||||
'public/*/*']},
|
||||
message_extractors={'brie': [
|
||||
('**.py', 'python', None),
|
||||
('templates/**.mako', 'mako', None),
|
||||
('templates/**.html', 'genshi', None),
|
||||
('public/**', 'ignore', None)]},
|
||||
|
||||
entry_points="""
|
||||
[paste.app_factory]
|
||||
main = brie.config.middleware:make_app
|
||||
|
||||
[paste.app_install]
|
||||
main = pylons.util:PylonsInstaller
|
||||
""",
|
||||
)
|
26
Brie/test.ini
Normal file
26
Brie/test.ini
Normal file
@ -0,0 +1,26 @@
|
||||
#
|
||||
# Brie - TurboGears 2 testing environment configuration
|
||||
#
|
||||
# The %(here)s variable will be replaced with the parent directory of this file
|
||||
#
|
||||
[DEFAULT]
|
||||
debug = true
|
||||
# Uncomment and replace with the address which should receive any error reports
|
||||
# email_to = you@yourdomain.com
|
||||
smtp_server = localhost
|
||||
error_email_from = paste@localhost
|
||||
|
||||
[server:main]
|
||||
use = egg:Paste#http
|
||||
host = 0.0.0.0
|
||||
port = 5000
|
||||
|
||||
[app:main]
|
||||
sqlalchemy.url = sqlite:///:memory:
|
||||
use = config:development.ini
|
||||
|
||||
[app:main_without_authn]
|
||||
use = main
|
||||
skip_authentication = True
|
||||
|
||||
# Add additional test specific configuration options as necessary.
|
Loading…
Reference in New Issue
Block a user