Compare commits

..

No commits in common. "master" and "v0.11.1" have entirely different histories.

5 changed files with 21 additions and 82 deletions

View file

@ -5,13 +5,6 @@ All notable changes to WuttaFarm will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
## v0.11.2 (2026-03-21)
### Fix
- use separate thread to sync changes to farmOS
- avoid error if asset has no geometry
## v0.11.1 (2026-03-21) ## v0.11.1 (2026-03-21)
### Fix ### Fix

View file

@ -5,7 +5,7 @@ build-backend = "hatchling.build"
[project] [project]
name = "WuttaFarm" name = "WuttaFarm"
version = "0.11.2" version = "0.11.1"
description = "Web app to integrate with and extend farmOS" description = "Web app to integrate with and extend farmOS"
readme = "README.md" readme = "README.md"
authors = [ authors = [
@ -34,7 +34,7 @@ dependencies = [
"pyramid_exclog", "pyramid_exclog",
"uvicorn[standard]", "uvicorn[standard]",
"WuttaSync", "WuttaSync",
"WuttaWeb[continuum]>=0.30.1", "WuttaWeb[continuum]>=0.29.3",
] ]

View file

@ -372,7 +372,7 @@ class AssetMasterView(WuttaFarmMasterView):
# TODO: eventually sync GIS data, avoid this API call? # TODO: eventually sync GIS data, avoid this API call?
client = get_farmos_client_for_user(self.request) client = get_farmos_client_for_user(self.request)
result = client.asset.get_id(asset.asset_type, asset.farmos_uuid) result = client.asset.get_id(asset.asset_type, asset.farmos_uuid)
if geometry := result["data"]["attributes"]["intrinsic_geometry"]: geometry = result["data"]["attributes"]["intrinsic_geometry"]
context["map_center"] = [geometry["lon"], geometry["lat"]] context["map_center"] = [geometry["lon"], geometry["lat"]]
@ -385,9 +385,7 @@ class AssetMasterView(WuttaFarmMasterView):
r"^POLYGON \(\((?P<points>[^\)]+)\)\)$", geometry["value"] r"^POLYGON \(\((?P<points>[^\)]+)\)\)$", geometry["value"]
): ):
points = match.group("points").split(", ") points = match.group("points").split(", ")
points = [ points = [[float(pt) for pt in pair.split(" ")] for pair in points]
[float(pt) for pt in pair.split(" ")] for pair in points
]
context["map_polygon"] = [points] context["map_polygon"] = [points]
return context return context

View file

@ -24,7 +24,6 @@ Base class for WuttaFarm master views
""" """
import threading import threading
import time
import requests import requests
from webhelpers2.html import tags from webhelpers2.html import tags
@ -111,35 +110,16 @@ class WuttaFarmMasterView(MasterView):
f.set_readonly("drupal_id") f.set_readonly("drupal_id")
def persist(self, obj, session=None): def persist(self, obj, session=None):
session = session or self.Session()
# save per usual # save per usual
super().persist(obj, session) super().persist(obj, session)
# maybe also sync change to farmOS # maybe also sync change to farmOS
if self.app.is_farmos_mirror(): if self.app.is_farmos_mirror():
if self.creating:
session.flush() # need the new uuid
client = get_farmos_client_for_user(self.request) client = get_farmos_client_for_user(self.request)
thread = threading.Thread( self.auto_sync_to_farmos(client, obj)
target=self.auto_sync_to_farmos, args=(client, obj.uuid)
)
thread.start()
def auto_sync_to_farmos(self, client, uuid):
model = self.app.model
model_class = self.get_model_class()
with self.app.short_session(commit=True) as session:
if user := session.query(model.User).filter_by(username="farmos").first():
session.info["continuum_user_id"] = user.uuid
obj = None
while not obj:
obj = session.get(model_class, uuid)
if not obj:
time.sleep(0.1)
def auto_sync_to_farmos(self, client, obj):
self.app.auto_sync_to_farmos(obj, client=client, require=False) self.app.auto_sync_to_farmos(obj, client=client, require=False)
def get_farmos_entity_type(self): def get_farmos_entity_type(self):

View file

@ -24,8 +24,6 @@ Quick Form for "Eggs"
""" """
import json import json
import threading
import time
import colander import colander
from deform.widget import SelectWidget from deform.widget import SelectWidget
@ -333,43 +331,13 @@ class EggsQuickForm(QuickFormView):
session.flush() session.flush()
if self.app.is_farmos_mirror(): if self.app.is_farmos_mirror():
thread = threading.Thread( if new_unit:
target=self.auto_sync_to_farmos, self.app.auto_sync_to_farmos(unit, client=self.farmos_client)
args=(log.uuid, quantity.uuid, new_unit.uuid if new_unit else None), self.app.auto_sync_to_farmos(quantity, client=self.farmos_client)
) self.app.auto_sync_to_farmos(log, client=self.farmos_client)
thread.start()
return log return log
def auto_sync_to_farmos(self, log_uuid, quantity_uuid, new_unit_uuid):
model = self.app.model
with self.app.short_session(commit=True) as session:
if user := session.query(model.User).filter_by(username="farmos").first():
session.info["continuum_user_id"] = user.uuid
if new_unit_uuid:
new_unit = None
while not new_unit:
new_unit = session.get(model.Unit, new_unit_uuid)
if not new_unit:
time.sleep(0.1)
self.app.auto_sync_to_farmos(unit, client=self.farmos_client)
quantity = None
while not quantity:
quantity = session.get(model.StandardQuantity, quantity_uuid)
if not quantity:
time.sleep(0.1)
self.app.auto_sync_to_farmos(quantity, client=self.farmos_client)
log = None
while not log:
log = session.get(model.HarvestLog, log_uuid)
if not log:
time.sleep(0.1)
self.app.auto_sync_to_farmos(log, client=self.farmos_client)
def redirect_after_save(self, log): def redirect_after_save(self, log):
model = self.app.model model = self.app.model