diff --git a/src/wuttafarm/web/menus.py b/src/wuttafarm/web/menus.py index 0f46281..60a3a41 100644 --- a/src/wuttafarm/web/menus.py +++ b/src/wuttafarm/web/menus.py @@ -48,15 +48,21 @@ class WuttaFarmMenuHandler(base.MenuHandler): "perm": "farmos_animals.list", }, { - "title": "Animal Types", - "route": "farmos_animal_types", - "perm": "farmos_animal_types.list", + "title": "Groups", + "route": "farmos_groups", + "perm": "farmos_groups.list", }, { "title": "Structures", "route": "farmos_structures", "perm": "farmos_structures.list", }, + {"type": "sep"}, + { + "title": "Animal Types", + "route": "farmos_animal_types", + "perm": "farmos_animal_types.list", + }, { "title": "Asset Types", "route": "farmos_asset_types", diff --git a/src/wuttafarm/web/views/common.py b/src/wuttafarm/web/views/common.py index 0a4e72f..23ed96b 100644 --- a/src/wuttafarm/web/views/common.py +++ b/src/wuttafarm/web/views/common.py @@ -54,6 +54,8 @@ class CommonView(base.CommonView): "farmos_animals.view", "farmos_asset_types.list", "farmos_asset_types.view", + "farmos_groups.list", + "farmos_groups.view", "farmos_structures.list", "farmos_structures.view", "farmos_users.list", diff --git a/src/wuttafarm/web/views/farmos/__init__.py b/src/wuttafarm/web/views/farmos/__init__.py index d7e699b..93e1341 100644 --- a/src/wuttafarm/web/views/farmos/__init__.py +++ b/src/wuttafarm/web/views/farmos/__init__.py @@ -32,3 +32,4 @@ def includeme(config): 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") diff --git a/src/wuttafarm/web/views/farmos/groups.py b/src/wuttafarm/web/views/farmos/groups.py new file mode 100644 index 0000000..4664a6b --- /dev/null +++ b/src/wuttafarm/web/views/farmos/groups.py @@ -0,0 +1,164 @@ +# -*- 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)