1
0
Fork 0
mirror of https://github.com/yweber/lodel2.git synced 2026-08-05 11:58:37 +02:00

Routing and Templating have been added

This commit is contained in:
Roland Haroutiounian 2016-04-27 16:25:32 +02:00
commit e16bd85072
17 changed files with 275 additions and 6 deletions

View file

@ -0,0 +1,32 @@
# -*- coding: utf-8 -*-
from werkzeug.wrappers import Response
from lodel.template.loader import TemplateLoader
# This module contains the web UI controllers that will be called from the web ui class
def admin(request):
loader = TemplateLoader()
response = Response(loader.render_to_response('templates/admin/admin.html'), mimetype='text/html')
response.status_code = 200
return response
def index(request):
loader = TemplateLoader()
response = Response(loader.render_to_response('templates/index/index.html'), mimetype='text/html')
response.status_code = 200
return response
def not_found(request):
loader = TemplateLoader()
response = Response(loader.render_to_response('templates/errors/404.html'), mimetype='text/html')
response.status_code = 404
return response
def test(request):
loader = TemplateLoader()
response = Response(loader.render_to_response('templates/test.html'), mimetype='text/html')
response.status_code = 200
return response

View file

@ -0,0 +1,12 @@
from werkzeug.wrappers import Request
from werkzeug.urls import url_decode
class LodelRequest(Request):
def __init__(self, environ):
super().__init__(environ)
self.PATH = self.path.lstrip('/')
self.FILES = self.files.to_dict(flat=False)
self.GET = url_decode(self.query_string).to_dict(flat=False)
self.POST = self.form.to_dict(flat=False)

View file

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
import re
from lodel.interface.web.controllers import *
import lodel.interface.web.urls as main_urls
def get_controller(request):
url_rules = []
for url in main_urls.urls:
url_rules.append((url[0], url[1]))
# Returning the right controller to call
for regex, callback in url_rules:
match = re.search(regex, request.PATH)
if match is not None:
request.url_args = match.groups()
return callback
return not_found

View file

@ -1,7 +1,66 @@
from werkzeug.wrappers import Response
# -*- coding: utf-8 -*-
import os
import datetime
from werkzeug.contrib.sessions import FilesystemSessionStore
def application(environ, start_response):
request = Request(environ)
text = 'Hello %s!' % request.args.get('name', 'World')
response = Response(text, mimetype='text/plain')
return response(environ, start_response)
from lodel.interface.web.router import get_controller
from lodel.interface.web.lodelrequest import LodelRequest
# TODO Déplacer ces trois paramètres dans les settings
SESSION_FILES_TEMPLATE = 'lodel_%s.sess'
SESSION_FILES_BASE_DIR = 'tmp/sessions'
SESSION_EXPIRATION_LIMIT = 900 # 15 min
session_store = FilesystemSessionStore(path=SESSION_FILES_BASE_DIR, filename_template=SESSION_FILES_TEMPLATE)
# TODO Déplacer cette méthode dans un module Lodel/utils/datetime.py
def get_utc_timestamp():
d = datetime.datetime.utcnow()
epoch = datetime.datetime(1970, 1, 1)
t = (d - epoch).total_seconds()
return t
# TODO déplacer dans un module "sessions.py"
def delete_old_session_files(timestamp_now):
session_files_path = os.path.abspath(session_store.path)
session_files = [file_object for file_object in os.listdir(session_files_path)
if os.path.isfile(os.path.join(session_files_path, file_object))]
for session_file in session_files:
expiration_timestamp = os.statos.path.join(session_files_path, session_file)).st_mtime + \
SESSION_EXPIRATION_LIMIT
if timestamp_now > expiration_timestamp:
os.unlink(os.path.join(session_files_path, session_file))
# TODO Déplacer dans une module "sessions.py"
def is_session_file_expired(timestamp_now, sid):
session_file = session_store.get_session_filename(sid)
expiration_timestamp = os.stat(session_file).st_mtime + SESSION_EXPIRATION_LIMIT
if timestamp_now < expiration_timestamp:
return False
return True
# WSGI Application
def application(env, start_response):
current_timestamp = get_utc_timestamp()
delete_old_session_files(current_timestamp)
request = LodelRequest(env)
sid = request.cookies.get('sid')
if sid is None or sid not in session_store.list():
request.session = session_store.new()
request.session['last_accessed'] = current_timestamp
else:
request.session = session_store.get(sid)
if is_session_file_expired(current_timestamp, sid):
session_store.delete(request.session)
request.session = session_store.new()
request.session['user_context'] = None
request.session['last_accessed'] = current_timestamp
controller = get_controller(request)
response = controller(request)
if request.session.should_save:
session_store.save(request.session)
response.set_cookie('sid', request.session.sid)
return response(env, start_response)

View file

@ -0,0 +1,9 @@
from lodel.interface.web.controllers import *
urls = (
(r'^$', index),
(r'admin/?$', admin),
(r'admin/(.+)$', admin),
(r'test/(.+)$', test),
(r'test/?$', test)
)

View file

View file

View file

@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-
# Lodel 2 templates API : loaded by default

View file

View file

@ -0,0 +1,7 @@
#-*- coding: utf-8 -*-
class NotAllowedCustomAPIKeyError(Exception):
def __init__(self, message):
self.message = message

71
lodel/template/loader.py Normal file
View file

@ -0,0 +1,71 @@
# -*- coding: utf-8 -*-
import jinja2
import os
import settings
from lodel.template.api import api_lodel_templates
from lodel.template.exceptions.not_allowed_custom_api_key_error import NotAllowedCustomAPIKeyError
class TemplateLoader(object):
_reserved_template_keys = ['lodel']
## @brief Initializes a template loader
#
# @param search_path str : the base path from which the templates are searched. To use absolute paths, you can set
# it to the root "/". By default, it will be the root of the project, defined in the settings of the application.
# @param follow_links bool : indicates whether or not to follow the symbolic links (default: True)
# @param is_cache_active bool : indicates whether or not the cache should be activated or not (default: True)
# @todo connect this to the new settings system
def __init__(self, search_path=settings.base_path, follow_links=True, is_cache_active=True):
self.search_path = search_path
self.follow_links = follow_links
self.is_cache_active = is_cache_active
## @brief Renders a HTML content of a template
#
# @see template.loader.TemplateLoader.render_to_response
#
# @return str. String containing the HTML output of the processed templated
def render_to_html(self, template_file, template_vars={}, template_extra=None):
loader = jinja2.FileSystemLoader(searchpath=self.search_path, followlinks=self.follow_links)
environment = jinja2.Environment(loader=loader) if self.is_cache_active else jinja2.Environment(loader=loader,
cache_size=0)
template = environment.get_template(template_file)
# lodel2 default api is loaded
# TODO change this if needed
template.globals['lodel'] = api_lodel_templates
# Extra modules are loaded
if template_extra is not None:
for extra in template_extra:
if not self._is_allowed_template_key(extra[0]):
raise NotAllowedCustomAPIKeyError("The name '%s' is a reserved one for the loaded APIs in "
"templates" % extra[0])
template.globals[extra[0]] = extra[1]
return template.render(template_vars)
## @brief Renders a template into an encoded form ready to be sent to a wsgi response
#
# @param template_file str : path to the template file (starting from the base path used to instanciate the
# TemplateLoader)
# @param template_vars dict : parameters to be used in the template
# @param template_extra list : list of tuples indicating the custom modules to import in the template
# (default: None).
#
# The modules are given as tuples with the format : ('name_to_use_in_the_template', module)
#
# @return str
def render_to_response(self, template_file, template_vars={}, template_extra=None):
return self.render_to_html(template_file=template_file, template_vars=template_vars,
template_extra=template_extra).encode()
## @brief Checks if the key used for the template is allowed
#
# @param key str
# @return bool
def _is_allowed_template_key(self, key):
return False if key in self.__class__.__reserved_template_keys else True

View file

@ -0,0 +1,3 @@
{% extends "templates/base_backend.html" %}
{% block title %}Lodel 2 - ADMIN{% endblock %}
{% block content %}ADMIN{% endblock %}

15
templates/base.html Normal file
View file

@ -0,0 +1,15 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>{% block title %}{% endblock %}</title>
{% block style %}{% endblock %}
{% block scripts %}{% endblock %}
</head>
<body>
<div id="content">
{% block content %}{% endblock %}
</div>
<script type="text/javascript">{% block javascript %}{% endblock %}</script>
</body>
</html>

View file

@ -0,0 +1,15 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>{% block title %}{% endblock %}</title>
{% block style %}{% endblock %}
{% block scripts %}{% endblock %}
</head>
<body>
<div id="content">
{% block content %}{% endblock %}
</div>
<script type="text/javascript">{% block javascript %}{% endblock %}</script>
</body>
</html>

View file

@ -0,0 +1,5 @@
{% extends "Lodel/templates/base.html" %}
{% block title %}Error 404{% endblock %}
{% block content %}
<h1>404 - File Not Found</h1>
{% endblock %}

View file

@ -0,0 +1,3 @@
{% extends "Lodel/templates/base.html" %}
{% block title %}Lodel 2 - DASHBOARD{% endblock %}
{% block content %}DASHBOARD{% endblock %}

15
templates/test.html Normal file
View file

@ -0,0 +1,15 @@
<html>
<head></head>
<body>
<form action="http://haroutiounian-devel.in.revues.org:9090/admin?r=1&rand[]=7&rand[]=5" method="POST" enctype="multipart/form-data">
<input type="text" name="re[]" value="3"><br />
<input type="text" name="re[]" value="1"><br />
<input type="text" name="val" value="8"><br />
<input type="file" name="myfile1"><br />
<input type="file" name="myfile2"><br />
<input type="file" name="myfiles[]"><br />
<input type="file" name="myfiles[]"><br />
<input type="submit" value="tester"><br />
</form>
</body>
</html>