diff --git a/CHANGELOG.md b/CHANGELOG.md index eabe9f0..5d6142c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,27 +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.2.0 (2026-02-08) - -### Feat - -- add view for farmOS activity logs -- add view for farmOS log types -- add view for farmOS structure types -- add view for farmOS land types -- add view for farmOS land assets -- add view for farmOS groups -- add view for farmOS asset types -- add view for farmOS structures -- add view for farmOS animal types -- add view for farmOS users - -### Fix - -- add pyramid_exclog dependency -- add menu option, "Go to farmOS" -- ensure Buefy version matches what we use for custom css - ## v0.1.5 (2026-02-07) ### Fix diff --git a/pyproject.toml b/pyproject.toml index 48faefd..d2c6ef1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ build-backend = "hatchling.build" [project] name = "WuttaFarm" -version = "0.2.0" +version = "0.1.5" description = "Web app to integrate with and extend farmOS" readme = "README.md" authors = [ @@ -31,7 +31,6 @@ license = {text = "GNU General Public License v3"} dependencies = [ "farmOS", "psycopg2", - "pyramid_exclog", "WuttaWeb[continuum]>=0.27.3", ] diff --git a/src/wuttafarm/web/app.py b/src/wuttafarm/web/app.py index 5c59434..83c9817 100644 --- a/src/wuttafarm/web/app.py +++ b/src/wuttafarm/web/app.py @@ -49,16 +49,11 @@ def main(global_config, **settings): app = wutta_config.get_app() path = app.resource_path("wuttafarm.web.static:css/wuttafarm-buefy.css") if os.path.exists(path): - # TODO: this is not robust enough, probably..but works for me/now wutta_config.setdefault( "wuttaweb.liburl.buefy_css", "/wuttafarm/css/wuttafarm-buefy.css" ) - # nb. ensure buefy version matches what we use for custom css - wutta_config.setdefault("wuttaweb.libver.buefy", "0.9.29") - wutta_config.setdefault("wuttaweb.libver.buefy_css", "0.9.29") - # bring in the rest of WuttaFarm pyramid_config.include("wuttafarm.web.static") pyramid_config.include("wuttafarm.web.subscribers") diff --git a/src/wuttafarm/web/forms/schema.py b/src/wuttafarm/web/forms/schema.py deleted file mode 100644 index a38588a..0000000 --- a/src/wuttafarm/web/forms/schema.py +++ /dev/null @@ -1,85 +0,0 @@ -# -*- coding: utf-8; -*- -################################################################################ -# -# WuttaFarm --Web app to integrate with and extend farmOS -# Copyright © 2026 Lance Edgar -# -# This file is part of WuttaFarm. -# -# WuttaFarm is free software: you can redistribute it and/or modify it under -# the terms of the GNU General Public License as published by the Free Software -# Foundation, either version 3 of the License, or (at your option) any later -# version. -# -# WuttaFarm is distributed in the hope that it will be useful, but WITHOUT ANY -# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR -# A PARTICULAR PURPOSE. See the GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along with -# WuttaFarm. If not, see . -# -################################################################################ -""" -Custom form widgets for WuttaFarm -""" - -import json - -import colander - - -class AnimalTypeType(colander.SchemaType): - - def __init__(self, request, *args, **kwargs): - super().__init__(*args, **kwargs) - self.request = request - - def serialize(self, node, appstruct): - if appstruct is colander.null: - return colander.null - - return json.dumps(appstruct) - - def widget_maker(self, **kwargs): # pylint: disable=empty-docstring - """ """ - from wuttafarm.web.forms.widgets import AnimalTypeWidget - - return AnimalTypeWidget(self.request, **kwargs) - - -class StructureType(colander.SchemaType): - - def __init__(self, request, *args, **kwargs): - super().__init__(*args, **kwargs) - self.request = request - - def serialize(self, node, appstruct): - if appstruct is colander.null: - return colander.null - - return json.dumps(appstruct) - - def widget_maker(self, **kwargs): # pylint: disable=empty-docstring - """ """ - from wuttafarm.web.forms.widgets import StructureWidget - - return StructureWidget(self.request, **kwargs) - - -class UsersType(colander.SchemaType): - - def __init__(self, request, *args, **kwargs): - super().__init__(*args, **kwargs) - self.request = request - - def serialize(self, node, appstruct): - if appstruct is colander.null: - return colander.null - - return json.dumps(appstruct) - - def widget_maker(self, **kwargs): # pylint: disable=empty-docstring - """ """ - from wuttafarm.web.forms.widgets import UsersWidget - - return UsersWidget(self.request, **kwargs) diff --git a/src/wuttafarm/web/forms/widgets.py b/src/wuttafarm/web/forms/widgets.py index 0ffb055..047a8cd 100644 --- a/src/wuttafarm/web/forms/widgets.py +++ b/src/wuttafarm/web/forms/widgets.py @@ -23,21 +23,18 @@ Custom form widgets for WuttaFarm """ -import json - import colander from deform.widget import Widget from webhelpers2.html import HTML, tags -class ImageWidget(Widget): - """ - Widget to display an image URL for a record. +class AnimalImage(Widget): """ + Widget to display an image URL for an animal. - def __init__(self, alt_text, *args, **kwargs): - super().__init__(*args, **kwargs) - self.alt_text = alt_text + TODO: this should be refactored to a more general name, once more + types of images need to be supported. + """ def serialize(self, field, cstruct, **kw): readonly = kw.get("readonly", self.readonly) @@ -45,86 +42,6 @@ class ImageWidget(Widget): if cstruct in (colander.null, None): return HTML.tag("span") - return tags.image(cstruct, self.alt_text, **kw) - - return super().serialize(field, cstruct, **kw) - - -class AnimalTypeWidget(Widget): - """ - Widget to display an "animal type" field. - """ - - def __init__(self, request, *args, **kwargs): - super().__init__(*args, **kwargs) - self.request = request - - def serialize(self, field, cstruct, **kw): - readonly = kw.get("readonly", self.readonly) - if readonly: - if cstruct in (colander.null, None): - return HTML.tag("span") - - animal_type = json.loads(cstruct) - return tags.link_to( - animal_type["name"], - self.request.route_url( - "farmos_animal_types.view", uuid=animal_type["uuid"] - ), - ) - - return super().serialize(field, cstruct, **kw) - - -class StructureWidget(Widget): - """ - Widget to display a "structure" field. - """ - - def __init__(self, request, *args, **kwargs): - super().__init__(*args, **kwargs) - self.request = request - - def serialize(self, field, cstruct, **kw): - readonly = kw.get("readonly", self.readonly) - if readonly: - if cstruct in (colander.null, None): - return HTML.tag("span") - - structure = json.loads(cstruct) - return tags.link_to( - structure["name"], - self.request.route_url( - "farmos_structures.view", uuid=structure["uuid"] - ), - ) - - return super().serialize(field, cstruct, **kw) - - -class UsersWidget(Widget): - """ - Widget to display the list of owners for an asset etc. - """ - - def __init__(self, request, *args, **kwargs): - super().__init__(*args, **kwargs) - self.request = request - - def serialize(self, field, cstruct, **kw): - readonly = kw.get("readonly", self.readonly) - if readonly: - if cstruct in (colander.null, None): - return HTML.tag("span") - - items = [] - for user in json.loads(cstruct): - link = tags.link_to( - user["display_name"], - self.request.route_url("farmos_users.view", uuid=user["uuid"]), - ) - items.append(HTML.tag("li", c=link)) - - return HTML.tag("ul", c=items) + return tags.image(cstruct, "animal image", **kw) return super().serialize(field, cstruct, **kw) diff --git a/src/wuttafarm/web/menus.py b/src/wuttafarm/web/menus.py index ab6f440..e999944 100644 --- a/src/wuttafarm/web/menus.py +++ b/src/wuttafarm/web/menus.py @@ -38,75 +38,14 @@ class WuttaFarmMenuHandler(base.MenuHandler): ] def make_farmos_menu(self, request): - config = request.wutta_config - app = config.get_app() return { "title": "farmOS", "type": "menu", "items": [ - { - "title": "Go to farmOS", - "url": app.get_farmos_url(), - "target": "_blank", - }, - {"type": "sep"}, { "title": "Animals", "route": "farmos_animals", "perm": "farmos_animals.list", }, - { - "title": "Groups", - "route": "farmos_groups", - "perm": "farmos_groups.list", - }, - { - "title": "Structures", - "route": "farmos_structures", - "perm": "farmos_structures.list", - }, - { - "title": "Land", - "route": "farmos_land_assets", - "perm": "farmos_land_assets.list", - }, - {"type": "sep"}, - { - "title": "Activity Logs", - "route": "farmos_logs_activity", - "perm": "farmos_logs_activity.list", - }, - {"type": "sep"}, - { - "title": "Animal Types", - "route": "farmos_animal_types", - "perm": "farmos_animal_types.list", - }, - { - "title": "Structure Types", - "route": "farmos_structure_types", - "perm": "farmos_structure_types.list", - }, - { - "title": "Land Types", - "route": "farmos_land_types", - "perm": "farmos_land_types.list", - }, - { - "title": "Asset Types", - "route": "farmos_asset_types", - "perm": "farmos_asset_types.list", - }, - { - "title": "Log Types", - "route": "farmos_log_types", - "perm": "farmos_log_types.list", - }, - {"type": "sep"}, - { - "title": "Users", - "route": "farmos_users", - "perm": "farmos_users.list", - }, ], } diff --git a/src/wuttafarm/web/views/common.py b/src/wuttafarm/web/views/common.py index f46c018..bb8a9c9 100644 --- a/src/wuttafarm/web/views/common.py +++ b/src/wuttafarm/web/views/common.py @@ -48,28 +48,8 @@ class CommonView(base.CommonView): site_admin = session.query(model.Role).filter_by(name="Site Admin").first() if site_admin: site_admin_perms = [ - "farmos_animal_types.list", - "farmos_animal_types.view", "farmos_animals.list", "farmos_animals.view", - "farmos_asset_types.list", - "farmos_asset_types.view", - "farmos_groups.list", - "farmos_groups.view", - "farmos_land_assets.list", - "farmos_land_assets.view", - "farmos_land_types.list", - "farmos_land_types.view", - "farmos_log_types.list", - "farmos_log_types.view", - "farmos_logs_activity.list", - "farmos_logs_activity.view", - "farmos_structure_types.list", - "farmos_structure_types.view", - "farmos_structures.list", - "farmos_structures.view", - "farmos_users.list", - "farmos_users.view", ] for perm in site_admin_perms: auth.grant_permission(site_admin, perm) diff --git a/src/wuttafarm/web/views/farmos/__init__.py b/src/wuttafarm/web/views/farmos/__init__.py index deacd7d..df789b3 100644 --- a/src/wuttafarm/web/views/farmos/__init__.py +++ b/src/wuttafarm/web/views/farmos/__init__.py @@ -27,14 +27,4 @@ from .master import FarmOSMasterView def includeme(config): - config.include("wuttafarm.web.views.farmos.users") - config.include("wuttafarm.web.views.farmos.asset_types") - config.include("wuttafarm.web.views.farmos.land_types") - config.include("wuttafarm.web.views.farmos.land_assets") - config.include("wuttafarm.web.views.farmos.structure_types") - config.include("wuttafarm.web.views.farmos.structures") - config.include("wuttafarm.web.views.farmos.animal_types") config.include("wuttafarm.web.views.farmos.animals") - config.include("wuttafarm.web.views.farmos.groups") - config.include("wuttafarm.web.views.farmos.log_types") - config.include("wuttafarm.web.views.farmos.logs_activity") diff --git a/src/wuttafarm/web/views/farmos/animal_types.py b/src/wuttafarm/web/views/farmos/animal_types.py deleted file mode 100644 index a974242..0000000 --- a/src/wuttafarm/web/views/farmos/animal_types.py +++ /dev/null @@ -1,136 +0,0 @@ -# -*- coding: utf-8; -*- -################################################################################ -# -# WuttaFarm --Web app to integrate with and extend farmOS -# Copyright © 2026 Lance Edgar -# -# This file is part of WuttaFarm. -# -# WuttaFarm is free software: you can redistribute it and/or modify it under -# the terms of the GNU General Public License as published by the Free Software -# Foundation, either version 3 of the License, or (at your option) any later -# version. -# -# WuttaFarm is distributed in the hope that it will be useful, but WITHOUT ANY -# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR -# A PARTICULAR PURPOSE. See the GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along with -# WuttaFarm. If not, see . -# -################################################################################ -""" -View for farmOS animal types -""" - -import datetime - -import colander - -from wuttaweb.forms.schema import WuttaDateTime - -from wuttafarm.web.views.farmos import FarmOSMasterView - - -class AnimalTypeView(FarmOSMasterView): - """ - Master view for Animal Types in farmOS. - """ - - model_name = "farmos_animal_type" - model_title = "farmOS Animal Type" - model_title_plural = "farmOS Animal Types" - - route_prefix = "farmos_animal_types" - url_prefix = "/farmOS/animal-types" - - farmos_refurl_path = "/admin/structure/taxonomy/manage/animal_type/overview" - - grid_columns = [ - "name", - "description", - "changed", - ] - - sort_defaults = "name" - - form_fields = [ - "name", - "description", - "changed", - ] - - def get_grid_data(self, columns=None, session=None): - animal_types = self.farmos_client.resource.get("taxonomy_term", "animal_type") - return [self.normalize_animal_type(t) for t in animal_types["data"]] - - def configure_grid(self, grid): - g = grid - super().configure_grid(g) - - # name - g.set_link("name") - g.set_searchable("name") - - # changed - g.set_renderer("changed", "datetime") - - def get_instance(self): - animal_type = self.farmos_client.resource.get_id( - "taxonomy_term", "animal_type", self.request.matchdict["uuid"] - ) - return self.normalize_animal_type(animal_type["data"]) - - def get_instance_title(self, animal_type): - return animal_type["name"] - - def normalize_animal_type(self, animal_type): - - if changed := animal_type["attributes"]["changed"]: - changed = datetime.datetime.fromisoformat(changed) - changed = self.app.localtime(changed) - - if description := animal_type["attributes"]["description"]: - description = description["value"] - - return { - "uuid": animal_type["id"], - "drupal_internal_id": animal_type["attributes"]["drupal_internal__tid"], - "name": animal_type["attributes"]["name"], - "description": description or colander.null, - "changed": changed, - } - - def configure_form(self, form): - f = form - super().configure_form(f) - - # description - f.set_widget("description", "notes") - - # changed - f.set_node("changed", WuttaDateTime()) - - def get_xref_buttons(self, animal_type): - return [ - self.make_button( - "View in farmOS", - primary=True, - url=self.app.get_farmos_url( - f"/taxonomy/term/{animal_type['drupal_internal_id']}" - ), - target="_blank", - icon_left="external-link-alt", - ), - ] - - -def defaults(config, **kwargs): - base = globals() - - AnimalTypeView = kwargs.get("AnimalTypeView", base["AnimalTypeView"]) - AnimalTypeView.defaults(config) - - -def includeme(config): - defaults(config) diff --git a/src/wuttafarm/web/views/farmos/animals.py b/src/wuttafarm/web/views/farmos/animals.py index 8eca5af..aa00412 100644 --- a/src/wuttafarm/web/views/farmos/animals.py +++ b/src/wuttafarm/web/views/farmos/animals.py @@ -28,9 +28,7 @@ import datetime import colander from wuttafarm.web.views.farmos import FarmOSMasterView - -from wuttafarm.web.forms.schema import UsersType, AnimalTypeType, StructureType -from wuttafarm.web.forms.widgets import ImageWidget +from wuttafarm.web.forms.widgets import AnimalImage class AnimalView(FarmOSMasterView): @@ -48,9 +46,11 @@ class AnimalView(FarmOSMasterView): farmos_refurl_path = "/assets/animal" labels = { - "animal_type": "Species / Breed", "is_castrated": "Castrated", - "location": "Current Location", + "location_name": "Current Location", + "raw_image_url": "Raw Image URL", + "large_image_url": "Large Image URL", + "thumbnail_image_url": "Thumbnail Image URL", } grid_columns = [ @@ -65,13 +65,13 @@ class AnimalView(FarmOSMasterView): form_fields = [ "name", - "animal_type", + "animal_type_name", "birthdate", "sex", "is_castrated", "status", "owners", - "location", + "location_name", "notes", "raw_image_url", "large_image_url", @@ -111,10 +111,7 @@ class AnimalView(FarmOSMasterView): animal_type = self.farmos_client.resource.get_id( "taxonomy_term", "animal_type", animal_type["data"]["id"] ) - data["animal_type"] = { - "uuid": animal_type["data"]["id"], - "name": animal_type["data"]["attributes"]["name"], - } + data["animal_type_name"] = animal_type["data"]["attributes"]["name"] # add location if location := relationships.get("location"): @@ -122,24 +119,20 @@ class AnimalView(FarmOSMasterView): location = self.farmos_client.resource.get_id( "asset", "structure", location["data"][0]["id"] ) - data["location"] = { - "uuid": location["data"]["id"], - "name": location["data"]["attributes"]["name"], - } + data["location_name"] = location["data"]["attributes"]["name"] # add owners if owner := relationships.get("owner"): - data["owners"] = [] + owners = [] for owner_data in owner["data"]: - owner = self.farmos_client.resource.get_id( - "user", "user", owner_data["id"] - ) - data["owners"].append( - { - "uuid": owner["data"]["id"], - "display_name": owner["data"]["attributes"]["display_name"], - } + owners.append( + self.farmos_client.resource.get_id( + "user", "user", owner_data["id"] + ) ) + data["owners"] = ", ".join( + [o["data"]["attributes"]["display_name"] for o in owners] + ) # add image urls if image := relationships.get("image"): @@ -174,6 +167,7 @@ class AnimalView(FarmOSMasterView): "uuid": animal["id"], "drupal_internal_id": animal["attributes"]["drupal_internal__id"], "name": animal["attributes"]["name"], + "species_breed": "", # TODO "birthdate": birthdate, "sex": animal["attributes"]["sex"], "is_castrated": animal["attributes"]["is_castrated"], @@ -187,24 +181,15 @@ class AnimalView(FarmOSMasterView): super().configure_form(f) animal = f.model_instance - # animal_type - f.set_node("animal_type", AnimalTypeType(self.request)) - # is_castrated f.set_node("is_castrated", colander.Boolean()) - # location - f.set_node("location", StructureType(self.request)) - - # owners - f.set_node("owners", UsersType(self.request)) - # notes f.set_widget("notes", "notes") # image if url := animal.get("large_image_url"): - f.set_widget("image", ImageWidget("animal image")) + f.set_widget("image", AnimalImage()) f.set_default("image", url) def get_xref_buttons(self, animal): diff --git a/src/wuttafarm/web/views/farmos/asset_types.py b/src/wuttafarm/web/views/farmos/asset_types.py deleted file mode 100644 index 75eebbe..0000000 --- a/src/wuttafarm/web/views/farmos/asset_types.py +++ /dev/null @@ -1,101 +0,0 @@ -# -*- coding: utf-8; -*- -################################################################################ -# -# WuttaFarm --Web app to integrate with and extend farmOS -# Copyright © 2026 Lance Edgar -# -# This file is part of WuttaFarm. -# -# WuttaFarm is free software: you can redistribute it and/or modify it under -# the terms of the GNU General Public License as published by the Free Software -# Foundation, either version 3 of the License, or (at your option) any later -# version. -# -# WuttaFarm is distributed in the hope that it will be useful, but WITHOUT ANY -# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR -# A PARTICULAR PURPOSE. See the GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along with -# WuttaFarm. If not, see . -# -################################################################################ -""" -View for farmOS asset types -""" - -from wuttafarm.web.views.farmos import FarmOSMasterView - - -class AssetTypeView(FarmOSMasterView): - """ - View for farmOS asset types - """ - - model_name = "farmos_asset_type" - model_title = "farmOS Asset Type" - model_title_plural = "farmOS Asset Types" - - route_prefix = "farmos_asset_types" - url_prefix = "/farmOS/asset-types" - - grid_columns = [ - "label", - "description", - ] - - sort_defaults = "label" - - form_fields = [ - "label", - "description", - ] - - def get_grid_data(self, columns=None, session=None): - asset_types = self.farmos_client.resource.get("asset_type", "asset_type") - return [self.normalize_asset_type(t) for t in asset_types["data"]] - - def configure_grid(self, grid): - g = grid - super().configure_grid(g) - - # label - g.set_link("label") - g.set_searchable("label") - - # description - g.set_searchable("description") - - def get_instance(self): - asset_type = self.farmos_client.resource.get_id( - "asset_type", "asset_type", self.request.matchdict["uuid"] - ) - return self.normalize_asset_type(asset_type["data"]) - - def get_instance_title(self, asset_type): - return asset_type["label"] - - def normalize_asset_type(self, asset_type): - return { - "uuid": asset_type["id"], - "drupal_internal_id": asset_type["attributes"]["drupal_internal__id"], - "label": asset_type["attributes"]["label"], - "description": asset_type["attributes"]["description"], - } - - def configure_form(self, form): - f = form - super().configure_form(f) - - # description - f.set_widget("description", "notes") - - -def defaults(config, **kwargs): - base = globals() - - AssetTypeView = kwargs.get("AssetTypeView", base["AssetTypeView"]) - AssetTypeView.defaults(config) - - -def includeme(config): - defaults(config) diff --git a/src/wuttafarm/web/views/farmos/groups.py b/src/wuttafarm/web/views/farmos/groups.py deleted file mode 100644 index 4664a6b..0000000 --- a/src/wuttafarm/web/views/farmos/groups.py +++ /dev/null @@ -1,164 +0,0 @@ -# -*- coding: utf-8; -*- -################################################################################ -# -# WuttaFarm --Web app to integrate with and extend farmOS -# Copyright © 2026 Lance Edgar -# -# This file is part of WuttaFarm. -# -# WuttaFarm is free software: you can redistribute it and/or modify it under -# the terms of the GNU General Public License as published by the Free Software -# Foundation, either version 3 of the License, or (at your option) any later -# version. -# -# WuttaFarm is distributed in the hope that it will be useful, but WITHOUT ANY -# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR -# A PARTICULAR PURPOSE. See the GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along with -# WuttaFarm. If not, see . -# -################################################################################ -""" -View for farmOS Groups -""" - -import datetime - -import colander - -from wuttafarm.web.views.farmos import FarmOSMasterView -from wuttaweb.forms.schema import WuttaDateTime -from wuttaweb.forms.widgets import WuttaDateTimeWidget - - -class GroupView(FarmOSMasterView): - """ - View for farmOS Groups - """ - - model_name = "farmos_group" - model_title = "farmOS Group" - model_title_plural = "farmOS Groups" - - route_prefix = "farmos_groups" - url_prefix = "/farmOS/groups" - - farmos_refurl_path = "/assets/group" - - grid_columns = [ - "name", - "is_fixed", - "is_location", - "status", - "changed", - ] - - sort_defaults = "name" - - form_fields = [ - "name", - "is_fixed", - "is_location", - "status", - "notes", - "created", - "changed", - ] - - def get_grid_data(self, columns=None, session=None): - groups = self.farmos_client.resource.get("asset", "group") - return [self.normalize_group(a) for a in groups["data"]] - - def configure_grid(self, grid): - g = grid - super().configure_grid(g) - - # name - g.set_link("name") - g.set_searchable("name") - - # is_fixed - g.set_renderer("is_fixed", "boolean") - - # is_location - g.set_renderer("is_location", "boolean") - - # changed - g.set_renderer("changed", "datetime") - - def get_instance(self): - - group = self.farmos_client.resource.get_id( - "asset", "group", self.request.matchdict["uuid"] - ) - - return self.normalize_group(group["data"]) - - def get_instance_title(self, group): - return group["name"] - - def normalize_group(self, group): - - if created := group["attributes"].get("created"): - created = datetime.datetime.fromisoformat(created) - created = self.app.localtime(created) - - if changed := group["attributes"].get("changed"): - changed = datetime.datetime.fromisoformat(changed) - changed = self.app.localtime(changed) - - return { - "uuid": group["id"], - "drupal_internal_id": group["attributes"]["drupal_internal__id"], - "name": group["attributes"]["name"], - "created": created, - "changed": changed, - "is_fixed": group["attributes"]["is_fixed"], - "is_location": group["attributes"]["is_location"], - "status": group["attributes"]["status"], - "notes": group["attributes"]["notes"]["value"], - } - - def configure_form(self, form): - f = form - super().configure_form(f) - - # is_fixed - f.set_node("is_fixed", colander.Boolean()) - - # is_location - f.set_node("is_location", colander.Boolean()) - - # notes - f.set_widget("notes", "notes") - - # created - f.set_node("created", WuttaDateTime()) - f.set_widget("created", WuttaDateTimeWidget(self.request)) - - # changed - f.set_node("changed", WuttaDateTime()) - f.set_widget("changed", WuttaDateTimeWidget(self.request)) - - def get_xref_buttons(self, group): - return [ - self.make_button( - "View in farmOS", - primary=True, - url=self.app.get_farmos_url(f"/asset/{group['drupal_internal_id']}"), - target="_blank", - icon_left="external-link-alt", - ), - ] - - -def defaults(config, **kwargs): - base = globals() - - GroupView = kwargs.get("GroupView", base["GroupView"]) - GroupView.defaults(config) - - -def includeme(config): - defaults(config) diff --git a/src/wuttafarm/web/views/farmos/land_assets.py b/src/wuttafarm/web/views/farmos/land_assets.py deleted file mode 100644 index a496cc5..0000000 --- a/src/wuttafarm/web/views/farmos/land_assets.py +++ /dev/null @@ -1,169 +0,0 @@ -# -*- coding: utf-8; -*- -################################################################################ -# -# WuttaFarm --Web app to integrate with and extend farmOS -# Copyright © 2026 Lance Edgar -# -# This file is part of WuttaFarm. -# -# WuttaFarm is free software: you can redistribute it and/or modify it under -# the terms of the GNU General Public License as published by the Free Software -# Foundation, either version 3 of the License, or (at your option) any later -# version. -# -# WuttaFarm is distributed in the hope that it will be useful, but WITHOUT ANY -# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR -# A PARTICULAR PURPOSE. See the GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along with -# WuttaFarm. If not, see . -# -################################################################################ -""" -View for farmOS Land Assets -""" - -import datetime - -import colander - -from wuttaweb.forms.schema import WuttaDateTime -from wuttaweb.forms.widgets import WuttaDateTimeWidget - -from wuttafarm.web.views.farmos import FarmOSMasterView - - -class LandAssetView(FarmOSMasterView): - """ - View for farmOS Land Assets - """ - - model_name = "farmos_land_asset" - model_title = "farmOS Land Asset" - model_title_plural = "farmOS Land Assets" - - route_prefix = "farmos_land_assets" - url_prefix = "/farmOS/land" - - farmos_refurl_path = "/assets/land" - - grid_columns = [ - "name", - "is_fixed", - "is_location", - "status", - "changed", - ] - - sort_defaults = "name" - - form_fields = [ - "name", - "is_fixed", - "is_location", - "status", - "notes", - "created", - "changed", - ] - - def get_grid_data(self, columns=None, session=None): - land_assets = self.farmos_client.resource.get("asset", "land") - return [self.normalize_land_asset(l) for l in land_assets["data"]] - - def configure_grid(self, grid): - g = grid - super().configure_grid(g) - - # name - g.set_link("name") - g.set_searchable("name") - - # is_fixed - g.set_renderer("is_fixed", "boolean") - - # is_location - g.set_renderer("is_location", "boolean") - - # created - g.set_renderer("created", "datetime") - - # changed - g.set_renderer("changed", "datetime") - - def get_instance(self): - land_asset = self.farmos_client.resource.get_id( - "asset", "land", self.request.matchdict["uuid"] - ) - return self.normalize_land_asset(land_asset["data"]) - - def get_instance_title(self, land_asset): - return land_asset["name"] - - def normalize_land_asset(self, land): - - if created := land["attributes"].get("created"): - created = datetime.datetime.fromisoformat(created) - created = self.app.localtime(created) - - if changed := land["attributes"].get("changed"): - changed = datetime.datetime.fromisoformat(changed) - changed = self.app.localtime(changed) - - if notes := land["attributes"]["notes"]: - notes = notes["value"] - - return { - "uuid": land["id"], - "drupal_internal_id": land["attributes"]["drupal_internal__id"], - "name": land["attributes"]["name"], - "created": created, - "changed": changed, - "is_fixed": land["attributes"]["is_fixed"], - "is_location": land["attributes"]["is_location"], - "status": land["attributes"]["status"], - "notes": notes or colander.null, - } - - def configure_form(self, form): - f = form - super().configure_form(f) - - # is_fixed - f.set_node("is_fixed", colander.Boolean()) - - # is_location - f.set_node("is_location", colander.Boolean()) - - # notes - f.set_widget("notes", "notes") - - # created - f.set_node("created", WuttaDateTime()) - f.set_widget("created", WuttaDateTimeWidget(self.request)) - - # changed - f.set_node("changed", WuttaDateTime()) - f.set_widget("changed", WuttaDateTimeWidget(self.request)) - - def get_xref_buttons(self, land): - return [ - self.make_button( - "View in farmOS", - primary=True, - url=self.app.get_farmos_url(f"/asset/{land['drupal_internal_id']}"), - target="_blank", - icon_left="external-link-alt", - ), - ] - - -def defaults(config, **kwargs): - base = globals() - - LandAssetView = kwargs.get("LandAssetView", base["LandAssetView"]) - LandAssetView.defaults(config) - - -def includeme(config): - defaults(config) diff --git a/src/wuttafarm/web/views/farmos/land_types.py b/src/wuttafarm/web/views/farmos/land_types.py deleted file mode 100644 index aadece8..0000000 --- a/src/wuttafarm/web/views/farmos/land_types.py +++ /dev/null @@ -1,88 +0,0 @@ -# -*- coding: utf-8; -*- -################################################################################ -# -# WuttaFarm --Web app to integrate with and extend farmOS -# Copyright © 2026 Lance Edgar -# -# This file is part of WuttaFarm. -# -# WuttaFarm is free software: you can redistribute it and/or modify it under -# the terms of the GNU General Public License as published by the Free Software -# Foundation, either version 3 of the License, or (at your option) any later -# version. -# -# WuttaFarm is distributed in the hope that it will be useful, but WITHOUT ANY -# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR -# A PARTICULAR PURPOSE. See the GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along with -# WuttaFarm. If not, see . -# -################################################################################ -""" -View for farmOS land types -""" - -from wuttafarm.web.views.farmos import FarmOSMasterView - - -class LandTypeView(FarmOSMasterView): - """ - Master view for Land Types in farmOS. - """ - - model_name = "farmos_land_type" - model_title = "farmOS Land Type" - model_title_plural = "farmOS Land Types" - - route_prefix = "farmos_land_types" - url_prefix = "/farmOS/land-types" - - grid_columns = [ - "label", - ] - - sort_defaults = "label" - - form_fields = [ - "label", - ] - - def get_grid_data(self, columns=None, session=None): - land_types = self.farmos_client.resource.get("land_type", "land_type") - return [self.normalize_land_type(t) for t in land_types["data"]] - - def configure_grid(self, grid): - g = grid - super().configure_grid(g) - - # label - g.set_link("label") - g.set_searchable("label") - - def get_instance(self): - land_type = self.farmos_client.resource.get_id( - "land_type", "land_type", self.request.matchdict["uuid"] - ) - return self.normalize_land_type(land_type["data"]) - - def get_instance_title(self, land_type): - return land_type["label"] - - def normalize_land_type(self, land_type): - return { - "uuid": land_type["id"], - "drupal_internal_id": land_type["attributes"]["drupal_internal__id"], - "label": land_type["attributes"]["label"], - } - - -def defaults(config, **kwargs): - base = globals() - - LandTypeView = kwargs.get("LandTypeView", base["LandTypeView"]) - LandTypeView.defaults(config) - - -def includeme(config): - defaults(config) diff --git a/src/wuttafarm/web/views/farmos/log_types.py b/src/wuttafarm/web/views/farmos/log_types.py deleted file mode 100644 index 6e72f8f..0000000 --- a/src/wuttafarm/web/views/farmos/log_types.py +++ /dev/null @@ -1,98 +0,0 @@ -# -*- coding: utf-8; -*- -################################################################################ -# -# WuttaFarm --Web app to integrate with and extend farmOS -# Copyright © 2026 Lance Edgar -# -# This file is part of WuttaFarm. -# -# WuttaFarm is free software: you can redistribute it and/or modify it under -# the terms of the GNU General Public License as published by the Free Software -# Foundation, either version 3 of the License, or (at your option) any later -# version. -# -# WuttaFarm is distributed in the hope that it will be useful, but WITHOUT ANY -# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR -# A PARTICULAR PURPOSE. See the GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along with -# WuttaFarm. If not, see . -# -################################################################################ -""" -View for farmOS log types -""" - -from wuttafarm.web.views.farmos import FarmOSMasterView - - -class LogTypeView(FarmOSMasterView): - """ - Master view for Log Types in farmOS. - """ - - model_name = "farmos_log_type" - model_title = "farmOS Log Type" - model_title_plural = "farmOS Log Types" - - route_prefix = "farmos_log_types" - url_prefix = "/farmOS/log-types" - - grid_columns = [ - "label", - "description", - ] - - sort_defaults = "label" - - form_fields = [ - "label", - "description", - ] - - def get_grid_data(self, columns=None, session=None): - log_types = self.farmos_client.resource.get("log_type", "log_type") - return [self.normalize_log_type(t) for t in log_types["data"]] - - def configure_grid(self, grid): - g = grid - super().configure_grid(g) - - # label - g.set_link("label") - g.set_searchable("label") - - def get_instance(self): - log_type = self.farmos_client.resource.get_id( - "log_type", "log_type", self.request.matchdict["uuid"] - ) - return self.normalize_log_type(log_type["data"]) - - def get_instance_title(self, log_type): - return log_type["label"] - - def normalize_log_type(self, log_type): - return { - "uuid": log_type["id"], - "drupal_internal_id": log_type["attributes"]["drupal_internal__id"], - "label": log_type["attributes"]["label"], - "description": log_type["attributes"]["description"], - } - - def configure_form(self, form): - f = form - super().configure_form(f) - - # description - f.set_widget("description", "notes") - - -def defaults(config, **kwargs): - base = globals() - - LogTypeView = kwargs.get("LogTypeView", base["LogTypeView"]) - LogTypeView.defaults(config) - - -def includeme(config): - defaults(config) diff --git a/src/wuttafarm/web/views/farmos/logs_activity.py b/src/wuttafarm/web/views/farmos/logs_activity.py deleted file mode 100644 index 61b4e85..0000000 --- a/src/wuttafarm/web/views/farmos/logs_activity.py +++ /dev/null @@ -1,136 +0,0 @@ -# -*- coding: utf-8; -*- -################################################################################ -# -# WuttaFarm --Web app to integrate with and extend farmOS -# Copyright © 2026 Lance Edgar -# -# This file is part of WuttaFarm. -# -# WuttaFarm is free software: you can redistribute it and/or modify it under -# the terms of the GNU General Public License as published by the Free Software -# Foundation, either version 3 of the License, or (at your option) any later -# version. -# -# WuttaFarm is distributed in the hope that it will be useful, but WITHOUT ANY -# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR -# A PARTICULAR PURPOSE. See the GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along with -# WuttaFarm. If not, see . -# -################################################################################ -""" -View for farmOS activity logs -""" - -import datetime - -import colander - -from wuttaweb.forms.schema import WuttaDateTime -from wuttaweb.forms.widgets import WuttaDateTimeWidget - -from wuttafarm.web.views.farmos import FarmOSMasterView - - -class ActivityLogView(FarmOSMasterView): - """ - View for farmOS activity logs - """ - - model_name = "farmos_activity_log" - model_title = "farmOS Activity Log" - model_title_plural = "farmOS Activity Logs" - - route_prefix = "farmos_logs_activity" - url_prefix = "/farmOS/logs/activity" - - farmos_refurl_path = "/logs/activity" - - grid_columns = [ - "name", - "timestamp", - "status", - ] - - sort_defaults = ("timestamp", "desc") - - form_fields = [ - "name", - "timestamp", - "status", - "notes", - ] - - def get_grid_data(self, columns=None, session=None): - logs = self.farmos_client.log.get("activity") - return [self.normalize_log(t) for t in logs["data"]] - - def configure_grid(self, grid): - g = grid - super().configure_grid(g) - - # name - g.set_link("name") - g.set_searchable("name") - - # timestamp - g.set_renderer("timestamp", "datetime") - - def get_instance(self): - log = self.farmos_client.log.get_id("activity", self.request.matchdict["uuid"]) - return self.normalize_log(log["data"]) - - def get_instance_title(self, log): - return log["name"] - - def normalize_log(self, log): - - if timestamp := log["attributes"]["timestamp"]: - timestamp = datetime.datetime.fromisoformat(timestamp) - timestamp = self.app.localtime(timestamp) - - if notes := log["attributes"]["notes"]: - notes = notes["value"] - - return { - "uuid": log["id"], - "drupal_internal_id": log["attributes"]["drupal_internal__id"], - "name": log["attributes"]["name"], - "timestamp": timestamp, - "status": log["attributes"]["status"], - "notes": notes or colander.null, - } - - def configure_form(self, form): - f = form - super().configure_form(f) - - # timestamp - f.set_node("timestamp", WuttaDateTime()) - f.set_widget("timestamp", WuttaDateTimeWidget(self.request)) - - # notes - f.set_widget("notes", "notes") - - def get_xref_buttons(self, log): - return [ - self.make_button( - "View in farmOS", - primary=True, - url=self.app.get_farmos_url(f"/log/{log['drupal_internal_id']}"), - target="_blank", - icon_left="external-link-alt", - ), - ] - - -def defaults(config, **kwargs): - base = globals() - - ActivityLogView = kwargs.get("ActivityLogView", base["ActivityLogView"]) - ActivityLogView.defaults(config) - - -def includeme(config): - defaults(config) diff --git a/src/wuttafarm/web/views/farmos/master.py b/src/wuttafarm/web/views/farmos/master.py index 59003d0..eed04d1 100644 --- a/src/wuttafarm/web/views/farmos/master.py +++ b/src/wuttafarm/web/views/farmos/master.py @@ -45,12 +45,6 @@ class FarmOSMasterView(MasterView): farmos_refurl_path = None - labels = { - "raw_image_url": "Raw Image URL", - "large_image_url": "Large Image URL", - "thumbnail_image_url": "Thumbnail Image URL", - } - def __init__(self, request, context=None): super().__init__(request, context=context) self.farmos_client = self.get_farmos_client() diff --git a/src/wuttafarm/web/views/farmos/structure_types.py b/src/wuttafarm/web/views/farmos/structure_types.py deleted file mode 100644 index 3fe4741..0000000 --- a/src/wuttafarm/web/views/farmos/structure_types.py +++ /dev/null @@ -1,90 +0,0 @@ -# -*- coding: utf-8; -*- -################################################################################ -# -# WuttaFarm --Web app to integrate with and extend farmOS -# Copyright © 2026 Lance Edgar -# -# This file is part of WuttaFarm. -# -# WuttaFarm is free software: you can redistribute it and/or modify it under -# the terms of the GNU General Public License as published by the Free Software -# Foundation, either version 3 of the License, or (at your option) any later -# version. -# -# WuttaFarm is distributed in the hope that it will be useful, but WITHOUT ANY -# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR -# A PARTICULAR PURPOSE. See the GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along with -# WuttaFarm. If not, see . -# -################################################################################ -""" -View for farmOS structure types -""" - -from wuttafarm.web.views.farmos import FarmOSMasterView - - -class StructureTypeView(FarmOSMasterView): - """ - Master view for Structure Types in farmOS. - """ - - model_name = "farmos_structure_type" - model_title = "farmOS Structure Type" - model_title_plural = "farmOS Structure Types" - - route_prefix = "farmos_structure_types" - url_prefix = "/farmOS/structure-types" - - grid_columns = [ - "label", - ] - - sort_defaults = "label" - - form_fields = [ - "label", - ] - - def get_grid_data(self, columns=None, session=None): - structure_types = self.farmos_client.resource.get( - "structure_type", "structure_type" - ) - return [self.normalize_structure_type(t) for t in structure_types["data"]] - - def configure_grid(self, grid): - g = grid - super().configure_grid(g) - - # label - g.set_link("label") - g.set_searchable("label") - - def get_instance(self): - structure_type = self.farmos_client.resource.get_id( - "structure_type", "structure_type", self.request.matchdict["uuid"] - ) - return self.normalize_structure_type(structure_type["data"]) - - def get_instance_title(self, structure_type): - return structure_type["label"] - - def normalize_structure_type(self, structure_type): - return { - "uuid": structure_type["id"], - "drupal_internal_id": structure_type["attributes"]["drupal_internal__id"], - "label": structure_type["attributes"]["label"], - } - - -def defaults(config, **kwargs): - base = globals() - - StructureTypeView = kwargs.get("StructureTypeView", base["StructureTypeView"]) - StructureTypeView.defaults(config) - - -def includeme(config): - defaults(config) diff --git a/src/wuttafarm/web/views/farmos/structures.py b/src/wuttafarm/web/views/farmos/structures.py deleted file mode 100644 index bbc4f1f..0000000 --- a/src/wuttafarm/web/views/farmos/structures.py +++ /dev/null @@ -1,209 +0,0 @@ -# -*- coding: utf-8; -*- -################################################################################ -# -# WuttaFarm --Web app to integrate with and extend farmOS -# Copyright © 2026 Lance Edgar -# -# This file is part of WuttaFarm. -# -# WuttaFarm is free software: you can redistribute it and/or modify it under -# the terms of the GNU General Public License as published by the Free Software -# Foundation, either version 3 of the License, or (at your option) any later -# version. -# -# WuttaFarm is distributed in the hope that it will be useful, but WITHOUT ANY -# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR -# A PARTICULAR PURPOSE. See the GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along with -# WuttaFarm. If not, see . -# -################################################################################ -""" -View for farmOS Structures -""" - -import datetime - -import colander - -from wuttaweb.forms.schema import WuttaDateTime -from wuttaweb.forms.widgets import WuttaDateTimeWidget - -from wuttafarm.web.views.farmos import FarmOSMasterView -from wuttafarm.web.forms.widgets import ImageWidget - - -class StructureView(FarmOSMasterView): - """ - View for farmOS Structures - """ - - model_name = "farmos_structure" - model_title = "farmOS Structure" - model_title_plural = "farmOS Structures" - - route_prefix = "farmos_structures" - url_prefix = "/farmOS/structures" - - farmos_refurl_path = "/assets/structure" - - grid_columns = [ - "name", - "status", - "created", - "changed", - ] - - sort_defaults = "name" - - form_fields = [ - "name", - "status", - "structure_type", - "is_location", - "is_fixed", - "notes", - "created", - "changed", - "raw_image_url", - "large_image_url", - "thumbnail_image_url", - "image", - ] - - def get_grid_data(self, columns=None, session=None): - structures = self.farmos_client.resource.get("asset", "structure") - return [self.normalize_structure(s) for s in structures["data"]] - - def configure_grid(self, grid): - g = grid - super().configure_grid(g) - - # name - g.set_link("name") - g.set_searchable("name") - - # created - g.set_renderer("created", "datetime") - - # changed - g.set_renderer("changed", "datetime") - - def get_instance(self): - structure = self.farmos_client.resource.get_id( - "asset", "structure", self.request.matchdict["uuid"] - ) - - data = self.normalize_structure(structure["data"]) - - if relationships := structure["data"].get("relationships"): - - # add owners - if owner := relationships.get("owner"): - data["owners"] = [] - for owner_data in owner["data"]: - owner = self.farmos_client.resource.get_id( - "user", "user", owner_data["id"] - ) - data["owners"].append( - { - "uuid": owner["data"]["id"], - "display_name": owner["data"]["attributes"]["display_name"], - } - ) - - # add image urls - if image := relationships.get("image"): - if image["data"]: - image = self.farmos_client.resource.get_id( - "file", "file", image["data"][0]["id"] - ) - data["raw_image_url"] = self.app.get_farmos_url( - image["data"]["attributes"]["uri"]["url"] - ) - # nb. other styles available: medium, wide - data["large_image_url"] = image["data"]["attributes"][ - "image_style_uri" - ]["large"] - data["thumbnail_image_url"] = image["data"]["attributes"][ - "image_style_uri" - ]["thumbnail"] - - return data - - def get_instance_title(self, structure): - return structure["name"] - - def normalize_structure(self, structure): - - if created := structure["attributes"].get("created"): - created = datetime.datetime.fromisoformat(created) - created = self.app.localtime(created) - - if changed := structure["attributes"].get("changed"): - changed = datetime.datetime.fromisoformat(changed) - changed = self.app.localtime(changed) - - return { - "uuid": structure["id"], - "drupal_internal_id": structure["attributes"]["drupal_internal__id"], - "name": structure["attributes"]["name"], - "structure_type": structure["attributes"]["structure_type"], - "is_fixed": structure["attributes"]["is_fixed"], - "is_location": structure["attributes"]["is_location"], - "notes": structure["attributes"]["notes"] or colander.null, - "status": structure["attributes"]["status"], - "created": created, - "changed": changed, - } - - def configure_form(self, form): - f = form - super().configure_form(f) - structure = f.model_instance - - # is_fixed - f.set_node("is_fixed", colander.Boolean()) - - # is_location - f.set_node("is_location", colander.Boolean()) - - # notes - f.set_widget("notes", "notes") - - # created - f.set_node("created", WuttaDateTime()) - f.set_widget("created", WuttaDateTimeWidget(self.request)) - - # changed - f.set_node("changed", WuttaDateTime()) - f.set_widget("changed", WuttaDateTimeWidget(self.request)) - - # image - if url := structure.get("large_image_url"): - f.set_widget("image", ImageWidget("structure image")) - f.set_default("image", url) - - def get_xref_buttons(self, structure): - drupal_id = structure["drupal_internal_id"] - return [ - self.make_button( - "View in farmOS", - primary=True, - url=self.app.get_farmos_url(f"/asset/{drupal_id}"), - target="_blank", - icon_left="external-link-alt", - ), - ] - - -def defaults(config, **kwargs): - base = globals() - - StructureView = kwargs.get("StructureView", base["StructureView"]) - StructureView.defaults(config) - - -def includeme(config): - defaults(config) diff --git a/src/wuttafarm/web/views/farmos/users.py b/src/wuttafarm/web/views/farmos/users.py deleted file mode 100644 index 317bfe3..0000000 --- a/src/wuttafarm/web/views/farmos/users.py +++ /dev/null @@ -1,139 +0,0 @@ -# -*- coding: utf-8; -*- -################################################################################ -# -# WuttaFarm --Web app to integrate with and extend farmOS -# Copyright © 2026 Lance Edgar -# -# This file is part of WuttaFarm. -# -# WuttaFarm is free software: you can redistribute it and/or modify it under -# the terms of the GNU General Public License as published by the Free Software -# Foundation, either version 3 of the License, or (at your option) any later -# version. -# -# WuttaFarm is distributed in the hope that it will be useful, but WITHOUT ANY -# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR -# A PARTICULAR PURPOSE. See the GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along with -# WuttaFarm. If not, see . -# -################################################################################ -""" -View for farmOS Users -""" - -import datetime - -import colander - -from wuttaweb.forms.schema import WuttaDateTime - -from wuttafarm.web.views.farmos import FarmOSMasterView - - -class UserView(FarmOSMasterView): - """ - Master view for Farm Animals - """ - - model_name = "farmos_user" - model_title = "farmOS User" - model_title_plural = "farmOS Users" - - route_prefix = "farmos_users" - url_prefix = "/farmOS/users" - - farmos_refurl_path = "/people" - - grid_columns = [ - "display_name", - ] - - sort_defaults = "display_name" - - form_fields = [ - "display_name", - "name", - "mail", - "timezone", - "created", - "changed", - ] - - def get_grid_data(self, columns=None, session=None): - users = self.farmos_client.resource.get("user", "user") - return [self.normalize_user(u) for u in users["data"]] - - def configure_grid(self, grid): - g = grid - super().configure_grid(g) - - # display_name - g.set_link("display_name") - g.set_searchable("display_name") - - def get_instance(self): - user = self.farmos_client.resource.get_id( - "user", "user", self.request.matchdict["uuid"] - ) - return self.normalize_user(user["data"]) - - def get_instance_title(self, user): - return user["display_name"] - - def normalize_user(self, user): - - if created := user["attributes"].get("created"): - created = datetime.datetime.fromisoformat(created) - created = self.app.localtime(created) - - if changed := user["attributes"].get("changed"): - changed = datetime.datetime.fromisoformat(changed) - changed = self.app.localtime(changed) - - return { - "uuid": user["id"], - "drupal_internal_id": user["attributes"].get("drupal_internal__uid"), - "display_name": user["attributes"]["display_name"], - "name": user["attributes"].get("name") or colander.null, - "mail": user["attributes"].get("mail") or colander.null, - "timezone": user["attributes"].get("timezone") or colander.null, - "created": created, - "changed": changed, - } - - def configure_form(self, form): - f = form - super().configure_form(f) - user = f.model_instance - - # created - f.set_node("created", WuttaDateTime()) - - # changed - f.set_node("changed", WuttaDateTime()) - - def get_xref_buttons(self, user): - if drupal_id := user["drupal_internal_id"]: - return [ - self.make_button( - "View in farmOS", - primary=True, - url=self.app.get_farmos_url(f"/user/{drupal_id}"), - target="_blank", - icon_left="external-link-alt", - ), - ] - return None - - -def defaults(config, **kwargs): - base = globals() - - UserView = kwargs.get("UserView", base["UserView"]) - UserView.defaults(config) - - -def includeme(config): - defaults(config)