feat: expose "group membership" for assets

This commit is contained in:
Lance Edgar 2026-03-04 12:29:23 -06:00
parent b2c3d3a301
commit e8a8ce2528
5 changed files with 58 additions and 6 deletions

View file

@ -32,6 +32,22 @@ class AssetHandler(GenericHandler):
:term:`handler`. :term:`handler`.
""" """
def get_groups(self, asset):
model = self.app.model
session = self.app.get_session(asset)
grplog = (
session.query(model.Log)
.join(model.LogAsset)
.filter(model.LogAsset.asset == asset)
.filter(model.Log.is_group_assignment == True)
.order_by(model.Log.timestamp.desc())
.first()
)
if grplog:
return grplog.groups
return []
def get_locations(self, asset): def get_locations(self, asset):
model = self.app.model model = self.app.model
session = self.app.get_session(asset) session = self.app.get_session(asset)

View file

@ -228,7 +228,7 @@ class AnimalAssetView(AssetMasterView):
"birthdate", "birthdate",
"is_sterile", "is_sterile",
"sex", "sex",
"group_membership", "groups",
"owners", "owners",
"locations", "locations",
"archived", "archived",
@ -245,6 +245,7 @@ class AnimalAssetView(AssetMasterView):
"asset_type", "asset_type",
"owners", "owners",
"locations", "locations",
"groups",
"archived", "archived",
"drupal_id", "drupal_id",
"farmos_uuid", "farmos_uuid",

View file

@ -66,6 +66,10 @@ class AssetMasterView(WuttaFarmMasterView):
farmos_entity_type = "asset" farmos_entity_type = "asset"
labels = {
"groups": "Group Membership",
}
sort_defaults = "asset_name" sort_defaults = "asset_name"
filter_defaults = { filter_defaults = {
@ -136,6 +140,9 @@ class AssetMasterView(WuttaFarmMasterView):
# parents # parents
g.set_renderer("parents", self.render_parents_for_grid) g.set_renderer("parents", self.render_parents_for_grid)
# groups
g.set_renderer("groups", self.render_groups_for_grid)
# owners # owners
g.set_label("owners", "Owner") g.set_label("owners", "Owner")
g.set_renderer("owners", self.render_owners_for_grid) g.set_renderer("owners", self.render_owners_for_grid)
@ -174,6 +181,21 @@ class AssetMasterView(WuttaFarmMasterView):
return ", ".join([user.username for user in asset.owners]) return ", ".join([user.username for user in asset.owners])
def render_groups_for_grid(self, asset, field, value):
asset_handler = self.app.get_asset_handler()
groups = asset_handler.get_groups(asset)
if self.farmos_style_grid_links:
links = []
for group in groups:
url = self.request.route_url(
f"{group.asset_type}_assets.view", uuid=group.uuid
)
links.append(tags.link_to(str(group), url))
return ", ".join(links)
return ", ".join([str(group) for group in groups])
def render_locations_for_grid(self, asset, field, value): def render_locations_for_grid(self, asset, field, value):
asset_handler = self.app.get_asset_handler() asset_handler = self.app.get_asset_handler()
locations = asset_handler.get_locations(asset) locations = asset_handler.get_locations(asset)
@ -229,6 +251,15 @@ class AssetMasterView(WuttaFarmMasterView):
# nb. must explicity declare value for non-standard field # nb. must explicity declare value for non-standard field
f.set_default("locations", asset_handler.get_locations(asset)) f.set_default("locations", asset_handler.get_locations(asset))
# groups
if self.creating or self.editing:
# nb. this is a calculated field
f.remove("groups")
else:
f.set_node("groups", AssetRefs(self.request))
# nb. must explicity declare value for non-standard field
f.set_default("groups", asset_handler.get_groups(asset))
# parents # parents
if self.creating or self.editing: if self.creating or self.editing:
f.remove("parents") # TODO: add support for this f.remove("parents") # TODO: add support for this
@ -367,7 +398,7 @@ class AllAssetView(AssetMasterView):
"thumbnail", "thumbnail",
"drupal_id", "drupal_id",
"asset_name", "asset_name",
"group_membership", "groups",
"asset_type", "asset_type",
"parents", "parents",
"owners", "owners",

View file

@ -39,7 +39,7 @@ from wuttafarm.web.grids import (
NullableBooleanFilter, NullableBooleanFilter,
DateTimeFilter, DateTimeFilter,
) )
from wuttafarm.web.forms.schema import FarmOSRef from wuttafarm.web.forms.schema import FarmOSRef, FarmOSAssetRefs
class AnimalView(AssetMasterView): class AnimalView(AssetMasterView):
@ -87,9 +87,9 @@ class AnimalView(AssetMasterView):
"is_sterile", "is_sterile",
"notes", "notes",
"asset_type_name", "asset_type_name",
"groups",
"owners", "owners",
"locations", "locations",
"groups",
"archived", "archived",
"thumbnail_url", "thumbnail_url",
"image_url", "image_url",
@ -147,7 +147,7 @@ class AnimalView(AssetMasterView):
def render_groups_for_grid(self, animal, field, value): def render_groups_for_grid(self, animal, field, value):
groups = [] groups = []
for group in animal["group_objects"]: for group in animal["groups"]:
if self.farmos_style_grid_links: if self.farmos_style_grid_links:
url = self.request.route_url( url = self.request.route_url(
"farmos_group_assets.view", uuid=group["uuid"] "farmos_group_assets.view", uuid=group["uuid"]
@ -209,6 +209,7 @@ class AnimalView(AssetMasterView):
group = { group = {
"uuid": group["id"], "uuid": group["id"],
"name": group["attributes"]["name"], "name": group["attributes"]["name"],
"asset_type": "group",
} }
group_objects.append(group) group_objects.append(group)
group_names.append(group["name"]) group_names.append(group["name"])
@ -218,7 +219,7 @@ class AnimalView(AssetMasterView):
"animal_type": animal_type_object, "animal_type": animal_type_object,
"animal_type_uuid": animal_type_object["uuid"], "animal_type_uuid": animal_type_object["uuid"],
"animal_type_name": animal_type_object["name"], "animal_type_name": animal_type_object["name"],
"group_objects": group_objects, "groups": group_objects,
"group_names": group_names, "group_names": group_names,
"birthdate": birthdate, "birthdate": birthdate,
"sex": animal["attributes"]["sex"] or colander.null, "sex": animal["attributes"]["sex"] or colander.null,
@ -273,6 +274,8 @@ class AnimalView(AssetMasterView):
# groups # groups
if self.creating or self.editing: if self.creating or self.editing:
f.remove("groups") # TODO f.remove("groups") # TODO
else:
f.set_node("groups", FarmOSAssetRefs(self.request))
def get_api_payload(self, animal): def get_api_payload(self, animal):
payload = super().get_api_payload(animal) payload = super().get_api_payload(animal)

View file

@ -54,6 +54,7 @@ class AssetMasterView(FarmOSMasterView):
"name": "Asset Name", "name": "Asset Name",
"asset_type_name": "Asset Type", "asset_type_name": "Asset Type",
"locations": "Location", "locations": "Location",
"groups": "Group Membership",
"thumbnail_url": "Thumbnail URL", "thumbnail_url": "Thumbnail URL",
"image_url": "Image URL", "image_url": "Image URL",
} }