Hide keyboard shortcuts

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 

11 

12 

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. 

32 

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 

58 

59 .. cmdref:: 

60 :title: Creates a local web-application with very simple authentification 

61 :cmd: -m mathenjeu qcm_local --help 

62 

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:: 

67 

68 python -m mathenjeu qcm_local --cookie_key=dummypwd --start=1 --port=8889 --userpwd=abc 

69 

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)) 

78 

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 

92 

93 

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. 

119 

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) 

142 

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 

158 

159 .. cmdref:: 

160 :title: Creates a https web-application (Q&A) with authentification 

161 :cmd: -m mathenjeu qcm_https --help 

162 

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:: 

167 

168 python -m mathenjeu qcm_https 

169 

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 ''") 

175 

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)) 

205 

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 

235 

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) 

242 

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