TaleLin / lin-cms-flask

🎀A simple and practical CMS implememted by Flask
http://doc.cms.talelin.com/
Other
832 stars 216 forks source link

[BUG] 行为日志记录装饰器报错:'NoneType' object has no attribute 'mount' #232

Closed Evilmass closed 6 months ago

Evilmass commented 1 year ago

代码版本:latest

python版本:3.9.10

复现过程:

  1. 克隆最新源码
  2. 配置数据库为 SQLite
  3. 在 api/v1/book.py 的新建图书接口按照官方文档: 行为日志(logger) 添加代码:
@book_api.route("", methods=["POST"])
@Logger(template="{user.username}查询了一本图书")  # 推送的消息
@login_required
@api.validate(
    resp=DocResponse(Success(12)),
    security=[AuthorizationBearerSecurity],
    tags=["图书"],
)
def create_book(json: BookInSchema):
    """
    创建图书
    """
    Book.create(**json.dict(), commit=True)
    return Success(12)

post请求: Snipaste_2023-08-17_18-27-40

详细报错信息如下:

<!doctype html>
<html lang=en>
  <head>
    <title>AttributeError: 'NoneType' object has no attribute 'mount'
 // Werkzeug Debugger</title>
    <link rel="stylesheet" href="?__debugger__=yes&amp;cmd=resource&amp;f=style.css">
    <link rel="shortcut icon"
        href="?__debugger__=yes&amp;cmd=resource&amp;f=console.png">
    <script src="?__debugger__=yes&amp;cmd=resource&amp;f=debugger.js"></script>
    <script>
      var CONSOLE_MODE = false,
          EVALEX = true,
          EVALEX_TRUSTED = false,
          SECRET = "HXMeHZRCCtA1cdfXjM0r";
    </script>
  </head>
  <body style="background-color: #fff">
    <div class="debugger">
<h1>AttributeError</h1>
<div class="detail">
  <p class="errormsg">AttributeError: &#x27;NoneType&#x27; object has no attribute &#x27;mount&#x27;
</p>
</div>
<h2 class="traceback">Traceback <em>(most recent call last)</em></h2>
<div class="traceback">
  <h3></h3>
  <ul><li><div class="frame" id="frame-2307669222000">
  <h4>File <cite class="filename">"C:\Users\qiyue\Envs\lin\lib\site-packages\flask\app.py"</cite>,
      line <em class="line">2091</em>,
      in <code class="function">__call__</code></h4>
  <div class="source "><pre class="line before"><span class="ws">    </span>def __call__(self, environ: dict, start_response: t.Callable) -&gt; t.Any:</pre>
<pre class="line before"><span class="ws">        </span>&quot;&quot;&quot;The WSGI server calls the Flask application object as the</pre>
<pre class="line before"><span class="ws">        </span>WSGI application. This calls :meth:`wsgi_app`, which can be</pre>
<pre class="line before"><span class="ws">        </span>wrapped to apply middleware.</pre>
<pre class="line before"><span class="ws">        </span>&quot;&quot;&quot;</pre>
<pre class="line current"><span class="ws">        </span>return self.wsgi_app(environ, start_response)</pre></div>
</div>

<li><div class="frame" id="frame-2307669795328">
  <h4>File <cite class="filename">"C:\Users\qiyue\Envs\lin\lib\site-packages\flask_socketio\__init__.py"</cite>,
      line <em class="line">43</em>,
      in <code class="function">__call__</code></h4>
  <div class="source "><pre class="line before"><span class="ws">                                                  </span>socketio_path=socketio_path)</pre>
<pre class="line before"><span class="ws"></span> </pre>
<pre class="line before"><span class="ws">    </span>def __call__(self, environ, start_response):</pre>
<pre class="line before"><span class="ws">        </span>environ = environ.copy()</pre>
<pre class="line before"><span class="ws">        </span>environ[&#x27;flask.app&#x27;] = self.flask_app</pre>
<pre class="line current"><span class="ws">        </span>return super(_SocketIOMiddleware, self).__call__(environ,</pre>
<pre class="line after"><span class="ws">                                                         </span>start_response)</pre>
<pre class="line after"><span class="ws"></span> </pre>
<pre class="line after"><span class="ws"></span> </pre>
<pre class="line after"><span class="ws"></span>class _ManagedSession(dict, SessionMixin):</pre>
<pre class="line after"><span class="ws">    </span>&quot;&quot;&quot;This class is used for user sessions that are managed by</pre></div>
</div>

<li><div class="frame" id="frame-2307669880608">
  <h4>File <cite class="filename">"C:\Users\qiyue\Envs\lin\lib\site-packages\engineio\middleware.py"</cite>,
      line <em class="line">74</em>,
      in <code class="function">__call__</code></h4>
  <div class="source "><pre class="line before"><span class="ws">                    </span>&#x27;200 OK&#x27;,</pre>
<pre class="line before"><span class="ws">                    </span>[(&#x27;Content-Type&#x27;, static_file[&#x27;content_type&#x27;])])</pre>
<pre class="line before"><span class="ws">                </span>with open(static_file[&#x27;filename&#x27;], &#x27;rb&#x27;) as f:</pre>
<pre class="line before"><span class="ws">                    </span>return [f.read()]</pre>
<pre class="line before"><span class="ws">            </span>elif self.wsgi_app is not None:</pre>
<pre class="line current"><span class="ws">                </span>return self.wsgi_app(environ, start_response)</pre>
<pre class="line after"><span class="ws">        </span>return self.not_found(start_response)</pre>
<pre class="line after"><span class="ws"></span> </pre>
<pre class="line after"><span class="ws">    </span>def not_found(self, start_response):</pre>
<pre class="line after"><span class="ws">        </span>start_response(&quot;404 Not Found&quot;, [(&#x27;Content-Type&#x27;, &#x27;text/plain&#x27;)])</pre>
<pre class="line after"><span class="ws">        </span>return [b&#x27;Not Found&#x27;]</pre></div>
</div>

<li><div class="frame" id="frame-2307669898848">
  <h4>File <cite class="filename">"C:\Users\qiyue\Envs\lin\lib\site-packages\flask\app.py"</cite>,
      line <em class="line">2076</em>,
      in <code class="function">wsgi_app</code></h4>
  <div class="source "><pre class="line before"><span class="ws">            </span>try:</pre>
<pre class="line before"><span class="ws">                </span>ctx.push()</pre>
<pre class="line before"><span class="ws">                </span>response = self.full_dispatch_request()</pre>
<pre class="line before"><span class="ws">            </span>except Exception as e:</pre>
<pre class="line before"><span class="ws">                </span>error = e</pre>
<pre class="line current"><span class="ws">                </span>response = self.handle_exception(e)</pre>
<pre class="line after"><span class="ws">            </span>except:  # noqa: B001</pre>
<pre class="line after"><span class="ws">                </span>error = sys.exc_info()[1]</pre>
<pre class="line after"><span class="ws">                </span>raise</pre>
<pre class="line after"><span class="ws">            </span>return response(environ, start_response)</pre>
<pre class="line after"><span class="ws">        </span>finally:</pre></div>
</div>

<li><div class="frame" id="frame-2307669898960">
  <h4>File <cite class="filename">"C:\Users\qiyue\Envs\lin\lib\site-packages\flask_cors\extension.py"</cite>,
      line <em class="line">165</em>,
      in <code class="function">wrapped_function</code></h4>
  <div class="source "><pre class="line before"><span class="ws">        </span># Wrap exception handlers with cross_origin</pre>
<pre class="line before"><span class="ws">        </span># These error handlers will still respect the behavior of the route</pre>
<pre class="line before"><span class="ws">        </span>if options.get(&#x27;intercept_exceptions&#x27;, True):</pre>
<pre class="line before"><span class="ws">            </span>def _after_request_decorator(f):</pre>
<pre class="line before"><span class="ws">                </span>def wrapped_function(*args, **kwargs):</pre>
<pre class="line current"><span class="ws">                    </span>return cors_after_request(app.make_response(f(*args, **kwargs)))</pre>
<pre class="line after"><span class="ws">                </span>return wrapped_function</pre>
<pre class="line after"><span class="ws"></span> </pre>
<pre class="line after"><span class="ws">            </span>if hasattr(app, &#x27;handle_exception&#x27;):</pre>
<pre class="line after"><span class="ws">                </span>app.handle_exception = _after_request_decorator(</pre>
<pre class="line after"><span class="ws">                    </span>app.handle_exception)</pre></div>
</div>

<li><div class="frame" id="frame-2307669926512">
  <h4>File <cite class="filename">"C:\Users\qiyue\Envs\lin\lib\site-packages\flask\app.py"</cite>,
      line <em class="line">2073</em>,
      in <code class="function">wsgi_app</code></h4>
  <div class="source "><pre class="line before"><span class="ws">        </span>ctx = self.request_context(environ)</pre>
<pre class="line before"><span class="ws">        </span>error: t.Optional[BaseException] = None</pre>
<pre class="line before"><span class="ws">        </span>try:</pre>
<pre class="line before"><span class="ws">            </span>try:</pre>
<pre class="line before"><span class="ws">                </span>ctx.push()</pre>
<pre class="line current"><span class="ws">                </span>response = self.full_dispatch_request()</pre>
<pre class="line after"><span class="ws">            </span>except Exception as e:</pre>
<pre class="line after"><span class="ws">                </span>error = e</pre>
<pre class="line after"><span class="ws">                </span>response = self.handle_exception(e)</pre>
<pre class="line after"><span class="ws">            </span>except:  # noqa: B001</pre>
<pre class="line after"><span class="ws">                </span>error = sys.exc_info()[1]</pre></div>
</div>

<li><div class="frame" id="frame-2307669926624">
  <h4>File <cite class="filename">"C:\Users\qiyue\Envs\lin\lib\site-packages\flask\app.py"</cite>,
      line <em class="line">1518</em>,
      in <code class="function">full_dispatch_request</code></h4>
  <div class="source "><pre class="line before"><span class="ws">            </span>request_started.send(self)</pre>
<pre class="line before"><span class="ws">            </span>rv = self.preprocess_request()</pre>
<pre class="line before"><span class="ws">            </span>if rv is None:</pre>
<pre class="line before"><span class="ws">                </span>rv = self.dispatch_request()</pre>
<pre class="line before"><span class="ws">        </span>except Exception as e:</pre>
<pre class="line current"><span class="ws">            </span>rv = self.handle_user_exception(e)</pre>
<pre class="line after"><span class="ws">        </span>return self.finalize_request(rv)</pre>
<pre class="line after"><span class="ws"></span> </pre>
<pre class="line after"><span class="ws">    </span>def finalize_request(</pre>
<pre class="line after"><span class="ws">        </span>self,</pre>
<pre class="line after"><span class="ws">        </span>rv: t.Union[ResponseReturnValue, HTTPException],</pre></div>
</div>

<li><div class="frame" id="frame-2307669926736">
  <h4>File <cite class="filename">"C:\Users\qiyue\Envs\lin\lib\site-packages\flask_cors\extension.py"</cite>,
      line <em class="line">165</em>,
      in <code class="function">wrapped_function</code></h4>
  <div class="source "><pre class="line before"><span class="ws">        </span># Wrap exception handlers with cross_origin</pre>
<pre class="line before"><span class="ws">        </span># These error handlers will still respect the behavior of the route</pre>
<pre class="line before"><span class="ws">        </span>if options.get(&#x27;intercept_exceptions&#x27;, True):</pre>
<pre class="line before"><span class="ws">            </span>def _after_request_decorator(f):</pre>
<pre class="line before"><span class="ws">                </span>def wrapped_function(*args, **kwargs):</pre>
<pre class="line current"><span class="ws">                    </span>return cors_after_request(app.make_response(f(*args, **kwargs)))</pre>
<pre class="line after"><span class="ws">                </span>return wrapped_function</pre>
<pre class="line after"><span class="ws"></span> </pre>
<pre class="line after"><span class="ws">            </span>if hasattr(app, &#x27;handle_exception&#x27;):</pre>
<pre class="line after"><span class="ws">                </span>app.handle_exception = _after_request_decorator(</pre>
<pre class="line after"><span class="ws">                    </span>app.handle_exception)</pre></div>
</div>

<li><div class="frame" id="frame-2307669926848">
  <h4>File <cite class="filename">"C:\Users\qiyue\Envs\lin\lib\site-packages\flask\app.py"</cite>,
      line <em class="line">1393</em>,
      in <code class="function">handle_user_exception</code></h4>
  <div class="source "><pre class="line before"><span class="ws">        </span>handler = self._find_error_handler(e)</pre>
<pre class="line before"><span class="ws"></span> </pre>
<pre class="line before"><span class="ws">        </span>if handler is None:</pre>
<pre class="line before"><span class="ws">            </span>raise</pre>
<pre class="line before"><span class="ws"></span> </pre>
<pre class="line current"><span class="ws">        </span>return self.ensure_sync(handler)(e)</pre>
<pre class="line after"><span class="ws"></span> </pre>
<pre class="line after"><span class="ws">    </span>def handle_exception(self, e: Exception) -&gt; Response:</pre>
<pre class="line after"><span class="ws">        </span>&quot;&quot;&quot;Handle an exception that did not have an error handler</pre>
<pre class="line after"><span class="ws">        </span>associated with it, or that was raised from an error handler.</pre>
<pre class="line after"><span class="ws">        </span>This always causes a 500 ``InternalServerError``.</pre></div>
</div>

<li><div class="frame" id="frame-2307669926960">
  <h4>File <cite class="filename">"C:\Users\qiyue\Envs\lin\lib\site-packages\lin\lin.py"</cite>,
      line <em class="line">172</em>,
      in <code class="function">handler</code></h4>
  <div class="source "><pre class="line before"><span class="ws">                    </span>import traceback</pre>
<pre class="line before"><span class="ws"></span> </pre>
<pre class="line before"><span class="ws">                    </span>app.logger.error(traceback.format_exc())</pre>
<pre class="line before"><span class="ws">                    </span>return InternalServerError()</pre>
<pre class="line before"><span class="ws">                </span>else:</pre>
<pre class="line current"><span class="ws">                    </span>raise e</pre>
<pre class="line after"><span class="ws"></span> </pre>
<pre class="line after"><span class="ws">    </span>def enable_auto_jsonify(self, app):</pre>
<pre class="line after"><span class="ws">        </span>app.json_encoder = self.jsonencoder or JSONEncoder</pre>
<pre class="line after"><span class="ws">        </span>app.make_response = auto_response(app.make_response)</pre>
<pre class="line after"><span class="ws">        </span>schema_response(app)</pre></div>
</div>

<li><div class="frame" id="frame-2307669942560">
  <h4>File <cite class="filename">"C:\Users\qiyue\Envs\lin\lib\site-packages\flask\app.py"</cite>,
      line <em class="line">1516</em>,
      in <code class="function">full_dispatch_request</code></h4>
  <div class="source "><pre class="line before"><span class="ws">        </span>self.try_trigger_before_first_request_functions()</pre>
<pre class="line before"><span class="ws">        </span>try:</pre>
<pre class="line before"><span class="ws">            </span>request_started.send(self)</pre>
<pre class="line before"><span class="ws">            </span>rv = self.preprocess_request()</pre>
<pre class="line before"><span class="ws">            </span>if rv is None:</pre>
<pre class="line current"><span class="ws">                </span>rv = self.dispatch_request()</pre>
<pre class="line after"><span class="ws">        </span>except Exception as e:</pre>
<pre class="line after"><span class="ws">            </span>rv = self.handle_user_exception(e)</pre>
<pre class="line after"><span class="ws">        </span>return self.finalize_request(rv)</pre>
<pre class="line after"><span class="ws"></span> </pre>
<pre class="line after"><span class="ws">    </span>def finalize_request(</pre></div>
</div>

<li><div class="frame" id="frame-2307669942672">
  <h4>File <cite class="filename">"C:\Users\qiyue\Envs\lin\lib\site-packages\flask\app.py"</cite>,
      line <em class="line">1502</em>,
      in <code class="function">dispatch_request</code></h4>
  <div class="source "><pre class="line before"><span class="ws">            </span>getattr(rule, &quot;provide_automatic_options&quot;, False)</pre>
<pre class="line before"><span class="ws">            </span>and req.method == &quot;OPTIONS&quot;</pre>
<pre class="line before"><span class="ws">        </span>):</pre>
<pre class="line before"><span class="ws">            </span>return self.make_default_options_response()</pre>
<pre class="line before"><span class="ws">        </span># otherwise dispatch to the handler for that endpoint</pre>
<pre class="line current"><span class="ws">        </span>return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)</pre>
<pre class="line after"><span class="ws"></span> </pre>
<pre class="line after"><span class="ws">    </span>def full_dispatch_request(self) -&gt; Response:</pre>
<pre class="line after"><span class="ws">        </span>&quot;&quot;&quot;Dispatches the request and on top of that performs request</pre>
<pre class="line after"><span class="ws">        </span>pre and postprocessing as well as HTTP exception catching and</pre>
<pre class="line after"><span class="ws">        </span>error handling.</pre></div>
</div>

<li><div class="frame" id="frame-2307669942784">
  <h4>File <cite class="filename">"C:\Users\qiyue\Envs\lin\lib\site-packages\lin\logger.py"</cite>,
      line <em class="line">131</em>,
      in <code class="function">wrap</code></h4>
  <div class="source "><pre class="line before"><span class="ws">            </span>self.response = response</pre>
<pre class="line before"><span class="ws">            </span>self.user = get_current_user()</pre>
<pre class="line before"><span class="ws">            </span>if not self.user:</pre>
<pre class="line before"><span class="ws">                </span>raise Exception(&quot;Logger must be used in the login state&quot;)</pre>
<pre class="line before"><span class="ws">            </span>self.message = self._parse_template()</pre>
<pre class="line current"><span class="ws">            </span>self.write_log()</pre>
<pre class="line after"><span class="ws">            </span>return response</pre>
<pre class="line after"><span class="ws"></span> </pre>
<pre class="line after"><span class="ws">        </span>return wrap</pre>
<pre class="line after"><span class="ws"></span> </pre>
<pre class="line after"><span class="ws">    </span>def write_log(self):</pre></div>
</div>

<li><div class="frame" id="frame-2307669945360">
  <h4>File <cite class="filename">"C:\Users\qiyue\Envs\lin\lib\site-packages\lin\logger.py"</cite>,
      line <em class="line">137</em>,
      in <code class="function">write_log</code></h4>
  <div class="source "><pre class="line before"><span class="ws">            </span>return response</pre>
<pre class="line before"><span class="ws"></span> </pre>
<pre class="line before"><span class="ws">        </span>return wrap</pre>
<pre class="line before"><span class="ws"></span> </pre>
<pre class="line before"><span class="ws">    </span>def write_log(self):</pre>
<pre class="line current"><span class="ws">        </span>info = manager.find_info_by_ep(request.endpoint)</pre>
<pre class="line after"><span class="ws">        </span>permission = info.name if info is not None else &quot;&quot;</pre>
<pre class="line after"><span class="ws">        </span>status_code = getattr(self.response, &quot;status_code&quot;, None)</pre>
<pre class="line after"><span class="ws">        </span>if status_code is None:</pre>
<pre class="line after"><span class="ws">            </span>status_code = getattr(self.response, &quot;code&quot;, None)</pre>
<pre class="line after"><span class="ws">        </span>if status_code is None:</pre></div>
</div>

<li><div class="frame" id="frame-2307669945584">
  <h4>File <cite class="filename">"C:\Users\qiyue\Envs\lin\lib\site-packages\lin\manager.py"</cite>,
      line <em class="line">71</em>,
      in <code class="function">find_info_by_ep</code></h4>
  <div class="source "><pre class="line before"><span class="ws">        </span>return infos</pre>
<pre class="line before"><span class="ws"></span> </pre>
<pre class="line before"><span class="ws">    </span>def find_info_by_ep(self, ep):</pre>
<pre class="line before"><span class="ws">        </span>&quot;&quot;&quot;通过请求的endpoint寻找路由函数的meta信息&quot;&quot;&quot;</pre>
<pre class="line before"><span class="ws">        </span>info = self.ep_meta.get(ep)</pre>
<pre class="line current"><span class="ws">        </span>return info if info.mount else None</pre>
<pre class="line after"><span class="ws"></span> </pre>
<pre class="line after"><span class="ws">    </span>def find_group_ids_by_user_id(self, user_id) -&gt; list:</pre>
<pre class="line after"><span class="ws">        </span>&quot;&quot;&quot;</pre>
<pre class="line after"><span class="ws">        </span>根据用户ID,通过User-Group关联表,获取所属用户组的Id列表</pre>
<pre class="line after"><span class="ws">        </span>&quot;&quot;&quot;</pre></div>
</div>
</ul>
  <blockquote>AttributeError: &#x27;NoneType&#x27; object has no attribute &#x27;mount&#x27;
</blockquote>
</div>

<div class="plain">
    <p>
      This is the Copy/Paste friendly version of the traceback.
    </p>
    <textarea cols="50" rows="10" name="code" readonly>Traceback (most recent call last):
  File &quot;C:\Users\qiyue\Envs\lin\lib\site-packages\flask\app.py&quot;, line 2091, in __call__
    return self.wsgi_app(environ, start_response)
  File &quot;C:\Users\qiyue\Envs\lin\lib\site-packages\flask_socketio\__init__.py&quot;, line 43, in __call__
    return super(_SocketIOMiddleware, self).__call__(environ,
  File &quot;C:\Users\qiyue\Envs\lin\lib\site-packages\engineio\middleware.py&quot;, line 74, in __call__
    return self.wsgi_app(environ, start_response)
  File &quot;C:\Users\qiyue\Envs\lin\lib\site-packages\flask\app.py&quot;, line 2076, in wsgi_app
    response = self.handle_exception(e)
  File &quot;C:\Users\qiyue\Envs\lin\lib\site-packages\flask_cors\extension.py&quot;, line 165, in wrapped_function
    return cors_after_request(app.make_response(f(*args, **kwargs)))
  File &quot;C:\Users\qiyue\Envs\lin\lib\site-packages\flask\app.py&quot;, line 2073, in wsgi_app
    response = self.full_dispatch_request()
  File &quot;C:\Users\qiyue\Envs\lin\lib\site-packages\flask\app.py&quot;, line 1518, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File &quot;C:\Users\qiyue\Envs\lin\lib\site-packages\flask_cors\extension.py&quot;, line 165, in wrapped_function
    return cors_after_request(app.make_response(f(*args, **kwargs)))
  File &quot;C:\Users\qiyue\Envs\lin\lib\site-packages\flask\app.py&quot;, line 1393, in handle_user_exception
    return self.ensure_sync(handler)(e)
  File &quot;C:\Users\qiyue\Envs\lin\lib\site-packages\lin\lin.py&quot;, line 172, in handler
    raise e
  File &quot;C:\Users\qiyue\Envs\lin\lib\site-packages\flask\app.py&quot;, line 1516, in full_dispatch_request
    rv = self.dispatch_request()
  File &quot;C:\Users\qiyue\Envs\lin\lib\site-packages\flask\app.py&quot;, line 1502, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)
  File &quot;C:\Users\qiyue\Envs\lin\lib\site-packages\lin\logger.py&quot;, line 131, in wrap
    self.write_log()
  File &quot;C:\Users\qiyue\Envs\lin\lib\site-packages\lin\logger.py&quot;, line 137, in write_log
    info = manager.find_info_by_ep(request.endpoint)
  File &quot;C:\Users\qiyue\Envs\lin\lib\site-packages\lin\manager.py&quot;, line 71, in find_info_by_ep
    return info if info.mount else None
AttributeError: &#x27;NoneType&#x27; object has no attribute &#x27;mount&#x27;
</textarea>
</div>
<div class="explanation">
  The debugger caught an exception in your WSGI application.  You can now
  look at the traceback which led to the error.  <span class="nojavascript">
  If you enable JavaScript you can also use additional features such as code
  execution (if the evalex feature is enabled), automatic pasting of the
  exceptions and much more.</span>
</div>
      <div class="footer">
        Brought to you by <strong class="arthur">DON'T PANIC</strong>, your
        friendly Werkzeug powered traceback interpreter.
      </div>
    </div>

    <div class="pin-prompt">
      <div class="inner">
        <h3>Console Locked</h3>
        <p>
          The console is locked and needs to be unlocked by entering the PIN.
          You can find the PIN printed out on the standard output of your
          shell that runs the server.
        <form>
          <p>PIN:
            <input type=text name=pin size=14>
            <input type=submit name=btn value="Confirm Pin">
        </form>
      </div>
    </div>
  </body>
</html>

<!--

Traceback (most recent call last):
  File "C:\Users\qiyue\Envs\lin\lib\site-packages\flask\app.py", line 2091, in __call__
    return self.wsgi_app(environ, start_response)
  File "C:\Users\qiyue\Envs\lin\lib\site-packages\flask_socketio\__init__.py", line 43, in __call__
    return super(_SocketIOMiddleware, self).__call__(environ,
  File "C:\Users\qiyue\Envs\lin\lib\site-packages\engineio\middleware.py", line 74, in __call__
    return self.wsgi_app(environ, start_response)
  File "C:\Users\qiyue\Envs\lin\lib\site-packages\flask\app.py", line 2076, in wsgi_app
    response = self.handle_exception(e)
  File "C:\Users\qiyue\Envs\lin\lib\site-packages\flask_cors\extension.py", line 165, in wrapped_function
    return cors_after_request(app.make_response(f(*args, **kwargs)))
  File "C:\Users\qiyue\Envs\lin\lib\site-packages\flask\app.py", line 2073, in wsgi_app
    response = self.full_dispatch_request()
  File "C:\Users\qiyue\Envs\lin\lib\site-packages\flask\app.py", line 1518, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "C:\Users\qiyue\Envs\lin\lib\site-packages\flask_cors\extension.py", line 165, in wrapped_function
    return cors_after_request(app.make_response(f(*args, **kwargs)))
  File "C:\Users\qiyue\Envs\lin\lib\site-packages\flask\app.py", line 1393, in handle_user_exception
    return self.ensure_sync(handler)(e)
  File "C:\Users\qiyue\Envs\lin\lib\site-packages\lin\lin.py", line 172, in handler
    raise e
  File "C:\Users\qiyue\Envs\lin\lib\site-packages\flask\app.py", line 1516, in full_dispatch_request
    rv = self.dispatch_request()
  File "C:\Users\qiyue\Envs\lin\lib\site-packages\flask\app.py", line 1502, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)
  File "C:\Users\qiyue\Envs\lin\lib\site-packages\lin\logger.py", line 131, in wrap
    self.write_log()
  File "C:\Users\qiyue\Envs\lin\lib\site-packages\lin\logger.py", line 137, in write_log
    info = manager.find_info_by_ep(request.endpoint)
  File "C:\Users\qiyue\Envs\lin\lib\site-packages\lin\manager.py", line 71, in find_info_by_ep
    return info if info.mount else None
AttributeError: 'NoneType' object has no attribute 'mount'

-->
sunlin92 commented 1 year ago

你好,行为日志中,记录用户信息需要用户登录,即请求头中需要携带用户令牌,相关功能可以参照源码app/api/cms/user.py中的部分

@user_api.route("/change_password", methods=["PUT"])
@permission_meta(name="修改密码", module="用户", mount=False)
@Logger(template="{user.username}修改了自己的密码")  # 记录日志
@login_required
@api.validate(
    tags=["用户"],
    security=[AuthorizationBearerSecurity],
    resp=DocResponse(Success("密码修改成功"), Failed("密码修改失败")),
)
def change_password(json: ChangePasswordSchema):
    """
    修改密码
    """
    user = get_current_user()
    ok = user.change_password(g.old_password, g.new_password)
    if ok:
        db.session.commit()
        return Success("密码修改成功")
    else:
        return Failed("修改密码失败")

image