Dans la série suppression des liens symboliques : /usr/scripts/lib devient /usr/scripts/cranslib
* Comme ça c'est plus clair que c'est un truc custom crans * Le lien symbolique /usr/scripts/gestion/crans/ est retiré. D'autres suivront.
This commit is contained in:
parent
c57795f23b
commit
10275229a1
35 changed files with 20 additions and 29 deletions
0
cranslib/__init__.py
Normal file
0
cranslib/__init__.py
Normal file
41
cranslib/cp.py
Normal file
41
cranslib/cp.py
Normal file
|
@ -0,0 +1,41 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: iso-8859-15 -*-
|
||||
# #############################################################
|
||||
# ..
|
||||
# .... ............ ........
|
||||
# . ....... . .... ..
|
||||
# . ... .. .. .. .. ..... . ..
|
||||
# .. .. ....@@@. .. . ........ .
|
||||
# .. . .. ..@.@@..@@. .@@@@@@@ @@@@@@. ....
|
||||
# .@@@@. .@@@@. .@@@@..@@.@@..@@@..@@@..@@@@.... ....
|
||||
# @@@@... .@@@.. @@ @@ .@..@@..@@...@@@. .@@@@@. ..
|
||||
# .@@@.. . @@@. @@.@@..@@.@@..@@@ @@ .@@@@@@.. .....
|
||||
# ...@@@.... @@@ .@@.......... ........ ..... ..
|
||||
# . ..@@@@.. . .@@@@. .. ....... . .............
|
||||
# . .. .... .. .. . ... ....
|
||||
# . . .... ............. .. ...
|
||||
# .. .. ... ........ ... ...
|
||||
# ................................
|
||||
#
|
||||
# #############################################################
|
||||
"""
|
||||
cp.py
|
||||
|
||||
Fonctions pour cherrypy (intranet)
|
||||
|
||||
Copyright (c) 2006 by www.crans.org
|
||||
"""
|
||||
import cherrypy
|
||||
|
||||
def log(string, keyword = "INTRANET", level = 0):
|
||||
"""Utilise la fonction log de cherrypy avec quelques modification
|
||||
|
||||
-> introduit le login de la session en cours s'il existe
|
||||
"""
|
||||
try:
|
||||
login = cherrypy.session['uid']
|
||||
string = u"[%s] %s" % ( login, string )
|
||||
except:
|
||||
pass
|
||||
string = string.encode("utf-8")
|
||||
cherrypy.log(string, keyword, level)
|
63
cranslib/deprecated.py
Normal file
63
cranslib/deprecated.py
Normal file
|
@ -0,0 +1,63 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import warnings
|
||||
import functools
|
||||
import inspect
|
||||
import sys
|
||||
|
||||
def deprecated(replace=None):
|
||||
'''This is a decorator which can be used to mark functions
|
||||
as deprecated. It will result in a warning being emitted
|
||||
when the function is used.'''
|
||||
|
||||
warnings.resetwarnings()
|
||||
|
||||
if replace == None:
|
||||
instead = ""
|
||||
elif isinstance(replace, str) or isinstance(replace, unicode):
|
||||
instead = " " + replace
|
||||
else:
|
||||
instead = " Use %s instead." % (replace.__name__,)
|
||||
|
||||
def real_decorator(func):
|
||||
"""Nested because a decorator with a parameter has to be coded this way"""
|
||||
@functools.wraps(func)
|
||||
def new_func(*args, **kwargs):
|
||||
warnings.warn_explicit(
|
||||
"Call to deprecated function %s.%s" % (func.__name__, instead),
|
||||
category=DeprecationWarning,
|
||||
filename=func.func_code.co_filename,
|
||||
lineno=func.func_code.co_firstlineno + 1
|
||||
)
|
||||
return func(*args, **kwargs)
|
||||
return new_func
|
||||
return real_decorator
|
||||
|
||||
|
||||
def module(replace=None):
|
||||
"""À appeler dans un module déprécié"""
|
||||
|
||||
warnings.resetwarnings()
|
||||
|
||||
# On récupère le nom du module appelant la fonction
|
||||
frm = inspect.stack()[1]
|
||||
mod = inspect.getmodule(frm[0])
|
||||
if mod and mod.__name__ != '__main__':
|
||||
module_name = mod.__name__
|
||||
else:
|
||||
module_name = sys.argv[0]
|
||||
|
||||
if replace == None:
|
||||
instead = ""
|
||||
elif isinstance(replace, str) or isinstance(replace, unicode):
|
||||
instead = " " + replace
|
||||
else:
|
||||
instead = " Use %s instead." % (replace.__name__,)
|
||||
|
||||
warnings.warn(
|
||||
"Call to deprecated module %s.%s" % (module_name, instead),
|
||||
category=DeprecationWarning,
|
||||
stacklevel=3
|
||||
)
|
||||
|
0
cranslib/dialogwizard/__init__.py
Normal file
0
cranslib/dialogwizard/__init__.py
Normal file
1624
cranslib/dialogwizard/dialog.py
Normal file
1624
cranslib/dialogwizard/dialog.py
Normal file
File diff suppressed because it is too large
Load diff
93
cranslib/dialogwizard/dialogwizard.py
Normal file
93
cranslib/dialogwizard/dialogwizard.py
Normal file
|
@ -0,0 +1,93 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# DIALOGWIZARD.PY--
|
||||
#
|
||||
# Copyright (C) 2009 Antoine Durand-Gasselin
|
||||
# Author: Antoine Durand-Gasselin <adg@crans.org>
|
||||
#
|
||||
|
||||
from wizard import Step, PreviousStep, EndScenario, TryAgain
|
||||
from itertools import izip
|
||||
import dialog, time, sys, commands
|
||||
|
||||
def really_quit(dico):
|
||||
raise EndScenario("game over!", data = dico)
|
||||
|
||||
def error_handler(exc):
|
||||
dialog.Dialog().msgbox(str(exc), widht=0, height =0, title = 'Erreur :')
|
||||
raise TryAgain()
|
||||
|
||||
class DialogStepGenerator:
|
||||
u"""This class defines a step, that will prompt the user for various
|
||||
fields."""
|
||||
|
||||
def __init__(self, backtitle):
|
||||
self.d = dialog.Dialog()
|
||||
self.d.add_persistent_args(["--backtitle", backtitle])
|
||||
|
||||
def _check_rc(self, rc):
|
||||
if rc == 2: really_quit(dico)
|
||||
if rc == 1: raise PreviousStep
|
||||
|
||||
def _skim_choices(self, choices, dico):
|
||||
return [ f for f in choices if f.get('show_cond', lambda x : True)(dico) ]
|
||||
|
||||
def form_step(self, title, enonce, form, **kw):
|
||||
def fn(dico, default):
|
||||
sform = self._skim_choices(form, dico)
|
||||
for field in sform:
|
||||
item = default.get(field['var'], dico.get(field['var'], ''))
|
||||
field['item'] = item
|
||||
rc, res = self.d.form(enonce % dico, fields = sform, title=title % dico, **kw)
|
||||
self._check_rc(rc)
|
||||
for field, val in izip (sform, res):
|
||||
dico[field['var']] = val
|
||||
return dico
|
||||
return Step(fn)
|
||||
|
||||
def select_step(self, title, enonce, var, choix, **kw):
|
||||
def fn(dico, default):
|
||||
schoix = []
|
||||
for c in choix:
|
||||
try:
|
||||
schoix.append((c[0], c[1]))
|
||||
except Exception,e:
|
||||
if c.get('show_cond', lambda x : True)(dico):
|
||||
schoix.append((c['label'], c['item']))
|
||||
print schoix
|
||||
rc, res = self.d.menu(enonce % dico, choices = schoix, title = title % dico, **kw)
|
||||
self._check_rc(rc)
|
||||
dico[var] = res
|
||||
return dico
|
||||
return Step(fn)
|
||||
|
||||
def input_step(self, title, enonce, var, **kw):
|
||||
def fn(dico, default):
|
||||
rc, res = self.d.inputbox(enonce % dico, title = title % dico, init = dico.get(var, ''), **kw)
|
||||
self._check_rc(rc)
|
||||
dico[var] = res
|
||||
return dico
|
||||
return Step(fn)
|
||||
|
||||
def checklist_step(self, title, enonce, liste, **kw):
|
||||
def fn(dico, default):
|
||||
sliste = []
|
||||
for c in liste:
|
||||
try:
|
||||
if dico.get(c[0], False): checked = 'on'
|
||||
else: checked = 'off'
|
||||
sliste.append((c[0], c[1], checked))
|
||||
except Exception,e:
|
||||
if c.get('show_cond', lambda x : True)(dico):
|
||||
if dico.get(c['var'], False): checked = 'on'
|
||||
else: checked = 'off'
|
||||
sliste.append((c['var'], c['item'], checked))
|
||||
rc, res = self.d.checklist(enonce % dico, title = title % dico, choices = sliste, **kw)
|
||||
self._check_rc(rc)
|
||||
for tag, item, status in liste:
|
||||
if tag in res:
|
||||
dico[tag] = True
|
||||
else:
|
||||
dico[tag] = False
|
||||
return dico
|
||||
return Step(fn)
|
220
cranslib/dialogwizard/wizard.py
Normal file
220
cranslib/dialogwizard/wizard.py
Normal file
|
@ -0,0 +1,220 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (C) 2009 Antoine Durand-Gasselin
|
||||
# Author: Antoine Durand-Gasselin <adg@crans.org>
|
||||
#
|
||||
|
||||
class TryAgain(Exception):
|
||||
"""Exception raised when the step should be taken again."""
|
||||
|
||||
class PreviousStep(Exception):
|
||||
"""Exception raised when should be backtracked to previous step."""
|
||||
|
||||
class EndScenario(Exception):
|
||||
"""Exception raised when the scenario should be halted.
|
||||
'msg' is the error message
|
||||
'data' is the updated state object"""
|
||||
def __init__(self, msg, data=None):
|
||||
self.msg = msg
|
||||
self.data = data
|
||||
|
||||
class Step:
|
||||
u"""This class defines a step. A step is defined by providing a
|
||||
function that, given an environment and an expected answer will
|
||||
return an update of the environment (as dictionnary)."""
|
||||
def __init__(self, update_fn):
|
||||
self.update = update_fn
|
||||
|
||||
def run(self, env, default):
|
||||
"""This function makes the call"""
|
||||
return self.update(env, default)
|
||||
|
||||
class Scenario:
|
||||
u"""This class allows us to define scenarios."""
|
||||
|
||||
def __init__(self):
|
||||
u"""empty scenario, with an error handler (that takes an exception as
|
||||
argument)"""
|
||||
self.steps = None
|
||||
|
||||
def nest(self, step):
|
||||
u"""Adds a step to a scenario"""
|
||||
if not isinstance(step, Step):
|
||||
raise TypeError("Can only bind steps")
|
||||
self.steps = ('NEST', step, self.steps)
|
||||
|
||||
def case(self, switch, cases, fallback = None): #revoir le fallback
|
||||
u"""Calls a function (passing to it the environment), and will
|
||||
call the corresponding scenario in the second arg."""
|
||||
if not callable(switch):
|
||||
raise TypeError("switch must be callable")
|
||||
if not isinstance(cases, dict):
|
||||
raise TypeError("cases must be a dict")
|
||||
for case in cases.values():
|
||||
if not isinstance(case, Scenario):
|
||||
raise TypeError("cases must all be Scenarios")
|
||||
self.steps = ('CASE', (switch, cases, fallback), self.steps)
|
||||
|
||||
def branch(self, cond, plan_A, plan_B):
|
||||
u"""Makes a test (will call it passing the environnement), and
|
||||
depending on the result, will process one of the two scenarios"""
|
||||
if not callable(cond):
|
||||
raise TypeError("cond must be callable")
|
||||
if not isinstance(plan_A, Scenario) or not isinstance(plan_B, Scenario):
|
||||
raise TypeError("Can only branch on scenarios")
|
||||
# self.steps = ('BRANCH', (cond, plan_A, plan_B) , self.steps)
|
||||
self.case(cond, { True: plan_A, False: plan_B })
|
||||
|
||||
def quote(self, scenario):
|
||||
u"""Runs a scenario as a single scenario step"""
|
||||
|
||||
if not isinstance(scenario, Scenario):
|
||||
raise TypeError("scenario must be a scenario")
|
||||
|
||||
def quote_scenar (dict1, dict2):
|
||||
try:
|
||||
return Running(scenario).run()
|
||||
except EndScenario:
|
||||
raise PreviousStep
|
||||
|
||||
self.nest(Step(quote_scenar))
|
||||
|
||||
def step_scenario(step):
|
||||
s = Scenario()
|
||||
s.nest(step)
|
||||
return s
|
||||
|
||||
def unit_scenario():
|
||||
return ( Scenario())
|
||||
|
||||
def _relance(exc): raise exc
|
||||
|
||||
class Running:
|
||||
u"""To run scenarios"""
|
||||
|
||||
defaults = {}
|
||||
steps = None
|
||||
stack = None
|
||||
|
||||
def __init__(self, scenario, env = {}, handle = _relance):
|
||||
if not isinstance(scenario, Scenario):
|
||||
raise TypeError("Can only run Scenarios")
|
||||
accu = scenario.steps
|
||||
self.env = env
|
||||
self.handle = handle
|
||||
|
||||
# To avoid brain spots on the walls, we shall reverse the list
|
||||
# of steps.
|
||||
while accu:
|
||||
self.steps = accu[0], accu[1], self.steps
|
||||
accu = accu[2]
|
||||
|
||||
def step(self):
|
||||
if self.steps:
|
||||
# Case of a Case, as a list of possible choices depending on
|
||||
# the result of a function call, if it is not handled, then
|
||||
# it does nothing.
|
||||
if self.steps[0] == 'CASE' :
|
||||
switch, cases, fallback = self.steps[1]
|
||||
self.steps = self.steps[2]
|
||||
scenar = cases.get(switch(self.env), fallback)
|
||||
if scenar: plan_steps = scenar.steps
|
||||
else: plan_steps = None
|
||||
while plan_steps:
|
||||
self.steps = plan_steps[0], plan_steps[1], self.steps
|
||||
plan_steps = plan_steps[2]
|
||||
|
||||
## # Case of a Branching
|
||||
## if self.steps[0] == 'BRANCH' :
|
||||
## # As it is (should be) an epsilon-test we won't
|
||||
## # backtrack it.
|
||||
## cond, plan_A, plan_B = self.steps[1]
|
||||
## self.steps = self.steps[2]
|
||||
## if cond(self.env):
|
||||
## plan_steps = plan_A.steps
|
||||
## else:
|
||||
## plan_steps = plan_B.steps
|
||||
## # Let's not forget we need to reverse the steps lists.
|
||||
## while plan_steps:
|
||||
## self.steps = plan_steps[0], plan_steps[1], self.steps
|
||||
## plan_steps = plan_steps[2]
|
||||
|
||||
# Case of nesting
|
||||
elif self.steps[0] == 'NEST':
|
||||
try:
|
||||
this_step = self.steps[1]
|
||||
new_env = this_step.run(self.env, self.defaults)
|
||||
# Should we perform sanity checks on new_env ? and raise
|
||||
# TryAgain if it fails ? After updating defaults ?
|
||||
|
||||
self.stack = (self.env.copy(), new_env, self.steps, self.stack)
|
||||
self.env.update(new_env)
|
||||
self.defaults = {}
|
||||
self.steps = self.steps[2]
|
||||
|
||||
except PreviousStep:
|
||||
if self.stack:
|
||||
self.env, self.defaults, self.steps, self.stack = self.stack
|
||||
else:
|
||||
raise EndScenario("No previous step", self.env)
|
||||
|
||||
except TryAgain:
|
||||
# We can update defaults
|
||||
pass
|
||||
|
||||
except Exception, e:
|
||||
try:
|
||||
self.handle(e)
|
||||
|
||||
except PreviousStep:
|
||||
if self.stack:
|
||||
self.env, self.defaults, self.steps, self.stack = self.stack
|
||||
else:
|
||||
raise EndScenario("No previous step", self.env)
|
||||
|
||||
except TryAgain:
|
||||
# We can update defaults
|
||||
pass
|
||||
|
||||
else:
|
||||
# Should not be called
|
||||
raise "invalid step"
|
||||
|
||||
def run(self):
|
||||
while self.steps:
|
||||
self.step()
|
||||
return (self.env)
|
||||
|
||||
|
||||
# For testing issues
|
||||
def prompt(var):
|
||||
def fn(dict, default):
|
||||
a = raw_input(u"%s (%s):= " % (var, default.get(var, '<no default>')))
|
||||
if a == 'n':
|
||||
raise TryAgain
|
||||
elif a == 'b':
|
||||
raise PreviousStep
|
||||
else:
|
||||
return { var : a }
|
||||
return Step(fn)
|
||||
|
||||
if __name__ == "__main__":
|
||||
s = Scenario()
|
||||
t = Scenario()
|
||||
u = Scenario()
|
||||
|
||||
for i in ['toto', 'tata', 'titi', 'tutu']:
|
||||
s.nest(prompt(i))
|
||||
t.nest(prompt(i[1]))
|
||||
|
||||
for i in range(6,9):
|
||||
u.nest(prompt(str(i)))
|
||||
|
||||
u.quote(t)
|
||||
|
||||
for i in range(12,15):
|
||||
u.nest(prompt(str(i)))
|
||||
|
||||
|
||||
print (Running(u).run())
|
0
cranslib/gestion/__init__.py
Normal file
0
cranslib/gestion/__init__.py
Normal file
80
cranslib/gestion/authentification.py
Normal file
80
cranslib/gestion/authentification.py
Normal file
|
@ -0,0 +1,80 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# #############################################################
|
||||
# ..
|
||||
# .... ............ ........
|
||||
# . ....... . .... ..
|
||||
# . ... .. .. .. .. ..... . ..
|
||||
# .. .. ....@@@. .. . ........ .
|
||||
# .. . .. ..@.@@..@@. .@@@@@@@ @@@@@@. ....
|
||||
# .@@@@. .@@@@. .@@@@..@@.@@..@@@..@@@..@@@@.... ....
|
||||
# @@@@... .@@@.. @@ @@ .@..@@..@@...@@@. .@@@@@. ..
|
||||
# .@@@.. . @@@. @@.@@..@@.@@..@@@ @@ .@@@@@@.. .....
|
||||
# ...@@@.... @@@ .@@.......... ........ ..... ..
|
||||
# . ..@@@@.. . .@@@@. .. ....... . .............
|
||||
# . .. .... .. .. . ... ....
|
||||
# . . .... ............. .. ...
|
||||
# .. .. ... ........ ... ...
|
||||
# ................................
|
||||
#
|
||||
# #############################################################
|
||||
# authentification.py
|
||||
#
|
||||
# Fonction de login et petite classe utilisateur
|
||||
#
|
||||
# Auteur: Grégoire Détrez <gdetrez@crans.org>
|
||||
# Copyright (c) 2008 by www.crans.org
|
||||
# #############################################################
|
||||
import ldap
|
||||
#import cransldap
|
||||
import models
|
||||
import fields
|
||||
LDAP_SERVER = "ldap.adm.crans.org"
|
||||
|
||||
# Petite classe Avec les infos de base de l'utilisateur
|
||||
class User(models.Model):
|
||||
prenom = fields.stringField( "Prénom" )
|
||||
nom = fields.stringField( "Nom" )
|
||||
mail = fields.stringField( "Couriel" )
|
||||
uid = fields.loginField( "Identifiant" )
|
||||
aid = fields.intField( "aid" )
|
||||
droits = fields.listField( "Droits", fields.stringField(None) )
|
||||
|
||||
def is_nounou(self):
|
||||
return u"Nounou" in self.droits
|
||||
|
||||
class AuthentificationFailed(Exception):
|
||||
def __str__(self):
|
||||
return "Oups, auth failed"
|
||||
|
||||
def login( id, password ):
|
||||
""" returns a User object """
|
||||
con = ldap.open( LDAP_SERVER )
|
||||
try:
|
||||
user_dn = get_dn_from_id( id, con )
|
||||
except ValueError:
|
||||
raise AuthentificationFailed
|
||||
try:
|
||||
con.bind_s(user_dn, password)
|
||||
except ldap.INVALID_CREDENTIALS, e:
|
||||
raise AuthentificationFailed
|
||||
data = con.search_s(user_dn, ldap.SCOPE_SUBTREE)
|
||||
con.unbind()
|
||||
data = data[0][1]
|
||||
return User(data)
|
||||
|
||||
def get_dn_from_id( id, ldap_connexion=None ):
|
||||
if ldap_connexion == None:
|
||||
ldap_connexion = ldap.open( LDAP_SERVER )
|
||||
try:
|
||||
aid = int( id )
|
||||
user_dn = "aid=%d,ou=data,dc=crans,dc=org" % aid
|
||||
return user_dn
|
||||
except ValueError:
|
||||
data = ldap_connexion.search_s("ou=data,dc=crans,dc=org",
|
||||
ldap.SCOPE_SUBTREE,
|
||||
"uid=%s" % id)
|
||||
if len(data) != 1:
|
||||
raise ValueError, "Id invalid"
|
||||
else: return data[0][0]
|
||||
|
225
cranslib/gestion/fields.py
Normal file
225
cranslib/gestion/fields.py
Normal file
|
@ -0,0 +1,225 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# #############################################################
|
||||
# ..
|
||||
# .... ............ ........
|
||||
# . ....... . .... ..
|
||||
# . ... .. .. .. .. ..... . ..
|
||||
# .. .. ....@@@. .. . ........ .
|
||||
# .. . .. ..@.@@..@@. .@@@@@@@ @@@@@@. ....
|
||||
# .@@@@. .@@@@. .@@@@..@@.@@..@@@..@@@..@@@@.... ....
|
||||
# @@@@... .@@@.. @@ @@ .@..@@..@@...@@@. .@@@@@. ..
|
||||
# .@@@.. . @@@. @@.@@..@@.@@..@@@ @@ .@@@@@@.. .....
|
||||
# ...@@@.... @@@ .@@.......... ........ ..... ..
|
||||
# . ..@@@@.. . .@@@@. .. ....... . .............
|
||||
# . .. .... .. .. . ... ....
|
||||
# . . .... ............. .. ...
|
||||
# .. .. ... ........ ... ...
|
||||
# ................................
|
||||
#
|
||||
# #############################################################
|
||||
# __init__.py
|
||||
#
|
||||
# Fields: outils pour passer les informations de la base
|
||||
# vers les objets python et vice-versa
|
||||
#
|
||||
# Auteur: Grégoire Détrez <gdetrez@crans.org>
|
||||
# Copyright (c) 2008 by www.crans.org
|
||||
# #############################################################
|
||||
import re
|
||||
|
||||
class baseField(object):
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
|
||||
def _save_field( self, data ):
|
||||
return data
|
||||
def _load_field( self, data ):
|
||||
return str(data)
|
||||
|
||||
def load( self, ldap_data ):
|
||||
if ldap_data == None: return None
|
||||
return self._load_field( ldap_data[0] )
|
||||
def save( self, field_data ):
|
||||
return [ self._save_field( field_data )]
|
||||
|
||||
class stringField( baseField ):
|
||||
pass
|
||||
|
||||
class reField( stringField ):
|
||||
def __init__( self, name, expr ):
|
||||
baseField.__init__(self, name)
|
||||
self.expr = re.compile(expr)
|
||||
|
||||
def _save_field(self, field_data):
|
||||
if self.expr.match( field_data ):
|
||||
return field_data
|
||||
else:
|
||||
raise ValueError, "Incorect value for field %s" % self.name
|
||||
|
||||
class macField( reField ):
|
||||
def __init__( self, name ):
|
||||
self = reField.__init__(self, name, "^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$")
|
||||
def _save_field( self, data ):
|
||||
data = data.lower()
|
||||
if not self.expr.match( data ):
|
||||
data = re.sub( "[^0-9a-fA-F]", "", data )
|
||||
if len(data) == 12:
|
||||
data = data[0:2] + ":" + data[2:4] + ":" + data [4:6] + ":" + data[6:8] + ":" + data[8:10] + ":" + data[10:12]
|
||||
return reField._save_field( self, data )
|
||||
|
||||
class ipField( reField ):
|
||||
def __init__( self, name ):
|
||||
self = reField.__init__(self, name, "^(\d{1,3}\.){3}\d{1,3}$")
|
||||
|
||||
class emailField( reField ):
|
||||
def __init__( self, name, suffix=None ):
|
||||
stringField.__init__( self, name)
|
||||
self.expr = re.compile("^(?P<prefix>[\w\+]+)(@(?P<suffix>[\w\.]+\.\w{1,3}))?$" )
|
||||
self.suffix = suffix
|
||||
|
||||
def _load_field(self, data):
|
||||
if self.suffix:
|
||||
m = self.expr.match( data )
|
||||
if m.group('suffix'):
|
||||
return data
|
||||
else:
|
||||
return data + u"@" + self.suffix
|
||||
else:
|
||||
return data
|
||||
|
||||
def _save_field(self, data):
|
||||
m = self.expr.match( data )
|
||||
if m:
|
||||
if self.suffix and m.group("suffix") == self.suffix:
|
||||
return m.group("prefix")
|
||||
return data
|
||||
else:
|
||||
raise ValueError, "Mail invalid"
|
||||
|
||||
|
||||
|
||||
class loginField( reField ):
|
||||
def __init__( self, name ):
|
||||
self = reField.__init__(self, name, "^[a-z]{4,}$")
|
||||
|
||||
class listField( baseField ):
|
||||
def __init__( self, name, type_field ):
|
||||
baseField.__init__(self, name)
|
||||
self.type_field = type_field
|
||||
def load( self, ldap_data ):
|
||||
if ldap_data == None: return []
|
||||
return map( self.type_field._load_field, ldap_data )
|
||||
def save( self, field_data ):
|
||||
return map( self.type_field._save_field, field_data )
|
||||
|
||||
class historyField( baseField ):
|
||||
pass
|
||||
|
||||
class pathField( baseField ):
|
||||
pass
|
||||
|
||||
class intField( baseField ):
|
||||
def _load_field( self, ldap_data ):
|
||||
return int( ldap_data )
|
||||
def _save_field(self, field_data ):
|
||||
return str( field_data )
|
||||
|
||||
class booleanField( baseField ):
|
||||
def _load_field( self, ldap_data ):
|
||||
return ldap_data == 'TRUE'
|
||||
def _save_field( self, field_Data ):
|
||||
if field_data: return 'TRUE'
|
||||
else: return 'FALSE'
|
||||
|
||||
class telField( reField ):
|
||||
def __init__(self, name ):
|
||||
reField.__init__( self, name, "^\d{10}$")
|
||||
def _save_field( self, data ):
|
||||
return reField._save_field( self, re.sub("[\ \.,]", "", data ) )
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import unittest
|
||||
|
||||
class TestFields(unittest.TestCase):
|
||||
def setUp(self):
|
||||
pass
|
||||
|
||||
def testBaseField( self ):
|
||||
field = baseField( "Un nom" )
|
||||
assert field.load(["un test"]) == "un test"
|
||||
assert field.save("un test") == ["un test"]
|
||||
|
||||
def testStringField( self ):
|
||||
field = stringField( "Un nom" )
|
||||
assert field.load(["une string"]) == "une string"
|
||||
assert field.save("une string") == ["une string"]
|
||||
|
||||
def testReField( self ):
|
||||
field = reField( "Un nom", "^[A-Z][a-z]+$" )
|
||||
assert field.load(["Coucou"]) == "Coucou"
|
||||
assert field.save("Coucou") == ["Coucou"]
|
||||
self.assertRaises(ValueError, field.save, "")
|
||||
self.assertRaises(ValueError, field.save, "coucou")
|
||||
self.assertRaises(ValueError, field.save, "coucou monde")
|
||||
self.assertRaises(ValueError, field.save, "Coucou monde")
|
||||
|
||||
def testMacField( self ):
|
||||
field = macField( "Un nom" )
|
||||
assert field.load(["00:0f:20:57:6e:81"]) == "00:0f:20:57:6e:81"
|
||||
assert field.save("00:0f:20:57:6e:81") == ["00:0f:20:57:6e:81"]
|
||||
assert field.save("00:0F:20:57:6E:81") == ["00:0f:20:57:6e:81"]
|
||||
assert field.save("000f20576e81") == ["00:0f:20:57:6e:81"]
|
||||
assert field.save("00 0f 20 57 6e 81") == ["00:0f:20:57:6e:81"]
|
||||
self.assertRaises(ValueError, field.save, "00:0f:20:57:6e:81:34")
|
||||
self.assertRaises(ValueError, field.save, "00:0f:20:57:6e:8")
|
||||
self.assertRaises(ValueError, field.save, "00:0f:20:57:6e")
|
||||
self.assertRaises(ValueError, field.save, "00:0f:20:57:6k:81")
|
||||
|
||||
def testIpField( self ):
|
||||
field = ipField( "Un nom" )
|
||||
assert field.load(["129.168.0.34"]) == "129.168.0.34"
|
||||
assert field.save("129.168.0.34") == ["129.168.0.34"]
|
||||
self.assertRaises(ValueError, field.save, "192.16.8")
|
||||
self.assertRaises(ValueError, field.save, "192.16.8.2.3")
|
||||
self.assertRaises(ValueError, field.save, "192.16.8.e")
|
||||
self.assertRaises(ValueError, field.save, "125.34..56")
|
||||
|
||||
def testEmailField( self ):
|
||||
field = emailField( "Un email", suffix="crans.org" )
|
||||
assert field.load(["toto@exemple.com"]) == "toto@exemple.com"
|
||||
assert field.save("toto@exemple.com") == ["toto@exemple.com"]
|
||||
assert field.load(["toto@crans.org"]) == "toto@crans.org"
|
||||
assert field.load(["toto"]) == "toto@crans.org"
|
||||
assert field.save("toto") == ["toto"]
|
||||
assert field.save("toto@crans.org") == ["toto"]
|
||||
self.assertRaises(ValueError, field.save, "toto@")
|
||||
self.assertRaises(ValueError, field.save, "toto@test")
|
||||
self.assertRaises(ValueError, field.save, "test.com")
|
||||
|
||||
def testLoginField( self ):
|
||||
field = loginField( "Un nom" )
|
||||
assert field.load(["toto"]) == "toto"
|
||||
assert field.save("toto") == ["toto"]
|
||||
# def testHistoryField( self ):
|
||||
# field = baseField( "Un nom" )
|
||||
# assert field.load(["un test"]) == "un test"
|
||||
# assert field.save("un test") == ["un test"]
|
||||
def testListField( self ):
|
||||
field = listField( "Un nom", stringField(None) )
|
||||
assert field.load(["un test"]) == ["un test"]
|
||||
assert field.load(["un test", "un autre"]) == ["un test", "un autre"]
|
||||
|
||||
def testTelField( self ):
|
||||
field = telField( "Un nom" )
|
||||
assert field.load(["0606060606"]) == "0606060606"
|
||||
assert field.save("0606060606") == ["0606060606"]
|
||||
assert field.save("06 060 606 06") == ["0606060606"]
|
||||
assert field.save("06 06 06 06 06") == ["0606060606"]
|
||||
self.assertRaises(ValueError, field.save, "06060606")
|
||||
self.assertRaises(ValueError, field.save, "06060606060606")
|
||||
|
||||
unittest.main()
|
48
cranslib/gestion/models.py
Normal file
48
cranslib/gestion/models.py
Normal file
|
@ -0,0 +1,48 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# #############################################################
|
||||
# ..
|
||||
# .... ............ ........
|
||||
# . ....... . .... ..
|
||||
# . ... .. .. .. .. ..... . ..
|
||||
# .. .. ....@@@. .. . ........ .
|
||||
# .. . .. ..@.@@..@@. .@@@@@@@ @@@@@@. ....
|
||||
# .@@@@. .@@@@. .@@@@..@@.@@..@@@..@@@..@@@@.... ....
|
||||
# @@@@... .@@@.. @@ @@ .@..@@..@@...@@@. .@@@@@. ..
|
||||
# .@@@.. . @@@. @@.@@..@@.@@..@@@ @@ .@@@@@@.. .....
|
||||
# ...@@@.... @@@ .@@.......... ........ ..... ..
|
||||
# . ..@@@@.. . .@@@@. .. ....... . .............
|
||||
# . .. .... .. .. . ... ....
|
||||
# . . .... ............. .. ...
|
||||
# .. .. ... ........ ... ...
|
||||
# ................................
|
||||
#
|
||||
# #############################################################
|
||||
# models.py
|
||||
#
|
||||
# Classe de base pour mapper automatiquement des
|
||||
# enregistrements ldap et des objets python
|
||||
#
|
||||
# Auteur: Grégoire Détrez <gdetrez@crans.org>
|
||||
# Copyright (c) 2008 by www.crans.org
|
||||
# #############################################################
|
||||
import fields
|
||||
|
||||
class MetaModel(type):
|
||||
def __init__(cls, name, bases, attrs):
|
||||
super(type, cls).__init__(cls, name, bases, attrs)
|
||||
_fields = {}
|
||||
for item_name in attrs:
|
||||
if isinstance(attrs[item_name], fields.baseField):
|
||||
_fields[item_name] = attrs[item_name]
|
||||
setattr(cls, "_model_fields", _fields)
|
||||
|
||||
|
||||
class Model(object):
|
||||
__metaclass__ = MetaModel
|
||||
def __init__( self, data ):
|
||||
k = self._model_fields
|
||||
for a_field in self._model_fields:
|
||||
val = self._model_fields[a_field].load(data.get(a_field, None))
|
||||
setattr(self, a_field, val)
|
||||
|
1
cranslib/lib
Symbolic link
1
cranslib/lib
Symbolic link
|
@ -0,0 +1 @@
|
|||
/usr/scripts/lib/
|
25
cranslib/mail/__init__.py
Normal file
25
cranslib/mail/__init__.py
Normal file
|
@ -0,0 +1,25 @@
|
|||
"""
|
||||
__init__.py
|
||||
|
||||
Fonction de base pour les mails.
|
||||
|
||||
Copyright (c) 2006 by www.crans.org
|
||||
"""
|
||||
|
||||
SENDMAIL = "/usr/sbin/sendmail" # sendmail location
|
||||
|
||||
def quickSend(From=None, To=None, Subject=None, Text=None, disconnect_on_bounce=0):
|
||||
"""envoie d'un mail"""
|
||||
OPTIONS = ' -t' #extract recipient from headers
|
||||
if disconnect_on_bounce:
|
||||
OPTIONS+= ' -V -f bounces'
|
||||
from os import popen
|
||||
p = popen("%s -t %s" % (SENDMAIL, OPTIONS), "w")
|
||||
p.write("From: %s\n" % From)
|
||||
p.write("To: %s\n" % To)
|
||||
p.write("Subject: %s\n" % Subject)
|
||||
p.write("\n") # blank line separating headers from body
|
||||
p.write("%s\n" % Text)
|
||||
sts = p.close()
|
||||
if sts:
|
||||
print "Sendmail exit status", sts
|
1689
cranslib/optparse_lenny.py
Normal file
1689
cranslib/optparse_lenny.py
Normal file
File diff suppressed because it is too large
Load diff
0
cranslib/scripts/__init__.py
Normal file
0
cranslib/scripts/__init__.py
Normal file
47
cranslib/scripts/autologout.py
Executable file
47
cranslib/scripts/autologout.py
Executable file
|
@ -0,0 +1,47 @@
|
|||
#! /usr/bin/env python
|
||||
|
||||
import re
|
||||
import commands
|
||||
import sys
|
||||
sys.path.append('/usr/scripts/')
|
||||
import cranslib.utils.logs
|
||||
import logging
|
||||
LOGGER = logging.getLogger("crans.autologout")
|
||||
LOGGER.addHandler(cranslib.utils.logs.CransFileHandler("autologout"))
|
||||
LOGGER.setLevel(logging.WARNING)
|
||||
|
||||
def run_autologout():
|
||||
LOGGER.debug("Starting autologout")
|
||||
# pour chaque ligne du w
|
||||
for w in commands.getoutput("w -h").split('\n') :
|
||||
if not w : continue
|
||||
# on splite
|
||||
w = w.split()
|
||||
|
||||
# on verifie que c'est une connection du bde
|
||||
hosts = ['cableur.crans.org','cableuse.crans.org','venus.crans.org','kfet.crans.org']
|
||||
if w[2] not in [ h[0:16] for h in hosts ] :
|
||||
continue
|
||||
|
||||
# on verifie qu'on a depase le timeout
|
||||
if re.match('^\d*\.\d*s$', w[4]) or re.match('^[0-4]:\d*m$', w[4]) :
|
||||
continue
|
||||
|
||||
# on reccuperre les processus s le tty
|
||||
ps = commands.getoutput('ps auwwx | grep "%s" | head -n 1' % w[1] ).split()
|
||||
|
||||
# on verrifie que c'est le bon user
|
||||
if ps[0] != w[0] :
|
||||
continue
|
||||
|
||||
# on verifie qu'on a pas de tty
|
||||
if ps[6] != '?' :
|
||||
continue
|
||||
|
||||
# on tue le process
|
||||
commands.getoutput('kill %s' % ps[1] )
|
||||
LOGGER.info("%s a ete deconnecte" % ps[0])
|
||||
#print ps
|
||||
|
||||
if __name__ == "__main__":
|
||||
run_autologout()
|
12
cranslib/scripts/helloworld.py
Normal file
12
cranslib/scripts/helloworld.py
Normal file
|
@ -0,0 +1,12 @@
|
|||
|
||||
import logging
|
||||
|
||||
import sys
|
||||
sys.path.append('/usr/scripts/')
|
||||
from cranslib.utils.logs import getFileLogger
|
||||
LOGGER = getFileLogger("helloworld")
|
||||
LOGGER.setLevel(logging.INFO)
|
||||
LOGGER.addHandler(logging.StreamHandler())
|
||||
|
||||
if __name__ == "__main__":
|
||||
LOGGER.info(u"Hello World")
|
0
cranslib/tv/__init__.py
Normal file
0
cranslib/tv/__init__.py
Normal file
12
cranslib/tv/channels.py
Normal file
12
cranslib/tv/channels.py
Normal file
|
@ -0,0 +1,12 @@
|
|||
SAP_FILE_URL = "http://tv/sap.txt"
|
||||
BASE_IMAGE_URL = "http://tv/images/"
|
||||
IMAGE_SUFFIX = ".jpg"
|
||||
SMALL_IMAGE_SUFFIX = "_petites.jpg"
|
||||
|
||||
|
||||
class Channel:
|
||||
pass
|
||||
|
||||
class ChannelGroup:
|
||||
pass
|
||||
|
40
cranslib/utils/__init__.py
Normal file
40
cranslib/utils/__init__.py
Normal file
|
@ -0,0 +1,40 @@
|
|||
import re
|
||||
import unicodedata
|
||||
|
||||
def __init__():
|
||||
pass
|
||||
|
||||
def QuoteForPOSIX(string):
|
||||
'''quote a string so it can be used as an argument in a posix shell
|
||||
|
||||
According to: http://www.unix.org/single_unix_specification/
|
||||
2.2.1 Escape Character (Backslash)
|
||||
|
||||
A backslash that is not quoted shall preserve the literal value
|
||||
of the following character, with the exception of a <newline>.
|
||||
|
||||
2.2.2 Single-Quotes
|
||||
|
||||
Enclosing characters in single-quotes ( '' ) shall preserve
|
||||
the literal value of each character within the single-quotes.
|
||||
A single-quote cannot occur within single-quotes.
|
||||
|
||||
source : http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/498202
|
||||
'''
|
||||
|
||||
return "\\'".join(["'" + p + "'" for p in string.split("'")])
|
||||
|
||||
|
||||
def suppression_diacritics(s):
|
||||
"""source : http://wikipython.flibuste.net/moin.py/JouerAvecUnicode#head-1213938516c633958921591439c33d202244e2f4
|
||||
"""
|
||||
def remove(char):
|
||||
deco = unicodedata.decomposition(char)
|
||||
if deco:
|
||||
return unichr(int(deco.split()[0],16))
|
||||
return char
|
||||
return ''.join([remove(a) for a in s])
|
||||
|
||||
supprimer_accents = suppression_diacritics
|
||||
desaccentuer = suppression_diacritics
|
||||
|
50
cranslib/utils/exceptions.py
Normal file
50
cranslib/utils/exceptions.py
Normal file
|
@ -0,0 +1,50 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: iso-8859-15 -*-
|
||||
# #############################################################
|
||||
# ..
|
||||
# .... ............ ........
|
||||
# . ....... . .... ..
|
||||
# . ... .. .. .. .. ..... . ..
|
||||
# .. .. ....@@@. .. . ........ .
|
||||
# .. . .. ..@.@@..@@. .@@@@@@@ @@@@@@. ....
|
||||
# .@@@@. .@@@@. .@@@@..@@.@@..@@@..@@@..@@@@.... ....
|
||||
# @@@@... .@@@.. @@ @@ .@..@@..@@...@@@. .@@@@@. ..
|
||||
# .@@@.. . @@@. @@.@@..@@.@@..@@@ @@ .@@@@@@.. .....
|
||||
# ...@@@.... @@@ .@@.......... ........ ..... ..
|
||||
# . ..@@@@.. . .@@@@. .. ....... . .............
|
||||
# . .. .... .. .. . ... ....
|
||||
# . . .... ............. .. ...
|
||||
# .. .. ... ........ ... ...
|
||||
# ................................
|
||||
#
|
||||
# #############################################################
|
||||
"""
|
||||
exceptions.py
|
||||
|
||||
Fonctions pour gérer les exceptions
|
||||
|
||||
Copyright (c) 2006 by www.crans.org
|
||||
Some code, from cherrypy lib
|
||||
"""
|
||||
|
||||
import sys, traceback
|
||||
|
||||
|
||||
def formatExc(exc=None):
|
||||
"""formatExc(exc=None) -> exc (or sys.exc_info if None), formatted."""
|
||||
if exc is None:
|
||||
exc = sys.exc_info()
|
||||
|
||||
if exc == (None, None, None):
|
||||
return ""
|
||||
|
||||
page_handler_str = ""
|
||||
args = list(getattr(exc[1], "args", []))
|
||||
if args:
|
||||
if len(args) > 1:
|
||||
page_handler = args.pop()
|
||||
page_handler_str = 'Page handler: %s\n' % repr(page_handler)
|
||||
exc[1].args = tuple(args)
|
||||
return page_handler_str + "".join(traceback.format_exception(*exc))
|
||||
|
||||
|
44
cranslib/utils/files.py
Normal file
44
cranslib/utils/files.py
Normal file
|
@ -0,0 +1,44 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: iso-8859-15 -*-
|
||||
# #############################################################
|
||||
# ..
|
||||
# .... ............ ........
|
||||
# . ....... . .... ..
|
||||
# . ... .. .. .. .. ..... . ..
|
||||
# .. .. ....@@@. .. . ........ .
|
||||
# .. . .. ..@.@@..@@. .@@@@@@@ @@@@@@. ....
|
||||
# .@@@@. .@@@@. .@@@@..@@.@@..@@@..@@@..@@@@.... ....
|
||||
# @@@@... .@@@.. @@ @@ .@..@@..@@...@@@. .@@@@@. ..
|
||||
# .@@@.. . @@@. @@.@@..@@.@@..@@@ @@ .@@@@@@.. .....
|
||||
# ...@@@.... @@@ .@@.......... ........ ..... ..
|
||||
# . ..@@@@.. . .@@@@. .. ....... . .............
|
||||
# . .. .... .. .. . ... ....
|
||||
# . . .... ............. .. ...
|
||||
# .. .. ... ........ ... ...
|
||||
# ................................
|
||||
#
|
||||
# #############################################################
|
||||
"""
|
||||
files.py
|
||||
|
||||
Fonction de base sur les fichiers
|
||||
|
||||
Copyright (c) 2006 by www.crans.org
|
||||
"""
|
||||
|
||||
import datetime, time, os
|
||||
|
||||
def ageOfFile(pathToFile):
|
||||
"""renvoie l'age d'un fichier en secondes"""
|
||||
pathToFile = os.path.expanduser(pathToFile)
|
||||
return int(time.time()) - os.path.getmtime(pathToFile)
|
||||
|
||||
def fileIsOlderThan(pathToFile, days=0, hours=0, minutes=0, seconds=0):
|
||||
"""teste si un fichier est plus vieux on non que la valeur donnée"""
|
||||
time= (((days*24) + hours) * 60 + minutes) * 60 + seconds
|
||||
return ageOfFile(pathToFile) > time
|
||||
|
||||
def dirIsEmpty(pathToDir):
|
||||
"""teste : répond True si le dossier est vide."""
|
||||
return os.listdir(pathToDir) == []
|
||||
|
36
cranslib/utils/logs.py
Normal file
36
cranslib/utils/logs.py
Normal file
|
@ -0,0 +1,36 @@
|
|||
# -*- coding: utf8 -*-
|
||||
""" Cr@ns logging : logging utilities for cr@ns scripts
|
||||
"""
|
||||
import logging
|
||||
import os
|
||||
|
||||
LOG_FOLDER = "/var/log/crans/"
|
||||
__version__ = "0.1"
|
||||
|
||||
def getFileLogger(name):
|
||||
LOGGER.warning("getFileLogger is deprecated, use CransFileHandler instead.")
|
||||
logger = logging.getLogger(name)
|
||||
hdlr = CransFileHandler(name)
|
||||
logger.addHandler(hdlr)
|
||||
logger.setLevel(logging.INFO)
|
||||
return logger
|
||||
|
||||
class CransFileHandler(logging.FileHandler):
|
||||
def __init__(self, name):
|
||||
filepath = os.path.join(LOG_FOLDER, name + ".log")
|
||||
logging.FileHandler.__init__(self, filepath)
|
||||
formatter = logging.Formatter('%(asctime)s %(name)s %(levelname)s %(message)s')
|
||||
self.setFormatter(formatter)
|
||||
|
||||
### Un peu de configuration
|
||||
# On log systematiquement les warning, error, exception sous "crans"
|
||||
# sur l'ecran.
|
||||
CRANSLOGGER = logging.getLogger("crans")
|
||||
CRANSLOGGER.setLevel(logging.WARNING)
|
||||
streamhdlr = logging.StreamHandler()
|
||||
streamhdlr.setLevel(logging.ERROR)
|
||||
streamhdlr.setFormatter(logging.Formatter('%(levelname)s: %(message)s'))
|
||||
CRANSLOGGER.addHandler(streamhdlr)
|
||||
CRANSLOGGER.addHandler(CransFileHandler("crans"))
|
||||
|
||||
LOGGER = logging.getLogger("crans.logging")
|
50
cranslib/utils/quota.py
Normal file
50
cranslib/utils/quota.py
Normal file
|
@ -0,0 +1,50 @@
|
|||
|
||||
# -*- coding: utf8 -*-
|
||||
import os
|
||||
|
||||
LABELS = {
|
||||
"/home":u"Dossier personnel",
|
||||
"/var/mail":u"Boite de réception"
|
||||
}
|
||||
|
||||
def getFloat( chose ):
|
||||
chose = chose.replace(',', '.')
|
||||
return float(chose)
|
||||
|
||||
def getUserQuota( userLogin ):
|
||||
pipe = os.popen("sudo quota %s" % userLogin)
|
||||
string_result = pipe.read()
|
||||
pipe.close()
|
||||
string_result = string_result.split("\n")
|
||||
quotas = []
|
||||
for a_line in string_result[2:3]:
|
||||
usage, quota, limite, percentage, fs = a_line.split("\t")
|
||||
line_dict = {
|
||||
"label": "Quota personnel",
|
||||
"usage":getFloat(usage),
|
||||
"quota":getFloat(quota),
|
||||
"limite":getFloat(limite),
|
||||
"%":getFloat(percentage),
|
||||
"filesystem":"rda", # pourquoi pas ?
|
||||
}
|
||||
quotas.append(line_dict)
|
||||
return quotas
|
||||
|
||||
|
||||
|
||||
def fake_getUserQuota( userLogin ):
|
||||
return [
|
||||
{'%': 33.9,
|
||||
'quota': 390.62,
|
||||
'label': u'Dossier personnel (fake)',
|
||||
'limite': 585.94,
|
||||
'filesystem': '/home',
|
||||
'usage': 420.32},
|
||||
{'%': 0.1,
|
||||
'quota': 100.00,
|
||||
'label': u'Boite de r\xe9ception (fake)',
|
||||
'limite': 150.00,
|
||||
'filesystem': '/var/mail',
|
||||
'usage': 0.06}
|
||||
]
|
||||
|
0
cranslib/www/__init__.py
Normal file
0
cranslib/www/__init__.py
Normal file
83
cranslib/www/pagesperso.py
Normal file
83
cranslib/www/pagesperso.py
Normal file
|
@ -0,0 +1,83 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
class PagePerso:
|
||||
"""Classe représentant la page perso d'une personne"""
|
||||
|
||||
home = "/home"
|
||||
www = "/www"
|
||||
|
||||
def __init__(self, login):
|
||||
"""Instanciation avec le login' de la personne"""
|
||||
self.login = login
|
||||
self.home = "%s/%s" % (self.home, login)
|
||||
_info = {}
|
||||
self._load_informations()
|
||||
|
||||
def _filename( self ):
|
||||
return "%s/.info" % self.home
|
||||
|
||||
def _load_informations(self):
|
||||
try:
|
||||
lignes = file( self._filename() )
|
||||
except IOError:
|
||||
lignes = []
|
||||
# self._info est un dictionnaire qui reprend le contenu du .info
|
||||
self._info = dict( map( lambda z: (unicode(z[0].lower(),"iso-8859-15"),
|
||||
unicode(z[1],"iso-8859-15")),
|
||||
filter(lambda w: len(w) == 2 and len(w[1]),
|
||||
map(lambda x: map(lambda y: y.strip(),
|
||||
x.split(":")),
|
||||
lignes))))
|
||||
|
||||
def _save_informations( self ):
|
||||
myfile = file(self._filename(), "w")
|
||||
for aKey in self._info.keys():
|
||||
myfile.write("%s:%s\n" % (aKey, self.
|
||||
_info[aKey]) )
|
||||
myfile.write("\n")
|
||||
|
||||
def save( self ):
|
||||
self._save_informations()
|
||||
|
||||
def chemin(self):
|
||||
"""Chemin vers le www"""
|
||||
return u"%s%s" % (self.home, self.www)
|
||||
|
||||
def url(self):
|
||||
"""URL vers la page perso"""
|
||||
return u"http://perso.crans.org/%s/" % self.login
|
||||
|
||||
def nom( self ):
|
||||
return self._info.get("nom", "")
|
||||
|
||||
def setNom( self, nom ):
|
||||
self._info["nom"] = nom
|
||||
|
||||
def slogan( self ):
|
||||
return self._info.get("slogan", "")
|
||||
|
||||
def setSlogan( self, slogan ):
|
||||
self._info["slogan"] = slogan
|
||||
|
||||
def logo(self):
|
||||
"""URL du logo s'il y en a un"""
|
||||
logo = self._info.get("logo", None)
|
||||
if logo:
|
||||
# Le logo peut être en absolu ou en relatif
|
||||
if logo.startswith(self.chemin()):
|
||||
logo = logo.replace("%s/" % self.chemin(), "")
|
||||
if os.path.isfile("%s/%s" % (self.chemin(), logo)):
|
||||
return u"%s%s" % (self.url(), logo)
|
||||
return u"http://perso.crans.org/pageperso.png"
|
||||
|
||||
def __str__(self):
|
||||
"""Renvoie le code HTML correspondant au fichier .info"""
|
||||
html = [ u'<div class="vignetteperso">',
|
||||
u'<a href="%s">' % self.url(),
|
||||
u'<img src="%s" alt="%s">' % (self.logo(), self.login),
|
||||
u'</a><br>',
|
||||
self.info("nom") and u'<b>%s</b><br>' % self.info("nom") or u'%s<br>' % self.login,
|
||||
self.info("devise") and u'<i>%s</i>' % self.info("devise") or u'',
|
||||
u'</div>' ]
|
||||
return u'\n'.join(html)
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue