diff --git a/CHANGELOG.md b/CHANGELOG.md
index 579fc2a..6c85559 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,30 +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/)
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)
-
-### Fix
-
-- improve behavior when deleting mirrored record from farmOS
-- use correct uuid when processing webhook to delete record
-
-## v0.11.0 (2026-03-15)
-
-### Feat
-
-- show basic map for "fixed" assets
-
-### Fix
-
-- include LogQuantity changes when viewing Log revision
-
## v0.10.0 (2026-03-11)
### Feat
diff --git a/pyproject.toml b/pyproject.toml
index b702d8c..7fdd859 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -5,7 +5,7 @@ build-backend = "hatchling.build"
[project]
name = "WuttaFarm"
-version = "0.11.2"
+version = "0.10.0"
description = "Web app to integrate with and extend farmOS"
readme = "README.md"
authors = [
@@ -34,7 +34,7 @@ dependencies = [
"pyramid_exclog",
"uvicorn[standard]",
"WuttaSync",
- "WuttaWeb[continuum]>=0.30.1",
+ "WuttaWeb[continuum]>=0.29.2",
]
diff --git a/src/wuttafarm/cli/process_webhooks.py b/src/wuttafarm/cli/process_webhooks.py
index 9d66a70..9731247 100644
--- a/src/wuttafarm/cli/process_webhooks.py
+++ b/src/wuttafarm/cli/process_webhooks.py
@@ -94,7 +94,8 @@ class ChangeProcessor:
return
# delete corresponding record from our app
- if obj := importer.get_target_object((change.farmos_uuid,)):
+ obj = importer.get_target_object((change.uuid,))
+ if obj:
importer.delete_target_object(obj)
# TODO: this should live elsewhere
diff --git a/src/wuttafarm/web/templates/assets/master/view.mako b/src/wuttafarm/web/templates/assets/master/view.mako
index 5b7b822..dac5a1c 100644
--- a/src/wuttafarm/web/templates/assets/master/view.mako
+++ b/src/wuttafarm/web/templates/assets/master/view.mako
@@ -10,74 +10,5 @@
% endif
-
-
- ## main form
-
- ${parent.page_content()}
-
-
- ## location map
- % if map_polygon:
-
- % endif
-
-
-
-%def>
-
-<%def name="modify_vue_vars()">
- ${parent.modify_vue_vars()}
- % if map_polygon:
-
- % endif
+ ${parent.page_content()}
%def>
diff --git a/src/wuttafarm/web/templates/base.mako b/src/wuttafarm/web/templates/base.mako
index caa5c67..b28b52f 100644
--- a/src/wuttafarm/web/templates/base.mako
+++ b/src/wuttafarm/web/templates/base.mako
@@ -1,16 +1,6 @@
<%inherit file="wuttaweb:templates/base.mako" />
<%namespace file="/wuttafarm-components.mako" import="make_wuttafarm_components" />
-<%def name="head_tags()">
- ${parent.head_tags()}
-
- ## TODO: this likely does not belong in the base template, and should be
- ## included per template where actually needed. but this is easier for now.
-
-
-
-%def>
-
<%def name="index_title_controls()">
${parent.index_title_controls()}
diff --git a/src/wuttafarm/web/views/assets.py b/src/wuttafarm/web/views/assets.py
index 1ada778..64f4dbc 100644
--- a/src/wuttafarm/web/views/assets.py
+++ b/src/wuttafarm/web/views/assets.py
@@ -23,7 +23,6 @@
Master view for Assets
"""
-import re
from collections import OrderedDict
from webhelpers2.html import tags
@@ -360,38 +359,6 @@ class AssetMasterView(WuttaFarmMasterView):
return buttons
- def get_template_context(self, context):
- context = super().get_template_context(context)
-
- if self.viewing:
- asset = context["instance"]
-
- # add location geometry if applicable
- if asset.is_fixed and asset.farmos_uuid and not self.app.is_standalone():
-
- # TODO: eventually sync GIS data, avoid this API call?
- client = get_farmos_client_for_user(self.request)
- result = client.asset.get_id(asset.asset_type, asset.farmos_uuid)
- if geometry := result["data"]["attributes"]["intrinsic_geometry"]:
-
- context["map_center"] = [geometry["lon"], geometry["lat"]]
-
- context["map_bounds"] = [
- [geometry["left"], geometry["bottom"]],
- [geometry["right"], geometry["top"]],
- ]
-
- if match := re.match(
- r"^POLYGON \(\((?P[^\)]+)\)\)$", geometry["value"]
- ):
- points = match.group("points").split(", ")
- points = [
- [float(pt) for pt in pair.split(" ")] for pair in points
- ]
- context["map_polygon"] = [points]
-
- return context
-
def get_version_joins(self):
"""
We override this to declare the relationship between the
diff --git a/src/wuttafarm/web/views/logs.py b/src/wuttafarm/web/views/logs.py
index 2a4e6e0..3d91ba1 100644
--- a/src/wuttafarm/web/views/logs.py
+++ b/src/wuttafarm/web/views/logs.py
@@ -491,7 +491,6 @@ class LogMasterView(WuttaFarmMasterView):
return super().get_version_joins() + [
model.Log,
(model.LogAsset, "log_uuid", "uuid"),
- (model.LogQuantity, "log_uuid", "uuid"),
]
diff --git a/src/wuttafarm/web/views/master.py b/src/wuttafarm/web/views/master.py
index c828b96..d9fe986 100644
--- a/src/wuttafarm/web/views/master.py
+++ b/src/wuttafarm/web/views/master.py
@@ -23,10 +23,6 @@
Base class for WuttaFarm master views
"""
-import threading
-import time
-
-import requests
from webhelpers2.html import tags
from wuttaweb.views import MasterView
@@ -111,36 +107,17 @@ class WuttaFarmMasterView(MasterView):
f.set_readonly("drupal_id")
def persist(self, obj, session=None):
- session = session or self.Session()
# save per usual
super().persist(obj, session)
# maybe also sync change to farmOS
if self.app.is_farmos_mirror():
- if self.creating:
- session.flush() # need the new uuid
client = get_farmos_client_for_user(self.request)
- thread = threading.Thread(
- target=self.auto_sync_to_farmos, args=(client, obj.uuid)
- )
- thread.start()
+ self.auto_sync_to_farmos(client, obj)
- 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)
-
- self.app.auto_sync_to_farmos(obj, client=client, require=False)
+ def auto_sync_to_farmos(self, client, obj):
+ self.app.auto_sync_to_farmos(obj, client=client, require=False)
def get_farmos_entity_type(self):
if self.farmos_entity_type:
@@ -168,24 +145,10 @@ class WuttaFarmMasterView(MasterView):
# maybe delete from farmOS also
if farmos_uuid:
+ entity_type = self.get_farmos_entity_type()
+ bundle = self.get_farmos_bundle()
client = get_farmos_client_for_user(self.request)
- # nb. must use separate thread to avoid some kind of race
- # condition (?) - seems as though maybe a "boomerang"
- # effect is happening; this seems to help anyway
- thread = threading.Thread(
- target=self.delete_from_farmos, args=(client, farmos_uuid)
- )
- thread.start()
-
- def delete_from_farmos(self, client, farmos_uuid):
- entity_type = self.get_farmos_entity_type()
- bundle = self.get_farmos_bundle()
- try:
client.resource.delete(entity_type, bundle, farmos_uuid)
- except requests.HTTPError as exc:
- # ignore if record not found in farmOS
- if exc.response.status_code != 404:
- raise
class TaxonomyMasterView(WuttaFarmMasterView):
diff --git a/src/wuttafarm/web/views/quick/eggs.py b/src/wuttafarm/web/views/quick/eggs.py
index fded73c..8aae46e 100644
--- a/src/wuttafarm/web/views/quick/eggs.py
+++ b/src/wuttafarm/web/views/quick/eggs.py
@@ -24,8 +24,6 @@ Quick Form for "Eggs"
"""
import json
-import threading
-import time
import colander
from deform.widget import SelectWidget
@@ -333,43 +331,13 @@ class EggsQuickForm(QuickFormView):
session.flush()
if self.app.is_farmos_mirror():
- thread = threading.Thread(
- target=self.auto_sync_to_farmos,
- args=(log.uuid, quantity.uuid, new_unit.uuid if new_unit else None),
- )
- thread.start()
+ if new_unit:
+ self.app.auto_sync_to_farmos(unit, client=self.farmos_client)
+ self.app.auto_sync_to_farmos(quantity, client=self.farmos_client)
+ self.app.auto_sync_to_farmos(log, client=self.farmos_client)
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):
model = self.app.model