diff --git a/CHANGELOG.md b/CHANGELOG.md index f6b8703..b5241ed 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.3.0 (2026-02-13) - -### Feat - -- add native table for Activity Logs; import from farmOS API -- add native table for Groups; import from farmOS API -- add native table for Animals; import from farmOS API -- add native table for Structures; import from farmOS API -- add native table for Land Assets; import from farmOS API -- add native table for Log Types; import from farmOS API -- add native table for Structure Types; import from farmOS API -- add native table for Land Types; import from farmOS API -- add native table for Asset Types; import from farmOS API -- add extension table for Users; import from farmOS API -- add native table for Animal Types; import from farmOS API -- add "See raw JSON data" button for farmOS API views - -### Fix - -- always make 'farmos' system user in app setup -- avoid error for Create User form -- add more perms to Site Admin role in app setup -- rename `drupal_internal_id` => `drupal_id` - ## v0.2.3 (2026-02-08) ### Fix diff --git a/docs/api/wuttafarm.cli.base.rst b/docs/api/wuttafarm.cli.base.rst deleted file mode 100644 index 19afd5c..0000000 --- a/docs/api/wuttafarm.cli.base.rst +++ /dev/null @@ -1,6 +0,0 @@ - -``wuttafarm.cli.base`` -====================== - -.. automodule:: wuttafarm.cli.base - :members: diff --git a/docs/api/wuttafarm.cli.import_farmos.rst b/docs/api/wuttafarm.cli.import_farmos.rst deleted file mode 100644 index 12a6d03..0000000 --- a/docs/api/wuttafarm.cli.import_farmos.rst +++ /dev/null @@ -1,6 +0,0 @@ - -``wuttafarm.cli.import_farmos`` -=============================== - -.. automodule:: wuttafarm.cli.import_farmos - :members: diff --git a/docs/api/wuttafarm.cli.install.rst b/docs/api/wuttafarm.cli.install.rst deleted file mode 100644 index e825989..0000000 --- a/docs/api/wuttafarm.cli.install.rst +++ /dev/null @@ -1,6 +0,0 @@ - -``wuttafarm.cli.install`` -========================= - -.. automodule:: wuttafarm.cli.install - :members: diff --git a/docs/api/wuttafarm.importing.farmos.rst b/docs/api/wuttafarm.importing.farmos.rst deleted file mode 100644 index b6e00b4..0000000 --- a/docs/api/wuttafarm.importing.farmos.rst +++ /dev/null @@ -1,6 +0,0 @@ - -``wuttafarm.importing.farmos`` -============================== - -.. automodule:: wuttafarm.importing.farmos - :members: diff --git a/docs/api/wuttafarm.importing.rst b/docs/api/wuttafarm.importing.rst deleted file mode 100644 index 5c331b9..0000000 --- a/docs/api/wuttafarm.importing.rst +++ /dev/null @@ -1,6 +0,0 @@ - -``wuttafarm.importing`` -======================= - -.. automodule:: wuttafarm.importing - :members: diff --git a/docs/conf.py b/docs/conf.py index f3fd9e2..3caa6e3 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -21,7 +21,6 @@ extensions = [ "sphinx.ext.intersphinx", "sphinx.ext.viewcode", "sphinx.ext.todo", - "sphinxcontrib.programoutput", ] templates_path = ["_templates"] diff --git a/docs/index.rst b/docs/index.rst index be04bee..4c7887b 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -8,6 +8,9 @@ and extend `farmOS`_. .. _WuttaWeb: https://wuttaproject.org .. _farmOS: https://farmos.org +.. image:: https://img.shields.io/badge/code%20style-black-000000.svg + :target: https://github.com/psf/black + It is just an experiment so far; the ideas I hope to play with include: @@ -16,9 +19,6 @@ include: - possibly add more schema / extra features - possibly sync data back to farmOS -.. image:: https://img.shields.io/badge/code%20style-black-000000.svg - :target: https://github.com/psf/black - .. toctree:: :maxdepth: 2 @@ -27,7 +27,6 @@ include: narr/install narr/auth narr/features - narr/cli .. toctree:: @@ -38,16 +37,11 @@ include: api/wuttafarm.app api/wuttafarm.auth api/wuttafarm.cli - api/wuttafarm.cli.base - api/wuttafarm.cli.import_farmos - api/wuttafarm.cli.install api/wuttafarm.config api/wuttafarm.db api/wuttafarm.db.model api/wuttafarm.farmos api/wuttafarm.farmos.handler - api/wuttafarm.importing - api/wuttafarm.importing.farmos api/wuttafarm.install api/wuttafarm.web api/wuttafarm.web.app diff --git a/docs/narr/auth.rst b/docs/narr/auth.rst index 536f3d0..67a63fa 100644 --- a/docs/narr/auth.rst +++ b/docs/narr/auth.rst @@ -36,13 +36,7 @@ browse farmOS data within the WuttaFarm views. If you login to WuttaFarm directly with username/password, then your user session will not have a farmOS access token and so the - farmOS data views in WuttaFarm will not work (i.e. anything under - the **farmOS** menu). - - (However this does not affect the "native" data views for - WuttaFarm. Users can see data which was already imported from - farmOS without an access token - if they have appropriate - permissions in WuttaFarm.) + farmOS data views in WuttaFarm will not work. On the login page, click the "Login via farmOS / OAuth2" button. This will initiate the OAuth2 workflow, at which point you may be asked to diff --git a/docs/narr/cli.rst b/docs/narr/cli.rst deleted file mode 100644 index 70b7c1e..0000000 --- a/docs/narr/cli.rst +++ /dev/null @@ -1,39 +0,0 @@ - -======================== - Command Line Interface -======================== - -WuttaFarm ships with the following commands. - -For more general info about CLI see -:doc:`wuttjamaican:narr/cli/index`. - - -.. _wuttafarm-install: - -``wuttafarm install`` ---------------------- - -Run the WuttaFarm app installer. - -This will create the :term:`app dir` and initial config files, and -create the schema within the :term:`app database`. - -Defined in: :mod:`wuttafarm.cli.install` - -.. program-output:: wuttafarm install --help - - -.. _wuttafarm-import-farmos: - -``wuttafarm import-farmos`` ---------------------------- - -Import data from the farmOS API into the WuttaFarm :term:`app -database`. - -Defined in: :mod:`wuttafarm.cli.import_farmos` - -.. program-output:: wuttafarm import-farmos --help - - diff --git a/docs/narr/features.rst b/docs/narr/features.rst index 60a9120..00e435b 100644 --- a/docs/narr/features.rst +++ b/docs/narr/features.rst @@ -14,10 +14,6 @@ Here is the list of features currently supported: * performance isn't bad, but data is not very "complete" * more data could be fetched, but not sure this is the best way..? -* import some data from farmOS - * limited data is imported from farmOS API into native app tables - * this data is exposed in views, similar to direct farmOS views (above) - Screenshots ----------- diff --git a/docs/narr/install.rst b/docs/narr/install.rst index 1147a6d..fdb9958 100644 --- a/docs/narr/install.rst +++ b/docs/narr/install.rst @@ -60,93 +60,3 @@ are encouraged to enable it anyway. When the installer completes it will output a command you can then use to run the web app. Do that and you can then view the app in a browser at http://localhost:9080 - - -OAuth2 Setup ------------- - -At this point the web app should be ready for OAuth2 login; however -the OAuth2 provider in farmOS needs some more config before it will -work. - -WuttaFarm uses the default ``farm`` consumer, so the only thing you -should have to do here is edit that to add your redirect URL. This -will vary based on your WuttaFarm site name, e.g. - -.. code-block:: none - - https://wuttafarm.example.com/farmos/oauth/callback - -With that in place you should be able to login via OAuth2; see also -:doc:`/narr/auth`. - -However while you're there, you should also do some setup for the sake -of the farmOS → WuttaFarm data import. This import will also use the -farmOS API and therefore also needs an oauth2 access token; however it -uses the Client Credentials workflow instead of the Authorization Code -workflow. Therefore you must create a new *user* and a new OAuth2 -*consumer* for it. - -First add a new user in farmOS, named ``wuttafarm``. It should -probably be given the Manager role, since WuttaFarm will eventually -also support "exporting" data back to farmOS. - -Then add a new OAuth2 consumer (aka. client) with these attributes: - -* **Label:** WuttaFarm -* **Client ID:** wuttafarm -* **New Secret:** (put something in here, to be used as client secret) -* **Grant Types:** Client Credentials, Refresh Token (maybe more?) -* **User:** wuttafarm -* **3rd Party?** yes -* **Confidential?** yes -* **Access Token Expiration Time:** maybe set to 3600? or maybe 300 - default is okay? -* **Allowed Origins:** put your oauth callback URL here (same as for - default ``farm`` consumer) - -WuttaFarm also needs to know the client secret for sake of running the -import; so add this to your ``app/wutta.conf`` file. Of course -replace the value with whatever client secret you gave the new -consumer: - -.. code-block:: ini - - [farmos.oauth2] - importing.client_secret = you_cant_guess_me - - -Import Data from farmOS ------------------------ - -You must have done all the OAuth2 setup (previous section) before the -import will work. - -But now that you did all that, importing should be quick and easy. - -The very first import will be limited and "special" to account for any -users which were already created in WuttaFarm. This command will -ensure WuttaFarm gets *all* user accounts and each is appropriately -mapped to the farmOS account: - -.. code-block:: sh - - ./venv/bin/wuttafarm --runas farmos import-farmos User --key username - -Note also the ``--runas farmos`` arg which helps the WuttaFarm data -versioning know "who" is responsible for the changes. We use a -dedicated ``farmos`` user account in WuttaFarm, to represent the -farmOS system as a whole. - -From now on you can run the "full" import normally: - -.. code-block:: sh - - ./venv/bin/wuttafarm --runas farmos import-farmos - -And it can sometimes be helpful to "double-check" in order to make -sure all data is fully synced: - -.. code-block:: sh - - ./venv/bin/wuttafarm --runas farmos import-farmos --delete --dry-run -W diff --git a/pyproject.toml b/pyproject.toml index f8fc499..fbc8df2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ build-backend = "hatchling.build" [project] name = "WuttaFarm" -version = "0.3.0" +version = "0.2.3" description = "Web app to integrate with and extend farmOS" readme = "README.md" authors = [ @@ -33,13 +33,12 @@ dependencies = [ "psycopg2", "pyramid_exclog", "uvicorn[standard]", - "WuttaSync", "WuttaWeb[continuum]>=0.27.4", ] [project.optional-dependencies] -docs = ["Sphinx", "furo", "sphinxcontrib-programoutput"] +docs = ["Sphinx", "furo"] [project.scripts] @@ -48,18 +47,12 @@ docs = ["Sphinx", "furo", "sphinxcontrib-programoutput"] [project.entry-points."paste.app_factory"] "main" = "wuttafarm.web.app:main" -[project.entry-points."wutta.app.providers"] -wuttafarm = "wuttafarm.app:WuttaFarmAppProvider" - [project.entry-points."wutta.config.extensions"] "wuttafarm" = "wuttafarm.config:WuttaFarmConfig" [project.entry-points."wutta.web.menus"] "wuttafarm" = "wuttafarm.web.menus:WuttaFarmMenuHandler" -[project.entry-points."wuttasync.importing"] -"import.to_wuttafarm.from_farmos" = "wuttafarm.importing.farmos:FromFarmOSToWuttaFarm" - [project.urls] Homepage = "https://forgejo.wuttaproject.org/wutta/wuttafarm" diff --git a/src/wuttafarm/app.py b/src/wuttafarm/app.py index 72dd675..26c6ef8 100644 --- a/src/wuttafarm/app.py +++ b/src/wuttafarm/app.py @@ -64,11 +64,3 @@ class WuttaFarmAppHandler(base.AppHandler): """ handler = self.get_farmos_handler() return handler.get_farmos_client(*args, **kwargs) - - -class WuttaFarmAppProvider(base.AppProvider): - """ - The :term:`app provider` for WuttaFarm. - """ - - email_modules = ["wuttafarm.emails"] diff --git a/src/wuttafarm/cli/install.py b/src/wuttafarm/cli.py similarity index 89% rename from src/wuttafarm/cli/install.py rename to src/wuttafarm/cli.py index c82dab2..2f377a3 100644 --- a/src/wuttafarm/cli/install.py +++ b/src/wuttafarm/cli.py @@ -25,7 +25,12 @@ WuttaFarm CLI import typer -from wuttafarm.cli import wuttafarm_typer +from wuttjamaican.cli import make_typer + + +wuttafarm_typer = make_typer( + name="wuttafarm", help="WuttaFarm -- Web app to integrate with and extend farmOS" +) @wuttafarm_typer.command() diff --git a/src/wuttafarm/cli/__init__.py b/src/wuttafarm/cli/__init__.py deleted file mode 100644 index 7f6c2bb..0000000 --- a/src/wuttafarm/cli/__init__.py +++ /dev/null @@ -1,30 +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 . -# -################################################################################ -""" -WuttaFarm CLI -""" - -from .base import wuttafarm_typer - -# nb. must bring in all modules for discovery to work -from . import import_farmos -from . import install diff --git a/src/wuttafarm/cli/base.py b/src/wuttafarm/cli/base.py deleted file mode 100644 index de16ead..0000000 --- a/src/wuttafarm/cli/base.py +++ /dev/null @@ -1,31 +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 . -# -################################################################################ -""" -WuttaFarm CLI - base Typer instance -""" - -from wuttjamaican.cli import make_typer - - -wuttafarm_typer = make_typer( - name="wuttafarm", help="WuttaFarm -- Web app to integrate with and extend farmOS" -) diff --git a/src/wuttafarm/cli/import_farmos.py b/src/wuttafarm/cli/import_farmos.py deleted file mode 100644 index 4343d43..0000000 --- a/src/wuttafarm/cli/import_farmos.py +++ /dev/null @@ -1,41 +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 . -# -################################################################################ -""" -See also: :ref:`wuttafarm-import-farmos` -""" - -import typer - -from wuttasync.cli import import_command, ImportCommandHandler - -from wuttafarm.cli import wuttafarm_typer - - -@wuttafarm_typer.command() -@import_command -def import_farmos(ctx: typer.Context, **kwargs): - """ - Import data from farmOS API to WuttaFarm - """ - config = ctx.parent.wutta_config - handler = ImportCommandHandler(config, key="import.to_wuttafarm.from_farmos") - handler.run(ctx) diff --git a/src/wuttafarm/db/alembic/versions/1b2d3224e5dc_add_animals.py b/src/wuttafarm/db/alembic/versions/1b2d3224e5dc_add_animals.py deleted file mode 100644 index 78400ac..0000000 --- a/src/wuttafarm/db/alembic/versions/1b2d3224e5dc_add_animals.py +++ /dev/null @@ -1,127 +0,0 @@ -"""add Animals - -Revision ID: 1b2d3224e5dc -Revises: 4dbba8aeb1e5 -Create Date: 2026-02-13 11:55:19.564221 - -""" - -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa -import wuttjamaican.db.util - - -# revision identifiers, used by Alembic. -revision: str = "1b2d3224e5dc" -down_revision: Union[str, None] = "4dbba8aeb1e5" -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - - # animal - op.create_table( - "animal", - sa.Column("uuid", wuttjamaican.db.util.UUID(), nullable=False), - sa.Column("name", sa.String(length=100), nullable=False), - sa.Column("animal_type_uuid", wuttjamaican.db.util.UUID(), nullable=False), - sa.Column("birthdate", sa.DateTime(), nullable=True), - sa.Column("sex", sa.String(length=1), nullable=True), - sa.Column("is_sterile", sa.Boolean(), nullable=True), - sa.Column("active", sa.Boolean(), nullable=False), - sa.Column("notes", sa.Text(), nullable=True), - sa.Column("image_url", sa.String(length=255), nullable=True), - sa.Column("farmos_uuid", wuttjamaican.db.util.UUID(), nullable=True), - sa.Column("drupal_id", sa.Integer(), nullable=True), - sa.ForeignKeyConstraint( - ["animal_type_uuid"], - ["animal_type.uuid"], - name=op.f("fk_animal_animal_type_uuid_animal_type"), - ), - sa.PrimaryKeyConstraint("uuid", name=op.f("pk_animal")), - sa.UniqueConstraint("drupal_id", name=op.f("uq_animal_drupal_id")), - sa.UniqueConstraint("farmos_uuid", name=op.f("uq_animal_farmos_uuid")), - ) - op.create_table( - "animal_version", - sa.Column( - "uuid", wuttjamaican.db.util.UUID(), autoincrement=False, nullable=False - ), - sa.Column("name", sa.String(length=100), autoincrement=False, nullable=True), - sa.Column( - "animal_type_uuid", - wuttjamaican.db.util.UUID(), - autoincrement=False, - nullable=True, - ), - sa.Column("birthdate", sa.DateTime(), autoincrement=False, nullable=True), - sa.Column("sex", sa.String(length=1), autoincrement=False, nullable=True), - sa.Column("is_sterile", sa.Boolean(), autoincrement=False, nullable=True), - sa.Column("active", sa.Boolean(), autoincrement=False, nullable=True), - sa.Column("notes", sa.Text(), autoincrement=False, nullable=True), - sa.Column( - "image_url", sa.String(length=255), autoincrement=False, nullable=True - ), - sa.Column( - "farmos_uuid", - wuttjamaican.db.util.UUID(), - autoincrement=False, - nullable=True, - ), - sa.Column("drupal_id", sa.Integer(), autoincrement=False, nullable=True), - sa.Column( - "transaction_id", sa.BigInteger(), autoincrement=False, nullable=False - ), - sa.Column("end_transaction_id", sa.BigInteger(), nullable=True), - sa.Column("operation_type", sa.SmallInteger(), nullable=False), - sa.PrimaryKeyConstraint( - "uuid", "transaction_id", name=op.f("pk_animal_version") - ), - ) - op.create_index( - op.f("ix_animal_version_end_transaction_id"), - "animal_version", - ["end_transaction_id"], - unique=False, - ) - op.create_index( - op.f("ix_animal_version_operation_type"), - "animal_version", - ["operation_type"], - unique=False, - ) - op.create_index( - "ix_animal_version_pk_transaction_id", - "animal_version", - ["uuid", sa.literal_column("transaction_id DESC")], - unique=False, - ) - op.create_index( - "ix_animal_version_pk_validity", - "animal_version", - ["uuid", "transaction_id", "end_transaction_id"], - unique=False, - ) - op.create_index( - op.f("ix_animal_version_transaction_id"), - "animal_version", - ["transaction_id"], - unique=False, - ) - - -def downgrade() -> None: - - # animal - op.drop_index(op.f("ix_animal_version_transaction_id"), table_name="animal_version") - op.drop_index("ix_animal_version_pk_validity", table_name="animal_version") - op.drop_index("ix_animal_version_pk_transaction_id", table_name="animal_version") - op.drop_index(op.f("ix_animal_version_operation_type"), table_name="animal_version") - op.drop_index( - op.f("ix_animal_version_end_transaction_id"), table_name="animal_version" - ) - op.drop_table("animal_version") - op.drop_table("animal") diff --git a/src/wuttafarm/db/alembic/versions/2b6385d0fa17_add_animal_types.py b/src/wuttafarm/db/alembic/versions/2b6385d0fa17_add_animal_types.py deleted file mode 100644 index 4e1481f..0000000 --- a/src/wuttafarm/db/alembic/versions/2b6385d0fa17_add_animal_types.py +++ /dev/null @@ -1,116 +0,0 @@ -"""add Animal Types - -Revision ID: 2b6385d0fa17 -Revises: -Create Date: 2026-02-08 14:55:42.236918 - -""" - -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa -import wuttjamaican.db.util - - -# revision identifiers, used by Alembic. -revision: str = "2b6385d0fa17" -down_revision: Union[str, None] = None -branch_labels: Union[str, Sequence[str], None] = ("wuttafarm",) -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - - # animal_type - op.create_table( - "animal_type", - sa.Column("uuid", wuttjamaican.db.util.UUID(), nullable=False), - sa.Column("name", sa.String(length=100), nullable=False), - sa.Column("description", sa.String(length=255), nullable=True), - sa.Column("changed", sa.DateTime(), nullable=True), - sa.Column("farmos_uuid", wuttjamaican.db.util.UUID(), nullable=True), - sa.Column("drupal_id", sa.Integer(), nullable=True), - sa.PrimaryKeyConstraint("uuid", name=op.f("pk_animal_type")), - sa.UniqueConstraint("drupal_id", name=op.f("uq_animal_type_drupal_id")), - sa.UniqueConstraint("farmos_uuid", name=op.f("uq_animal_type_farmos_uuid")), - sa.UniqueConstraint("name", name=op.f("uq_animal_type_name")), - ) - op.create_table( - "animal_type_version", - sa.Column( - "uuid", wuttjamaican.db.util.UUID(), autoincrement=False, nullable=False - ), - sa.Column("name", sa.String(length=100), autoincrement=False, nullable=True), - sa.Column( - "description", sa.String(length=255), autoincrement=False, nullable=True - ), - sa.Column( - "farmos_uuid", - wuttjamaican.db.util.UUID(), - autoincrement=False, - nullable=True, - ), - sa.Column("drupal_id", sa.Integer(), autoincrement=False, nullable=True), - sa.Column( - "transaction_id", sa.BigInteger(), autoincrement=False, nullable=False - ), - sa.Column("end_transaction_id", sa.BigInteger(), nullable=True), - sa.Column("operation_type", sa.SmallInteger(), nullable=False), - sa.PrimaryKeyConstraint( - "uuid", "transaction_id", name=op.f("pk_animal_type_version") - ), - ) - op.create_index( - op.f("ix_animal_type_version_end_transaction_id"), - "animal_type_version", - ["end_transaction_id"], - unique=False, - ) - op.create_index( - op.f("ix_animal_type_version_operation_type"), - "animal_type_version", - ["operation_type"], - unique=False, - ) - op.create_index( - "ix_animal_type_version_pk_transaction_id", - "animal_type_version", - ["uuid", sa.literal_column("transaction_id DESC")], - unique=False, - ) - op.create_index( - "ix_animal_type_version_pk_validity", - "animal_type_version", - ["uuid", "transaction_id", "end_transaction_id"], - unique=False, - ) - op.create_index( - op.f("ix_animal_type_version_transaction_id"), - "animal_type_version", - ["transaction_id"], - unique=False, - ) - - -def downgrade() -> None: - - # animal_type - op.drop_index( - op.f("ix_animal_type_version_transaction_id"), table_name="animal_type_version" - ) - op.drop_index( - "ix_animal_type_version_pk_validity", table_name="animal_type_version" - ) - op.drop_index( - "ix_animal_type_version_pk_transaction_id", table_name="animal_type_version" - ) - op.drop_index( - op.f("ix_animal_type_version_operation_type"), table_name="animal_type_version" - ) - op.drop_index( - op.f("ix_animal_type_version_end_transaction_id"), - table_name="animal_type_version", - ) - op.drop_table("animal_type_version") - op.drop_table("animal_type") diff --git a/src/wuttafarm/db/alembic/versions/3e2ef02bf264_add_activity_logs.py b/src/wuttafarm/db/alembic/versions/3e2ef02bf264_add_activity_logs.py deleted file mode 100644 index 5fca4be..0000000 --- a/src/wuttafarm/db/alembic/versions/3e2ef02bf264_add_activity_logs.py +++ /dev/null @@ -1,118 +0,0 @@ -"""add Activity Logs - -Revision ID: 3e2ef02bf264 -Revises: 92b813360b99 -Create Date: 2026-02-13 14:36:47.191922 - -""" - -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa -import wuttjamaican.db.util - - -# revision identifiers, used by Alembic. -revision: str = "3e2ef02bf264" -down_revision: Union[str, None] = "92b813360b99" -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - - # log_activity - op.create_table( - "log_activity", - sa.Column("uuid", wuttjamaican.db.util.UUID(), nullable=False), - sa.Column("message", sa.String(length=255), nullable=False), - sa.Column("timestamp", sa.DateTime(), nullable=False), - sa.Column("status", sa.String(length=20), nullable=False), - sa.Column("notes", sa.Text(), nullable=True), - sa.Column("farmos_uuid", wuttjamaican.db.util.UUID(), nullable=True), - sa.Column("drupal_id", sa.Integer(), nullable=True), - sa.PrimaryKeyConstraint("uuid", name=op.f("pk_log_activity")), - sa.UniqueConstraint("drupal_id", name=op.f("uq_log_activity_drupal_id")), - sa.UniqueConstraint("farmos_uuid", name=op.f("uq_log_activity_farmos_uuid")), - ) - op.create_table( - "log_activity_version", - sa.Column( - "uuid", wuttjamaican.db.util.UUID(), autoincrement=False, nullable=False - ), - sa.Column("message", sa.String(length=255), autoincrement=False, nullable=True), - sa.Column("timestamp", sa.DateTime(), autoincrement=False, nullable=True), - sa.Column("status", sa.String(length=20), autoincrement=False, nullable=True), - sa.Column("notes", sa.Text(), autoincrement=False, nullable=True), - sa.Column( - "farmos_uuid", - wuttjamaican.db.util.UUID(), - autoincrement=False, - nullable=True, - ), - sa.Column("drupal_id", sa.Integer(), autoincrement=False, nullable=True), - sa.Column( - "transaction_id", sa.BigInteger(), autoincrement=False, nullable=False - ), - sa.Column("end_transaction_id", sa.BigInteger(), nullable=True), - sa.Column("operation_type", sa.SmallInteger(), nullable=False), - sa.PrimaryKeyConstraint( - "uuid", "transaction_id", name=op.f("pk_log_activity_version") - ), - ) - op.create_index( - op.f("ix_log_activity_version_end_transaction_id"), - "log_activity_version", - ["end_transaction_id"], - unique=False, - ) - op.create_index( - op.f("ix_log_activity_version_operation_type"), - "log_activity_version", - ["operation_type"], - unique=False, - ) - op.create_index( - "ix_log_activity_version_pk_transaction_id", - "log_activity_version", - ["uuid", sa.literal_column("transaction_id DESC")], - unique=False, - ) - op.create_index( - "ix_log_activity_version_pk_validity", - "log_activity_version", - ["uuid", "transaction_id", "end_transaction_id"], - unique=False, - ) - op.create_index( - op.f("ix_log_activity_version_transaction_id"), - "log_activity_version", - ["transaction_id"], - unique=False, - ) - - -def downgrade() -> None: - - # log_activity - op.drop_index( - op.f("ix_log_activity_version_transaction_id"), - table_name="log_activity_version", - ) - op.drop_index( - "ix_log_activity_version_pk_validity", table_name="log_activity_version" - ) - op.drop_index( - "ix_log_activity_version_pk_transaction_id", table_name="log_activity_version" - ) - op.drop_index( - op.f("ix_log_activity_version_operation_type"), - table_name="log_activity_version", - ) - op.drop_index( - op.f("ix_log_activity_version_end_transaction_id"), - table_name="log_activity_version", - ) - op.drop_table("log_activity_version") - op.drop_table("log_activity") diff --git a/src/wuttafarm/db/alembic/versions/4dbba8aeb1e5_add_structures.py b/src/wuttafarm/db/alembic/versions/4dbba8aeb1e5_add_structures.py deleted file mode 100644 index 94e8186..0000000 --- a/src/wuttafarm/db/alembic/versions/4dbba8aeb1e5_add_structures.py +++ /dev/null @@ -1,132 +0,0 @@ -"""add Structures - -Revision ID: 4dbba8aeb1e5 -Revises: e416b96467fc -Create Date: 2026-02-13 10:17:15.179202 - -""" - -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa -import wuttjamaican.db.util - - -# revision identifiers, used by Alembic. -revision: str = "4dbba8aeb1e5" -down_revision: Union[str, None] = "e416b96467fc" -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - - # structure - op.create_table( - "structure", - sa.Column("uuid", wuttjamaican.db.util.UUID(), nullable=False), - sa.Column("name", sa.String(length=100), nullable=False), - sa.Column("active", sa.Boolean(), nullable=False), - sa.Column("structure_type_uuid", wuttjamaican.db.util.UUID(), nullable=False), - sa.Column("is_location", sa.Boolean(), nullable=False), - sa.Column("is_fixed", sa.Boolean(), nullable=False), - sa.Column("notes", sa.Text(), nullable=True), - sa.Column("image_url", sa.String(length=255), nullable=True), - sa.Column("farmos_uuid", wuttjamaican.db.util.UUID(), nullable=True), - sa.Column("drupal_id", sa.Integer(), nullable=True), - sa.ForeignKeyConstraint( - ["structure_type_uuid"], - ["structure_type.uuid"], - name=op.f("fk_structure_structure_type_uuid_structure_type"), - ), - sa.PrimaryKeyConstraint("uuid", name=op.f("pk_structure")), - sa.UniqueConstraint("drupal_id", name=op.f("uq_structure_drupal_id")), - sa.UniqueConstraint("farmos_uuid", name=op.f("uq_structure_farmos_uuid")), - sa.UniqueConstraint("name", name=op.f("uq_structure_name")), - ) - op.create_table( - "structure_version", - sa.Column( - "uuid", wuttjamaican.db.util.UUID(), autoincrement=False, nullable=False - ), - sa.Column("name", sa.String(length=100), autoincrement=False, nullable=True), - sa.Column("active", sa.Boolean(), autoincrement=False, nullable=True), - sa.Column( - "structure_type_uuid", - wuttjamaican.db.util.UUID(), - autoincrement=False, - nullable=True, - ), - sa.Column("is_location", sa.Boolean(), autoincrement=False, nullable=True), - sa.Column("is_fixed", sa.Boolean(), autoincrement=False, nullable=True), - sa.Column("notes", sa.Text(), autoincrement=False, nullable=True), - sa.Column( - "image_url", sa.String(length=255), autoincrement=False, nullable=True - ), - sa.Column( - "farmos_uuid", - wuttjamaican.db.util.UUID(), - autoincrement=False, - nullable=True, - ), - sa.Column("drupal_id", sa.Integer(), autoincrement=False, nullable=True), - sa.Column( - "transaction_id", sa.BigInteger(), autoincrement=False, nullable=False - ), - sa.Column("end_transaction_id", sa.BigInteger(), nullable=True), - sa.Column("operation_type", sa.SmallInteger(), nullable=False), - sa.PrimaryKeyConstraint( - "uuid", "transaction_id", name=op.f("pk_structure_version") - ), - ) - op.create_index( - op.f("ix_structure_version_end_transaction_id"), - "structure_version", - ["end_transaction_id"], - unique=False, - ) - op.create_index( - op.f("ix_structure_version_operation_type"), - "structure_version", - ["operation_type"], - unique=False, - ) - op.create_index( - "ix_structure_version_pk_transaction_id", - "structure_version", - ["uuid", sa.literal_column("transaction_id DESC")], - unique=False, - ) - op.create_index( - "ix_structure_version_pk_validity", - "structure_version", - ["uuid", "transaction_id", "end_transaction_id"], - unique=False, - ) - op.create_index( - op.f("ix_structure_version_transaction_id"), - "structure_version", - ["transaction_id"], - unique=False, - ) - - -def downgrade() -> None: - - # structure - op.drop_index( - op.f("ix_structure_version_transaction_id"), table_name="structure_version" - ) - op.drop_index("ix_structure_version_pk_validity", table_name="structure_version") - op.drop_index( - "ix_structure_version_pk_transaction_id", table_name="structure_version" - ) - op.drop_index( - op.f("ix_structure_version_operation_type"), table_name="structure_version" - ) - op.drop_index( - op.f("ix_structure_version_end_transaction_id"), table_name="structure_version" - ) - op.drop_table("structure_version") - op.drop_table("structure") diff --git a/src/wuttafarm/db/alembic/versions/6c56bcd1c028_add_wuttafarmuser.py b/src/wuttafarm/db/alembic/versions/6c56bcd1c028_add_wuttafarmuser.py deleted file mode 100644 index 0dc2d29..0000000 --- a/src/wuttafarm/db/alembic/versions/6c56bcd1c028_add_wuttafarmuser.py +++ /dev/null @@ -1,112 +0,0 @@ -"""add WuttaFarmUser - -Revision ID: 6c56bcd1c028 -Revises: 2b6385d0fa17 -Create Date: 2026-02-09 20:46:20.995903 - -""" - -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa -import wuttjamaican.db.util - - -# revision identifiers, used by Alembic. -revision: str = "6c56bcd1c028" -down_revision: Union[str, None] = "2b6385d0fa17" -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - - # wuttafarm_user - op.create_table( - "wuttafarm_user", - sa.Column("uuid", wuttjamaican.db.util.UUID(), nullable=False), - sa.Column("farmos_uuid", wuttjamaican.db.util.UUID(), nullable=True), - sa.Column("drupal_id", sa.Integer(), nullable=True), - sa.ForeignKeyConstraint( - ["uuid"], ["user.uuid"], name=op.f("fk_wuttafarm_user_uuid_user") - ), - sa.PrimaryKeyConstraint("uuid", name=op.f("pk_wuttafarm_user")), - ) - op.create_table( - "wuttafarm_user_version", - sa.Column( - "uuid", wuttjamaican.db.util.UUID(), autoincrement=False, nullable=False - ), - sa.Column( - "farmos_uuid", - wuttjamaican.db.util.UUID(), - autoincrement=False, - nullable=True, - ), - sa.Column("drupal_id", sa.Integer(), autoincrement=False, nullable=True), - sa.Column( - "transaction_id", sa.BigInteger(), autoincrement=False, nullable=False - ), - sa.Column("end_transaction_id", sa.BigInteger(), nullable=True), - sa.Column("operation_type", sa.SmallInteger(), nullable=False), - sa.PrimaryKeyConstraint( - "uuid", "transaction_id", name=op.f("pk_wuttafarm_user_version") - ), - ) - op.create_index( - op.f("ix_wuttafarm_user_version_end_transaction_id"), - "wuttafarm_user_version", - ["end_transaction_id"], - unique=False, - ) - op.create_index( - op.f("ix_wuttafarm_user_version_operation_type"), - "wuttafarm_user_version", - ["operation_type"], - unique=False, - ) - op.create_index( - "ix_wuttafarm_user_version_pk_transaction_id", - "wuttafarm_user_version", - ["uuid", sa.literal_column("transaction_id DESC")], - unique=False, - ) - op.create_index( - "ix_wuttafarm_user_version_pk_validity", - "wuttafarm_user_version", - ["uuid", "transaction_id", "end_transaction_id"], - unique=False, - ) - op.create_index( - op.f("ix_wuttafarm_user_version_transaction_id"), - "wuttafarm_user_version", - ["transaction_id"], - unique=False, - ) - - -def downgrade() -> None: - - # wuttafarm_user - op.drop_index( - op.f("ix_wuttafarm_user_version_transaction_id"), - table_name="wuttafarm_user_version", - ) - op.drop_index( - "ix_wuttafarm_user_version_pk_validity", table_name="wuttafarm_user_version" - ) - op.drop_index( - "ix_wuttafarm_user_version_pk_transaction_id", - table_name="wuttafarm_user_version", - ) - op.drop_index( - op.f("ix_wuttafarm_user_version_operation_type"), - table_name="wuttafarm_user_version", - ) - op.drop_index( - op.f("ix_wuttafarm_user_version_end_transaction_id"), - table_name="wuttafarm_user_version", - ) - op.drop_table("wuttafarm_user_version") - op.drop_table("wuttafarm_user") diff --git a/src/wuttafarm/db/alembic/versions/92b813360b99_add_groups.py b/src/wuttafarm/db/alembic/versions/92b813360b99_add_groups.py deleted file mode 100644 index 7223844..0000000 --- a/src/wuttafarm/db/alembic/versions/92b813360b99_add_groups.py +++ /dev/null @@ -1,110 +0,0 @@ -"""add Groups - -Revision ID: 92b813360b99 -Revises: 1b2d3224e5dc -Create Date: 2026-02-13 13:09:48.718064 - -""" - -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa -import wuttjamaican.db.util - - -# revision identifiers, used by Alembic. -revision: str = "92b813360b99" -down_revision: Union[str, None] = "1b2d3224e5dc" -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - - # group - op.create_table( - "group", - sa.Column("uuid", wuttjamaican.db.util.UUID(), nullable=False), - sa.Column("name", sa.String(length=100), nullable=False), - sa.Column("is_location", sa.Boolean(), nullable=False), - sa.Column("is_fixed", sa.Boolean(), nullable=False), - sa.Column("active", sa.Boolean(), nullable=False), - sa.Column("notes", sa.Text(), nullable=True), - sa.Column("farmos_uuid", wuttjamaican.db.util.UUID(), nullable=True), - sa.Column("drupal_id", sa.Integer(), nullable=True), - sa.PrimaryKeyConstraint("uuid", name=op.f("pk_group")), - sa.UniqueConstraint("drupal_id", name=op.f("uq_group_drupal_id")), - sa.UniqueConstraint("farmos_uuid", name=op.f("uq_group_farmos_uuid")), - sa.UniqueConstraint("name", name=op.f("uq_group_name")), - ) - op.create_table( - "group_version", - sa.Column( - "uuid", wuttjamaican.db.util.UUID(), autoincrement=False, nullable=False - ), - sa.Column("name", sa.String(length=100), autoincrement=False, nullable=True), - sa.Column("is_location", sa.Boolean(), autoincrement=False, nullable=True), - sa.Column("is_fixed", sa.Boolean(), autoincrement=False, nullable=True), - sa.Column("active", sa.Boolean(), autoincrement=False, nullable=True), - sa.Column("notes", sa.Text(), autoincrement=False, nullable=True), - sa.Column( - "farmos_uuid", - wuttjamaican.db.util.UUID(), - autoincrement=False, - nullable=True, - ), - sa.Column("drupal_id", sa.Integer(), autoincrement=False, nullable=True), - sa.Column( - "transaction_id", sa.BigInteger(), autoincrement=False, nullable=False - ), - sa.Column("end_transaction_id", sa.BigInteger(), nullable=True), - sa.Column("operation_type", sa.SmallInteger(), nullable=False), - sa.PrimaryKeyConstraint( - "uuid", "transaction_id", name=op.f("pk_group_version") - ), - ) - op.create_index( - op.f("ix_group_version_end_transaction_id"), - "group_version", - ["end_transaction_id"], - unique=False, - ) - op.create_index( - op.f("ix_group_version_operation_type"), - "group_version", - ["operation_type"], - unique=False, - ) - op.create_index( - "ix_group_version_pk_transaction_id", - "group_version", - ["uuid", sa.literal_column("transaction_id DESC")], - unique=False, - ) - op.create_index( - "ix_group_version_pk_validity", - "group_version", - ["uuid", "transaction_id", "end_transaction_id"], - unique=False, - ) - op.create_index( - op.f("ix_group_version_transaction_id"), - "group_version", - ["transaction_id"], - unique=False, - ) - - -def downgrade() -> None: - - # group - op.drop_index(op.f("ix_group_version_transaction_id"), table_name="group_version") - op.drop_index("ix_group_version_pk_validity", table_name="group_version") - op.drop_index("ix_group_version_pk_transaction_id", table_name="group_version") - op.drop_index(op.f("ix_group_version_operation_type"), table_name="group_version") - op.drop_index( - op.f("ix_group_version_end_transaction_id"), table_name="group_version" - ) - op.drop_table("group_version") - op.drop_table("group") diff --git a/src/wuttafarm/db/alembic/versions/9f2243df9566_add_land_types.py b/src/wuttafarm/db/alembic/versions/9f2243df9566_add_land_types.py deleted file mode 100644 index 15d89fa..0000000 --- a/src/wuttafarm/db/alembic/versions/9f2243df9566_add_land_types.py +++ /dev/null @@ -1,110 +0,0 @@ -"""add Land Types - -Revision ID: 9f2243df9566 -Revises: cf3f8f46d8bc -Create Date: 2026-02-10 19:10:02.851756 - -""" - -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa -import wuttjamaican.db.util - - -# revision identifiers, used by Alembic. -revision: str = "9f2243df9566" -down_revision: Union[str, None] = "cf3f8f46d8bc" -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - - # land_type - op.create_table( - "land_type", - sa.Column("uuid", wuttjamaican.db.util.UUID(), nullable=False), - sa.Column("name", sa.String(length=100), nullable=False), - sa.Column("farmos_uuid", wuttjamaican.db.util.UUID(), nullable=True), - sa.Column("drupal_id", sa.String(length=50), nullable=True), - sa.PrimaryKeyConstraint("uuid", name=op.f("pk_land_type")), - sa.UniqueConstraint("drupal_id", name=op.f("uq_land_type_drupal_id")), - sa.UniqueConstraint("farmos_uuid", name=op.f("uq_land_type_farmos_uuid")), - sa.UniqueConstraint("name", name=op.f("uq_land_type_name")), - ) - op.create_table( - "land_type_version", - sa.Column( - "uuid", wuttjamaican.db.util.UUID(), autoincrement=False, nullable=False - ), - sa.Column("name", sa.String(length=100), autoincrement=False, nullable=True), - sa.Column( - "farmos_uuid", - wuttjamaican.db.util.UUID(), - autoincrement=False, - nullable=True, - ), - sa.Column( - "drupal_id", sa.String(length=50), autoincrement=False, nullable=True - ), - sa.Column( - "transaction_id", sa.BigInteger(), autoincrement=False, nullable=False - ), - sa.Column("end_transaction_id", sa.BigInteger(), nullable=True), - sa.Column("operation_type", sa.SmallInteger(), nullable=False), - sa.PrimaryKeyConstraint( - "uuid", "transaction_id", name=op.f("pk_land_type_version") - ), - ) - op.create_index( - op.f("ix_land_type_version_end_transaction_id"), - "land_type_version", - ["end_transaction_id"], - unique=False, - ) - op.create_index( - op.f("ix_land_type_version_operation_type"), - "land_type_version", - ["operation_type"], - unique=False, - ) - op.create_index( - "ix_land_type_version_pk_transaction_id", - "land_type_version", - ["uuid", sa.literal_column("transaction_id DESC")], - unique=False, - ) - op.create_index( - "ix_land_type_version_pk_validity", - "land_type_version", - ["uuid", "transaction_id", "end_transaction_id"], - unique=False, - ) - op.create_index( - op.f("ix_land_type_version_transaction_id"), - "land_type_version", - ["transaction_id"], - unique=False, - ) - - -def downgrade() -> None: - - # land_type - op.drop_index( - op.f("ix_land_type_version_transaction_id"), table_name="land_type_version" - ) - op.drop_index("ix_land_type_version_pk_validity", table_name="land_type_version") - op.drop_index( - "ix_land_type_version_pk_transaction_id", table_name="land_type_version" - ) - op.drop_index( - op.f("ix_land_type_version_operation_type"), table_name="land_type_version" - ) - op.drop_index( - op.f("ix_land_type_version_end_transaction_id"), table_name="land_type_version" - ) - op.drop_table("land_type_version") - op.drop_table("land_type") diff --git a/src/wuttafarm/db/alembic/versions/cf3f8f46d8bc_add_asset_types.py b/src/wuttafarm/db/alembic/versions/cf3f8f46d8bc_add_asset_types.py deleted file mode 100644 index ed4c344..0000000 --- a/src/wuttafarm/db/alembic/versions/cf3f8f46d8bc_add_asset_types.py +++ /dev/null @@ -1,115 +0,0 @@ -"""add Asset Types - -Revision ID: cf3f8f46d8bc -Revises: 6c56bcd1c028 -Create Date: 2026-02-10 18:42:24.560312 - -""" - -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa -import wuttjamaican.db.util - - -# revision identifiers, used by Alembic. -revision: str = "cf3f8f46d8bc" -down_revision: Union[str, None] = "6c56bcd1c028" -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - - # asset_type - op.create_table( - "asset_type", - sa.Column("uuid", wuttjamaican.db.util.UUID(), nullable=False), - sa.Column("name", sa.String(length=100), nullable=False), - sa.Column("description", sa.String(length=255), nullable=True), - sa.Column("farmos_uuid", wuttjamaican.db.util.UUID(), nullable=True), - sa.Column("drupal_id", sa.String(length=50), nullable=True), - sa.PrimaryKeyConstraint("uuid", name=op.f("pk_asset_type")), - sa.UniqueConstraint("drupal_id", name=op.f("uq_asset_type_drupal_id")), - sa.UniqueConstraint("farmos_uuid", name=op.f("uq_asset_type_farmos_uuid")), - sa.UniqueConstraint("name", name=op.f("uq_asset_type_name")), - ) - op.create_table( - "asset_type_version", - sa.Column( - "uuid", wuttjamaican.db.util.UUID(), autoincrement=False, nullable=False - ), - sa.Column("name", sa.String(length=100), autoincrement=False, nullable=True), - sa.Column( - "description", sa.String(length=255), autoincrement=False, nullable=True - ), - sa.Column( - "farmos_uuid", - wuttjamaican.db.util.UUID(), - autoincrement=False, - nullable=True, - ), - sa.Column( - "drupal_id", sa.String(length=50), autoincrement=False, nullable=True - ), - sa.Column( - "transaction_id", sa.BigInteger(), autoincrement=False, nullable=False - ), - sa.Column("end_transaction_id", sa.BigInteger(), nullable=True), - sa.Column("operation_type", sa.SmallInteger(), nullable=False), - sa.PrimaryKeyConstraint( - "uuid", "transaction_id", name=op.f("pk_asset_type_version") - ), - ) - op.create_index( - op.f("ix_asset_type_version_end_transaction_id"), - "asset_type_version", - ["end_transaction_id"], - unique=False, - ) - op.create_index( - op.f("ix_asset_type_version_operation_type"), - "asset_type_version", - ["operation_type"], - unique=False, - ) - op.create_index( - "ix_asset_type_version_pk_transaction_id", - "asset_type_version", - ["uuid", sa.literal_column("transaction_id DESC")], - unique=False, - ) - op.create_index( - "ix_asset_type_version_pk_validity", - "asset_type_version", - ["uuid", "transaction_id", "end_transaction_id"], - unique=False, - ) - op.create_index( - op.f("ix_asset_type_version_transaction_id"), - "asset_type_version", - ["transaction_id"], - unique=False, - ) - - -def downgrade() -> None: - - # asset_type - op.drop_index( - op.f("ix_asset_type_version_transaction_id"), table_name="asset_type_version" - ) - op.drop_index("ix_asset_type_version_pk_validity", table_name="asset_type_version") - op.drop_index( - "ix_asset_type_version_pk_transaction_id", table_name="asset_type_version" - ) - op.drop_index( - op.f("ix_asset_type_version_operation_type"), table_name="asset_type_version" - ) - op.drop_index( - op.f("ix_asset_type_version_end_transaction_id"), - table_name="asset_type_version", - ) - op.drop_table("asset_type_version") - op.drop_table("asset_type") diff --git a/src/wuttafarm/db/alembic/versions/d7479d7161a8_add_structure_types.py b/src/wuttafarm/db/alembic/versions/d7479d7161a8_add_structure_types.py deleted file mode 100644 index b71c4a6..0000000 --- a/src/wuttafarm/db/alembic/versions/d7479d7161a8_add_structure_types.py +++ /dev/null @@ -1,116 +0,0 @@ -"""add Structure Types - -Revision ID: d7479d7161a8 -Revises: 9f2243df9566 -Create Date: 2026-02-10 19:24:20.249826 - -""" - -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa -import wuttjamaican.db.util - - -# revision identifiers, used by Alembic. -revision: str = "d7479d7161a8" -down_revision: Union[str, None] = "9f2243df9566" -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - - # structure_type - op.create_table( - "structure_type", - sa.Column("uuid", wuttjamaican.db.util.UUID(), nullable=False), - sa.Column("name", sa.String(length=100), nullable=False), - sa.Column("farmos_uuid", wuttjamaican.db.util.UUID(), nullable=True), - sa.Column("drupal_id", sa.String(length=50), nullable=True), - sa.PrimaryKeyConstraint("uuid", name=op.f("pk_structure_type")), - sa.UniqueConstraint("drupal_id", name=op.f("uq_structure_type_drupal_id")), - sa.UniqueConstraint("farmos_uuid", name=op.f("uq_structure_type_farmos_uuid")), - sa.UniqueConstraint("name", name=op.f("uq_structure_type_name")), - ) - op.create_table( - "structure_type_version", - sa.Column( - "uuid", wuttjamaican.db.util.UUID(), autoincrement=False, nullable=False - ), - sa.Column("name", sa.String(length=100), autoincrement=False, nullable=True), - sa.Column( - "farmos_uuid", - wuttjamaican.db.util.UUID(), - autoincrement=False, - nullable=True, - ), - sa.Column( - "drupal_id", sa.String(length=50), autoincrement=False, nullable=True - ), - sa.Column( - "transaction_id", sa.BigInteger(), autoincrement=False, nullable=False - ), - sa.Column("end_transaction_id", sa.BigInteger(), nullable=True), - sa.Column("operation_type", sa.SmallInteger(), nullable=False), - sa.PrimaryKeyConstraint( - "uuid", "transaction_id", name=op.f("pk_structure_type_version") - ), - ) - op.create_index( - op.f("ix_structure_type_version_end_transaction_id"), - "structure_type_version", - ["end_transaction_id"], - unique=False, - ) - op.create_index( - op.f("ix_structure_type_version_operation_type"), - "structure_type_version", - ["operation_type"], - unique=False, - ) - op.create_index( - "ix_structure_type_version_pk_transaction_id", - "structure_type_version", - ["uuid", sa.literal_column("transaction_id DESC")], - unique=False, - ) - op.create_index( - "ix_structure_type_version_pk_validity", - "structure_type_version", - ["uuid", "transaction_id", "end_transaction_id"], - unique=False, - ) - op.create_index( - op.f("ix_structure_type_version_transaction_id"), - "structure_type_version", - ["transaction_id"], - unique=False, - ) - - -def downgrade() -> None: - - # structure_type - op.drop_index( - op.f("ix_structure_type_version_transaction_id"), - table_name="structure_type_version", - ) - op.drop_index( - "ix_structure_type_version_pk_validity", table_name="structure_type_version" - ) - op.drop_index( - "ix_structure_type_version_pk_transaction_id", - table_name="structure_type_version", - ) - op.drop_index( - op.f("ix_structure_type_version_operation_type"), - table_name="structure_type_version", - ) - op.drop_index( - op.f("ix_structure_type_version_end_transaction_id"), - table_name="structure_type_version", - ) - op.drop_table("structure_type_version") - op.drop_table("structure_type") diff --git a/src/wuttafarm/db/alembic/versions/e0d9f72575d6_add_log_types.py b/src/wuttafarm/db/alembic/versions/e0d9f72575d6_add_log_types.py deleted file mode 100644 index 862d3be..0000000 --- a/src/wuttafarm/db/alembic/versions/e0d9f72575d6_add_log_types.py +++ /dev/null @@ -1,114 +0,0 @@ -"""add Log Types - -Revision ID: e0d9f72575d6 -Revises: d7479d7161a8 -Create Date: 2026-02-10 19:35:06.631814 - -""" - -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa -import wuttjamaican.db.util - - -# revision identifiers, used by Alembic. -revision: str = "e0d9f72575d6" -down_revision: Union[str, None] = "d7479d7161a8" -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - - # log_type - op.create_table( - "log_type", - sa.Column("uuid", wuttjamaican.db.util.UUID(), nullable=False), - sa.Column("name", sa.String(length=100), nullable=False), - sa.Column("description", sa.String(length=255), nullable=True), - sa.Column("farmos_uuid", wuttjamaican.db.util.UUID(), nullable=True), - sa.Column("drupal_id", sa.String(length=50), nullable=True), - sa.PrimaryKeyConstraint("uuid", name=op.f("pk_log_type")), - sa.UniqueConstraint("drupal_id", name=op.f("uq_log_type_drupal_id")), - sa.UniqueConstraint("farmos_uuid", name=op.f("uq_log_type_farmos_uuid")), - sa.UniqueConstraint("name", name=op.f("uq_log_type_name")), - ) - op.create_table( - "log_type_version", - sa.Column( - "uuid", wuttjamaican.db.util.UUID(), autoincrement=False, nullable=False - ), - sa.Column("name", sa.String(length=100), autoincrement=False, nullable=True), - sa.Column( - "description", sa.String(length=255), autoincrement=False, nullable=True - ), - sa.Column( - "farmos_uuid", - wuttjamaican.db.util.UUID(), - autoincrement=False, - nullable=True, - ), - sa.Column( - "drupal_id", sa.String(length=50), autoincrement=False, nullable=True - ), - sa.Column( - "transaction_id", sa.BigInteger(), autoincrement=False, nullable=False - ), - sa.Column("end_transaction_id", sa.BigInteger(), nullable=True), - sa.Column("operation_type", sa.SmallInteger(), nullable=False), - sa.PrimaryKeyConstraint( - "uuid", "transaction_id", name=op.f("pk_log_type_version") - ), - ) - op.create_index( - op.f("ix_log_type_version_end_transaction_id"), - "log_type_version", - ["end_transaction_id"], - unique=False, - ) - op.create_index( - op.f("ix_log_type_version_operation_type"), - "log_type_version", - ["operation_type"], - unique=False, - ) - op.create_index( - "ix_log_type_version_pk_transaction_id", - "log_type_version", - ["uuid", sa.literal_column("transaction_id DESC")], - unique=False, - ) - op.create_index( - "ix_log_type_version_pk_validity", - "log_type_version", - ["uuid", "transaction_id", "end_transaction_id"], - unique=False, - ) - op.create_index( - op.f("ix_log_type_version_transaction_id"), - "log_type_version", - ["transaction_id"], - unique=False, - ) - - -def downgrade() -> None: - - # log_type - op.drop_index( - op.f("ix_log_type_version_transaction_id"), table_name="log_type_version" - ) - op.drop_index("ix_log_type_version_pk_validity", table_name="log_type_version") - op.drop_index( - "ix_log_type_version_pk_transaction_id", table_name="log_type_version" - ) - op.drop_index( - op.f("ix_log_type_version_operation_type"), table_name="log_type_version" - ) - op.drop_index( - op.f("ix_log_type_version_end_transaction_id"), table_name="log_type_version" - ) - op.drop_table("log_type_version") - op.drop_table("log_type") diff --git a/src/wuttafarm/db/alembic/versions/e416b96467fc_add_land_assets.py b/src/wuttafarm/db/alembic/versions/e416b96467fc_add_land_assets.py deleted file mode 100644 index 5f7dd87..0000000 --- a/src/wuttafarm/db/alembic/versions/e416b96467fc_add_land_assets.py +++ /dev/null @@ -1,132 +0,0 @@ -"""add Land Assets - -Revision ID: e416b96467fc -Revises: e0d9f72575d6 -Create Date: 2026-02-13 09:39:31.327442 - -""" - -from typing import Sequence, Union - -from alembic import op -import sqlalchemy as sa -import wuttjamaican.db.util - - -# revision identifiers, used by Alembic. -revision: str = "e416b96467fc" -down_revision: Union[str, None] = "e0d9f72575d6" -branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None - - -def upgrade() -> None: - - # land_asset - op.create_table( - "land_asset", - sa.Column("uuid", wuttjamaican.db.util.UUID(), nullable=False), - sa.Column("name", sa.String(length=100), nullable=False), - sa.Column("land_type_uuid", wuttjamaican.db.util.UUID(), nullable=False), - sa.Column("is_location", sa.Boolean(), nullable=False), - sa.Column("is_fixed", sa.Boolean(), nullable=False), - sa.Column("notes", sa.Text(), nullable=True), - sa.Column("active", sa.Boolean(), nullable=False), - sa.Column("farmos_uuid", wuttjamaican.db.util.UUID(), nullable=True), - sa.Column("drupal_id", sa.Integer(), nullable=True), - sa.ForeignKeyConstraint( - ["land_type_uuid"], - ["land_type.uuid"], - name=op.f("fk_land_asset_land_type_uuid_land_type"), - ), - sa.PrimaryKeyConstraint("uuid", name=op.f("pk_land_asset")), - sa.UniqueConstraint("drupal_id", name=op.f("uq_land_asset_drupal_id")), - sa.UniqueConstraint("farmos_uuid", name=op.f("uq_land_asset_farmos_uuid")), - sa.UniqueConstraint( - "land_type_uuid", name=op.f("uq_land_asset_land_type_uuid") - ), - sa.UniqueConstraint("name", name=op.f("uq_land_asset_name")), - ) - op.create_table( - "land_asset_version", - sa.Column( - "uuid", wuttjamaican.db.util.UUID(), autoincrement=False, nullable=False - ), - sa.Column("name", sa.String(length=100), autoincrement=False, nullable=True), - sa.Column( - "land_type_uuid", - wuttjamaican.db.util.UUID(), - autoincrement=False, - nullable=True, - ), - sa.Column("is_location", sa.Boolean(), autoincrement=False, nullable=True), - sa.Column("is_fixed", sa.Boolean(), autoincrement=False, nullable=True), - sa.Column("notes", sa.Text(), autoincrement=False, nullable=True), - sa.Column("active", sa.Boolean(), autoincrement=False, nullable=True), - sa.Column( - "farmos_uuid", - wuttjamaican.db.util.UUID(), - autoincrement=False, - nullable=True, - ), - sa.Column("drupal_id", sa.Integer(), autoincrement=False, nullable=True), - sa.Column( - "transaction_id", sa.BigInteger(), autoincrement=False, nullable=False - ), - sa.Column("end_transaction_id", sa.BigInteger(), nullable=True), - sa.Column("operation_type", sa.SmallInteger(), nullable=False), - sa.PrimaryKeyConstraint( - "uuid", "transaction_id", name=op.f("pk_land_asset_version") - ), - ) - op.create_index( - op.f("ix_land_asset_version_end_transaction_id"), - "land_asset_version", - ["end_transaction_id"], - unique=False, - ) - op.create_index( - op.f("ix_land_asset_version_operation_type"), - "land_asset_version", - ["operation_type"], - unique=False, - ) - op.create_index( - "ix_land_asset_version_pk_transaction_id", - "land_asset_version", - ["uuid", sa.literal_column("transaction_id DESC")], - unique=False, - ) - op.create_index( - "ix_land_asset_version_pk_validity", - "land_asset_version", - ["uuid", "transaction_id", "end_transaction_id"], - unique=False, - ) - op.create_index( - op.f("ix_land_asset_version_transaction_id"), - "land_asset_version", - ["transaction_id"], - unique=False, - ) - - -def downgrade() -> None: - - # land_asset - op.drop_index( - op.f("ix_land_asset_version_transaction_id"), table_name="land_asset_version" - ) - op.drop_index("ix_land_asset_version_pk_validity", table_name="land_asset_version") - op.drop_index( - "ix_land_asset_version_pk_transaction_id", table_name="land_asset_version" - ) - op.drop_index( - op.f("ix_land_asset_version_operation_type"), table_name="land_asset_version" - ) - op.drop_index( - op.f("ix_land_asset_version_end_transaction_id"), - table_name="land_asset_version", - ) - op.drop_table("land_asset_version") - op.drop_table("land_asset") diff --git a/src/wuttafarm/db/model/__init__.py b/src/wuttafarm/db/model/__init__.py index 27d0070..b52d7c8 100644 --- a/src/wuttafarm/db/model/__init__.py +++ b/src/wuttafarm/db/model/__init__.py @@ -26,13 +26,4 @@ WuttaFarm data models # bring in all of wutta from wuttjamaican.db.model import * -# wutta model extensions -from .users import WuttaFarmUser - -# wuttafarm proper models -from .assets import AssetType -from .land import LandType, LandAsset -from .structures import StructureType, Structure -from .animals import AnimalType, Animal -from .groups import Group -from .logs import LogType, ActivityLog +# TODO: import other/custom models here... diff --git a/src/wuttafarm/db/model/animals.py b/src/wuttafarm/db/model/animals.py deleted file mode 100644 index e23f0c5..0000000 --- a/src/wuttafarm/db/model/animals.py +++ /dev/null @@ -1,194 +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 . -# -################################################################################ -""" -Model definition for Animal Types -""" - -import sqlalchemy as sa -from sqlalchemy import orm - -from wuttjamaican.db import model - - -class AnimalType(model.Base): - """ - Represents an "animal type" (taxonomy term) from farmOS - """ - - __tablename__ = "animal_type" - __versioned__ = { - "exclude": [ - "changed", - ], - } - __wutta_hint__ = { - "model_title": "Animal Type", - "model_title_plural": "Animal Types", - } - - uuid = model.uuid_column() - - name = sa.Column( - sa.String(length=100), - nullable=False, - unique=True, - doc=""" - Name of the animal type. - """, - ) - - description = sa.Column( - sa.String(length=255), - nullable=True, - doc=""" - Optional description for the animal type. - """, - ) - - changed = sa.Column( - sa.DateTime(), - nullable=True, - doc=""" - When the animal type was last changed, according to farmOS. - """, - ) - - farmos_uuid = sa.Column( - model.UUID(), - nullable=True, - unique=True, - doc=""" - UUID for the animal type within farmOS. - """, - ) - - drupal_id = sa.Column( - sa.Integer(), - nullable=True, - unique=True, - doc=""" - Drupal internal ID for the animal type. - """, - ) - - def __str__(self): - return self.name or "" - - -class Animal(model.Base): - """ - Represents an animal from farmOS - """ - - __tablename__ = "animal" - __versioned__ = {} - __wutta_hint__ = { - "model_title": "Animal", - "model_title_plural": "Animals", - } - - uuid = model.uuid_column() - - name = sa.Column( - sa.String(length=100), - nullable=False, - doc=""" - Name for the animal. - """, - ) - - animal_type_uuid = model.uuid_fk_column("animal_type.uuid", nullable=False) - animal_type = orm.relationship( - "AnimalType", - doc=""" - Reference to the animal type. - """, - ) - - birthdate = sa.Column( - sa.DateTime(), - nullable=True, - doc=""" - Birth date (and time) for the animal, if known. - """, - ) - - sex = sa.Column( - sa.String(length=1), - nullable=True, - doc=""" - Sex of the animal. - """, - ) - - is_sterile = sa.Column( - sa.Boolean(), - nullable=True, - doc=""" - Whether the animal is sterile (e.g. castrated). - """, - ) - - active = sa.Column( - sa.Boolean(), - nullable=False, - doc=""" - Whether the animal is currently active. - """, - ) - - notes = sa.Column( - sa.Text(), - nullable=True, - doc=""" - Arbitrary notes for the animal. - """, - ) - - image_url = sa.Column( - sa.String(length=255), - nullable=True, - doc=""" - Optional image URL for the animal. - """, - ) - - farmos_uuid = sa.Column( - model.UUID(), - nullable=True, - unique=True, - doc=""" - UUID for the animal within farmOS. - """, - ) - - drupal_id = sa.Column( - sa.Integer(), - nullable=True, - unique=True, - doc=""" - Drupal internal ID for the animal. - """, - ) - - def __str__(self): - return self.name or "" diff --git a/src/wuttafarm/db/model/assets.py b/src/wuttafarm/db/model/assets.py deleted file mode 100644 index 581be62..0000000 --- a/src/wuttafarm/db/model/assets.py +++ /dev/null @@ -1,82 +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 . -# -################################################################################ -""" -Model definition for Asset Types -""" - -import sqlalchemy as sa -from sqlalchemy import orm - -from wuttjamaican.db import model - - -class AssetType(model.Base): - """ - Represents an "asset type" from farmOS - """ - - __tablename__ = "asset_type" - __versioned__ = {} - __wutta_hint__ = { - "model_title": "Asset Type", - "model_title_plural": "Asset Types", - } - - uuid = model.uuid_column() - - name = sa.Column( - sa.String(length=100), - nullable=False, - unique=True, - doc=""" - Name of the asset type. - """, - ) - - description = sa.Column( - sa.String(length=255), - nullable=True, - doc=""" - Description for the asset type. - """, - ) - - farmos_uuid = sa.Column( - model.UUID(), - nullable=True, - unique=True, - doc=""" - UUID for the asset type within farmOS. - """, - ) - - drupal_id = sa.Column( - sa.String(length=50), - nullable=True, - unique=True, - doc=""" - Drupal internal ID for the asset type. - """, - ) - - def __str__(self): - return self.name or "" diff --git a/src/wuttafarm/db/model/groups.py b/src/wuttafarm/db/model/groups.py deleted file mode 100644 index eae034f..0000000 --- a/src/wuttafarm/db/model/groups.py +++ /dev/null @@ -1,106 +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 . -# -################################################################################ -""" -Model definition for Groups -""" - -import sqlalchemy as sa -from sqlalchemy import orm - -from wuttjamaican.db import model - - -class Group(model.Base): - """ - Represents a "group" from farmOS - """ - - __tablename__ = "group" - __versioned__ = {} - __wutta_hint__ = { - "model_title": "Group", - "model_title_plural": "Groups", - } - - uuid = model.uuid_column() - - name = sa.Column( - sa.String(length=100), - nullable=False, - unique=True, - doc=""" - Name for the group. - """, - ) - - is_location = sa.Column( - sa.Boolean(), - nullable=False, - doc=""" - Whether the group is considered to be a location. - """, - ) - - is_fixed = sa.Column( - sa.Boolean(), - nullable=False, - doc=""" - Whether the group location is fixed. - """, - ) - - active = sa.Column( - sa.Boolean(), - nullable=False, - doc=""" - Whether the group is active. - """, - ) - - notes = sa.Column( - sa.Text(), - nullable=True, - doc=""" - Arbitrary notes for the group. - """, - ) - - farmos_uuid = sa.Column( - model.UUID(), - nullable=True, - unique=True, - doc=""" - UUID for the group within farmOS. - """, - ) - - drupal_id = sa.Column( - sa.Integer(), - nullable=True, - unique=True, - doc=""" - Drupal internal ID for the group. - """, - ) - - def __str__(self): - return self.name or "" diff --git a/src/wuttafarm/db/model/land.py b/src/wuttafarm/db/model/land.py deleted file mode 100644 index 53c93cf..0000000 --- a/src/wuttafarm/db/model/land.py +++ /dev/null @@ -1,156 +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 . -# -################################################################################ -""" -Model definition for Land Types -""" - -import sqlalchemy as sa -from sqlalchemy import orm - -from wuttjamaican.db import model - - -class LandType(model.Base): - """ - Represents a "land type" from farmOS - """ - - __tablename__ = "land_type" - __versioned__ = {} - __wutta_hint__ = { - "model_title": "Land Type", - "model_title_plural": "Land Types", - } - - uuid = model.uuid_column() - - name = sa.Column( - sa.String(length=100), - nullable=False, - unique=True, - doc=""" - Name of the land type. - """, - ) - - farmos_uuid = sa.Column( - model.UUID(), - nullable=True, - unique=True, - doc=""" - UUID for the land type within farmOS. - """, - ) - - drupal_id = sa.Column( - sa.String(length=50), - nullable=True, - unique=True, - doc=""" - Drupal internal ID for the land type. - """, - ) - - land_assets = orm.relationship("LandAsset", back_populates="land_type") - - def __str__(self): - return self.name or "" - - -class LandAsset(model.Base): - """ - Represents a "land asset" from farmOS - """ - - __tablename__ = "land_asset" - __versioned__ = {} - __wutta_hint__ = { - "model_title": "Land Asset", - "model_title_plural": "Land Assets", - } - - uuid = model.uuid_column() - - name = sa.Column( - sa.String(length=100), - nullable=False, - unique=True, - doc=""" - Name of the land asset. - """, - ) - - land_type_uuid = model.uuid_fk_column("land_type.uuid", nullable=False, unique=True) - land_type = orm.relationship(LandType, back_populates="land_assets") - - is_location = sa.Column( - sa.Boolean(), - nullable=False, - doc=""" - Whether the land asset should be considered a location. - """, - ) - - is_fixed = sa.Column( - sa.Boolean(), - nullable=False, - doc=""" - Whether the land asset's location is fixed. - """, - ) - - notes = sa.Column( - sa.Text(), - nullable=True, - doc=""" - Notes for the land asset. - """, - ) - - active = sa.Column( - sa.Boolean(), - nullable=False, - doc=""" - Whether the land asset is currently active. - """, - ) - - farmos_uuid = sa.Column( - model.UUID(), - nullable=True, - unique=True, - doc=""" - UUID for the land asset within farmOS. - """, - ) - - drupal_id = sa.Column( - sa.Integer(), - nullable=True, - unique=True, - doc=""" - Drupal internal ID for the land asset. - """, - ) - - def __str__(self): - return self.name or "" diff --git a/src/wuttafarm/db/model/logs.py b/src/wuttafarm/db/model/logs.py deleted file mode 100644 index 76f7715..0000000 --- a/src/wuttafarm/db/model/logs.py +++ /dev/null @@ -1,150 +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 . -# -################################################################################ -""" -Model definition for Log Types -""" - -import sqlalchemy as sa -from sqlalchemy import orm - -from wuttjamaican.db import model - - -class LogType(model.Base): - """ - Represents a "log type" from farmOS - """ - - __tablename__ = "log_type" - __versioned__ = {} - __wutta_hint__ = { - "model_title": "Log Type", - "model_title_plural": "Log Types", - } - - uuid = model.uuid_column() - - name = sa.Column( - sa.String(length=100), - nullable=False, - unique=True, - doc=""" - Name of the log type. - """, - ) - - description = sa.Column( - sa.String(length=255), - nullable=True, - doc=""" - Optional description for the log type. - """, - ) - - farmos_uuid = sa.Column( - model.UUID(), - nullable=True, - unique=True, - doc=""" - UUID for the log type within farmOS. - """, - ) - - drupal_id = sa.Column( - sa.String(length=50), - nullable=True, - unique=True, - doc=""" - Drupal internal ID for the log type. - """, - ) - - def __str__(self): - return self.name or "" - - -class ActivityLog(model.Base): - """ - Represents an activity log from farmOS - """ - - __tablename__ = "log_activity" - __versioned__ = {} - __wutta_hint__ = { - "model_title": "Activity Log", - "model_title_plural": "Activity Logs", - } - - uuid = model.uuid_column() - - message = sa.Column( - sa.String(length=255), - nullable=False, - doc=""" - Message text for the log. - """, - ) - - timestamp = sa.Column( - sa.DateTime(), - nullable=False, - doc=""" - Date and time when the log event occurred / will occur. - """, - ) - - status = sa.Column( - sa.String(length=20), - nullable=False, - doc=""" - Current status of the log event. - """, - ) - - notes = sa.Column( - sa.Text(), - nullable=True, - doc=""" - Arbitrary notes for the log event. - """, - ) - - farmos_uuid = sa.Column( - model.UUID(), - nullable=True, - unique=True, - doc=""" - UUID for the log within farmOS. - """, - ) - - drupal_id = sa.Column( - sa.Integer(), - nullable=True, - unique=True, - doc=""" - Drupal internal ID for the log. - """, - ) - - def __str__(self): - return self.message or "" diff --git a/src/wuttafarm/db/model/structures.py b/src/wuttafarm/db/model/structures.py deleted file mode 100644 index d9fccdb..0000000 --- a/src/wuttafarm/db/model/structures.py +++ /dev/null @@ -1,167 +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 . -# -################################################################################ -""" -Model definition for Structure Types -""" - -import sqlalchemy as sa -from sqlalchemy import orm - -from wuttjamaican.db import model - - -class StructureType(model.Base): - """ - Represents a "structure type" from farmOS - """ - - __tablename__ = "structure_type" - __versioned__ = {} - __wutta_hint__ = { - "model_title": "Structure Type", - "model_title_plural": "Structure Types", - } - - uuid = model.uuid_column() - - name = sa.Column( - sa.String(length=100), - nullable=False, - unique=True, - doc=""" - Name of the structure type. - """, - ) - - farmos_uuid = sa.Column( - model.UUID(), - nullable=True, - unique=True, - doc=""" - UUID for the structure type within farmOS. - """, - ) - - drupal_id = sa.Column( - sa.String(length=50), - nullable=True, - unique=True, - doc=""" - Drupal internal ID for the structure type. - """, - ) - - def __str__(self): - return self.name or "" - - -class Structure(model.Base): - """ - Represents a structure from farmOS - """ - - __tablename__ = "structure" - __versioned__ = {} - __wutta_hint__ = { - "model_title": "Structure", - "model_title_plural": "Structures", - } - - uuid = model.uuid_column() - - name = sa.Column( - sa.String(length=100), - nullable=False, - unique=True, - doc=""" - Name for the structure. - """, - ) - - active = sa.Column( - sa.Boolean(), - nullable=False, - doc=""" - Whether the structure is currently active. - """, - ) - - structure_type_uuid = model.uuid_fk_column("structure_type.uuid", nullable=False) - structure_type = orm.relationship( - "StructureType", - doc=""" - Reference to the type of structure. - """, - ) - - is_location = sa.Column( - sa.Boolean(), - nullable=False, - doc=""" - Whether the structure is considered a location. - """, - ) - - is_fixed = sa.Column( - sa.Boolean(), - nullable=False, - doc=""" - Whether the structure location is fixed. - """, - ) - - notes = sa.Column( - sa.Text(), - nullable=True, - doc=""" - Arbitrary notes for the structure. - """, - ) - - image_url = sa.Column( - sa.String(length=255), - nullable=True, - doc=""" - Optional image URL for the structure. - """, - ) - - farmos_uuid = sa.Column( - model.UUID(), - nullable=True, - unique=True, - doc=""" - UUID for the structure within farmOS. - """, - ) - - drupal_id = sa.Column( - sa.Integer(), - nullable=True, - unique=True, - doc=""" - Drupal internal ID for the structure. - """, - ) - - def __str__(self): - return self.name or "" diff --git a/src/wuttafarm/db/model/users.py b/src/wuttafarm/db/model/users.py deleted file mode 100644 index d194175..0000000 --- a/src/wuttafarm/db/model/users.py +++ /dev/null @@ -1,80 +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 . -# -################################################################################ -""" -Model definition for Users (extension) -""" - -import sqlalchemy as sa -from sqlalchemy import orm - -from wuttjamaican.db import model - - -class WuttaFarmUser(model.Base): - """ - WuttaFarm extension for the User model. - """ - - __tablename__ = "wuttafarm_user" - __versioned__ = {} - - uuid = model.uuid_column(sa.ForeignKey("user.uuid"), default=None) - - user = orm.relationship( - model.User, - doc=""" - Reference to the User which this record extends. - """, - backref=orm.backref( - "_wuttafarm", - uselist=False, - cascade="all, delete-orphan", - cascade_backrefs=False, - doc=""" - Reference to the WuttaFarm-specific extension record for - the user. - """, - ), - ) - - farmos_uuid = sa.Column( - model.UUID(), - nullable=True, - doc=""" - UUID for the user within farmOS - """, - ) - - drupal_id = sa.Column( - sa.Integer(), - nullable=True, - doc=""" - Drupal internal ID for the user. - """, - ) - - def __str__(self): - return str(self.user or "") - - -WuttaFarmUser.make_proxy(model.User, "_wuttafarm", "farmos_uuid") -WuttaFarmUser.make_proxy(model.User, "_wuttafarm", "drupal_id") diff --git a/src/wuttafarm/emails.py b/src/wuttafarm/emails.py deleted file mode 100644 index 55b1612..0000000 --- a/src/wuttafarm/emails.py +++ /dev/null @@ -1,32 +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 . -# -################################################################################ -""" -Email sending config for WuttaFarm -""" - -from wuttasync.emails import ImportExportWarning - - -class import_to_wuttafarm_from_farmos_warning(ImportExportWarning): - """ - Diff warning for farmOS → WuttaFarm import. - """ diff --git a/src/wuttafarm/importing/__init__.py b/src/wuttafarm/importing/__init__.py deleted file mode 100644 index 6711d56..0000000 --- a/src/wuttafarm/importing/__init__.py +++ /dev/null @@ -1,24 +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 . -# -################################################################################ -""" -Importing data to WuttaFarm -""" diff --git a/src/wuttafarm/importing/farmos.py b/src/wuttafarm/importing/farmos.py deleted file mode 100644 index 4717c78..0000000 --- a/src/wuttafarm/importing/farmos.py +++ /dev/null @@ -1,620 +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 . -# -################################################################################ -""" -Data import for farmOS -> WuttaFarm -""" - -import datetime -import logging -from uuid import UUID - -from oauthlib.oauth2 import BackendApplicationClient -from requests_oauthlib import OAuth2Session - -from wuttasync.importing import ImportHandler, ToWuttaHandler, Importer, ToWutta - -from wuttafarm.db import model - - -log = logging.getLogger(__name__) - - -class FromFarmOSHandler(ImportHandler): - """ - Base class for import handler using farmOS API as data source. - """ - - source_key = "farmos" - generic_source_title = "farmOS" - - def begin_source_transaction(self): - """ - Establish the farmOS API client. - """ - token = self.get_farmos_oauth2_token() - self.farmos_client = self.app.get_farmos_client(token=token) - - def get_farmos_oauth2_token(self): - - client_id = self.config.get( - "farmos.oauth2.importing.client_id", default="wuttafarm" - ) - client_secret = self.config.require("farmos.oauth2.importing.client_secret") - scope = self.config.get("farmos.oauth2.importing.scope", default="farm_manager") - - client = BackendApplicationClient(client_id=client_id) - oauth = OAuth2Session(client=client) - - return oauth.fetch_token( - token_url=self.app.get_farmos_url("/oauth/token"), - include_client_id=True, - client_secret=client_secret, - scope=scope, - ) - - def get_importer_kwargs(self, key, **kwargs): - kwargs = super().get_importer_kwargs(key, **kwargs) - kwargs["farmos_client"] = self.farmos_client - return kwargs - - -class ToWuttaFarmHandler(ToWuttaHandler): - """ - Base class for import handler targeting WuttaFarm - """ - - target_key = "wuttafarm" - - -class FromFarmOSToWuttaFarm(FromFarmOSHandler, ToWuttaFarmHandler): - """ - Handler for farmOS → WuttaFarm import. - """ - - def define_importers(self): - """ """ - importers = super().define_importers() - importers["User"] = UserImporter - importers["AssetType"] = AssetTypeImporter - importers["LandType"] = LandTypeImporter - importers["LandAsset"] = LandAssetImporter - importers["StructureType"] = StructureTypeImporter - importers["Structure"] = StructureImporter - importers["AnimalType"] = AnimalTypeImporter - importers["Animal"] = AnimalImporter - importers["Group"] = GroupImporter - importers["LogType"] = LogTypeImporter - importers["ActivityLog"] = ActivityLogImporter - return importers - - -class FromFarmOS(Importer): - """ - Base class for importers using farmOS API as data source. - """ - - key = "farmos_uuid" - - def get_supported_fields(self): - """ - Auto-remove the ``uuid`` field, since we use ``farmos_uuid`` - instead for the importer key. - """ - fields = list(super().get_supported_fields()) - if "uuid" in fields: - fields.remove("uuid") - return fields - - def normalize_datetime(self, dt): - """ - Convert a farmOS datetime value to naive UTC used by - WuttaFarm. - - :param dt: Date/time string value "as-is" from the farmOS API. - - :returns: Equivalent naive UTC ``datetime`` - """ - dt = datetime.datetime.fromisoformat(dt) - return self.app.make_utc(dt) - - -class ActivityLogImporter(FromFarmOS, ToWutta): - """ - farmOS API → WuttaFarm importer for Activity Logs - """ - - model_class = model.ActivityLog - - supported_fields = [ - "farmos_uuid", - "drupal_id", - "message", - "timestamp", - "notes", - "status", - ] - - def get_source_objects(self): - """ """ - logs = self.farmos_client.log.get("activity") - return logs["data"] - - def normalize_source_object(self, log): - """ """ - - if notes := log["attributes"]["notes"]: - notes = notes["value"] - - return { - "farmos_uuid": UUID(log["id"]), - "drupal_id": log["attributes"]["drupal_internal__id"], - "message": log["attributes"]["name"], - "timestamp": self.normalize_datetime(log["attributes"]["timestamp"]), - "notes": notes, - "status": log["attributes"]["status"], - } - - -class AnimalImporter(FromFarmOS, ToWutta): - """ - farmOS API → WuttaFarm importer for Animals - """ - - model_class = model.Animal - - supported_fields = [ - "farmos_uuid", - "drupal_id", - "name", - "animal_type_uuid", - "sex", - "is_sterile", - "birthdate", - "notes", - "active", - "image_url", - ] - - def setup(self): - super().setup() - model = self.app.model - - self.animal_types_by_farmos_uuid = {} - for animal_type in self.target_session.query(model.AnimalType): - if animal_type.farmos_uuid: - self.animal_types_by_farmos_uuid[animal_type.farmos_uuid] = animal_type - - def get_source_objects(self): - """ """ - animals = self.farmos_client.asset.get("animal") - return animals["data"] - - def normalize_source_object(self, animal): - """ """ - animal_type_uuid = None - image_url = None - if relationships := animal.get("relationships"): - - if animal_type := relationships.get("animal_type"): - if animal_type["data"]: - if animal_type := self.animal_types_by_farmos_uuid.get( - UUID(animal_type["data"]["id"]) - ): - animal_type_uuid = animal_type.uuid - - if image := relationships.get("image"): - if image["data"]: - image = self.farmos_client.resource.get_id( - "file", "file", image["data"][0]["id"] - ) - if image_style := image["data"]["attributes"].get( - "image_style_uri" - ): - image_url = image_style["large"] - - if not animal_type_uuid: - log.warning("missing/invalid animal_type for farmOS Animal: %s", animal) - return None - - birthdate = animal["attributes"]["birthdate"] - if birthdate: - birthdate = datetime.datetime.fromisoformat(birthdate) - birthdate = self.app.localtime(birthdate) - birthdate = self.app.make_utc(birthdate) - - if notes := animal["attributes"]["notes"]: - notes = notes["value"] - - return { - "farmos_uuid": UUID(animal["id"]), - "drupal_id": animal["attributes"]["drupal_internal__id"], - "name": animal["attributes"]["name"], - "animal_type_uuid": animal_type.uuid, - "sex": animal["attributes"]["sex"], - "is_sterile": animal["attributes"]["is_castrated"], - "birthdate": birthdate, - "active": animal["attributes"]["status"] == "active", - "notes": notes, - "image_url": image_url, - } - - -class AnimalTypeImporter(FromFarmOS, ToWutta): - """ - farmOS API → WuttaFarm importer for Animal Types - """ - - model_class = model.AnimalType - - supported_fields = [ - "farmos_uuid", - "drupal_id", - "name", - "description", - "changed", - ] - - def get_source_objects(self): - """ """ - animal_types = self.farmos_client.resource.get("taxonomy_term", "animal_type") - return animal_types["data"] - - def normalize_source_object(self, animal_type): - """ """ - return { - "farmos_uuid": UUID(animal_type["id"]), - "drupal_id": animal_type["attributes"]["drupal_internal__tid"], - "name": animal_type["attributes"]["name"], - "description": animal_type["attributes"]["description"], - "changed": self.normalize_datetime(animal_type["attributes"]["changed"]), - } - - -class AssetTypeImporter(FromFarmOS, ToWutta): - """ - farmOS API → WuttaFarm importer for Asset Types - """ - - model_class = model.AssetType - - supported_fields = [ - "farmos_uuid", - "drupal_id", - "name", - "description", - ] - - def get_source_objects(self): - """ """ - asset_types = self.farmos_client.resource.get("asset_type") - return asset_types["data"] - - def normalize_source_object(self, asset_type): - """ """ - return { - "farmos_uuid": UUID(asset_type["id"]), - "drupal_id": asset_type["attributes"]["drupal_internal__id"], - "name": asset_type["attributes"]["label"], - "description": asset_type["attributes"]["description"], - } - - -class GroupImporter(FromFarmOS, ToWutta): - """ - farmOS API → WuttaFarm importer for Groups - """ - - model_class = model.Group - - supported_fields = [ - "farmos_uuid", - "drupal_id", - "name", - "is_location", - "is_fixed", - "notes", - "active", - ] - - def get_source_objects(self): - """ """ - groups = self.farmos_client.asset.get("group") - return groups["data"] - - def normalize_source_object(self, group): - """ """ - if notes := group["attributes"]["notes"]: - notes = notes["value"] - - return { - "farmos_uuid": UUID(group["id"]), - "drupal_id": group["attributes"]["drupal_internal__id"], - "name": group["attributes"]["name"], - "is_location": group["attributes"]["is_location"], - "is_fixed": group["attributes"]["is_fixed"], - "active": group["attributes"]["status"] == "active", - "notes": notes, - } - - -class LandAssetImporter(FromFarmOS, ToWutta): - """ - farmOS API → WuttaFarm importer for Land Assets - """ - - model_class = model.LandAsset - - supported_fields = [ - "farmos_uuid", - "drupal_id", - "name", - "land_type_uuid", - "is_location", - "is_fixed", - "notes", - "active", - ] - - def setup(self): - super().setup() - model = self.app.model - - self.land_types_by_id = {} - for land_type in self.target_session.query(model.LandType): - self.land_types_by_id[land_type.drupal_id] = land_type - - def get_source_objects(self): - """ """ - land_assets = self.farmos_client.asset.get("land") - return land_assets["data"] - - def normalize_source_object(self, land): - """ """ - land_type_id = land["attributes"]["land_type"] - land_type = self.land_types_by_id.get(land_type_id) - if not land_type: - log.warning( - "invalid land_type '%s' for farmOS Land Asset: %s", land_type_id, land - ) - return None - - if notes := land["attributes"]["notes"]: - notes = notes["value"] - - return { - "farmos_uuid": UUID(land["id"]), - "drupal_id": land["attributes"]["drupal_internal__id"], - "name": land["attributes"]["name"], - "land_type_uuid": land_type.uuid, - "is_location": land["attributes"]["is_location"], - "is_fixed": land["attributes"]["is_fixed"], - "active": land["attributes"]["status"] == "active", - "notes": notes, - } - - -class LandTypeImporter(FromFarmOS, ToWutta): - """ - farmOS API → WuttaFarm importer for Land Types - """ - - model_class = model.LandType - - supported_fields = [ - "farmos_uuid", - "drupal_id", - "name", - ] - - def get_source_objects(self): - """ """ - land_types = self.farmos_client.resource.get("land_type") - return land_types["data"] - - def normalize_source_object(self, land_type): - """ """ - return { - "farmos_uuid": UUID(land_type["id"]), - "drupal_id": land_type["attributes"]["drupal_internal__id"], - "name": land_type["attributes"]["label"], - } - - -class LogTypeImporter(FromFarmOS, ToWutta): - """ - farmOS API → WuttaFarm importer for Log Types - """ - - model_class = model.LogType - - supported_fields = [ - "farmos_uuid", - "drupal_id", - "name", - "description", - ] - - def get_source_objects(self): - """ """ - log_types = self.farmos_client.resource.get("log_type") - return log_types["data"] - - def normalize_source_object(self, log_type): - """ """ - return { - "farmos_uuid": UUID(log_type["id"]), - "drupal_id": log_type["attributes"]["drupal_internal__id"], - "name": log_type["attributes"]["label"], - "description": log_type["attributes"]["description"], - } - - -class StructureImporter(FromFarmOS, ToWutta): - """ - farmOS API → WuttaFarm importer for Structures - """ - - model_class = model.Structure - - supported_fields = [ - "farmos_uuid", - "drupal_id", - "name", - "structure_type_uuid", - "is_location", - "is_fixed", - "notes", - "active", - "image_url", - ] - - def setup(self): - super().setup() - model = self.app.model - - self.structure_types_by_id = {} - for structure_type in self.target_session.query(model.StructureType): - self.structure_types_by_id[structure_type.drupal_id] = structure_type - - def get_source_objects(self): - """ """ - structures = self.farmos_client.asset.get("structure") - return structures["data"] - - def normalize_source_object(self, structure): - """ """ - structure_type_id = structure["attributes"]["structure_type"] - structure_type = self.structure_types_by_id.get(structure_type_id) - if not structure_type: - log.warning( - "invalid structure_type '%s' for farmOS Structure: %s", - structure_type_id, - structure, - ) - return None - - if notes := structure["attributes"]["notes"]: - notes = notes["value"] - - image_url = None - if relationships := structure.get("relationships"): - if image := relationships.get("image"): - if image["data"]: - image = self.farmos_client.resource.get_id( - "file", "file", image["data"][0]["id"] - ) - if image_style := image["data"]["attributes"].get( - "image_style_uri" - ): - image_url = image_style["large"] - - return { - "farmos_uuid": UUID(structure["id"]), - "drupal_id": structure["attributes"]["drupal_internal__id"], - "name": structure["attributes"]["name"], - "structure_type_uuid": structure_type.uuid, - "is_location": structure["attributes"]["is_location"], - "is_fixed": structure["attributes"]["is_fixed"], - "active": structure["attributes"]["status"] == "active", - "notes": notes, - "image_url": image_url, - } - - -class StructureTypeImporter(FromFarmOS, ToWutta): - """ - farmOS API → WuttaFarm importer for Structure Types - """ - - model_class = model.StructureType - - supported_fields = [ - "farmos_uuid", - "drupal_id", - "name", - ] - - def get_source_objects(self): - """ """ - structure_types = self.farmos_client.resource.get("structure_type") - return structure_types["data"] - - def normalize_source_object(self, structure_type): - """ """ - return { - "farmos_uuid": UUID(structure_type["id"]), - "drupal_id": structure_type["attributes"]["drupal_internal__id"], - "name": structure_type["attributes"]["label"], - } - - -class UserImporter(FromFarmOS, ToWutta): - """ - farmOS API → WuttaFarm importer for Users - """ - - model_class = model.User - - supported_fields = [ - "farmos_uuid", - "drupal_id", - "username", - ] - - def get_simple_fields(self): - """ """ - fields = list(super().get_simple_fields()) - # nb. must explicitly declare extension fields - fields.extend( - [ - "farmos_uuid", - "drupal_id", - ] - ) - return fields - - def get_source_objects(self): - """ """ - users = self.farmos_client.resource.get("user") - return users["data"] - - def normalize_source_object(self, user): - """ """ - - # nb. skip Anonymous user which does not have drupal id - drupal_id = user["attributes"].get("drupal_internal__uid") - if not drupal_id: - return None - - return { - "farmos_uuid": UUID(user["id"]), - "drupal_id": drupal_id, - "username": user["attributes"]["name"], - } - - def can_delete_object(self, user, data=None): - """ - Prevent delete for users which do not exist in farmOS. - """ - if not user.farmos_uuid: - return False - return True diff --git a/src/wuttafarm/web/forms/schema.py b/src/wuttafarm/web/forms/schema.py index f646a96..a38588a 100644 --- a/src/wuttafarm/web/forms/schema.py +++ b/src/wuttafarm/web/forms/schema.py @@ -27,33 +27,6 @@ import json import colander -from wuttaweb.forms.schema import ObjectRef - - -class AnimalTypeRef(ObjectRef): - """ - Custom schema type for a - :class:`~wuttafarm.db.model.animals.AnimalType` reference field. - - This is a subclass of - :class:`~wuttaweb:wuttaweb.forms.schema.ObjectRef`. - """ - - @property - def model_class(self): # pylint: disable=empty-docstring - """ """ - model = self.app.model - return model.AnimalType - - def sort_query(self, query): # pylint: disable=empty-docstring - """ """ - return query.order_by(self.model_class.name) - - def get_object_url(self, obj): # pylint: disable=empty-docstring - """ """ - animal_type = obj - return self.request.route_url("animal_types.view", uuid=animal_type.uuid) - class AnimalTypeType(colander.SchemaType): @@ -74,31 +47,6 @@ class AnimalTypeType(colander.SchemaType): return AnimalTypeWidget(self.request, **kwargs) -class LandTypeRef(ObjectRef): - """ - Custom schema type for a - :class:`~wuttafarm.db.model.land.LandType` reference field. - - This is a subclass of - :class:`~wuttaweb:wuttaweb.forms.schema.ObjectRef`. - """ - - @property - def model_class(self): # pylint: disable=empty-docstring - """ """ - model = self.app.model - return model.LandType - - def sort_query(self, query): # pylint: disable=empty-docstring - """ """ - return query.order_by(self.model_class.name) - - def get_object_url(self, obj): # pylint: disable=empty-docstring - """ """ - land_type = obj - return self.request.route_url("land_types.view", uuid=land_type.uuid) - - class StructureType(colander.SchemaType): def __init__(self, request, *args, **kwargs): @@ -118,31 +66,6 @@ class StructureType(colander.SchemaType): return StructureWidget(self.request, **kwargs) -class StructureTypeRef(ObjectRef): - """ - Custom schema type for a - :class:`~wuttafarm.db.model.structures.Structure` reference field. - - This is a subclass of - :class:`~wuttaweb:wuttaweb.forms.schema.ObjectRef`. - """ - - @property - def model_class(self): # pylint: disable=empty-docstring - """ """ - model = self.app.model - return model.StructureType - - def sort_query(self, query): # pylint: disable=empty-docstring - """ """ - return query.order_by(self.model_class.name) - - def get_object_url(self, obj): # pylint: disable=empty-docstring - """ """ - structure_type = obj - return self.request.route_url("structure_types.view", uuid=structure_type.uuid) - - class UsersType(colander.SchemaType): def __init__(self, request, *args, **kwargs): diff --git a/src/wuttafarm/web/menus.py b/src/wuttafarm/web/menus.py index 3e5bb46..ab6f440 100644 --- a/src/wuttafarm/web/menus.py +++ b/src/wuttafarm/web/menus.py @@ -33,80 +33,10 @@ class WuttaFarmMenuHandler(base.MenuHandler): def make_menus(self, request, **kwargs): return [ - self.make_asset_menu(request), - self.make_log_menu(request), self.make_farmos_menu(request), self.make_admin_menu(request, include_people=True), ] - def make_asset_menu(self, request): - return { - "title": "Assets", - "type": "menu", - "items": [ - { - "title": "Animals", - "route": "animals", - "perm": "animals.list", - }, - { - "title": "Groups", - "route": "groups", - "perm": "groups.list", - }, - { - "title": "Structures", - "route": "structures", - "perm": "structures.list", - }, - { - "title": "Land", - "route": "land_assets", - "perm": "land_assets.list", - }, - {"type": "sep"}, - { - "title": "Animal Types", - "route": "animal_types", - "perm": "animal_types.list", - }, - { - "title": "Structure Types", - "route": "structure_types", - "perm": "structure_types.list", - }, - { - "title": "Land Types", - "route": "land_types", - "perm": "land_types.list", - }, - { - "title": "Asset Types", - "route": "asset_types", - "perm": "asset_types.list", - }, - ], - } - - def make_log_menu(self, request): - return { - "title": "Logs", - "type": "menu", - "items": [ - { - "title": "Activity Logs", - "route": "activity_logs", - "perm": "activity_logs.list", - }, - {"type": "sep"}, - { - "title": "Log Types", - "route": "log_types", - "perm": "log_types.list", - }, - ], - } - def make_farmos_menu(self, request): config = request.wutta_config app = config.get_app() diff --git a/src/wuttafarm/web/templates/farmos/master/view.mako b/src/wuttafarm/web/templates/farmos/master/view.mako deleted file mode 100644 index 5e7bcd0..0000000 --- a/src/wuttafarm/web/templates/farmos/master/view.mako +++ /dev/null @@ -1,45 +0,0 @@ -## -*- coding: utf-8; -*- -<%inherit file="/master/view.mako" /> - -<%def name="tool_panels()"> - ${parent.tool_panels()} - ${self.tool_panel_tools()} - - -<%def name="tool_panel_tools()"> - % if raw_json: - - - - See raw JSON data - - - - <${b}-modal :width="1200" - % if request.use_oruga: - v-model:active="viewJsonShowDialog" - % else: - :active.sync="viewJsonShowDialog" - % endif - > -
-
- ${rendered_json|n} -
-
- - - % endif - - -<%def name="modify_vue_vars()"> - ${parent.modify_vue_vars()} - % if raw_json: - - % endif - diff --git a/src/wuttafarm/web/views/__init__.py b/src/wuttafarm/web/views/__init__.py index a4d12dd..63ce536 100644 --- a/src/wuttafarm/web/views/__init__.py +++ b/src/wuttafarm/web/views/__init__.py @@ -25,8 +25,6 @@ WuttaFarm Views from wuttaweb.views import essential -from .master import WuttaFarmMasterView - def includeme(config): @@ -36,21 +34,8 @@ def includeme(config): **{ "wuttaweb.views.auth": "wuttafarm.web.views.auth", "wuttaweb.views.common": "wuttafarm.web.views.common", - "wuttaweb.views.users": "wuttafarm.web.views.users", } ) - # native table views - config.include("wuttafarm.web.views.asset_types") - config.include("wuttafarm.web.views.land_types") - config.include("wuttafarm.web.views.structure_types") - config.include("wuttafarm.web.views.animal_types") - config.include("wuttafarm.web.views.land_assets") - config.include("wuttafarm.web.views.structures") - config.include("wuttafarm.web.views.animals") - config.include("wuttafarm.web.views.groups") - config.include("wuttafarm.web.views.log_types") - config.include("wuttafarm.web.views.logs_activity") - # views for farmOS config.include("wuttafarm.web.views.farmos") diff --git a/src/wuttafarm/web/views/animal_types.py b/src/wuttafarm/web/views/animal_types.py deleted file mode 100644 index 09d1e25..0000000 --- a/src/wuttafarm/web/views/animal_types.py +++ /dev/null @@ -1,128 +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 . -# -################################################################################ -""" -Master view for Animal Types -""" - -from wuttafarm.db.model.animals import AnimalType, Animal -from wuttafarm.web.views import WuttaFarmMasterView - - -class AnimalTypeView(WuttaFarmMasterView): - """ - Master view for Animal Types - """ - - model_class = AnimalType - route_prefix = "animal_types" - url_prefix = "/animal-types" - - farmos_refurl_path = "/admin/structure/taxonomy/manage/animal_type/overview" - - grid_columns = [ - "name", - "description", - "changed", - ] - - sort_defaults = "name" - - filter_defaults = { - "name": {"active": True, "verb": "contains"}, - } - - form_fields = [ - "name", - "description", - "changed", - "farmos_uuid", - "drupal_id", - ] - - has_rows = True - row_model_class = Animal - rows_viewable = True - - row_grid_columns = [ - "name", - "sex", - "is_sterile", - "birthdate", - "active", - ] - - rows_sort_defaults = "name" - - def configure_grid(self, grid): - g = grid - super().configure_grid(g) - - # name - g.set_link("name") - - def get_farmos_url(self, animal_type): - return self.app.get_farmos_url(f"/taxonomy/term/{animal_type.drupal_id}") - - def get_xref_buttons(self, animal_type): - buttons = super().get_xref_buttons(animal_type) - - if animal_type.farmos_uuid: - buttons.append( - self.make_button( - "View farmOS record", - primary=True, - url=self.request.route_url( - "farmos_animal_types.view", uuid=animal_type.farmos_uuid - ), - icon_left="eye", - ) - ) - - return buttons - - def get_row_grid_data(self, animal_type): - model = self.app.model - session = self.Session() - return session.query(model.Animal).filter( - model.Animal.animal_type == animal_type - ) - - def configure_row_grid(self, grid): - g = grid - super().configure_row_grid(g) - - # name - g.set_link("name") - - def get_row_action_url_view(self, animal, i): - return self.request.route_url("animals.view", uuid=animal.uuid) - - -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/animals.py b/src/wuttafarm/web/views/animals.py deleted file mode 100644 index e22095e..0000000 --- a/src/wuttafarm/web/views/animals.py +++ /dev/null @@ -1,130 +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 . -# -################################################################################ -""" -Master view for Animals -""" - -from wuttafarm.db.model.animals import Animal -from wuttafarm.web.views import WuttaFarmMasterView -from wuttafarm.web.forms.schema import AnimalTypeRef -from wuttafarm.web.forms.widgets import ImageWidget - - -class AnimalView(WuttaFarmMasterView): - """ - Master view for Animals - """ - - model_class = Animal - route_prefix = "animals" - url_prefix = "/animals" - - farmos_refurl_path = "/assets/animal" - - grid_columns = [ - "name", - "animal_type", - "sex", - "is_sterile", - "birthdate", - "active", - ] - - sort_defaults = "name" - - filter_defaults = { - "name": {"active": True, "verb": "contains"}, - } - - form_fields = [ - "name", - "animal_type", - "birthdate", - "sex", - "is_sterile", - "active", - "notes", - "farmos_uuid", - "drupal_id", - "image_url", - "image", - ] - - def configure_grid(self, grid): - g = grid - super().configure_grid(g) - model = self.app.model - - # name - g.set_link("name") - - # animal_type - g.set_joiner("animal_type", lambda q: q.join(model.AnimalType)) - g.set_sorter("animal_type", model.AnimalType.name) - g.set_filter("animal_type", model.AnimalType.name, label="Animal Type Name") - - def configure_form(self, form): - f = form - super().configure_form(f) - animal = form.model_instance - - # animal_type - f.set_node("animal_type", AnimalTypeRef(self.request)) - - # notes - f.set_widget("notes", "notes") - - # image - if animal.image_url: - f.set_widget("image", ImageWidget("animal image")) - f.set_default("image", animal.image_url) - - def get_farmos_url(self, animal): - return self.app.get_farmos_url(f"/asset/{animal.drupal_id}") - - def get_xref_buttons(self, animal): - buttons = super().get_xref_buttons(animal) - - if animal.farmos_uuid: - buttons.append( - self.make_button( - "View farmOS record", - primary=True, - url=self.request.route_url( - "farmos_animals.view", uuid=animal.farmos_uuid - ), - icon_left="eye", - ) - ) - - return buttons - - -def defaults(config, **kwargs): - base = globals() - - AnimalView = kwargs.get("AnimalView", base["AnimalView"]) - AnimalView.defaults(config) - - -def includeme(config): - defaults(config) diff --git a/src/wuttafarm/web/views/asset_types.py b/src/wuttafarm/web/views/asset_types.py deleted file mode 100644 index 775fa3a..0000000 --- a/src/wuttafarm/web/views/asset_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 . -# -################################################################################ -""" -Master view for Asset Types -""" - -from wuttafarm.db.model.assets import AssetType -from wuttafarm.web.views import WuttaFarmMasterView - - -class AssetTypeView(WuttaFarmMasterView): - """ - Master view for Asset Types - """ - - model_class = AssetType - route_prefix = "asset_types" - url_prefix = "/asset-types" - - grid_columns = [ - "name", - "description", - ] - - sort_defaults = "name" - - filter_defaults = { - "name": {"active": True, "verb": "contains"}, - } - - form_fields = [ - "name", - "description", - "farmos_uuid", - "drupal_id", - ] - - def configure_grid(self, grid): - g = grid - super().configure_grid(g) - - # name - g.set_link("name") - - def get_xref_buttons(self, asset_type): - buttons = super().get_xref_buttons(asset_type) - - if asset_type.farmos_uuid: - buttons.append( - self.make_button( - "View farmOS record", - primary=True, - url=self.request.route_url( - "farmos_asset_types.view", uuid=asset_type.farmos_uuid - ), - icon_left="eye", - ) - ) - - return buttons - - -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/common.py b/src/wuttafarm/web/views/common.py index cd68b78..f46c018 100644 --- a/src/wuttafarm/web/views/common.py +++ b/src/wuttafarm/web/views/common.py @@ -45,24 +45,9 @@ class CommonView(base.CommonView): farm_viewer = auth.get_role_farm_viewer(session) farm_viewer.notes = "this is meant to mirror the corresponding role in farmOS" - # create system user to represent farmOS - auth.make_user(session, username="farmos", prevent_edit=True) - site_admin = session.query(model.Role).filter_by(name="Site Admin").first() if site_admin: site_admin_perms = [ - "activity_logs.list", - "activity_logs.view", - "activity_logs.versions", - "animal_types.list", - "animal_types.view", - "animal_types.versions", - "animals.list", - "animals.view", - "animals.versions", - "asset_types.list", - "asset_types.view", - "asset_types.versions", "farmos_animal_types.list", "farmos_animal_types.view", "farmos_animals.list", @@ -85,24 +70,6 @@ class CommonView(base.CommonView): "farmos_structures.view", "farmos_users.list", "farmos_users.view", - "groups.list", - "groups.view", - "groups.versions", - "land_assets.list", - "land_assets.view", - "land_assets.versions", - "land_types.list", - "land_types.view", - "land_types.versions", - "log_types.list", - "log_types.view", - "log_types.versions", - "structure_types.list", - "structure_types.view", - "structure_types.versions", - "structures.list", - "structures.view", - "structures.versions", ] for perm in site_admin_perms: auth.grant_permission(site_admin, perm) diff --git a/src/wuttafarm/web/views/farmos/animal_types.py b/src/wuttafarm/web/views/farmos/animal_types.py index 94d02d8..a974242 100644 --- a/src/wuttafarm/web/views/farmos/animal_types.py +++ b/src/wuttafarm/web/views/farmos/animal_types.py @@ -79,7 +79,6 @@ class AnimalTypeView(FarmOSMasterView): animal_type = self.farmos_client.resource.get_id( "taxonomy_term", "animal_type", self.request.matchdict["uuid"] ) - self.raw_json = animal_type return self.normalize_animal_type(animal_type["data"]) def get_instance_title(self, animal_type): @@ -96,7 +95,7 @@ class AnimalTypeView(FarmOSMasterView): return { "uuid": animal_type["id"], - "drupal_id": animal_type["attributes"]["drupal_internal__tid"], + "drupal_internal_id": animal_type["attributes"]["drupal_internal__tid"], "name": animal_type["attributes"]["name"], "description": description or colander.null, "changed": changed, @@ -113,39 +112,18 @@ class AnimalTypeView(FarmOSMasterView): f.set_node("changed", WuttaDateTime()) def get_xref_buttons(self, animal_type): - model = self.app.model - session = self.Session() - - buttons = [ + return [ self.make_button( "View in farmOS", primary=True, url=self.app.get_farmos_url( - f"/taxonomy/term/{animal_type['drupal_id']}" + f"/taxonomy/term/{animal_type['drupal_internal_id']}" ), target="_blank", icon_left="external-link-alt", - ) + ), ] - if wf_animal_type := ( - session.query(model.AnimalType) - .filter(model.AnimalType.farmos_uuid == animal_type["uuid"]) - .first() - ): - buttons.append( - self.make_button( - f"View {self.app.get_title()} record", - primary=True, - url=self.request.route_url( - "animal_types.view", uuid=wf_animal_type.uuid - ), - icon_left="eye", - ) - ) - - return buttons - def defaults(config, **kwargs): base = globals() diff --git a/src/wuttafarm/web/views/farmos/animals.py b/src/wuttafarm/web/views/farmos/animals.py index 760ad34..8eca5af 100644 --- a/src/wuttafarm/web/views/farmos/animals.py +++ b/src/wuttafarm/web/views/farmos/animals.py @@ -27,10 +27,8 @@ 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.schema import UsersType, AnimalTypeType, StructureType from wuttafarm.web.forms.widgets import ImageWidget @@ -101,7 +99,6 @@ class AnimalView(FarmOSMasterView): animal = self.farmos_client.resource.get_id( "asset", "animal", self.request.matchdict["uuid"] ) - self.raw_json = animal # instance data data = self.normalize_animal(animal["data"]) @@ -175,7 +172,7 @@ class AnimalView(FarmOSMasterView): return { "uuid": animal["id"], - "drupal_id": animal["attributes"]["drupal_internal__id"], + "drupal_internal_id": animal["attributes"]["drupal_internal__id"], "name": animal["attributes"]["name"], "birthdate": birthdate, "sex": animal["attributes"]["sex"], @@ -193,10 +190,6 @@ class AnimalView(FarmOSMasterView): # animal_type f.set_node("animal_type", AnimalTypeType(self.request)) - # birthdate - f.set_node("birthdate", WuttaDateTime()) - f.set_widget("birthdate", WuttaDateTimeWidget(self.request)) - # is_castrated f.set_node("is_castrated", colander.Boolean()) @@ -215,35 +208,16 @@ class AnimalView(FarmOSMasterView): f.set_default("image", url) def get_xref_buttons(self, animal): - model = self.app.model - session = self.Session() - - buttons = [ + return [ self.make_button( "View in farmOS", primary=True, - url=self.app.get_farmos_url(f"/asset/{animal['drupal_id']}"), + url=self.app.get_farmos_url(f"/asset/{animal['drupal_internal_id']}"), target="_blank", icon_left="external-link-alt", ), ] - if wf_animal := ( - session.query(model.Animal) - .filter(model.Animal.farmos_uuid == animal["uuid"]) - .first() - ): - buttons.append( - self.make_button( - f"View {self.app.get_title()} record", - primary=True, - url=self.request.route_url("animals.view", uuid=wf_animal.uuid), - icon_left="eye", - ) - ) - - return buttons - def defaults(config, **kwargs): base = globals() diff --git a/src/wuttafarm/web/views/farmos/asset_types.py b/src/wuttafarm/web/views/farmos/asset_types.py index a2fac2f..75eebbe 100644 --- a/src/wuttafarm/web/views/farmos/asset_types.py +++ b/src/wuttafarm/web/views/farmos/asset_types.py @@ -69,7 +69,6 @@ class AssetTypeView(FarmOSMasterView): asset_type = self.farmos_client.resource.get_id( "asset_type", "asset_type", self.request.matchdict["uuid"] ) - self.raw_json = asset_type return self.normalize_asset_type(asset_type["data"]) def get_instance_title(self, asset_type): @@ -78,7 +77,7 @@ class AssetTypeView(FarmOSMasterView): def normalize_asset_type(self, asset_type): return { "uuid": asset_type["id"], - "drupal_id": asset_type["attributes"]["drupal_internal__id"], + "drupal_internal_id": asset_type["attributes"]["drupal_internal__id"], "label": asset_type["attributes"]["label"], "description": asset_type["attributes"]["description"], } @@ -90,29 +89,6 @@ class AssetTypeView(FarmOSMasterView): # description f.set_widget("description", "notes") - def get_xref_buttons(self, asset_type): - model = self.app.model - session = self.Session() - buttons = [] - - if wf_asset_type := ( - session.query(model.AssetType) - .filter(model.AssetType.farmos_uuid == asset_type["uuid"]) - .first() - ): - buttons.append( - self.make_button( - f"View {self.app.get_title()} record", - primary=True, - url=self.request.route_url( - "asset_types.view", uuid=wf_asset_type.uuid - ), - icon_left="eye", - ) - ) - - return buttons - def defaults(config, **kwargs): base = globals() diff --git a/src/wuttafarm/web/views/farmos/groups.py b/src/wuttafarm/web/views/farmos/groups.py index 66224fe..4664a6b 100644 --- a/src/wuttafarm/web/views/farmos/groups.py +++ b/src/wuttafarm/web/views/farmos/groups.py @@ -88,10 +88,11 @@ class GroupView(FarmOSMasterView): g.set_renderer("changed", "datetime") def get_instance(self): + group = self.farmos_client.resource.get_id( "asset", "group", self.request.matchdict["uuid"] ) - self.raw_json = group + return self.normalize_group(group["data"]) def get_instance_title(self, group): @@ -109,7 +110,7 @@ class GroupView(FarmOSMasterView): return { "uuid": group["id"], - "drupal_id": group["attributes"]["drupal_internal__id"], + "drupal_internal_id": group["attributes"]["drupal_internal__id"], "name": group["attributes"]["name"], "created": created, "changed": changed, @@ -141,35 +142,16 @@ class GroupView(FarmOSMasterView): f.set_widget("changed", WuttaDateTimeWidget(self.request)) def get_xref_buttons(self, group): - model = self.app.model - session = self.Session() - - buttons = [ + return [ self.make_button( "View in farmOS", primary=True, - url=self.app.get_farmos_url(f"/asset/{group['drupal_id']}"), + url=self.app.get_farmos_url(f"/asset/{group['drupal_internal_id']}"), target="_blank", icon_left="external-link-alt", ), ] - if wf_group := ( - session.query(model.Group) - .filter(model.Group.farmos_uuid == group["uuid"]) - .first() - ): - buttons.append( - self.make_button( - f"View {self.app.get_title()} record", - primary=True, - url=self.request.route_url("groups.view", uuid=wf_group.uuid), - icon_left="eye", - ) - ) - - return buttons - def defaults(config, **kwargs): base = globals() diff --git a/src/wuttafarm/web/views/farmos/land_assets.py b/src/wuttafarm/web/views/farmos/land_assets.py index 64f43cc..a496cc5 100644 --- a/src/wuttafarm/web/views/farmos/land_assets.py +++ b/src/wuttafarm/web/views/farmos/land_assets.py @@ -49,7 +49,6 @@ class LandAssetView(FarmOSMasterView): grid_columns = [ "name", - "land_type", "is_fixed", "is_location", "status", @@ -60,7 +59,6 @@ class LandAssetView(FarmOSMasterView): form_fields = [ "name", - "land_type", "is_fixed", "is_location", "status", @@ -97,7 +95,6 @@ class LandAssetView(FarmOSMasterView): land_asset = self.farmos_client.resource.get_id( "asset", "land", self.request.matchdict["uuid"] ) - self.raw_json = land_asset return self.normalize_land_asset(land_asset["data"]) def get_instance_title(self, land_asset): @@ -118,9 +115,8 @@ class LandAssetView(FarmOSMasterView): return { "uuid": land["id"], - "drupal_id": land["attributes"]["drupal_internal__id"], + "drupal_internal_id": land["attributes"]["drupal_internal__id"], "name": land["attributes"]["name"], - "land_type": land["attributes"]["land_type"], "created": created, "changed": changed, "is_fixed": land["attributes"]["is_fixed"], @@ -155,42 +151,12 @@ class LandAssetView(FarmOSMasterView): self.make_button( "View in farmOS", primary=True, - url=self.app.get_farmos_url(f"/asset/{land['drupal_id']}"), + url=self.app.get_farmos_url(f"/asset/{land['drupal_internal_id']}"), target="_blank", icon_left="external-link-alt", ), ] - def get_xref_buttons(self, land): - model = self.app.model - session = self.Session() - - buttons = [ - self.make_button( - "View in farmOS", - primary=True, - url=self.app.get_farmos_url(f"/asset/{land['drupal_id']}"), - target="_blank", - icon_left="external-link-alt", - ), - ] - - if wf_land := ( - session.query(model.LandAsset) - .filter(model.LandAsset.farmos_uuid == land["uuid"]) - .first() - ): - buttons.append( - self.make_button( - f"View {self.app.get_title()} record", - primary=True, - url=self.request.route_url("land_assets.view", uuid=wf_land.uuid), - icon_left="eye", - ) - ) - - return buttons - def defaults(config, **kwargs): base = globals() diff --git a/src/wuttafarm/web/views/farmos/land_types.py b/src/wuttafarm/web/views/farmos/land_types.py index e9eccea..aadece8 100644 --- a/src/wuttafarm/web/views/farmos/land_types.py +++ b/src/wuttafarm/web/views/farmos/land_types.py @@ -64,7 +64,6 @@ class LandTypeView(FarmOSMasterView): land_type = self.farmos_client.resource.get_id( "land_type", "land_type", self.request.matchdict["uuid"] ) - self.raw_json = land_type return self.normalize_land_type(land_type["data"]) def get_instance_title(self, land_type): @@ -73,33 +72,10 @@ class LandTypeView(FarmOSMasterView): def normalize_land_type(self, land_type): return { "uuid": land_type["id"], - "drupal_id": land_type["attributes"]["drupal_internal__id"], + "drupal_internal_id": land_type["attributes"]["drupal_internal__id"], "label": land_type["attributes"]["label"], } - def get_xref_buttons(self, land_type): - model = self.app.model - session = self.Session() - buttons = [] - - if wf_land_type := ( - session.query(model.LandType) - .filter(model.LandType.farmos_uuid == land_type["uuid"]) - .first() - ): - buttons.append( - self.make_button( - f"View {self.app.get_title()} record", - primary=True, - url=self.request.route_url( - "land_types.view", uuid=wf_land_type.uuid - ), - icon_left="eye", - ) - ) - - return buttons - def defaults(config, **kwargs): base = globals() diff --git a/src/wuttafarm/web/views/farmos/log_types.py b/src/wuttafarm/web/views/farmos/log_types.py index 1f6404a..6e72f8f 100644 --- a/src/wuttafarm/web/views/farmos/log_types.py +++ b/src/wuttafarm/web/views/farmos/log_types.py @@ -66,7 +66,6 @@ class LogTypeView(FarmOSMasterView): log_type = self.farmos_client.resource.get_id( "log_type", "log_type", self.request.matchdict["uuid"] ) - self.raw_json = log_type return self.normalize_log_type(log_type["data"]) def get_instance_title(self, log_type): @@ -75,7 +74,7 @@ class LogTypeView(FarmOSMasterView): def normalize_log_type(self, log_type): return { "uuid": log_type["id"], - "drupal_id": log_type["attributes"]["drupal_internal__id"], + "drupal_internal_id": log_type["attributes"]["drupal_internal__id"], "label": log_type["attributes"]["label"], "description": log_type["attributes"]["description"], } @@ -87,27 +86,6 @@ class LogTypeView(FarmOSMasterView): # description f.set_widget("description", "notes") - def get_xref_buttons(self, log_type): - model = self.app.model - session = self.Session() - buttons = [] - - if wf_log_type := ( - session.query(model.LogType) - .filter(model.LogType.farmos_uuid == log_type["uuid"]) - .first() - ): - buttons.append( - self.make_button( - f"View {self.app.get_title()} record", - primary=True, - url=self.request.route_url("log_types.view", uuid=wf_log_type.uuid), - icon_left="eye", - ) - ) - - return buttons - def defaults(config, **kwargs): base = globals() diff --git a/src/wuttafarm/web/views/farmos/logs_activity.py b/src/wuttafarm/web/views/farmos/logs_activity.py index e966810..61b4e85 100644 --- a/src/wuttafarm/web/views/farmos/logs_activity.py +++ b/src/wuttafarm/web/views/farmos/logs_activity.py @@ -79,7 +79,6 @@ class ActivityLogView(FarmOSMasterView): def get_instance(self): log = self.farmos_client.log.get_id("activity", self.request.matchdict["uuid"]) - self.raw_json = log return self.normalize_log(log["data"]) def get_instance_title(self, log): @@ -96,7 +95,7 @@ class ActivityLogView(FarmOSMasterView): return { "uuid": log["id"], - "drupal_id": log["attributes"]["drupal_internal__id"], + "drupal_internal_id": log["attributes"]["drupal_internal__id"], "name": log["attributes"]["name"], "timestamp": timestamp, "status": log["attributes"]["status"], @@ -115,35 +114,16 @@ class ActivityLogView(FarmOSMasterView): f.set_widget("notes", "notes") def get_xref_buttons(self, log): - model = self.app.model - session = self.Session() - - buttons = [ + return [ self.make_button( "View in farmOS", primary=True, - url=self.app.get_farmos_url(f"/log/{log['drupal_id']}"), + url=self.app.get_farmos_url(f"/log/{log['drupal_internal_id']}"), target="_blank", icon_left="external-link-alt", ), ] - if wf_log := ( - session.query(model.ActivityLog) - .filter(model.ActivityLog.farmos_uuid == log["uuid"]) - .first() - ): - buttons.append( - self.make_button( - f"View {self.app.get_title()} record", - primary=True, - url=self.request.route_url("activity_logs.view", uuid=wf_log.uuid), - icon_left="eye", - ) - ) - - return buttons - def defaults(config, **kwargs): base = globals() diff --git a/src/wuttafarm/web/views/farmos/master.py b/src/wuttafarm/web/views/farmos/master.py index 955120b..59003d0 100644 --- a/src/wuttafarm/web/views/farmos/master.py +++ b/src/wuttafarm/web/views/farmos/master.py @@ -23,10 +23,6 @@ Base class for farmOS master views """ -import json - -import markdown - from wuttaweb.views import MasterView from wuttafarm.web.util import save_farmos_oauth2_token @@ -58,7 +54,6 @@ class FarmOSMasterView(MasterView): def __init__(self, request, context=None): super().__init__(request, context=context) self.farmos_client = self.get_farmos_client() - self.raw_json = None def get_farmos_client(self): token = self.request.session.get("farmos.oauth2.token") @@ -76,26 +71,9 @@ class FarmOSMasterView(MasterView): return self.app.get_farmos_client(token=token, token_updater=token_updater) - def get_fallback_templates(self, template): - """ """ - templates = super().get_fallback_templates(template) - - if template == "view": - templates.insert(0, "/farmos/master/view.mako") - - return templates - def get_template_context(self, context): if self.listing and self.farmos_refurl_path: context["farmos_refurl"] = self.app.get_farmos_url(self.farmos_refurl_path) - if self.viewing and self.raw_json: - context["raw_json"] = self.raw_json - code = "```json\n" + json.dumps(self.raw_json, indent=2) + "\n```" - # TODO: this does not seem to be adding syntax highlight - context["rendered_json"] = markdown.markdown( - code, extensions=["fenced_code", "codehilite"] - ) - return context diff --git a/src/wuttafarm/web/views/farmos/structure_types.py b/src/wuttafarm/web/views/farmos/structure_types.py index b7e58d8..3fe4741 100644 --- a/src/wuttafarm/web/views/farmos/structure_types.py +++ b/src/wuttafarm/web/views/farmos/structure_types.py @@ -66,7 +66,6 @@ class StructureTypeView(FarmOSMasterView): structure_type = self.farmos_client.resource.get_id( "structure_type", "structure_type", self.request.matchdict["uuid"] ) - self.raw_json = structure_type return self.normalize_structure_type(structure_type["data"]) def get_instance_title(self, structure_type): @@ -75,33 +74,10 @@ class StructureTypeView(FarmOSMasterView): def normalize_structure_type(self, structure_type): return { "uuid": structure_type["id"], - "drupal_id": structure_type["attributes"]["drupal_internal__id"], + "drupal_internal_id": structure_type["attributes"]["drupal_internal__id"], "label": structure_type["attributes"]["label"], } - def get_xref_buttons(self, structure_type): - model = self.app.model - session = self.Session() - buttons = [] - - if wf_structure_type := ( - session.query(model.StructureType) - .filter(model.StructureType.farmos_uuid == structure_type["uuid"]) - .first() - ): - buttons.append( - self.make_button( - f"View {self.app.get_title()} record", - primary=True, - url=self.request.route_url( - "structure_types.view", uuid=wf_structure_type.uuid - ), - icon_left="eye", - ) - ) - - return buttons - def defaults(config, **kwargs): base = globals() diff --git a/src/wuttafarm/web/views/farmos/structures.py b/src/wuttafarm/web/views/farmos/structures.py index 3626fb1..bbc4f1f 100644 --- a/src/wuttafarm/web/views/farmos/structures.py +++ b/src/wuttafarm/web/views/farmos/structures.py @@ -94,7 +94,7 @@ class StructureView(FarmOSMasterView): structure = self.farmos_client.resource.get_id( "asset", "structure", self.request.matchdict["uuid"] ) - self.raw_json = structure + data = self.normalize_structure(structure["data"]) if relationships := structure["data"].get("relationships"): @@ -147,7 +147,7 @@ class StructureView(FarmOSMasterView): return { "uuid": structure["id"], - "drupal_id": structure["attributes"]["drupal_internal__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"], @@ -186,37 +186,17 @@ class StructureView(FarmOSMasterView): f.set_default("image", url) def get_xref_buttons(self, structure): - model = self.app.model - session = self.Session() - - buttons = [ + drupal_id = structure["drupal_internal_id"] + return [ self.make_button( "View in farmOS", primary=True, - url=self.app.get_farmos_url(f"/asset/{structure['drupal_id']}"), + url=self.app.get_farmos_url(f"/asset/{drupal_id}"), target="_blank", icon_left="external-link-alt", ), ] - if wf_structure := ( - session.query(model.Structure) - .filter(model.Structure.farmos_uuid == structure["uuid"]) - .first() - ): - buttons.append( - self.make_button( - f"View {self.app.get_title()} record", - primary=True, - url=self.request.route_url( - "structures.view", uuid=wf_structure.uuid - ), - icon_left="eye", - ) - ) - - return buttons - def defaults(config, **kwargs): base = globals() diff --git a/src/wuttafarm/web/views/farmos/users.py b/src/wuttafarm/web/views/farmos/users.py index bb004ee..317bfe3 100644 --- a/src/wuttafarm/web/views/farmos/users.py +++ b/src/wuttafarm/web/views/farmos/users.py @@ -77,7 +77,6 @@ class UserView(FarmOSMasterView): user = self.farmos_client.resource.get_id( "user", "user", self.request.matchdict["uuid"] ) - self.raw_json = user return self.normalize_user(user["data"]) def get_instance_title(self, user): @@ -95,7 +94,7 @@ class UserView(FarmOSMasterView): return { "uuid": user["id"], - "drupal_id": user["attributes"].get("drupal_internal__uid"), + "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, @@ -116,36 +115,17 @@ class UserView(FarmOSMasterView): f.set_node("changed", WuttaDateTime()) def get_xref_buttons(self, user): - model = self.app.model - session = self.Session() - buttons = [] - - if drupal_id := user["drupal_id"]: - buttons.append( + 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", - ) - ) - - if wf_user := ( - session.query(model.WuttaFarmUser) - .filter(model.WuttaFarmUser.farmos_uuid == user["uuid"]) - .first() - ): - buttons.append( - self.make_button( - f"View {self.app.get_title()} record", - primary=True, - url=self.request.route_url("users.view", uuid=wf_user.uuid), - icon_left="eye", - ) - ) - - return buttons + ), + ] + return None def defaults(config, **kwargs): diff --git a/src/wuttafarm/web/views/groups.py b/src/wuttafarm/web/views/groups.py deleted file mode 100644 index 5f2746b..0000000 --- a/src/wuttafarm/web/views/groups.py +++ /dev/null @@ -1,107 +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 . -# -################################################################################ -""" -Master view for Groups -""" - -from wuttafarm.db.model.groups import Group -from wuttafarm.web.views import WuttaFarmMasterView - - -class GroupView(WuttaFarmMasterView): - """ - Master view for Groups - """ - - model_class = Group - route_prefix = "groups" - url_prefix = "/groups" - - farmos_refurl_path = "/assets/group" - - grid_columns = [ - "name", - "is_location", - "is_fixed", - "active", - ] - - sort_defaults = "name" - - filter_defaults = { - "name": {"active": True, "verb": "contains"}, - } - - form_fields = [ - "name", - "is_location", - "is_fixed", - "active", - "notes", - "farmos_uuid", - "drupal_id", - ] - - def configure_grid(self, grid): - g = grid - super().configure_grid(g) - - # name - g.set_link("name") - - def configure_form(self, form): - f = form - super().configure_form(f) - - # notes - f.set_widget("notes", "notes") - - def get_farmos_url(self, group): - return self.app.get_farmos_url(f"/asset/{group.drupal_id}") - - def get_xref_buttons(self, group): - buttons = super().get_xref_buttons(group) - - if group.farmos_uuid: - buttons.append( - self.make_button( - "View farmOS record", - primary=True, - url=self.request.route_url( - "farmos_groups.view", uuid=group.farmos_uuid - ), - icon_left="eye", - ) - ) - - return buttons - - -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/land_assets.py b/src/wuttafarm/web/views/land_assets.py deleted file mode 100644 index 18f7a3d..0000000 --- a/src/wuttafarm/web/views/land_assets.py +++ /dev/null @@ -1,117 +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 . -# -################################################################################ -""" -Master view for Land Assets -""" - -from wuttafarm.db.model.land import LandAsset -from wuttafarm.web.views import WuttaFarmMasterView -from wuttafarm.web.forms.schema import LandTypeRef - - -class LandAssetView(WuttaFarmMasterView): - """ - Master view for Land Assets - """ - - model_class = LandAsset - route_prefix = "land_assets" - url_prefix = "/land-assets" - - farmos_refurl_path = "/assets/land" - - grid_columns = [ - "name", - "land_type", - "is_location", - "is_fixed", - "notes", - "active", - ] - - sort_defaults = "name" - - filter_defaults = { - "name": {"active": True, "verb": "contains"}, - } - - form_fields = [ - "name", - "land_type", - "is_location", - "is_fixed", - "notes", - "active", - "farmos_uuid", - "drupal_id", - ] - - def configure_grid(self, grid): - g = grid - super().configure_grid(g) - model = self.app.model - - # name - g.set_link("name") - - # land_type - g.set_joiner("land_type", lambda q: q.join(model.LandType)) - g.set_sorter("land_type", model.LandType.name) - g.set_filter("land_type", model.LandType.name, label="Land Type Name") - - def configure_form(self, form): - f = form - super().configure_form(f) - - # land_type - f.set_node("land_type", LandTypeRef(self.request)) - - def get_farmos_url(self, land): - return self.app.get_farmos_url(f"/asset/{land.drupal_id}") - - def get_xref_buttons(self, land_asset): - buttons = super().get_xref_buttons(land_asset) - - if land_asset.farmos_uuid: - buttons.append( - self.make_button( - "View farmOS record", - primary=True, - url=self.request.route_url( - "farmos_land_assets.view", uuid=land_asset.farmos_uuid - ), - icon_left="eye", - ) - ) - - return buttons - - -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/land_types.py b/src/wuttafarm/web/views/land_types.py deleted file mode 100644 index 21bfabc..0000000 --- a/src/wuttafarm/web/views/land_types.py +++ /dev/null @@ -1,118 +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 . -# -################################################################################ -""" -Master view for Land Types -""" - -from wuttafarm.db.model.land import LandType, LandAsset -from wuttafarm.web.views import WuttaFarmMasterView - - -class LandTypeView(WuttaFarmMasterView): - """ - Master view for Land Types - """ - - model_class = LandType - route_prefix = "land_types" - url_prefix = "/land-types" - - grid_columns = [ - "name", - ] - - sort_defaults = "name" - - filter_defaults = { - "name": {"active": True, "verb": "contains"}, - } - - form_fields = [ - "name", - "farmos_uuid", - "drupal_id", - ] - - has_rows = True - row_model_class = LandAsset - rows_viewable = True - - row_grid_columns = [ - "name", - "is_location", - "is_fixed", - "active", - ] - - rows_sort_defaults = "name" - - def configure_grid(self, grid): - g = grid - super().configure_grid(g) - - # name - g.set_link("name") - - def get_xref_buttons(self, land_type): - buttons = super().get_xref_buttons(land_type) - - if land_type.farmos_uuid: - buttons.append( - self.make_button( - "View farmOS record", - primary=True, - url=self.request.route_url( - "farmos_land_types.view", uuid=land_type.farmos_uuid - ), - icon_left="eye", - ) - ) - - return buttons - - def get_row_grid_data(self, land_type): - model = self.app.model - session = self.Session() - return session.query(model.LandAsset).filter( - model.LandAsset.land_type == land_type - ) - - def configure_row_grid(self, grid): - g = grid - super().configure_row_grid(g) - - # name - g.set_link("name") - - def get_row_action_url_view(self, land_asset, i): - return self.request.route_url("land_assets.view", uuid=land_asset.uuid) - - -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/log_types.py b/src/wuttafarm/web/views/log_types.py deleted file mode 100644 index 13ea35f..0000000 --- a/src/wuttafarm/web/views/log_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 . -# -################################################################################ -""" -Master view for Log Types -""" - -from wuttafarm.db.model.logs import LogType -from wuttafarm.web.views import WuttaFarmMasterView - - -class LogTypeView(WuttaFarmMasterView): - """ - Master view for Log Types - """ - - model_class = LogType - route_prefix = "log_types" - url_prefix = "/log-types" - - grid_columns = [ - "name", - "description", - ] - - sort_defaults = "name" - - filter_defaults = { - "name": {"active": True, "verb": "contains"}, - } - - form_fields = [ - "name", - "description", - "farmos_uuid", - "drupal_id", - ] - - def configure_grid(self, grid): - g = grid - super().configure_grid(g) - - # name - g.set_link("name") - - def get_xref_buttons(self, log_type): - buttons = super().get_xref_buttons(log_type) - - if log_type.farmos_uuid: - buttons.append( - self.make_button( - "View farmOS record", - primary=True, - url=self.request.route_url( - "farmos_log_types.view", uuid=log_type.farmos_uuid - ), - icon_left="eye", - ) - ) - - return buttons - - -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/logs_activity.py b/src/wuttafarm/web/views/logs_activity.py deleted file mode 100644 index a2b2154..0000000 --- a/src/wuttafarm/web/views/logs_activity.py +++ /dev/null @@ -1,105 +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 . -# -################################################################################ -""" -Master view for Activity Logs -""" - -from wuttafarm.db.model.logs import ActivityLog -from wuttafarm.web.views import WuttaFarmMasterView - - -class ActivityLogView(WuttaFarmMasterView): - """ - Master view for Activity Logs - """ - - model_class = ActivityLog - route_prefix = "activity_logs" - url_prefix = "/logs/activity" - - farmos_refurl_path = "/logs/activity" - - grid_columns = [ - "message", - "timestamp", - "status", - ] - - sort_defaults = ("timestamp", "desc") - - filter_defaults = { - "message": {"active": True, "verb": "contains"}, - } - - form_fields = [ - "message", - "timestamp", - "status", - "notes", - "farmos_uuid", - "drupal_id", - ] - - def configure_grid(self, grid): - g = grid - super().configure_grid(g) - - # message - g.set_link("message") - - def configure_form(self, form): - f = form - super().configure_form(f) - - # notes - f.set_widget("notes", "notes") - - def get_farmos_url(self, log): - return self.app.get_farmos_url(f"/log/{log.drupal_id}") - - def get_xref_buttons(self, log): - buttons = super().get_xref_buttons(log) - - if log.farmos_uuid: - buttons.append( - self.make_button( - "View farmOS record", - primary=True, - url=self.request.route_url( - "farmos_logs_activity.view", uuid=log.farmos_uuid - ), - icon_left="eye", - ) - ) - - return buttons - - -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/master.py b/src/wuttafarm/web/views/master.py deleted file mode 100644 index 7ff165b..0000000 --- a/src/wuttafarm/web/views/master.py +++ /dev/null @@ -1,70 +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 . -# -################################################################################ -""" -Base class for WuttaFarm master views -""" - -from wuttaweb.views import MasterView - - -class WuttaFarmMasterView(MasterView): - """ - Base class for WuttaFarm master views - """ - - farmos_refurl_path = None - - labels = { - "farmos_uuid": "farmOS UUID", - "drupal_id": "Drupal ID", - "image_url": "Image URL", - } - - row_labels = { - "farmos_uuid": "farmOS UUID", - "drupal_id": "Drupal ID", - "image_url": "Image URL", - } - - def get_farmos_url(self, obj): - return None - - def get_template_context(self, context): - - if self.listing and self.farmos_refurl_path: - context["farmos_refurl"] = self.app.get_farmos_url(self.farmos_refurl_path) - - return context - - def get_xref_buttons(self, obj): - url = self.get_farmos_url(obj) - if url: - return [ - self.make_button( - "View in farmOS", - primary=True, - url=url, - target="_blank", - icon_left="external-link-alt", - ) - ] - return [] diff --git a/src/wuttafarm/web/views/structure_types.py b/src/wuttafarm/web/views/structure_types.py deleted file mode 100644 index ca85fb9..0000000 --- a/src/wuttafarm/web/views/structure_types.py +++ /dev/null @@ -1,118 +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 . -# -################################################################################ -""" -Master view for Structure Types -""" - -from wuttafarm.db.model.structures import StructureType, Structure -from wuttafarm.web.views import WuttaFarmMasterView - - -class StructureTypeView(WuttaFarmMasterView): - """ - Master view for Structure Types - """ - - model_class = StructureType - route_prefix = "structure_types" - url_prefix = "/structure-types" - - grid_columns = [ - "name", - ] - - sort_defaults = "name" - - filter_defaults = { - "name": {"active": True, "verb": "contains"}, - } - - form_fields = [ - "name", - "farmos_uuid", - "drupal_id", - ] - - has_rows = True - row_model_class = Structure - rows_viewable = True - - row_grid_columns = [ - "name", - "is_location", - "is_fixed", - "active", - ] - - rows_sort_defaults = "name" - - def configure_grid(self, grid): - g = grid - super().configure_grid(g) - - # name - g.set_link("name") - - def get_xref_buttons(self, structure_type): - buttons = super().get_xref_buttons(structure_type) - - if structure_type.farmos_uuid: - buttons.append( - self.make_button( - "View farmOS record", - primary=True, - url=self.request.route_url( - "farmos_structure_types.view", uuid=structure_type.farmos_uuid - ), - icon_left="eye", - ) - ) - - return buttons - - def get_row_grid_data(self, structure_type): - model = self.app.model - session = self.Session() - return session.query(model.Structure).filter( - model.Structure.structure_type == structure_type - ) - - def configure_row_grid(self, grid): - g = grid - super().configure_row_grid(g) - - # name - g.set_link("name") - - def get_row_action_url_view(self, structure, i): - return self.request.route_url("structures.view", uuid=structure.uuid) - - -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/structures.py b/src/wuttafarm/web/views/structures.py deleted file mode 100644 index df58fda..0000000 --- a/src/wuttafarm/web/views/structures.py +++ /dev/null @@ -1,127 +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 . -# -################################################################################ -""" -Master view for Structures -""" - -from wuttafarm.db.model.structures import Structure -from wuttafarm.web.views import WuttaFarmMasterView -from wuttafarm.web.forms.schema import StructureTypeRef -from wuttafarm.web.forms.widgets import ImageWidget - - -class StructureView(WuttaFarmMasterView): - """ - Master view for Structures - """ - - model_class = Structure - route_prefix = "structures" - url_prefix = "/structures" - - farmos_refurl_path = "/assets/structure" - - grid_columns = [ - "name", - "structure_type", - "is_location", - "is_fixed", - "active", - ] - - sort_defaults = "name" - - filter_defaults = { - "name": {"active": True, "verb": "contains"}, - } - - form_fields = [ - "name", - "structure_type", - "is_location", - "is_fixed", - "notes", - "active", - "farmos_uuid", - "drupal_id", - "image_url", - "image", - ] - - def configure_grid(self, grid): - g = grid - super().configure_grid(g) - model = self.app.model - - # name - g.set_link("name") - - # structure_type - g.set_joiner("structure_type", lambda q: q.join(model.StructureType)) - g.set_sorter("structure_type", model.StructureType.name) - g.set_filter( - "structure_type", model.StructureType.name, label="Structure Type Name" - ) - - def configure_form(self, form): - f = form - super().configure_form(f) - structure = form.model_instance - - # structure_type - f.set_node("structure_type", StructureTypeRef(self.request)) - - # image - if structure.image_url: - f.set_widget("image", ImageWidget("structure image")) - f.set_default("image", structure.image_url) - - def get_farmos_url(self, structure): - return self.app.get_farmos_url(f"/asset/{structure.drupal_id}") - - def get_xref_buttons(self, structure): - buttons = super().get_xref_buttons(structure) - - if structure.farmos_uuid: - buttons.append( - self.make_button( - "View farmOS record", - primary=True, - url=self.request.route_url( - "farmos_structures.view", uuid=structure.farmos_uuid - ), - icon_left="eye", - ) - ) - - return buttons - - -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/users.py b/src/wuttafarm/web/views/users.py deleted file mode 100644 index f35aef7..0000000 --- a/src/wuttafarm/web/views/users.py +++ /dev/null @@ -1,99 +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 . -# -################################################################################ -""" -Views for Users -""" - -from wuttaweb.views import users as base - - -class UserView(base.UserView): - """ - Custom master view for Users. - """ - - labels = { - "farmos_uuid": "farmOS UUID", - "drupal_id": "Drupal ID", - } - - def get_template_context(self, context): - context = super().get_template_context(context) - - if self.listing: - context["farmos_refurl"] = self.app.get_farmos_url("/admin/people") - - return context - - def configure_form(self, form): - """ """ - f = form - super().configure_form(f) - user = f.model_instance - - # farmos_uuid - if not self.creating: - f.fields.append("farmos_uuid") - f.set_default("farmos_uuid", user.farmos_uuid) - - # drupal_id - if not self.creating: - f.fields.append("drupal_id") - f.set_default("drupal_id", user.drupal_id) - - def get_xref_buttons(self, user): - buttons = [] - - if user.drupal_id: - buttons.append( - self.make_button( - "View in farmOS", - primary=True, - url=self.app.get_farmos_url(f"/user/{user.drupal_id}"), - target="_blank", - icon_left="external-link-alt", - ) - ) - - if user.farmos_uuid: - buttons.append( - self.make_button( - "View farmOS record", - primary=True, - url=self.request.route_url( - "farmos_users.view", uuid=user.farmos_uuid - ), - icon_left="eye", - ) - ) - - return buttons - - -def defaults(config, **kwargs): - local = globals() - UserView = kwargs.get("UserView", local["UserView"]) - base.defaults(config, **{"UserView": UserView}) - - -def includeme(config): - defaults(config)