feat: initial basic app to prove display of API (animal) data
This commit is contained in:
parent
54ff9d5d83
commit
e0f91417cb
23 changed files with 950 additions and 40 deletions
|
|
@ -6,7 +6,7 @@ build-backend = "hatchling.build"
|
||||||
[project]
|
[project]
|
||||||
name = "WuttaFarm"
|
name = "WuttaFarm"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
description = "Web app to expose / extend farmOS"
|
description = "Web app to integrate with and extend farmOS"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
authors = [
|
authors = [
|
||||||
{name = "Lance Edgar", email = "lance@wuttaproject.org"}
|
{name = "Lance Edgar", email = "lance@wuttaproject.org"}
|
||||||
|
|
@ -29,8 +29,9 @@ classifiers = [
|
||||||
]
|
]
|
||||||
license = {text = "GNU General Public License v3"}
|
license = {text = "GNU General Public License v3"}
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"psycopg2",
|
"farmOS",
|
||||||
"WuttaWeb[continuum]",
|
"psycopg2",
|
||||||
|
"WuttaWeb[continuum]",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
26
src/wuttafarm/__init__.py
Normal file
26
src/wuttafarm/__init__.py
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
# -*- 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/>.
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
|
"""
|
||||||
|
package root
|
||||||
|
"""
|
||||||
|
|
||||||
|
from ._version import __version__
|
||||||
9
src/wuttafarm/_version.py
Normal file
9
src/wuttafarm/_version.py
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
# -*- coding: utf-8; -*-
|
||||||
|
"""
|
||||||
|
Package Version
|
||||||
|
"""
|
||||||
|
|
||||||
|
from importlib.metadata import version
|
||||||
|
|
||||||
|
|
||||||
|
__version__ = version("WuttaFarm")
|
||||||
57
src/wuttafarm/app.py
Normal file
57
src/wuttafarm/app.py
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
# -*- 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/>.
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
|
"""
|
||||||
|
Custom app handler for WuttaFarm
|
||||||
|
"""
|
||||||
|
|
||||||
|
from wuttjamaican import app as base
|
||||||
|
|
||||||
|
|
||||||
|
class WuttaFarmAppHandler(base.AppHandler):
|
||||||
|
"""
|
||||||
|
Custom :term:`app handler` for WuttaFarm.
|
||||||
|
"""
|
||||||
|
|
||||||
|
default_auth_handler_spec = "wuttafarm.auth:WuttaFarmAuthHandler"
|
||||||
|
|
||||||
|
def get_farmos_handler(self):
|
||||||
|
"""
|
||||||
|
Get the configured farmOS integration handler.
|
||||||
|
|
||||||
|
:rtype: :class:`~wuttafarm.farmos.FarmOSHandler`
|
||||||
|
"""
|
||||||
|
if "farmos" not in self.handlers:
|
||||||
|
spec = self.config.get(
|
||||||
|
f"{self.appname}.farmos_handler",
|
||||||
|
default="wuttafarm.farmos:FarmOSHandler",
|
||||||
|
)
|
||||||
|
factory = self.load_object(spec)
|
||||||
|
self.handlers["farmos"] = factory(self.config)
|
||||||
|
return self.handlers["farmos"]
|
||||||
|
|
||||||
|
def get_farmos_url(self, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
Get a farmOS URL. This is a convenience wrapper around
|
||||||
|
:meth:`~wuttafarm.farmos.FarmOSHandler.get_farmos_url()`.
|
||||||
|
"""
|
||||||
|
handler = self.get_farmos_handler()
|
||||||
|
return handler.get_farmos_url(*args, **kwargs)
|
||||||
117
src/wuttafarm/auth.py
Normal file
117
src/wuttafarm/auth.py
Normal file
|
|
@ -0,0 +1,117 @@
|
||||||
|
# -*- 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/>.
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
|
"""
|
||||||
|
Auth handler for use with farmOS
|
||||||
|
"""
|
||||||
|
|
||||||
|
from uuid import UUID
|
||||||
|
|
||||||
|
from farmOS import farmOS
|
||||||
|
from oauthlib.oauth2.rfc6749.errors import InvalidGrantError
|
||||||
|
from sqlalchemy import orm
|
||||||
|
|
||||||
|
from wuttjamaican.auth import AuthHandler
|
||||||
|
|
||||||
|
|
||||||
|
class WuttaFarmAuthHandler(AuthHandler):
|
||||||
|
"""
|
||||||
|
Custom auth handler for WuttaFarm. This adds some magic around
|
||||||
|
the user login process.
|
||||||
|
|
||||||
|
It can attempt authentication against the configured farmOS
|
||||||
|
instance, auto-creating native users within the app DB as needed.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
def get_role_farm_manager(self, session):
|
||||||
|
"""
|
||||||
|
Returns the special "Farm Manager" role.
|
||||||
|
"""
|
||||||
|
return self._special_role(
|
||||||
|
session, UUID("06979646-b1b9-723b-8000-b86161427f9f"), "Farm Manager"
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_role_farm_worker(self, session):
|
||||||
|
"""
|
||||||
|
Returns the special "Farm Worker" role.
|
||||||
|
"""
|
||||||
|
return self._special_role(
|
||||||
|
session, UUID("06979648-9bd6-7b61-8000-ee8818052ee8"), "Farm Worker"
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_role_farm_viewer(self, session):
|
||||||
|
"""
|
||||||
|
Returns the special "Farm Viewer" role.
|
||||||
|
"""
|
||||||
|
return self._special_role(
|
||||||
|
session, UUID("06979649-ed32-7e97-8000-113ddf0ab5f3"), "Farm Viewer"
|
||||||
|
)
|
||||||
|
|
||||||
|
def authenticate_user(self, session, username, password):
|
||||||
|
"""
|
||||||
|
When authentication is attempted, this first will check
|
||||||
|
credentials against the app DB per normal logic. If that
|
||||||
|
succeeds, the result is no different from the typical
|
||||||
|
behavior.
|
||||||
|
|
||||||
|
If default logic fails, this will try to obtain an OAuth2
|
||||||
|
token from the farmOS site. If that succeeds, then a lookup
|
||||||
|
is done in the app DB for a matching user. If the user does
|
||||||
|
not yet exist it will be created automatically.
|
||||||
|
"""
|
||||||
|
if user := super().authenticate_user(session, username, password):
|
||||||
|
return user
|
||||||
|
|
||||||
|
if token := self.get_farmos_oauth2_token(username, password):
|
||||||
|
if user := self.get_or_make_farmos_user(session, username):
|
||||||
|
user.__dict__["farmos_oauth2_token"] = token
|
||||||
|
return user
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_farmos_oauth2_token(self, username, password):
|
||||||
|
url = self.app.get_farmos_url()
|
||||||
|
client = farmOS(url)
|
||||||
|
try:
|
||||||
|
return client.authorize(username=username, password=password)
|
||||||
|
except InvalidGrantError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_or_make_farmos_user(self, session, username):
|
||||||
|
model = self.app.model
|
||||||
|
try:
|
||||||
|
user = (
|
||||||
|
session.query(model.User).filter(model.User.username == username).one()
|
||||||
|
)
|
||||||
|
except orm.exc.NoResultFound:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
return user if user.active else None
|
||||||
|
|
||||||
|
# nb. prevent edit for farmOS mirrored user accounts
|
||||||
|
user = self.make_user(session, username=username, prevent_edit=True)
|
||||||
|
|
||||||
|
# TODO
|
||||||
|
manager = self.get_role_farm_manager(session)
|
||||||
|
user.roles.append(manager)
|
||||||
|
|
||||||
|
return user
|
||||||
|
|
@ -1,4 +1,24 @@
|
||||||
# -*- coding: utf-8; -*-
|
# -*- 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
|
WuttaFarm CLI
|
||||||
"""
|
"""
|
||||||
|
|
@ -9,22 +29,23 @@ from wuttjamaican.cli import make_typer
|
||||||
|
|
||||||
|
|
||||||
wuttafarm_typer = make_typer(
|
wuttafarm_typer = make_typer(
|
||||||
name='wuttafarm',
|
name="wuttafarm", help="WuttaFarm -- Web app to integrate with and extend farmOS"
|
||||||
help="WuttaFarm -- Web app to expose / extend farmOS"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@wuttafarm_typer.command()
|
@wuttafarm_typer.command()
|
||||||
def install(
|
def install(
|
||||||
ctx: typer.Context,
|
ctx: typer.Context,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Install the WuttaFarm app
|
Install the WuttaFarm app
|
||||||
"""
|
"""
|
||||||
config = ctx.parent.wutta_config
|
config = ctx.parent.wutta_config
|
||||||
app = config.get_app()
|
app = config.get_app()
|
||||||
install = app.get_install_handler(pkg_name='wuttafarm',
|
install = app.get_install_handler(
|
||||||
app_title="WuttaFarm",
|
pkg_name="wuttafarm",
|
||||||
pypi_name='WuttaFarm',
|
app_title="WuttaFarm",
|
||||||
egg_name='WuttaFarm')
|
pypi_name="WuttaFarm",
|
||||||
|
egg_name="WuttaFarm",
|
||||||
|
)
|
||||||
install.run()
|
install.run()
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,24 @@
|
||||||
# -*- coding: utf-8; -*-
|
# -*- 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 config extensions
|
WuttaFarm config extensions
|
||||||
"""
|
"""
|
||||||
|
|
@ -10,20 +30,28 @@ class WuttaFarmConfig(WuttaConfigExtension):
|
||||||
"""
|
"""
|
||||||
Config extension for WuttaFarm
|
Config extension for WuttaFarm
|
||||||
"""
|
"""
|
||||||
key = 'wuttafarm'
|
|
||||||
|
key = "wuttafarm"
|
||||||
|
|
||||||
def configure(self, config):
|
def configure(self, config):
|
||||||
|
|
||||||
# app info
|
# app info
|
||||||
config.setdefault(f'{config.appname}.app_title', "WuttaFarm")
|
config.setdefault(f"{config.appname}.app_title", "WuttaFarm")
|
||||||
config.setdefault(f'{config.appname}.app_dist', "WuttaFarm")
|
config.setdefault(f"{config.appname}.app_dist", "WuttaFarm")
|
||||||
|
|
||||||
# app model
|
# app model
|
||||||
config.setdefault(f'{config.appname}.model_spec', 'wuttafarm.db.model')
|
config.setdefault(f"{config.appname}.model_spec", "wuttafarm.db.model")
|
||||||
|
|
||||||
|
# app handler
|
||||||
|
config.setdefault(
|
||||||
|
f"{config.appname}.app.handler", "wuttafarm.app:WuttaFarmAppHandler"
|
||||||
|
)
|
||||||
|
|
||||||
# web app menu
|
# web app menu
|
||||||
config.setdefault(f'{config.appname}.web.menus.handler.spec',
|
config.setdefault(
|
||||||
'wuttafarm.web.menus:WuttaFarmMenuHandler')
|
f"{config.appname}.web.menus.handler.spec",
|
||||||
|
"wuttafarm.web.menus:WuttaFarmMenuHandler",
|
||||||
|
)
|
||||||
|
|
||||||
# web app libcache
|
# web app libcache
|
||||||
#config.setdefault('wuttaweb.static_libcache.module', 'wuttafarm.web.static')
|
# config.setdefault('wuttaweb.static_libcache.module', 'wuttafarm.web.static')
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,24 @@
|
||||||
# -*- coding: utf-8; -*-
|
# -*- 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 data models
|
WuttaFarm data models
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
57
src/wuttafarm/farmos.py
Normal file
57
src/wuttafarm/farmos.py
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
# -*- 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/>.
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
|
"""
|
||||||
|
farmOS integration handler
|
||||||
|
"""
|
||||||
|
|
||||||
|
from wuttjamaican.app import GenericHandler
|
||||||
|
|
||||||
|
|
||||||
|
class FarmOSHandler(GenericHandler):
|
||||||
|
"""
|
||||||
|
Base class and default implementation for the farmOS integration
|
||||||
|
:term:`handler`.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def get_farmos_url(self, path=None, require=True):
|
||||||
|
"""
|
||||||
|
Returns the base URL for farmOS, or one with ``path`` appended.
|
||||||
|
|
||||||
|
Note that if no path is provided, the final slash will be
|
||||||
|
stripped from the base URL.
|
||||||
|
|
||||||
|
:param path: Optional path to append to the base URL.
|
||||||
|
|
||||||
|
:param require: If true, an error is raised when base URL
|
||||||
|
cannot be determined.
|
||||||
|
|
||||||
|
:returns: URL string
|
||||||
|
"""
|
||||||
|
base = self.config.get("farmos.url.base", require=require)
|
||||||
|
if base:
|
||||||
|
base = base.rstrip("/")
|
||||||
|
|
||||||
|
if path:
|
||||||
|
path = path.lstrip("/")
|
||||||
|
return f"{base}/{path}"
|
||||||
|
|
||||||
|
return base
|
||||||
|
|
@ -1,4 +1,24 @@
|
||||||
# -*- coding: utf-8; -*-
|
# -*- 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 web app
|
WuttaFarm web app
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
0
src/wuttafarm/web/forms/__init__.py
Normal file
0
src/wuttafarm/web/forms/__init__.py
Normal file
47
src/wuttafarm/web/forms/widgets.py
Normal file
47
src/wuttafarm/web/forms/widgets.py
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
# -*- 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/>.
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
|
"""
|
||||||
|
Custom form widgets for WuttaFarm
|
||||||
|
"""
|
||||||
|
|
||||||
|
import colander
|
||||||
|
from deform.widget import Widget
|
||||||
|
from webhelpers2.html import HTML, tags
|
||||||
|
|
||||||
|
|
||||||
|
class AnimalImage(Widget):
|
||||||
|
"""
|
||||||
|
Widget to display an image URL for an animal.
|
||||||
|
|
||||||
|
TODO: this should be refactored to a more general name, once more
|
||||||
|
types of images need to be supported.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def serialize(self, field, cstruct, **kw):
|
||||||
|
readonly = kw.get("readonly", self.readonly)
|
||||||
|
if readonly:
|
||||||
|
if cstruct in (colander.null, None):
|
||||||
|
return HTML.tag("span")
|
||||||
|
|
||||||
|
return tags.image(cstruct, "animal image", **kw)
|
||||||
|
|
||||||
|
return super().serialize(field, cstruct, **kw)
|
||||||
|
|
@ -1,4 +1,24 @@
|
||||||
# -*- coding: utf-8; -*-
|
# -*- 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 Menu
|
WuttaFarm Menu
|
||||||
"""
|
"""
|
||||||
|
|
@ -12,30 +32,20 @@ class WuttaFarmMenuHandler(base.MenuHandler):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def make_menus(self, request, **kwargs):
|
def make_menus(self, request, **kwargs):
|
||||||
|
|
||||||
# nb. the products menu is just an example; you should
|
|
||||||
# replace it and add more as needed
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
self.make_products_menu(request),
|
self.make_farmos_menu(request),
|
||||||
self.make_admin_menu(request, include_people=True),
|
self.make_admin_menu(request, include_people=True),
|
||||||
]
|
]
|
||||||
|
|
||||||
def make_products_menu(self, request):
|
def make_farmos_menu(self, request):
|
||||||
return {
|
return {
|
||||||
"title": "Products",
|
"title": "farmOS",
|
||||||
"type": "menu",
|
"type": "menu",
|
||||||
"items": [
|
"items": [
|
||||||
{
|
{
|
||||||
"title": "Products",
|
"title": "Animals",
|
||||||
"route": "products",
|
"route": "farmos_animals",
|
||||||
"perm": "products.list",
|
"perm": "farmos_animals.list",
|
||||||
},
|
|
||||||
{'type': 'sep'},
|
|
||||||
{
|
|
||||||
"title": "Vendors",
|
|
||||||
"route": "vendors",
|
|
||||||
"perm": "vendors.list",
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,24 @@
|
||||||
# -*- coding: utf-8; -*-
|
# -*- 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/>.
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
"""
|
"""
|
||||||
Static assets
|
Static assets
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,24 @@
|
||||||
# -*- coding: utf-8; -*-
|
# -*- 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/>.
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
"""
|
"""
|
||||||
Pyramid event subscribers
|
Pyramid event subscribers
|
||||||
"""
|
"""
|
||||||
|
|
@ -8,9 +28,9 @@ import wuttafarm
|
||||||
|
|
||||||
def add_wuttafarm_to_context(event):
|
def add_wuttafarm_to_context(event):
|
||||||
renderer_globals = event
|
renderer_globals = event
|
||||||
renderer_globals['wuttafarm'] = wuttafarm
|
renderer_globals["wuttafarm"] = wuttafarm
|
||||||
|
|
||||||
|
|
||||||
def includeme(config):
|
def includeme(config):
|
||||||
config.include('wuttaweb.subscribers')
|
config.include("wuttaweb.subscribers")
|
||||||
config.add_subscriber(add_wuttafarm_to_context, 'pyramid.events.BeforeRender')
|
config.add_subscriber(add_wuttafarm_to_context, "pyramid.events.BeforeRender")
|
||||||
|
|
|
||||||
16
src/wuttafarm/web/templates/base.mako
Normal file
16
src/wuttafarm/web/templates/base.mako
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
<%inherit file="wuttaweb:templates/base.mako" />
|
||||||
|
|
||||||
|
<%def name="index_title_controls()">
|
||||||
|
${parent.index_title_controls()}
|
||||||
|
|
||||||
|
% if master is not Undefined and master.listing and farmos_refurl is not Undefined:
|
||||||
|
<b-button type="is-primary"
|
||||||
|
tag="a" target="_blank"
|
||||||
|
href="${farmos_refurl}"
|
||||||
|
icon-pack="fas"
|
||||||
|
icon-left="external-link-alt">
|
||||||
|
View in farmOS
|
||||||
|
</b-button>
|
||||||
|
% endif
|
||||||
|
|
||||||
|
</%def>
|
||||||
|
|
@ -1,13 +1,41 @@
|
||||||
# -*- coding: utf-8; -*-
|
# -*- 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 Views
|
WuttaFarm Views
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from wuttaweb.views import essential
|
||||||
|
|
||||||
|
|
||||||
def includeme(config):
|
def includeme(config):
|
||||||
|
|
||||||
# core views for wuttaweb
|
# wuttaweb core
|
||||||
config.include("wuttaweb.views.essential")
|
essential.defaults(
|
||||||
|
config,
|
||||||
|
**{
|
||||||
|
"wuttaweb.views.auth": "wuttafarm.web.views.auth",
|
||||||
|
"wuttaweb.views.common": "wuttafarm.web.views.common",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
# TODO: include your own views here
|
# views for farmOS
|
||||||
# config.include('wuttafarm.web.views.widgets')
|
config.include("wuttafarm.web.views.farmos")
|
||||||
|
|
|
||||||
58
src/wuttafarm/web/views/auth.py
Normal file
58
src/wuttafarm/web/views/auth.py
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
# -*- 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/>.
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
|
"""
|
||||||
|
Auth views
|
||||||
|
"""
|
||||||
|
|
||||||
|
from wuttaweb.views import auth as base
|
||||||
|
|
||||||
|
|
||||||
|
class AuthView(base.AuthView):
|
||||||
|
"""
|
||||||
|
Auth views
|
||||||
|
"""
|
||||||
|
|
||||||
|
def authenticate_user(self, session, username, password):
|
||||||
|
if user := super().authenticate_user(session, username, password):
|
||||||
|
|
||||||
|
# nb. auth handler will stash the farmOS oauth2 token in
|
||||||
|
# the user object, if applicable (i.e. unless the user
|
||||||
|
# authenticated normally via the app DB). when a token is
|
||||||
|
# involved we need to put that in the user's web session.
|
||||||
|
if "farmos_oauth2_token" in user.__dict__:
|
||||||
|
self.request.session["farmos.oauth2.token"] = user.__dict__.pop(
|
||||||
|
"farmos_oauth2_token"
|
||||||
|
)
|
||||||
|
|
||||||
|
return user
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def defaults(config, **kwargs):
|
||||||
|
local = globals()
|
||||||
|
AuthView = kwargs.get("AuthView", local["AuthView"])
|
||||||
|
base.defaults(config, **{"AuthView": AuthView})
|
||||||
|
|
||||||
|
|
||||||
|
def includeme(config):
|
||||||
|
defaults(config)
|
||||||
65
src/wuttafarm/web/views/common.py
Normal file
65
src/wuttafarm/web/views/common.py
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
# -*- 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/>.
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
|
"""
|
||||||
|
Common views
|
||||||
|
"""
|
||||||
|
|
||||||
|
from wuttaweb.views import common as base
|
||||||
|
|
||||||
|
|
||||||
|
class CommonView(base.CommonView):
|
||||||
|
"""
|
||||||
|
Common views
|
||||||
|
"""
|
||||||
|
|
||||||
|
def setup_enhance_admin_user(self, user):
|
||||||
|
""" """
|
||||||
|
model = self.app.model
|
||||||
|
session = self.app.get_session(user)
|
||||||
|
auth = self.app.get_auth_handler()
|
||||||
|
|
||||||
|
# initialize built-in roles
|
||||||
|
farm_manager = auth.get_role_farm_manager(session)
|
||||||
|
farm_manager.notes = "this is meant to mirror the corresponding role in farmOS"
|
||||||
|
farm_worker = auth.get_role_farm_worker(session)
|
||||||
|
farm_worker.notes = "this is meant to mirror the corresponding role in farmOS"
|
||||||
|
farm_viewer = auth.get_role_farm_viewer(session)
|
||||||
|
farm_viewer.notes = "this is meant to mirror the corresponding role in farmOS"
|
||||||
|
|
||||||
|
site_admin = session.query(model.Role).filter_by(name="Site Admin").first()
|
||||||
|
if site_admin:
|
||||||
|
site_admin_perms = [
|
||||||
|
"farmos_animals.list",
|
||||||
|
"farmos_animals.view",
|
||||||
|
]
|
||||||
|
for perm in site_admin_perms:
|
||||||
|
auth.grant_permission(site_admin, perm)
|
||||||
|
|
||||||
|
|
||||||
|
def defaults(config, **kwargs):
|
||||||
|
local = globals()
|
||||||
|
CommonView = kwargs.get("CommonView", local["CommonView"])
|
||||||
|
base.defaults(config, **{"CommonView": CommonView})
|
||||||
|
|
||||||
|
|
||||||
|
def includeme(config):
|
||||||
|
defaults(config)
|
||||||
30
src/wuttafarm/web/views/farmos/__init__.py
Normal file
30
src/wuttafarm/web/views/farmos/__init__.py
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
# -*- 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 to expose farmOS data directly
|
||||||
|
"""
|
||||||
|
|
||||||
|
from .master import FarmOSMasterView
|
||||||
|
|
||||||
|
|
||||||
|
def includeme(config):
|
||||||
|
config.include("wuttafarm.web.views.farmos.animals")
|
||||||
171
src/wuttafarm/web/views/farmos/animals.py
Normal file
171
src/wuttafarm/web/views/farmos/animals.py
Normal file
|
|
@ -0,0 +1,171 @@
|
||||||
|
# -*- 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 Farm Animals
|
||||||
|
"""
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
from farmOS import farmOS
|
||||||
|
|
||||||
|
from wuttafarm.web.views.farmos import FarmOSMasterView
|
||||||
|
from wuttafarm.web.forms.widgets import AnimalImage
|
||||||
|
|
||||||
|
|
||||||
|
class AnimalView(FarmOSMasterView):
|
||||||
|
"""
|
||||||
|
Master view for Farm Animals
|
||||||
|
"""
|
||||||
|
|
||||||
|
model_name = "farmos_animal"
|
||||||
|
model_title = "farmOS Animal"
|
||||||
|
model_title_plural = "farmOS Animals"
|
||||||
|
|
||||||
|
route_prefix = "farmos_animals"
|
||||||
|
url_prefix = "/farmOS/animals"
|
||||||
|
|
||||||
|
farmos_refurl_path = "/assets/animal"
|
||||||
|
|
||||||
|
labels = {
|
||||||
|
"species_breed": "Species / Breed",
|
||||||
|
"raw_image_url": "Raw Image URL",
|
||||||
|
"large_image_url": "Large Image URL",
|
||||||
|
"thumbnail_image_url": "Thumbnail Image URL",
|
||||||
|
}
|
||||||
|
|
||||||
|
grid_columns = [
|
||||||
|
"name",
|
||||||
|
"species_breed",
|
||||||
|
"birthdate",
|
||||||
|
"sex",
|
||||||
|
"location",
|
||||||
|
]
|
||||||
|
|
||||||
|
sort_defaults = "name"
|
||||||
|
|
||||||
|
form_fields = [
|
||||||
|
"name",
|
||||||
|
"species_breed",
|
||||||
|
"birthdate",
|
||||||
|
"sex",
|
||||||
|
"location",
|
||||||
|
"raw_image_url",
|
||||||
|
"large_image_url",
|
||||||
|
"thumbnail_image_url",
|
||||||
|
"image",
|
||||||
|
]
|
||||||
|
|
||||||
|
def get_grid_data(self, columns=None, session=None):
|
||||||
|
animals = self.farmos_client.resource.get("asset", "animal")
|
||||||
|
return [self.normalize_animal(a) for a in animals["data"]]
|
||||||
|
|
||||||
|
def configure_grid(self, grid):
|
||||||
|
g = grid
|
||||||
|
super().configure_grid(g)
|
||||||
|
|
||||||
|
# name
|
||||||
|
g.set_link("name")
|
||||||
|
g.set_searchable("name")
|
||||||
|
|
||||||
|
# birthdate
|
||||||
|
g.set_renderer("birthdate", "date")
|
||||||
|
|
||||||
|
def get_instance(self):
|
||||||
|
|
||||||
|
animal = self.farmos_client.resource.get_id(
|
||||||
|
"asset", "animal", self.request.matchdict["uuid"]
|
||||||
|
)
|
||||||
|
|
||||||
|
# instance data
|
||||||
|
data = self.normalize_animal(animal["data"])
|
||||||
|
|
||||||
|
# add image_url
|
||||||
|
if relationships := animal["data"].get("relationships"):
|
||||||
|
if image := relationships.get("image"):
|
||||||
|
if image["data"]:
|
||||||
|
image = self.farmos_client.resource.get_id(
|
||||||
|
"file", "file", image["data"][0]["id"]
|
||||||
|
)
|
||||||
|
data["raw_image_url"] = self.app.get_farmos_url(
|
||||||
|
image["data"]["attributes"]["uri"]["url"]
|
||||||
|
)
|
||||||
|
# nb. other styles available: medium, wide
|
||||||
|
data["large_image_url"] = image["data"]["attributes"][
|
||||||
|
"image_style_uri"
|
||||||
|
]["large"]
|
||||||
|
data["thumbnail_image_url"] = image["data"]["attributes"][
|
||||||
|
"image_style_uri"
|
||||||
|
]["thumbnail"]
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
def get_instance_title(self, animal):
|
||||||
|
return animal["name"]
|
||||||
|
|
||||||
|
def normalize_animal(self, animal):
|
||||||
|
|
||||||
|
birthdate = animal["attributes"]["birthdate"]
|
||||||
|
if birthdate:
|
||||||
|
birthdate = datetime.datetime.fromisoformat(birthdate)
|
||||||
|
birthdate = self.app.localtime(birthdate)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"uuid": animal["id"],
|
||||||
|
"drupal_internal_id": animal["attributes"]["drupal_internal__id"],
|
||||||
|
"name": animal["attributes"]["name"],
|
||||||
|
"species_breed": "", # TODO
|
||||||
|
"birthdate": birthdate,
|
||||||
|
"sex": animal["attributes"]["sex"],
|
||||||
|
"location": "", # TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
def configure_form(self, form):
|
||||||
|
f = form
|
||||||
|
super().configure_form(f)
|
||||||
|
animal = f.model_instance
|
||||||
|
|
||||||
|
# image
|
||||||
|
if url := animal.get("large_image_url"):
|
||||||
|
f.set_widget("image", AnimalImage())
|
||||||
|
f.set_default("image", url)
|
||||||
|
|
||||||
|
def get_xref_buttons(self, animal):
|
||||||
|
return [
|
||||||
|
self.make_button(
|
||||||
|
"View in farmOS",
|
||||||
|
primary=True,
|
||||||
|
url=self.app.get_farmos_url(f"/asset/{animal['drupal_internal_id']}"),
|
||||||
|
target="_blank",
|
||||||
|
icon_left="external-link-alt",
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def defaults(config, **kwargs):
|
||||||
|
base = globals()
|
||||||
|
|
||||||
|
AnimalView = kwargs.get("AnimalView", base["AnimalView"])
|
||||||
|
AnimalView.defaults(config)
|
||||||
|
|
||||||
|
|
||||||
|
def includeme(config):
|
||||||
|
defaults(config)
|
||||||
65
src/wuttafarm/web/views/farmos/master.py
Normal file
65
src/wuttafarm/web/views/farmos/master.py
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
# -*- 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 farmOS master views
|
||||||
|
"""
|
||||||
|
|
||||||
|
from farmOS import farmOS
|
||||||
|
|
||||||
|
from wuttaweb.views import MasterView
|
||||||
|
|
||||||
|
|
||||||
|
class FarmOSMasterView(MasterView):
|
||||||
|
"""
|
||||||
|
Base class for farmOS master views
|
||||||
|
"""
|
||||||
|
|
||||||
|
model_key = "uuid"
|
||||||
|
|
||||||
|
creatable = False
|
||||||
|
editable = False
|
||||||
|
deletable = False
|
||||||
|
|
||||||
|
filterable = False
|
||||||
|
sort_on_backend = False
|
||||||
|
paginate_on_backend = False
|
||||||
|
|
||||||
|
farmos_refurl_path = None
|
||||||
|
|
||||||
|
def __init__(self, request, context=None):
|
||||||
|
super().__init__(request, context=context)
|
||||||
|
self.farmos_client = self.get_farmos_client()
|
||||||
|
|
||||||
|
def get_farmos_client(self):
|
||||||
|
token = self.request.session.get("farmos.oauth2.token")
|
||||||
|
if not token:
|
||||||
|
raise self.forbidden()
|
||||||
|
|
||||||
|
url = self.app.get_farmos_url()
|
||||||
|
return farmOS(url, token=token)
|
||||||
|
|
||||||
|
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
|
||||||
24
tasks.py
Normal file
24
tasks.py
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
# -*- coding: utf-8; -*-
|
||||||
|
"""
|
||||||
|
Tasks for WuttaFarm
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
from invoke import task
|
||||||
|
|
||||||
|
|
||||||
|
@task
|
||||||
|
def release(c, skip_tests=False):
|
||||||
|
"""
|
||||||
|
Release a new version of WuttaFarm
|
||||||
|
"""
|
||||||
|
if not skip_tests:
|
||||||
|
c.run("pytest")
|
||||||
|
|
||||||
|
if os.path.exists("dist"):
|
||||||
|
shutil.rmtree("dist")
|
||||||
|
|
||||||
|
c.run("python -m build --sdist")
|
||||||
|
c.run("twine upload dist/*")
|
||||||
Loading…
Add table
Add a link
Reference in a new issue