Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1"""
2@file
3@brief Starts an app locally to test it.
4"""
5import os
6import sys
7import uvicorn
8from ..apps import QCMApp
9from ..apps.server import ServerHypercorn
10from .cli_helper import build_games
13def create_qcm_local_app(
14 # log parameters
15 secret_log=None,
16 folder='.',
17 # authentification parameters
18 max_age=14 * 24 * 60 * 60,
19 cookie_key=None, cookie_name="mathenjeu",
20 cookie_domain="127.0.0.1", cookie_path="/",
21 # application parameters
22 title="Web Application MathEnJeu", short_title="MathEnJeu",
23 page_doc="http://www.xavierdupre.fr/app/mathenjeu/helpsphinx/",
24 secure=False, display=None, fct_game=None,
25 games=("simple_cinema_qcm,simple_cinema_qcm,0;"
26 "simple_french_qcm,simple_french_qcm,0;"
27 "ml_french_qcm,ml_french_qcm,0"),
28 port=8868, middles=None, start=False,
29 userpwd=None, debug=False, fLOG=print):
30 """
31 Creates a local web-application with very simple authentification.
33 :param secret_log: to encrypt log (None to ignore)
34 :param folder: folder where to write the logs (None to disable the logging)
35 :param max_age: cookie's duration in seconds
36 :param cookie_key: to encrypt information in the cookie (cannot be None)
37 :param cookie_name: name of the session cookie
38 :param cookie_domain: cookie is valid for this path only, also defines the
39 domain of the web app (its url)
40 :param cookie_path: path of the cookie once storeds
41 :param secure: use secured connection for cookies
42 :param title: title
43 :param short_title: short application title
44 :param page_doc: page documentation (default is :epkg:`mathenjeu`)
45 :param display: display such as @see cl DisplayQuestionChoiceHTML
46 :param fct_game: function *lambda name:* @see cl ActivityGroup
47 :param games: defines which games is available as a dictionary
48 ``{ game_id: (game name, first page id) }`` or
49 ``id,name,page;id,name,page``, *id* can be a filename.
50 :param port: port to deploy the application
51 :param middles: middles ware, list of couple ``[(class, **kwargs)]``
52 where *kwargs* are the parameter constructor
53 :param start: starts the application with :epkg:`uvicorn`
54 :param userpwd: users are authentified with any alias but a common password
55 :param debug: display debug information (:epkg:`starlette` option)
56 :param fLOG: logging function
57 :return: @see cl QCMApp
59 .. cmdref::
60 :title: Creates a local web-application with very simple authentification
61 :cmd: -m mathenjeu qcm_local --help
63 The command line runs a web application meant to be local
64 as there is not *https* involved. It implements a Q&A.
65 The web app relies on :epkg:`starlette`, the server relies
66 on :epkg:`uvicorn`. Example of use::
68 python -m mathenjeu qcm_local --cookie_key=dummypwd --start=1 --port=8889 --userpwd=abc
70 With that application, every user can login with a unique password *abc*.
71 """
72 if secret_log == '':
73 raise ValueError( # pragma: no cover
74 "secret_log must be not empty or None, not ''")
75 games, fct_game = build_games(games, fct_game)
76 if fLOG:
77 fLOG("[create_qcm_local_app] games=" + str(games))
79 app = QCMApp(secret_log=secret_log, middles=middles,
80 folder=folder, max_age=max_age,
81 cookie_key=cookie_key, cookie_name=cookie_name,
82 cookie_domain=cookie_domain, cookie_path=cookie_path,
83 title=title, short_title=short_title,
84 secure=secure, display=display, fct_game=fct_game,
85 games=games, page_doc=page_doc, userpwd=userpwd)
86 if start:
87 if fLOG:
88 fLOG(
89 "[create_qcm_local_app] start server 'http://{0}:{1}'".format(cookie_domain, port))
90 uvicorn.run(app.app, host=cookie_domain, port=port)
91 return app
94def create_qcm_https_app(
95 # log parameters
96 secret_log=None,
97 folder='.',
98 # authentification parameters
99 max_age=14 * 24 * 60 * 60,
100 cookie_key=None, cookie_name="mathenjeu",
101 cookie_domain="127.0.0.1", cookie_path="/",
102 # application parameters
103 title="Web Application MathEnJeu", short_title="MathEnJeu",
104 page_doc="http://www.xavierdupre.fr/app/mathenjeu/helpsphinx/",
105 secure=False, display=None,
106 games=("simple_cinema_qcm,simple_cinema_qcm,0;"
107 "simple_french_qcm,simple_french_qcm,0;"
108 "ml_french_qcm,ml_french_qcm,0"),
109 port=8868, middles=None, start=False,
110 userpwd=None, debug=False,
111 # hypercorn parameters
112 access_log="-",
113 access_log_format="%(h)s %(r)s %(s)s %(b)s %(D)s",
114 ca_certs=None, certfile=None, error_log='-',
115 keep_alive=600, keyfile=None, root_path='', workers=1,
116 reload=False, ciphers="ECDHE+AESGCM", fLOG=print):
117 """
118 Creates a https web-application with https authentification.
120 :param secret_log: to encrypt log (None to ignore)
121 :param folder: folder where to write the logs (None to disable the logging)
122 :param max_age: cookie's duration in seconds
123 :param cookie_key: to encrypt information in the cookie (cannot be None)
124 :param cookie_name: name of the session cookie
125 :param cookie_domain: cookie is valid for this path only, also defines the
126 domain of the web app (its url)
127 :param cookie_path: path of the cookie once storeds
128 :param secure: use secured connection for cookies
129 :param title: title
130 :param short_title: short application title
131 :param page_doc: page documentation (default is 'http://www.xavierdupre.fr/app/mathenjeu/helpsphinx')
132 :param display: display such as @see cl DisplayQuestionChoiceHTML
133 :param games: defines which games is available as a dictionary
134 ``{ game_id: (game name, first page id) }`` or
135 ``id,name,page;id,name,page``, *id* can be a filename.
136 :param port: port to deploy the application
137 :param middles: middles ware, list of couple ``[(class, **kwargs)]``
138 where *kwargs* are the parameter constructor
139 :param start: starts the application with :epkg:`uvicorn`
140 :param userpwd: users are authentified with any alias but a common password
141 :param debug: display debug information (:epkg:`starlette` option)
143 :param access_log: The target location for the access log, use - for stdout.
144 :param access_log_format: The log format for the access log, see help docs,
145 see `Logging <https://pgjones.gitlab.io/hypercorn/logging.html>`_.
146 :param ca_certs: Path to the SSL CA certificate file.
147 :param certfile: Path to the SSL certificate file.
148 :param ciphers: Ciphers to use for the SSL setup, the default can be found at
149 `config.py <https://github.com/pgjones/hypercorn/blob/master/hypercorn/config.py#L32>`_
150 :param error_log: The target location for the error log, use - for stderr.
151 :param keep_alive: Seconds to keep inactive connections alive for.
152 :param keyfile: Path to the SSL key file
153 :param root_path: The setting for the ASGI root_path variable.
154 :param workers: The number of workers to spawn and use.
155 :param reload: Enable automatic reloads on code changes.
156 :param fLOG: logging function
157 :return: @see cl QCMApp
159 .. cmdref::
160 :title: Creates a https web-application (Q&A) with authentification
161 :cmd: -m mathenjeu qcm_https --help
163 The command line runs a web application meant to be local
164 as there is not :epkg:`https` involved. It implements a Q&Q.
165 The web app relies on :epkg:`starlette`, the server relies
166 on :epkg:`hypercorn`. Example::
168 python -m mathenjeu qcm_https
170 With that application, every user can login with a unique password *abc*.
171 """
172 if secret_log == '':
173 raise ValueError( # pragma: no cover
174 "secret_log must be not empty or None, not ''")
176 games, fct_game = build_games(games, None)
177 if fLOG:
178 fLOG("[create_qcm_https_app] games=" + str(games))
179 kwargs = dict(secret_log=secret_log, middles=middles,
180 folder=folder, max_age=max_age,
181 cookie_key=cookie_key, cookie_name=cookie_name,
182 cookie_domain=cookie_domain, cookie_path=cookie_path,
183 title=title, short_title=short_title,
184 secure=secure, display=display, debug=debug,
185 page_doc=page_doc, userpwd=userpwd)
186 app = QCMApp(games=games, fct_game=fct_game, **kwargs)
187 if app.app is None:
188 raise RuntimeError( # pragma: no cover
189 "Unable to create a starlette application.")
190 if fLOG:
191 fLOG("[create_qcm_https_app] app is created")
192 rows = []
193 rows.append('"Creates a starlette application."')
194 rows.append("from mathenjeu.cli.cli_helper import build_games")
195 rows.append("from mathenjeu.apps import QCMApp")
196 rows.append("games = {0}".format(games))
197 rows.append("games, fct_game = build_games(games, None)")
198 rows.append("kwargs = " + str(kwargs))
199 rows.append("app = QCMApp(games=games, fct_game=fct_game, **kwargs).app")
200 name = os.path.join(folder, "apphyper.py")
201 with open(name, "w", encoding="utf-8") as f:
202 f.write("\n".join(rows))
203 if fLOG:
204 fLOG("[create_qcm_https_app] saved file '{0}'".format(name))
206 bind = "{0}:{1}".format(cookie_domain, port)
207 folder = os.path.abspath(folder)
208 sys.path.append(folder)
209 try:
210 import apphyper # pylint: disable=C0415
211 pa = apphyper.app
212 if pa is None:
213 raise RuntimeError("pa should not be None")
214 except ImportError as e: # pragma: no cover
215 # For unit test purposes.
216 from .. import __file__ as mejfile
217 main_folder = os.path.abspath(os.path.dirname(mejfile))
218 main_folder = os.path.normpath(os.path.join(main_folder, ".."))
219 if main_folder not in sys.path:
220 sys.path.append(main_folder)
221 try:
222 import apphyper # pylint: disable=C0415
223 pa = apphyper.app
224 if pa is None:
225 raise RuntimeError( # pylint: disable=W0707
226 "pa should not be None")
227 except ImportError as e:
228 raise ImportError(
229 "Unable to import 'apphyper' from '{0}'\n--sys.path--\n{1}".format(
230 folder, "\n".join(sys.path))) from e
231 else:
232 raise ImportError(
233 "Unable to import 'apphyper' from '{0}'\nFolder '{1}' already present.\n--sys.path--\n{2}".format(
234 folder, main_folder, "\n".join(sys.path))) from e
236 application_path = "apphyper:app"
237 kwargs = dict(application_path=application_path, access_log=access_log,
238 access_log_format=access_log_format, bind=bind,
239 ca_certs=ca_certs, certfile=certfile, debug=debug, error_log=error_log,
240 keep_alive=keep_alive, keyfile=keyfile, root_path=root_path, workers=workers,
241 reload=reload, ciphers=ciphers)
243 if fLOG:
244 fLOG("[create_qcm_https_app] create server")
245 server = ServerHypercorn(**kwargs)
246 if start:
247 if fLOG: # pragma: no cover
248 fLOG("[create_qcm_https_app] starts server on '{0}'".format(bind))
249 server.run()
250 while folder in sys.path:
251 del sys.path[sys.path.index(folder)]
252 return server