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