fix: explicitly save session when token refresh happens

this should only affect "secondary" threads for use with real-time
sync to farmOS.  the belief is that when a token refresh happens in
main thread, the session is auto-saved with the new token.  but when a
token refresh happens in secondary thread, the session was not being
auto-saved with new token.  so this should fix that...
This commit is contained in:
Lance Edgar 2026-08-23 11:39:27 -05:00
parent 78c6a8070a
commit 47d817712b
2 changed files with 30 additions and 5 deletions

View file

@ -27,7 +27,26 @@ from pyramid import httpexceptions
from webhelpers2.html import HTML from webhelpers2.html import HTML
def get_farmos_client_for_user(request): def get_farmos_client_for_user(request, main_thread=True):
"""
Make and return a new farmOS API client instance.
This is a wrapper around
:meth:`~wuttafarm.farmos.handler.FarmOSHandler.get_farmos_client()`
with conveniences to automatically handle token refresh for the
current user session.
:param request: Current web request; this determines the user.
:param main_thread: Boolean indicating whether this client is for
use within the main thread, or a separate one. In the latter
case it must perform certain extra steps to help with token
refresh. This defaults to ``True`` in which case the client is
part of the main thread, i.e. the normal request/response
cycle.
:returns: farmOS API client instance
"""
token = request.session.get("farmos.oauth2.token") token = request.session.get("farmos.oauth2.token")
if not token: if not token:
raise httpexceptions.HTTPForbidden() raise httpexceptions.HTTPForbidden()
@ -39,14 +58,14 @@ def get_farmos_client_for_user(request):
token = dict(token) token = dict(token)
def token_updater(token): def token_updater(token):
save_farmos_oauth2_token(request, token) save_farmos_oauth2_token(request, token, main_thread=main_thread)
config = request.wutta_config config = request.wutta_config
app = config.get_app() app = config.get_app()
return app.get_farmos_client(token=token, token_updater=token_updater) return app.get_farmos_client(token=token, token_updater=token_updater)
def save_farmos_oauth2_token(request, token): def save_farmos_oauth2_token(request, token, main_thread=True):
""" """
Common logic for saving the given OAuth2 token within the user Common logic for saving the given OAuth2 token within the user
session. This function is called from 2 places: session. This function is called from 2 places:
@ -61,6 +80,12 @@ def save_farmos_oauth2_token(request, token):
# save token to user session # save token to user session
request.session["farmos.oauth2.token"] = token request.session["farmos.oauth2.token"] = token
if not main_thread:
# nb. must call persist() explicitly in separate thread, since
# pyramid_beaker may not be in effect (iiuc?)
request.session.save()
request.session.persist()
def use_farmos_style_grid_links(config): def use_farmos_style_grid_links(config):
return config.get_bool(f"{config.appname}.farmos_style_grid_links", default=True) return config.get_bool(f"{config.appname}.farmos_style_grid_links", default=True)

View file

@ -120,7 +120,7 @@ class WuttaFarmMasterView(MasterView):
if self.app.is_farmos_mirror(): if self.app.is_farmos_mirror():
if self.creating: if self.creating:
session.flush() # need the new uuid session.flush() # need the new uuid
client = get_farmos_client_for_user(self.request) client = get_farmos_client_for_user(self.request, main_thread=False)
thread = threading.Thread( thread = threading.Thread(
target=self.auto_sync_to_farmos, args=(client, obj.uuid) target=self.auto_sync_to_farmos, args=(client, obj.uuid)
) )
@ -168,7 +168,7 @@ class WuttaFarmMasterView(MasterView):
# maybe delete from farmOS also # maybe delete from farmOS also
if farmos_uuid: if farmos_uuid:
client = get_farmos_client_for_user(self.request) client = get_farmos_client_for_user(self.request, main_thread=False)
# nb. must use separate thread to avoid some kind of race # nb. must use separate thread to avoid some kind of race
# condition (?) - seems as though maybe a "boomerang" # condition (?) - seems as though maybe a "boomerang"
# effect is happening; this seems to help anyway # effect is happening; this seems to help anyway