Compare commits
No commits in common. "34cb6b210d172a5a17ae6407730fda53c0a5db9c" and "9cc7237bfb103672087b99d0fd6ecd90da58e62c" have entirely different histories.
34cb6b210d
...
9cc7237bfb
69 changed files with 46 additions and 5095 deletions
24
CHANGELOG.md
24
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
|
||||
|
|
|
|||
|
|
@ -1,6 +0,0 @@
|
|||
|
||||
``wuttafarm.cli.base``
|
||||
======================
|
||||
|
||||
.. automodule:: wuttafarm.cli.base
|
||||
:members:
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
|
||||
``wuttafarm.cli.import_farmos``
|
||||
===============================
|
||||
|
||||
.. automodule:: wuttafarm.cli.import_farmos
|
||||
:members:
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
|
||||
``wuttafarm.cli.install``
|
||||
=========================
|
||||
|
||||
.. automodule:: wuttafarm.cli.install
|
||||
:members:
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
|
||||
``wuttafarm.importing.farmos``
|
||||
==============================
|
||||
|
||||
.. automodule:: wuttafarm.importing.farmos
|
||||
:members:
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
|
||||
``wuttafarm.importing``
|
||||
=======================
|
||||
|
||||
.. automodule:: wuttafarm.importing
|
||||
:members:
|
||||
|
|
@ -21,7 +21,6 @@ extensions = [
|
|||
"sphinx.ext.intersphinx",
|
||||
"sphinx.ext.viewcode",
|
||||
"sphinx.ext.todo",
|
||||
"sphinxcontrib.programoutput",
|
||||
]
|
||||
|
||||
templates_path = ["_templates"]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
@ -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
|
||||
-----------
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"]
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
WuttaFarm CLI
|
||||
"""
|
||||
|
||||
from .base import wuttafarm_typer
|
||||
|
||||
# nb. must bring in all modules for discovery to work
|
||||
from . import import_farmos
|
||||
from . import install
|
||||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
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"
|
||||
)
|
||||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
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)
|
||||
|
|
@ -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")
|
||||
|
|
@ -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")
|
||||
|
|
@ -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")
|
||||
|
|
@ -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")
|
||||
|
|
@ -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")
|
||||
|
|
@ -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")
|
||||
|
|
@ -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")
|
||||
|
|
@ -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")
|
||||
|
|
@ -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")
|
||||
|
|
@ -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")
|
||||
|
|
@ -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")
|
||||
|
|
@ -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...
|
||||
|
|
|
|||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
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 ""
|
||||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
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 ""
|
||||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
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 ""
|
||||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
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 ""
|
||||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
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 ""
|
||||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
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 ""
|
||||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
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")
|
||||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
Email sending config for WuttaFarm
|
||||
"""
|
||||
|
||||
from wuttasync.emails import ImportExportWarning
|
||||
|
||||
|
||||
class import_to_wuttafarm_from_farmos_warning(ImportExportWarning):
|
||||
"""
|
||||
Diff warning for farmOS → WuttaFarm import.
|
||||
"""
|
||||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
Importing data to WuttaFarm
|
||||
"""
|
||||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
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
|
||||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -1,45 +0,0 @@
|
|||
## -*- coding: utf-8; -*-
|
||||
<%inherit file="/master/view.mako" />
|
||||
|
||||
<%def name="tool_panels()">
|
||||
${parent.tool_panels()}
|
||||
${self.tool_panel_tools()}
|
||||
</%def>
|
||||
|
||||
<%def name="tool_panel_tools()">
|
||||
% if raw_json:
|
||||
|
||||
<wutta-tool-panel heading="Tools">
|
||||
<b-button type="is-primary"
|
||||
icon-pack="fas"
|
||||
icon-left="code"
|
||||
@click="viewJsonShowDialog = true">
|
||||
See raw JSON data
|
||||
</b-button>
|
||||
</wutta-tool-panel>
|
||||
|
||||
<${b}-modal :width="1200"
|
||||
% if request.use_oruga:
|
||||
v-model:active="viewJsonShowDialog"
|
||||
% else:
|
||||
:active.sync="viewJsonShowDialog"
|
||||
% endif
|
||||
>
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
${rendered_json|n}
|
||||
</div>
|
||||
</div>
|
||||
</${b}-modal>
|
||||
|
||||
% endif
|
||||
</%def>
|
||||
|
||||
<%def name="modify_vue_vars()">
|
||||
${parent.modify_vue_vars()}
|
||||
% if raw_json:
|
||||
<script>
|
||||
ThisPageData.viewJsonShowDialog = false
|
||||
</script>
|
||||
% endif
|
||||
</%def>
|
||||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
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)
|
||||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
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)
|
||||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
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)
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
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)
|
||||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
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)
|
||||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
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)
|
||||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
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)
|
||||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
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)
|
||||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
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 []
|
||||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
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)
|
||||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
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)
|
||||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
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)
|
||||
Loading…
Add table
Add a link
Reference in a new issue