fix: use current user token for auto-sync within web app

to ensure data writes to farmOS have correct authorship
This commit is contained in:
Lance Edgar 2026-02-26 17:04:55 -06:00
parent f4b5f3960c
commit 9b4afb845b
5 changed files with 23 additions and 15 deletions

View file

@ -136,7 +136,7 @@ class WuttaFarmAppHandler(base.AppHandler):
factory = self.load_object(spec) factory = self.load_object(spec)
return factory(self.config, farmos_client) return factory(self.config, farmos_client)
def auto_sync_to_farmos(self, obj, model_name=None, require=True): def auto_sync_to_farmos(self, obj, model_name=None, token=None, require=True):
""" """
Export the given object to farmOS, using configured handler. Export the given object to farmOS, using configured handler.
@ -147,6 +147,9 @@ class WuttaFarmAppHandler(base.AppHandler):
:param obj: Any data object in WuttaFarm, e.g. AnimalAsset :param obj: Any data object in WuttaFarm, e.g. AnimalAsset
instance. instance.
:param token: OAuth2 token for the farmOS client. If not
specified, the import handler will obtain a new token.
:param require: If true, this will *require* the export :param require: If true, this will *require* the export
handler to support objects of the given type. If false, handler to support objects of the given type. If false,
then nothing will happen / export is silently skipped when then nothing will happen / export is silently skipped when
@ -162,14 +165,12 @@ class WuttaFarmAppHandler(base.AppHandler):
return return
# nb. begin txn to establish the API client # nb. begin txn to establish the API client
# TODO: should probably use current user oauth2 token instead handler.begin_target_transaction(token)
# of always making a new one here, which is what happens IIUC
handler.begin_target_transaction()
importer = handler.get_importer(model_name, caches_target=False) importer = handler.get_importer(model_name, caches_target=False)
normal = importer.normalize_source_object(obj) normal = importer.normalize_source_object(obj)
importer.process_data(source_data=[normal]) importer.process_data(source_data=[normal])
def auto_sync_from_farmos(self, obj, model_name, require=True): def auto_sync_from_farmos(self, obj, model_name, token=None, require=True):
""" """
Import the given object from farmOS, using configured handler. Import the given object from farmOS, using configured handler.
@ -178,6 +179,9 @@ class WuttaFarmAppHandler(base.AppHandler):
:param model_name': Model name for the importer to use, :param model_name': Model name for the importer to use,
e.g. ``"AnimalAsset"``. e.g. ``"AnimalAsset"``.
:param token: OAuth2 token for the farmOS client. If not
specified, the import handler will obtain a new token.
:param require: If true, this will *require* the import :param require: If true, this will *require* the import
handler to support objects of the given type. If false, handler to support objects of the given type. If false,
then nothing will happen / import is silently skipped when then nothing will happen / import is silently skipped when
@ -191,9 +195,7 @@ class WuttaFarmAppHandler(base.AppHandler):
return return
# nb. begin txn to establish the API client # nb. begin txn to establish the API client
# TODO: should probably use current user oauth2 token instead handler.begin_source_transaction(token)
# of always making a new one here, which is what happens IIUC
handler.begin_source_transaction()
with self.short_session(commit=True) as session: with self.short_session(commit=True) as session:
handler.target_session = session handler.target_session = session
importer = handler.get_importer(model_name, caches_target=False) importer = handler.get_importer(model_name, caches_target=False)

View file

@ -50,10 +50,11 @@ class ToFarmOSHandler(ImportHandler):
# TODO: a lot of duplication to cleanup here; see FromFarmOSHandler # TODO: a lot of duplication to cleanup here; see FromFarmOSHandler
def begin_target_transaction(self): def begin_target_transaction(self, token=None):
""" """
Establish the farmOS API client. Establish the farmOS API client.
""" """
if not token:
token = self.get_farmos_oauth2_token() token = self.get_farmos_oauth2_token()
self.farmos_client = self.app.get_farmos_client(token=token) self.farmos_client = self.app.get_farmos_client(token=token)
self.farmos_4x = self.app.is_farmos_4x(self.farmos_client) self.farmos_4x = self.app.is_farmos_4x(self.farmos_client)

View file

@ -46,10 +46,11 @@ class FromFarmOSHandler(ImportHandler):
source_key = "farmos" source_key = "farmos"
generic_source_title = "farmOS" generic_source_title = "farmOS"
def begin_source_transaction(self): def begin_source_transaction(self, token=None):
""" """
Establish the farmOS API client. Establish the farmOS API client.
""" """
if not token:
token = self.get_farmos_oauth2_token() token = self.get_farmos_oauth2_token()
self.farmos_client = self.app.get_farmos_client(token=token) self.farmos_client = self.app.get_farmos_client(token=token)
self.farmos_4x = self.app.is_farmos_4x(self.farmos_client) self.farmos_4x = self.app.is_farmos_4x(self.farmos_client)

View file

@ -105,4 +105,5 @@ class WuttaFarmMasterView(MasterView):
def persist(self, obj, session=None): def persist(self, obj, session=None):
super().persist(obj, session) super().persist(obj, session)
self.app.auto_sync_to_farmos(obj, require=False) token = self.request.session.get("farmos.oauth2.token")
self.app.auto_sync_to_farmos(obj, token=token, require=False)

View file

@ -118,8 +118,11 @@ class EggsQuickForm(QuickFormView):
if self.app.is_farmos_mirror(): if self.app.is_farmos_mirror():
quantity = json.loads(response["create-quantity"]["body"]) quantity = json.loads(response["create-quantity"]["body"])
self.app.auto_sync_from_farmos(quantity["data"], "StandardQuantity") token = self.request.session.get("farmos.oauth2.token")
self.app.auto_sync_from_farmos(log["data"], "HarvestLog") self.app.auto_sync_from_farmos(
quantity["data"], "StandardQuantity", token=token
)
self.app.auto_sync_from_farmos(log["data"], "HarvestLog", token=token)
return log return log