Modification de la structure de l'intranet

darcs-hash:20070124113425-f46e9-b0dc2101073d5c4d896539104cc418693bab419a.gz
This commit is contained in:
gdetrez 2007-01-24 12:34:25 +01:00
parent 0570881d34
commit 8713311bc1
13 changed files with 331 additions and 191 deletions

View file

@ -1,5 +1,6 @@
from cherrypy.filters.basefilter import BaseFilter from cherrypy.filters.basefilter import BaseFilter
import cherrypy._cputil import cherrypy._cputil
import cherrypy
########################## ##########################
# verification des droits # verification des droits
@ -8,7 +9,7 @@ import cherrypy._cputil
def verifDroits(mesDroits, lesDroitsQuilFaut): def verifDroits(mesDroits, lesDroitsQuilFaut):
if not type(mesDroits) == list: if not type(mesDroits) == list:
raise ValueError, "mesDroits doit etre une liste" raise ValueError, "mesDroits doit etre une liste"
if (lesDroitsQuilFaut == "all"): if (lesDroitsQuilFaut == "all") or (lesDroitsQuilFaut == []):
return True return True
if ("Nounou" in mesDroits): if ("Nounou" in mesDroits):
return True return True
@ -18,7 +19,7 @@ def verifDroits(mesDroits, lesDroitsQuilFaut):
return True in [d in mesDroits for d in lesDroitsQuilFaut] return True in [d in mesDroits for d in lesDroitsQuilFaut]
return False return False
class VerifDroitsFilter(BaseFilter): class AuthorisationsFilter(BaseFilter):
def before_main(self): def before_main(self):
if not cherrypy.config.get('sessionAuthenticateFilter.on', False): if not cherrypy.config.get('sessionAuthenticateFilter.on', False):
@ -29,3 +30,13 @@ class VerifDroitsFilter(BaseFilter):
if not verifDroits(cherrypy.session['droits'], droits): if not verifDroits(cherrypy.session['droits'], droits):
raise cherrypy.HTTPError(403, "Vous n'avez pas les droits nécessaires pour accéder à cette page.") raise cherrypy.HTTPError(403, "Vous n'avez pas les droits nécessaires pour accéder à cette page.")
##########################
# mise en place des droits
##########################
#
def setDroits(chemin, lesDroitsQuilFaut):
settings= {
chemin:
{ 'crans.droits': lesDroitsQuilFaut}
}
cherrypy.config.update(settings)

View file

@ -0,0 +1,224 @@
#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-
# #############################################################
# ..
# .... ............ ........
# . ....... . .... ..
# . ... .. .. .. .. ..... . ..
# .. .. ....@@@. .. . ........ .
# .. . .. ..@.@@..@@. .@@@@@@@ @@@@@@. ....
# .@@@@. .@@@@. .@@@@..@@.@@..@@@..@@@..@@@@.... ....
# @@@@... .@@@.. @@ @@ .@..@@..@@...@@@. .@@@@@. ..
# .@@@.. . @@@. @@.@@..@@.@@..@@@ @@ .@@@@@@.. .....
# ...@@@.... @@@ .@@.......... ........ ..... ..
# . ..@@@@.. . .@@@@. .. ....... . .............
# . .. .... .. .. . ... ....
# . . .... ............. .. ...
# .. .. ... ........ ... ...
# ................................
#
# #############################################################
# Intranet.py
#
# Classe Intranet, clase de base de l'intranet
#
# Copyright (c) 2006 by www.crans.org
# #############################################################
import crans.cp as _crans_cp
import cherrypy, os
import crans.utils.exceptions
from ClassesIntranet.AuthorisationsManager import setDroits
class Intranet:
# ######################################################## #
# GESTION DES MODULES #
# ######################################################## #
#
#
_loaded_modules = {}
def _make_static_path_for_module(self, module_name ):
return "/" + module_name + "/static"
def loadModule(self, un_module):
MODULES_DIR = cherrypy.config.get("crans.modules.dir")
if not un_module.startswith("."):
# faire ici l'importation
# importer le fichier main.py
try:
module_path = MODULES_DIR + "/" + un_module + "/main"
mon_module = __import__(module_path)
module_root = mon_module.main()
# on ajoute la classe a l'arborescence de cherrypy :
setattr( self, un_module, module_root)
# on ajoute le module aux modules connus :
try:
cat = module_root.category()
if not self._loaded_modules.has_key(cat):
self._loaded_modules[cat] = {}
self._loaded_modules[cat][un_module] = module_root
except:
if cherrypy.config.get("server.environment") == "development":
_crans_cp.log("Impossible d'obtenir les parametres du module %s" % un_module)
_crans_cp.log(crans.utils.exceptions.formatExc())
# on ajoute les droits du module :
try:
droits_module = module_root.droits()
setDroits("/%s" % un_module, droits_module)
except:
if cherrypy.config.get("server.environment") == "development":
_crans_cp.log("Impossible d'obtenir les parametres du module %s" % un_module)
_crans_cp.log(crans.utils.exceptions.formatExc())
except:
_crans_cp.log("Impossible de charger le module %s" % un_module)
if cherrypy.config.get("server.environment") == "development":
_crans_cp.log(crans.utils.exceptions.formatExc())
# ajouter le dossier static ou il faut
staticPath = cherrypy.config.get("rootDir") + "/" + MODULES_DIR + "/" + un_module + "/static"
if os.path.isdir(staticPath):
settings= { self._make_static_path_for_module(un_module):
{ 'sessionAuthenticateFilter.on': False,
'sessionFilter.on': False,
'server.output_filters.templatesEngine.on' : False,
'staticFilter.on': True,
'staticFilter.dir': staticPath,
}
}
cherrypy.config.update(settings)
if cherrypy.config.get("server.environment") == "development":
_crans_cp.log("New static : %s" % staticPath)
# fin de l'ajout du dossier static
def __init__(self):
##
#### import automatique des modules
##
MODULES_DIR = cherrypy.config.get("crans.modules.dir", False)
if MODULES_DIR:
if os.path.isdir(MODULES_DIR):
Liste_Modules = os.listdir(MODULES_DIR)
for un_module in Liste_Modules:
self.loadModule(un_module)
else:
_crans_cp.log("Dossier des modules invalide", 'LOADING', 2)
else:
_crans_cp.log("Pas de dossier de modules", 'LOADING', 2)
# ######################################################## #
# QUELQUES PAGES #
# ######################################################## #
#
#
def index(self):
items = {}
for a_category in self._loaded_modules:
items[a_category] = {}
for a_module_name in self._loaded_modules[a_category]:
module_object = self._loaded_modules[a_category][a_module_name]
if module_object.accessible():
items[a_category][a_module_name] = {}
items[a_category][a_module_name]["name"] = module_object.title()
items[a_category][a_module_name]["icon"] = self._make_static_path_for_module(a_module_name) + "/" + module_object.icon()
items[a_category][a_module_name]["url"] = "/" + a_module_name + "/"
# si la categorie est vide, on la vire
if items[a_category] == {}:
del items[a_category]
return {
'template':'accueil',
'values':{"modules":items},
'stylesheets':['css/accueil.css'],
}
index.exposed= True
def info(self):
return {
'template':'info-diverses',
'values':{},
'stylesheets':['accueil.css'],
}
info.exposed = True
def send_error_repport(self, **kw):
# on récupère tout de suite le traceback
tb = crans.utils.exceptions.formatExc()
# entêtes du mail
exp = "intranet"
dest = cherrypy.config.get("mail.bugreport", "nounous@crans.org")
subject = "Rapport de Bug"
text = """
Bonsoir,
Ceci est un rapport de bug envoye par l'intranet.
%s
""" % "\n".join( [ "%s: %s" % (str(a), str(kw[a])) for a in kw] )
#On ajoute des variables de cherrypy
text += "\n= Cherrypy vars =\n"
try:
text += "url: %s\n" % cherrypy.request.browser_url
except:
pass
try:
text += "headers: \n %s\n" % "\n".join( [" %s: %s" % (str(a), str(cherrypy.request.headers[a])) for a in cherrypy.request.headers] )
except:
pass
try:
text += "query_string: %s\n" % cherrypy.request.query_string
except:
pass
try:
text += "path: %s\n" % cherrypy.request.path
except:
pass
# on ajoute le traceback
text += "\n= Traceback =\n"
text += tb
#on signe, quand même !
text += "\n-- \nRoot.py pour l'intranet\n"
quickSend(exp, dest, subject, text)
return self.index()
send_error_repport.exposed = True
def testErreur(self):
raise Exception, "sdlfkjqmsdklj"
testErreur.exposed = True
def test(self):
return cherrypy.request.remote_addr
test.exposed = True
def _cp_on_http_error(self, status, message):
if (cherrypy.config.configMap["global"]["server.environment"] == "development"):
cherrypy._cputil._cp_on_http_error(status, message)
return
if status==403:
cherrypy.response.body = {
'template':'error403',
'values':{'status':status, 'message':message },
'standalone':False,
}
elif status==404:
cherrypy.response.body = {
'template':'error',
'values':{'status':status, 'message':message },
'standalone':False,
}
elif status==500:
self.send_error_repport(status = status, message = message )
# les filtres ne sont pas appliqués, on le fait à la main...
from plugins.templatesfilter import TemplatesFilter
TemplatesFilter().goWithThisDict({'template':'error', 'values':{'status':status, 'message':message }})
else:
self.send_error_repport(status = status, message = message)
cherrypy._cputil._cp_on_http_error(status, message)

View file

@ -0,0 +1,18 @@
import cherrypy
from AuthorisationsManager import verifDroits
class ModuleBase:
def category(self):
return "Personnel"
def title(self):
return "Titre"
def icon(self):
return "icon.png"
_droits = []
def droits(self):
return self._droits
def accessible(self):
return verifDroits(cherrypy.session['droits'], self.droits())

View file

@ -1,17 +1,25 @@
from cherrypy.filters.basefilter import BaseFilter from cherrypy.filters.basefilter import BaseFilter
import cherrypy, os import cherrypy, os
from Cheetah.Template import Template from Cheetah.Template import Template
import crans.cp as _crans_cp
from ClassesIntranet import current_module
# ######################################################## # # ######################################################## #
# Configuration de Cheetah # # Configuration de Cheetah #
# ######################################################## # # ######################################################## #
def serverSidePath(self, path): def serverSidePath(self, path):
if (cherrypy.config.configMap["global"]["server.environment"] == "development"): root_dir = cherrypy.config.configMap["global"]["rootDir"]
if os.path.isfile(cherrypy.config.configMap["global"]["rootDir"]+'/templates/'+path+".dev"): if os.path.isfile(path):
return cherrypy.config.configMap["global"]["rootDir"]+'/templates/'+path+".dev" return path
# les template se trouve dans le dossier template try:
return cherrypy.config.configMap["global"]["rootDir"]+'/templates/'+path module_name = current_module()
hyp_path = root_dir + '/modules/' + module_name + '/templates/' + path
if os.path.isfile(hyp_path):
return hyp_path
except:
pass
return root_dir + '/templates/' + path
# on surcharge cette fonction dans la classe Template # on surcharge cette fonction dans la classe Template
Template.serverSidePath = serverSidePath Template.serverSidePath = serverSidePath
@ -25,6 +33,19 @@ Template.serverSidePath = serverSidePath
# avec plein de test chians # avec plein de test chians
# #
class TemplatesFilter(BaseFilter): class TemplatesFilter(BaseFilter):
def _getCorrectStaticMethod(self):
try:
module_name = current_module()
if module_name != None:
def static(truc):
return "/" + module_name + "/static/" + truc
return static
except:
pass
def static(truc):
return "/static/" + truc
return static
def _getBodyTemplate(self, body): def _getBodyTemplate(self, body):
if isinstance(body, dict): if isinstance(body, dict):
@ -55,10 +76,13 @@ class TemplatesFilter(BaseFilter):
return {} return {}
def _useMainTemplate(self, body): def _useMainTemplate(self, body):
values = {'environment':cherrypy.config.configMap["global"]["server.environment"],
'static':self._getCorrectStaticMethod(),
}
try: try:
t = Template(file='main.tmpl', searchList=[body,{'login':cherrypy.session['uid'], 'environment':cherrypy.config.configMap["global"]["server.environment"]}]) t = Template(file='main.tmpl', searchList= [body,{'login':cherrypy.session['uid']}, values])
except: except:
t = Template(file='main.tmpl', searchList=[body,{'login':'', 'environment':cherrypy.config.configMap["global"]["server.environment"]}]) t = Template(file='main.tmpl', searchList=[body,{'login':''},values])
return str(t) return str(t)
@ -67,7 +91,8 @@ class TemplatesFilter(BaseFilter):
bodyTemplate = self._getBodyTemplate(body) bodyTemplate = self._getBodyTemplate(body)
if bodyTemplate: if bodyTemplate:
templatevalues = self._getBodyNameSpace(body) templatevalues = self._getBodyNameSpace(body)
t = Template(file=bodyTemplate, searchList=[templatevalues]) defaultvalues = {'static':self._getCorrectStaticMethod()}
t = Template(file=bodyTemplate, searchList=[templatevalues, defaultvalues])
body['page'] = str(t) body['page'] = str(t)
if not self._isStandaloneBody(body): if not self._isStandaloneBody(body):

View file

@ -0,0 +1,8 @@
import cherrypy
def current_module():
current_path = cherrypy.request.object_path
module_name = current_path.split('/')[1]
if module_name != 'index':
return module_name
return None

View file

@ -24,13 +24,9 @@
# #
# Copyright (c) 2006 by www.crans.org # Copyright (c) 2006 by www.crans.org
# ############################################################# # #############################################################
import cherrypy, sys, os, datetime import cherrypy, sys, os, datetime
import crans.utils.exceptions import crans.utils.exceptions
sys.path.append('/usr/scripts/gestion/') sys.path.append('/usr/scripts/gestion/')
# ######################################################## # # ######################################################## #
# COMMAND LINE OPTION # # COMMAND LINE OPTION #
# ######################################################## # # ######################################################## #
@ -61,7 +57,7 @@ parser.add_option("-p", "--port",
if (options.dev): if (options.dev):
cherrypy.config.update(file=os.getcwd() + "/conf/intranet.cfg") cherrypy.config.update(file=os.getcwd() + "/conf/intranet.cfg")
cherrypy.config.update(file=os.getcwd() + "/conf/dev.cfg") cherrypy.config.update(file=os.getcwd() + "/conf/dev.cfg")
settings={'global': { 'rootDir': os.getcwd() } } settings= { 'global': { 'rootDir': os.getcwd() } }
cherrypy.config.update(settings) cherrypy.config.update(settings)
else: else:
@ -75,142 +71,28 @@ if (options.port):
# import du CransLdap qu'il va bien (on utilise CransLdap et non crans_ldap car on veut # import du CransLdap qu'il va bien (on utilise CransLdap et non crans_ldap car on veut
# forcer l'ouverture d'une nouvelle connexion à chaque login) # forcer l'ouverture d'une nouvelle connexion à chaque login)
if (cherrypy.config.configMap["global"]["server.environment"] == "development"): if (cherrypy.config.configMap["global"]["server.environment"] == "development"):
from ldap_crans_test import CransLdap from ldap_crans_test import CransLdap
cherrypy.log("settings : unsing test ldap : env=" + cherrypy.config.configMap["global"]["server.environment"], "LDAP")
else: else:
from ldap_crans import CransLdap from ldap_crans import CransLdap
cherrypy.log("settings : unsing prod ldap : env=" + cherrypy.config.configMap["global"]["server.environment"], "LDAP")
sys.path.append(cherrypy.config.get('rootDir'))
# ######################################################## # # ######################################################## #
# FILTRES MAISON # # FILTRES MAISON #
# ######################################################## # # ######################################################## #
from plugins.domfilter import DOMFilter from ClassesIntranet.AJAXManager import DOMFilter
from plugins.templatesfilter import TemplatesFilter from ClassesIntranet.TemplatesManager import TemplatesFilter
from plugins.verifdroitsfilter import VerifDroitsFilter from ClassesIntranet.AuthorisationsManager import AuthorisationsFilter
from crans.mail import quickSend from crans.mail import quickSend
import crans.cp as _crans_cp
# ######################################################## # # ######################################################## #
# SERVER # # SERVER #
# ######################################################## # # ######################################################## #
class Intranet: from ClassesIntranet.Intranet import Intranet
def __init__(self): # GESTION DES FILTRES
from pages import monCompte, impression, factures, digicode, mesmachines Intranet._cpFilterList = [TemplatesFilter(), DOMFilter(), AuthorisationsFilter()]
from pages import gestionFactures
# liste des modules disponibles
self.monCompte = monCompte.monCompte()
self.sous = factures.root()
self.impression = impression.root()
self.digicode = digicode.root()
self.mesMachines = mesmachines.root()
self.gestionFactures = gestionFactures.root()
# liste des modules en developpement
#if (cherrypy.config.configMap["global"]["server.environment"] == "development"):
_cpFilterList = [TemplatesFilter(), DOMFilter(), VerifDroitsFilter()]
def index(self):
return {
'template':'accueil',
'values':{},
'stylesheets':['accueil.css'],
}
index.exposed= True
def info(self):
return {
'template':'info-diverses',
'values':{},
'stylesheets':['accueil.css'],
}
info.exposed = True
def send_error_repport(self, **kw):
# on récupère tout de suite le traceback
tb = crans.utils.exceptions.formatExc()
# entêtes du mail
exp = "intranet"
dest = cherrypy.config.get("mail.bugreport", "nounous@crans.org")
subject = "Rapport de Bug"
text = """
Bonsoir,
Ceci est un rapport de bug envoye par l'intranet.
%s
""" % "\n".join( [ "%s: %s" % (str(a), str(kw[a])) for a in kw] )
#On ajoute des variables de cherrypy
text += "\n= Cherrypy vars =\n"
try:
text += "url: %s\n" % cherrypy.request.browser_url
except:
pass
try:
text += "headers: \n %s\n" % "\n".join( [" %s: %s" % (str(a), str(cherrypy.request.headers[a])) for a in cherrypy.request.headers] )
except:
pass
try:
text += "query_string: %s\n" % cherrypy.request.query_string
except:
pass
try:
text += "path: %s\n" % cherrypy.request.path
except:
pass
# on ajoute le traceback
text += "\n= Traceback =\n"
text += tb
#on signe, quand même !
text += "\n-- \nRoot.py pour l'intranet\n"
quickSend(exp, dest, subject, text)
return self.index()
send_error_repport.exposed = True
def testErreur(self):
raise Exception, "sdlfkjqmsdklj"
testErreur.exposed = True
def test(self):
return cherrypy.request.remote_addr
test.exposed = True
def _cp_on_http_error(self, status, message):
if (cherrypy.config.configMap["global"]["server.environment"] == "development"):
cherrypy._cputil._cp_on_http_error(status, message)
return
if status==403:
cherrypy.response.body = {
'template':'error403',
'values':{'status':status, 'message':message },
'standalone':False,
}
elif status==404:
cherrypy.response.body = {
'template':'error',
'values':{'status':status, 'message':message },
'standalone':False,
}
elif status==500:
self.send_error_repport(status = status, message = message )
# les filtres ne sont pas appliqués, on le fait à la main...
from plugins.templatesfilter import TemplatesFilter
TemplatesFilter().goWithThisDict({'template':'error', 'values':{'status':status, 'message':message }})
else:
self.send_error_repport(status = status, message = message)
cherrypy._cputil._cp_on_http_error(status, message)
# ######################################################## # # ######################################################## #
# LOGIN MAISON # # LOGIN MAISON #
@ -266,5 +148,5 @@ cherrypy.config.update(settings)
# ######################################################## # # ######################################################## #
# LANCEMENT DE CHERRYPY # # LANCEMENT DE CHERRYPY #
# ######################################################## # # ######################################################## #
cherrypy.root = Intranet() cherrypy.tree.mount(Intranet(),'/')
cherrypy.server.start() cherrypy.server.start()

View file

@ -20,9 +20,12 @@ logDebugInfoFilter.on = False
paypal.businessAdress = "gdetrez-buisness@crans.org" paypal.businessAdress = "gdetrez-buisness@crans.org"
paypal.useSandbox = True paypal.useSandbox = True
crans.modules.dir = "modules"
# #
[/test] [/test]
crans.droits = "Nounous" crans.droits = "Nounous"
[/static] [/static]
# cherrypy veut des chemins absolus
staticFilter.dir = "/home/gdetrez/crans.usr.scripts/intranet/static/" staticFilter.dir = "/home/gdetrez/crans.usr.scripts/intranet/static/"

View file

@ -5,10 +5,7 @@ mail.bugreport = "intranet-bugreport@lists.crans.org"
sessionAuthenticateFilter.on=True sessionAuthenticateFilter.on=True
sessionFilter.on = True sessionFilter.on = True
sessionFilter.locking = "implicit" sessionFilter.locking = "implicit"
crans.modules.dir = "/usr/scripts/intranet/modules/"
# ceci est un exemple de definission de droits
#[/nounous]
#crans.droits="Nounou"
[/] [/]
# Now we can work on our filter as with the standard filters # Now we can work on our filter as with the standard filters
@ -21,7 +18,7 @@ crans.droits="Imprimeur"
[/impression] [/impression]
crans.activate = True crans.activate = True
crans.activate.errorMsg = u"Plus d'encre ! Le fournisseur s'est trompé dans la commande." crans.activate.errorMsg = u"Plus d'encre ! Le fournisseur s'est trompé dans la commande."
[/static] [/static]
sessionAuthenticateFilter.on=False sessionAuthenticateFilter.on=False
@ -30,9 +27,9 @@ server.output_filters.templatesEngine.on = False
staticFilter.on = True staticFilter.on = True
staticFilter.dir = "/usr/scripts/intranet/static/" staticFilter.dir = "/usr/scripts/intranet/static/"
[/favicon.ico] #[/favicon.ico]
sessionAuthenticateFilter.on=False #sessionAuthenticateFilter.on=False
sessionFilter.on = False #sessionFilter.on = False
server.output_filters.templatesEngine.on = False #server.output_filters.templatesEngine.on = False
staticFilter.on = True #staticFilter.on = True
staticFilter.file = "/usr/scripts/intranet/static/favicon.ico" #staticFilter.file = "/usr/scripts/intranet/static/favicon.ico"

View file

@ -1,4 +1,4 @@
# The configuration file called myconfigfile.conf # The configuration file called prod.conf
[global] [global]
server.socketPort=8080 server.socketPort=8080
server.socketHost="" server.socketHost=""

View file

@ -2,46 +2,18 @@
$sys.path.append(cherrypy.config.get('rootDir')) $sys.path.append(cherrypy.config.get('rootDir'))
#from plugins.verifdroitsfilter import verifDroits #from plugins.verifdroitsfilter import verifDroits
<div class="framed_gray"> <div class="framed_gray">
#for a_category in $modules
<fieldset> <fieldset>
<legend>Personnel</legend> <legend>$a_category</legend>
<ul> <ul>
<li><a href="/monCompte"> #for a_module_name in $modules[a_category]
<img src="/static/images/icon_monCompte.png" alt="icon" /> #set the_module = $modules[a_category][a_module_name]
<span>Mon Compte</span> <li><a href="$the_module.url">
<img src="$the_module.icon" alt="icon" />
<span>$the_module.name</span>
</a></li> </a></li>
<li><a href="/mesMachines"> #end for
<img src="/static/images/machines_icon_fixe.png" alt="icon" /> <ul>
<span>Mes Machines</span>
</a></li>
<li><a href="/impression">
<img src="/static/images/icon_impression.png" alt="icon" />
<span>Impression</span>
</a></li>
<li><a href="/sous">
<img src="/static/images/icon_factures.png" alt="icon" />
<span>Mes Factures</span>
</a></li>
<li><a href="/info">
<img src="/static/images/icon_info.png" alt="icon" />
<span>Informations utiles</span>
</a></li>
</ul>
</fieldset> </fieldset>
<div style="clear:both;"></div> #end for
#if verifDroits($cherrypy.session['droits'],'Imprimeur')
<fieldset>
<legend>Imprimeur</legend>
<ul>
<li><a href="/digicode">
<img src="/static/images/icon_digicode.png" alt="icon" />
<span>Digicode</span>
</a></li>
<li><a href="/gestionFactures">
<img src="/static/images/icon_gestionFactures.png" alt="icon" />
<span>Gestion factures</span>
</a></li>
</ul>
</fieldset>
<div class="visualClear"></div>
#end if
</div> </div>

View file

@ -10,7 +10,7 @@
<link rel="stylesheet" type="text/css" href="/static/css/mainInterface.css" /> <link rel="stylesheet" type="text/css" href="/static/css/mainInterface.css" />
#if $getVar('stylesheets',False) #if $getVar('stylesheets',False)
#for $a_stylesheet in $stylesheets #for $a_stylesheet in $stylesheets
<link rel="stylesheet" type="text/css" href="/static/css/$a_stylesheet" /> <link rel="stylesheet" type="text/css" href="$static($a_stylesheet)" />
#end for #end for
#end if #end if
@ -21,7 +21,7 @@
#if $getVar('scripts',False) #if $getVar('scripts',False)
#for $a_script in $scripts #for $a_script in $scripts
<script src="/static/scripts/$a_script" type="text/javascript"></script> <script src="$static($a_script)" type="text/javascript"></script>
#end for #end for
#end if #end if