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:
parent
872fc47724
commit
e16bd85072
17 changed files with 275 additions and 6 deletions
32
lodel/interface/web/controllers.py
Normal file
32
lodel/interface/web/controllers.py
Normal 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
|
||||
12
lodel/interface/web/lodelrequest.py
Normal file
12
lodel/interface/web/lodelrequest.py
Normal 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)
|
||||
20
lodel/interface/web/router.py
Normal file
20
lodel/interface/web/router.py
Normal 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
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
9
lodel/interface/web/urls.py
Normal file
9
lodel/interface/web/urls.py
Normal 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)
|
||||
)
|
||||
0
lodel/template/__init__.py
Normal file
0
lodel/template/__init__.py
Normal file
0
lodel/template/api/__init__.py
Normal file
0
lodel/template/api/__init__.py
Normal file
3
lodel/template/api/api_lodel_templates.py
Normal file
3
lodel/template/api/api_lodel_templates.py
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Lodel 2 templates API : loaded by default
|
||||
0
lodel/template/exceptions/__init__.py
Normal file
0
lodel/template/exceptions/__init__.py
Normal 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
71
lodel/template/loader.py
Normal 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
|
||||
3
templates/admin/admin.html
Normal file
3
templates/admin/admin.html
Normal 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
15
templates/base.html
Normal 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>
|
||||
15
templates/base_backend.html
Normal file
15
templates/base_backend.html
Normal 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>
|
||||
5
templates/errors/404.html
Normal file
5
templates/errors/404.html
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
{% extends "Lodel/templates/base.html" %}
|
||||
{% block title %}Error 404{% endblock %}
|
||||
{% block content %}
|
||||
<h1>404 - File Not Found</h1>
|
||||
{% endblock %}
|
||||
3
templates/index/index.html
Normal file
3
templates/index/index.html
Normal 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
15
templates/test.html
Normal 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>
|
||||
Loading…
Add table
Add a link
Reference in a new issue