diff --git a/src/wuttafarm/web/util.py b/src/wuttafarm/web/util.py new file mode 100644 index 0000000..65d637d --- /dev/null +++ b/src/wuttafarm/web/util.py @@ -0,0 +1,40 @@ +# -*- 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 . +# +################################################################################ +""" +Misc. utilities for web app +""" + + +def save_farmos_oauth2_token(request, token): + """ + Common logic for saving the given OAuth2 token within the user + session. This function is called from 2 places: + + * :meth:`wuttafarm.web.views.auth.farmos_oauth_callback()` + * :meth:`wuttafarm.web.views.farmos.master.FarmOSMasterView.get_farmos_client()` + """ + # nb. we pretend the token expires 1 minute early, to avoid edge + # cases around token refresh + token["expires_at"] -= 60 + + # save token to user session + request.session["farmos.oauth2.token"] = token diff --git a/src/wuttafarm/web/views/auth.py b/src/wuttafarm/web/views/auth.py index 77e9f20..db757cc 100644 --- a/src/wuttafarm/web/views/auth.py +++ b/src/wuttafarm/web/views/auth.py @@ -30,6 +30,8 @@ from wuttaweb.views import auth as base from wuttaweb.auth import login_user from wuttaweb.db import Session +from wuttafarm.web.util import save_farmos_oauth2_token + class AuthView(base.AuthView): """ @@ -91,7 +93,13 @@ class AuthView(base.AuthView): return self.redirect(self.request.route_url("login")) # save token in user session - self.request.session["farmos.oauth2.token"] = token + save_farmos_oauth2_token(self.request, token) + + # nb. must give a *copy* of the token to farmOS client, since + # it will mutate it in-place and we don't want that to happen + # for our original copy in the user session. (otherwise the + # auto-refresh will not work correctly for subsequent calls.) + token = dict(token) # get (or create) native app user farmos_client = self.app.get_farmos_client(token=token) diff --git a/src/wuttafarm/web/views/farmos/master.py b/src/wuttafarm/web/views/farmos/master.py index d653418..eed04d1 100644 --- a/src/wuttafarm/web/views/farmos/master.py +++ b/src/wuttafarm/web/views/farmos/master.py @@ -25,6 +25,8 @@ Base class for farmOS master views from wuttaweb.views import MasterView +from wuttafarm.web.util import save_farmos_oauth2_token + class FarmOSMasterView(MasterView): """ @@ -52,15 +54,15 @@ class FarmOSMasterView(MasterView): if not token: raise self.forbidden() - def token_updater(token): - self.request.session["farmos.oauth2.token"] = token - # nb. must give a *copy* of the token to farmOS client, since # it will mutate it in-place and we don't want that to happen # for our original copy in the user session. (otherwise the # auto-refresh will not work correctly for subsequent calls.) token = dict(token) + def token_updater(token): + save_farmos_oauth2_token(self.request, token) + return self.app.get_farmos_client(token=token, token_updater=token_updater) def get_template_context(self, context):