feat: add initial views for upgrades
CRUD only so far, still need execute features
This commit is contained in:
parent
1804e74d13
commit
6650ee698e
|
@ -32,4 +32,5 @@
|
|||
views.people
|
||||
views.roles
|
||||
views.settings
|
||||
views.upgrades
|
||||
views.users
|
||||
|
|
6
docs/api/wuttaweb/views.upgrades.rst
Normal file
6
docs/api/wuttaweb/views.upgrades.rst
Normal file
|
@ -0,0 +1,6 @@
|
|||
|
||||
``wuttaweb.views.upgrades``
|
||||
===========================
|
||||
|
||||
.. automodule:: wuttaweb.views.upgrades
|
||||
:members:
|
|
@ -92,6 +92,53 @@ class ObjectNode(colander.SchemaNode):
|
|||
raise NotImplementedError(f"you must define {class_name}.objectify()")
|
||||
|
||||
|
||||
class WuttaEnum(colander.Enum):
|
||||
"""
|
||||
Custom schema type for enum fields.
|
||||
|
||||
This is a subclass of :class:`colander.Enum`, but adds a
|
||||
default widget (``SelectWidget``) with enum choices.
|
||||
|
||||
:param request: Current :term:`request` object.
|
||||
"""
|
||||
|
||||
def __init__(self, request, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.request = request
|
||||
self.config = self.request.wutta_config
|
||||
self.app = self.config.get_app()
|
||||
|
||||
def widget_maker(self, **kwargs):
|
||||
""" """
|
||||
|
||||
if 'values' not in kwargs:
|
||||
kwargs['values'] = [(getattr(e, self.attr), getattr(e, self.attr))
|
||||
for e in self.enum_cls]
|
||||
|
||||
return widgets.SelectWidget(**kwargs)
|
||||
|
||||
|
||||
class WuttaSet(colander.Set):
|
||||
"""
|
||||
Custom schema type for :class:`python:set` fields.
|
||||
|
||||
This is a subclass of :class:`colander.Set`, but adds
|
||||
Wutta-related params to the constructor.
|
||||
|
||||
:param request: Current :term:`request` object.
|
||||
|
||||
:param session: Optional :term:`db session` to use instead of
|
||||
:class:`wuttaweb.db.Session`.
|
||||
"""
|
||||
|
||||
def __init__(self, request, session=None):
|
||||
super().__init__()
|
||||
self.request = request
|
||||
self.config = self.request.wutta_config
|
||||
self.app = self.config.get_app()
|
||||
self.session = session or Session()
|
||||
|
||||
|
||||
class ObjectRef(colander.SchemaType):
|
||||
"""
|
||||
Custom schema type for a model class reference field.
|
||||
|
@ -199,7 +246,7 @@ class ObjectRef(colander.SchemaType):
|
|||
|
||||
# fetch object from DB
|
||||
model = self.app.model
|
||||
obj = self.session.query(self.model_class).get(value)
|
||||
obj = self.session.get(self.model_class, value)
|
||||
|
||||
# raise error if not found
|
||||
if not obj:
|
||||
|
@ -247,14 +294,28 @@ class ObjectRef(colander.SchemaType):
|
|||
kwargs['values'] = values
|
||||
|
||||
if 'url' not in kwargs:
|
||||
kwargs['url'] = lambda person: self.request.route_url('people.view', uuid=person.uuid)
|
||||
kwargs['url'] = self.get_object_url
|
||||
|
||||
return widgets.ObjectRefWidget(self.request, **kwargs)
|
||||
|
||||
def get_object_url(self, obj):
|
||||
"""
|
||||
Returns the "view" URL for the given object, if applicable.
|
||||
|
||||
This is used when rendering the field readonly. If this
|
||||
method returns a URL then the field text will be wrapped with
|
||||
a hyperlink, otherwise it will be shown as-is.
|
||||
|
||||
Default logic always returns ``None``; subclass should
|
||||
override as needed.
|
||||
"""
|
||||
|
||||
|
||||
class PersonRef(ObjectRef):
|
||||
"""
|
||||
Custom schema type for a ``Person`` reference field.
|
||||
Custom schema type for a
|
||||
:class:`~wuttjamaican:wuttjamaican.db.model.base.Person` reference
|
||||
field.
|
||||
|
||||
This is a subclass of :class:`ObjectRef`.
|
||||
"""
|
||||
|
@ -269,26 +330,33 @@ class PersonRef(ObjectRef):
|
|||
""" """
|
||||
return query.order_by(self.model_class.full_name)
|
||||
|
||||
def get_object_url(self, person):
|
||||
""" """
|
||||
return self.request.route_url('people.view', uuid=person.uuid)
|
||||
|
||||
class WuttaSet(colander.Set):
|
||||
|
||||
class UserRef(ObjectRef):
|
||||
"""
|
||||
Custom schema type for :class:`python:set` fields.
|
||||
Custom schema type for a
|
||||
:class:`~wuttjamaican:wuttjamaican.db.model.auth.User` reference
|
||||
field.
|
||||
|
||||
This is a subclass of :class:`colander.Set`, but adds
|
||||
Wutta-related params to the constructor.
|
||||
|
||||
:param request: Current :term:`request` object.
|
||||
|
||||
:param session: Optional :term:`db session` to use instead of
|
||||
:class:`wuttaweb.db.Session`.
|
||||
This is a subclass of :class:`ObjectRef`.
|
||||
"""
|
||||
|
||||
def __init__(self, request, session=None):
|
||||
super().__init__()
|
||||
self.request = request
|
||||
self.config = self.request.wutta_config
|
||||
self.app = self.config.get_app()
|
||||
self.session = session or Session()
|
||||
@property
|
||||
def model_class(self):
|
||||
""" """
|
||||
model = self.app.model
|
||||
return model.User
|
||||
|
||||
def sort_query(self, query):
|
||||
""" """
|
||||
return query.order_by(self.model_class.username)
|
||||
|
||||
def get_object_url(self, user):
|
||||
""" """
|
||||
return self.request.route_url('users.view', uuid=user.uuid)
|
||||
|
||||
|
||||
class RoleRefs(WuttaSet):
|
||||
|
|
|
@ -1078,6 +1078,7 @@ class Grid:
|
|||
:returns: A :class:`~wuttaweb.grids.filters.GridFilter`
|
||||
instance.
|
||||
"""
|
||||
key = kwargs.pop('key', None)
|
||||
|
||||
# model_property is required
|
||||
model_property = None
|
||||
|
@ -1102,7 +1103,7 @@ class Grid:
|
|||
|
||||
# make filter
|
||||
kwargs['model_property'] = model_property
|
||||
return factory(self.request, model_property.key, **kwargs)
|
||||
return factory(self.request, key or model_property.key, **kwargs)
|
||||
|
||||
def set_filter(self, key, filterinfo=None, **kwargs):
|
||||
"""
|
||||
|
@ -1132,6 +1133,7 @@ class Grid:
|
|||
# filtr = filterinfo
|
||||
raise NotImplementedError
|
||||
else:
|
||||
kwargs['key'] = key
|
||||
kwargs.setdefault('label', self.get_label(key))
|
||||
filtr = self.make_filter(filterinfo or key, **kwargs)
|
||||
|
||||
|
|
|
@ -168,6 +168,11 @@ class MenuHandler(GenericHandler):
|
|||
'route': 'settings',
|
||||
'perm': 'settings.list',
|
||||
},
|
||||
{
|
||||
'title': "Upgrades",
|
||||
'route': 'upgrades',
|
||||
'perm': 'upgrades.list',
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
|
|
|
@ -83,6 +83,32 @@ class FieldList(list):
|
|||
field, newfield)
|
||||
self.append(newfield)
|
||||
|
||||
def set_sequence(self, fields):
|
||||
"""
|
||||
Sort the list such that it matches the same sequence as the
|
||||
given fields list.
|
||||
|
||||
This does not add or remove any elements, it just
|
||||
(potentially) rearranges the internal list elements.
|
||||
Therefore you do not need to explicitly declare *all* fields;
|
||||
just the ones you care about.
|
||||
|
||||
The resulting field list will have the requested fields in
|
||||
order, at the *beginning* of the list. Any unrequested fields
|
||||
will remain in the same order as they were previously, but
|
||||
will be placed *after* the requested fields.
|
||||
|
||||
:param fields: List of fields in the desired order.
|
||||
"""
|
||||
unimportant = len(self) + 1
|
||||
|
||||
def getkey(field):
|
||||
if field in fields:
|
||||
return fields.index(field)
|
||||
return unimportant
|
||||
|
||||
self.sort(key=getkey)
|
||||
|
||||
|
||||
def get_form_data(request):
|
||||
"""
|
||||
|
|
|
@ -154,6 +154,11 @@ class CommonView(View):
|
|||
'settings.view',
|
||||
'settings.edit',
|
||||
'settings.delete',
|
||||
'upgrades.list',
|
||||
'upgrades.create',
|
||||
'upgrades.view',
|
||||
'upgrades.edit',
|
||||
'upgrades.delete',
|
||||
'users.list',
|
||||
'users.create',
|
||||
'users.view',
|
||||
|
|
|
@ -35,6 +35,7 @@ That will in turn include the following modules:
|
|||
* :mod:`wuttaweb.views.people`
|
||||
* :mod:`wuttaweb.views.roles`
|
||||
* :mod:`wuttaweb.views.users`
|
||||
* :mod:`wuttaweb.views.upgrades`
|
||||
"""
|
||||
|
||||
|
||||
|
@ -47,6 +48,7 @@ def defaults(config, **kwargs):
|
|||
config.include(mod('wuttaweb.views.people'))
|
||||
config.include(mod('wuttaweb.views.roles'))
|
||||
config.include(mod('wuttaweb.views.users'))
|
||||
config.include(mod('wuttaweb.views.upgrades'))
|
||||
|
||||
|
||||
def includeme(config):
|
||||
|
|
|
@ -1040,6 +1040,56 @@ class MasterView(View):
|
|||
fmt = f"${{:0,.{scale}f}}"
|
||||
return fmt.format(value)
|
||||
|
||||
def grid_render_datetime(self, record, key, value, fmt=None):
|
||||
"""
|
||||
Custom grid value renderer for
|
||||
:class:`~python:datetime.datetime` fields.
|
||||
|
||||
:param fmt: Optional format string to use instead of the
|
||||
default: ``'%Y-%m-%d %I:%M:%S %p'``
|
||||
|
||||
To use this feature for your grid::
|
||||
|
||||
grid.set_renderer('my_datetime_field', self.grid_render_datetime)
|
||||
|
||||
# you can also override format
|
||||
grid.set_renderer('my_datetime_field', self.grid_render_datetime,
|
||||
fmt='%Y-%m-%d %H:%M:%S')
|
||||
"""
|
||||
# nb. get new value since the one provided will just be a
|
||||
# (json-safe) *string* if the original type was datetime
|
||||
value = record[key]
|
||||
|
||||
if value is None:
|
||||
return
|
||||
|
||||
return value.strftime(fmt or '%Y-%m-%d %I:%M:%S %p')
|
||||
|
||||
def grid_render_enum(self, record, key, value, enum=None):
|
||||
"""
|
||||
Custom grid value renderer for "enum" fields.
|
||||
|
||||
:param enum: Enum class for the field. This should be an
|
||||
instance of :class:`~python:enum.Enum`.
|
||||
|
||||
To use this feature for your grid::
|
||||
|
||||
from enum import Enum
|
||||
|
||||
class MyEnum(Enum):
|
||||
ONE = 1
|
||||
TWO = 2
|
||||
THREE = 3
|
||||
|
||||
grid.set_renderer('my_enum_field', self.grid_render_enum, enum=MyEnum)
|
||||
"""
|
||||
if enum:
|
||||
original = record[key]
|
||||
if original:
|
||||
return original.name
|
||||
|
||||
return value
|
||||
|
||||
def grid_render_notes(self, record, key, value, maxlen=100):
|
||||
"""
|
||||
Custom grid value renderer for "notes" fields.
|
||||
|
|
187
src/wuttaweb/views/upgrades.py
Normal file
187
src/wuttaweb/views/upgrades.py
Normal file
|
@ -0,0 +1,187 @@
|
|||
# -*- coding: utf-8; -*-
|
||||
################################################################################
|
||||
#
|
||||
# wuttaweb -- Web App for Wutta Framework
|
||||
# Copyright © 2024 Lance Edgar
|
||||
#
|
||||
# This file is part of Wutta Framework.
|
||||
#
|
||||
# Wutta Framework 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.
|
||||
#
|
||||
# Wutta Framework 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
|
||||
# Wutta Framework. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
Upgrade Views
|
||||
"""
|
||||
|
||||
from sqlalchemy import orm
|
||||
|
||||
from wuttjamaican.db.model import Upgrade
|
||||
from wuttaweb.views import MasterView
|
||||
from wuttaweb.forms import widgets
|
||||
from wuttaweb.forms.schema import UserRef, WuttaEnum
|
||||
|
||||
|
||||
class UpgradeView(MasterView):
|
||||
"""
|
||||
Master view for upgrades.
|
||||
|
||||
Default route prefix is ``upgrades``.
|
||||
|
||||
Notable URLs provided by this class:
|
||||
|
||||
* ``/upgrades/``
|
||||
* ``/upgrades/new``
|
||||
* ``/upgrades/XXX``
|
||||
* ``/upgrades/XXX/edit``
|
||||
* ``/upgrades/XXX/delete``
|
||||
"""
|
||||
model_class = Upgrade
|
||||
|
||||
grid_columns = [
|
||||
'created',
|
||||
'description',
|
||||
'status',
|
||||
'executed',
|
||||
'executed_by',
|
||||
]
|
||||
|
||||
sort_defaults = ('created', 'desc')
|
||||
|
||||
def configure_grid(self, g):
|
||||
""" """
|
||||
super().configure_grid(g)
|
||||
model = self.app.model
|
||||
enum = self.app.enum
|
||||
|
||||
# description
|
||||
g.set_link('description')
|
||||
|
||||
# created
|
||||
g.set_renderer('created', self.grid_render_datetime)
|
||||
|
||||
# created_by
|
||||
g.set_link('created_by')
|
||||
Creator = orm.aliased(model.User)
|
||||
g.set_joiner('created_by', lambda q: q.join(Creator,
|
||||
Creator.uuid == model.Upgrade.created_by_uuid))
|
||||
g.set_filter('created_by', Creator.username,
|
||||
label="Created By Username")
|
||||
|
||||
# status
|
||||
g.set_renderer('status', self.grid_render_enum, enum=enum.UpgradeStatus)
|
||||
|
||||
# executed_by
|
||||
g.set_link('executed_by')
|
||||
Executor = orm.aliased(model.User)
|
||||
g.set_joiner('executed_by', lambda q: q.outerjoin(Executor,
|
||||
Executor.uuid == model.Upgrade.executed_by_uuid))
|
||||
g.set_filter('executed_by', Executor.username,
|
||||
label="Executed By Username")
|
||||
|
||||
def grid_row_class(self, upgrade, data, i):
|
||||
""" """
|
||||
enum = self.app.enum
|
||||
if upgrade.status == enum.UpgradeStatus.EXECUTING:
|
||||
return 'has-background-warning'
|
||||
if upgrade.status == enum.UpgradeStatus.FAILURE:
|
||||
return 'has-background-warning'
|
||||
|
||||
def configure_form(self, f):
|
||||
""" """
|
||||
super().configure_form(f)
|
||||
enum = self.app.enum
|
||||
upgrade = f.model_instance
|
||||
|
||||
# never show these
|
||||
f.remove('created_by_uuid',
|
||||
'executing',
|
||||
'executed_by_uuid')
|
||||
|
||||
# sequence sanity
|
||||
f.fields.set_sequence([
|
||||
'description',
|
||||
'notes',
|
||||
'status',
|
||||
'created',
|
||||
'created_by',
|
||||
'executed',
|
||||
'executed_by',
|
||||
])
|
||||
|
||||
# created
|
||||
if self.creating or self.editing:
|
||||
f.remove('created')
|
||||
|
||||
# created_by
|
||||
if self.creating or self.editing:
|
||||
f.remove('created_by')
|
||||
else:
|
||||
f.set_node('created_by', UserRef(self.request))
|
||||
|
||||
# notes
|
||||
f.set_widget('notes', widgets.NotesWidget())
|
||||
|
||||
# status
|
||||
if self.creating:
|
||||
f.remove('status')
|
||||
else:
|
||||
f.set_node('status', WuttaEnum(self.request, enum.UpgradeStatus))
|
||||
|
||||
# exit_code
|
||||
if self.creating or not upgrade.executed:
|
||||
f.remove('exit_code')
|
||||
|
||||
# executed
|
||||
if self.creating or self.editing or not upgrade.executed:
|
||||
f.remove('executed')
|
||||
|
||||
# executed_by
|
||||
if self.creating or self.editing or not upgrade.executed:
|
||||
f.remove('executed_by')
|
||||
else:
|
||||
f.set_node('executed_by', UserRef(self.request))
|
||||
|
||||
def objectify(self, form):
|
||||
""" """
|
||||
upgrade = super().objectify(form)
|
||||
enum = self.app.enum
|
||||
|
||||
# set user, status when creating
|
||||
if self.creating:
|
||||
upgrade.created_by = self.request.user
|
||||
upgrade.status = enum.UpgradeStatus.PENDING
|
||||
|
||||
return upgrade
|
||||
|
||||
@classmethod
|
||||
def defaults(cls, config):
|
||||
""" """
|
||||
|
||||
# nb. Upgrade may come from custom model
|
||||
wutta_config = config.registry.settings['wutta_config']
|
||||
app = wutta_config.get_app()
|
||||
cls.model_class = app.model.Upgrade
|
||||
|
||||
cls._defaults(config)
|
||||
|
||||
|
||||
def defaults(config, **kwargs):
|
||||
base = globals()
|
||||
|
||||
UpgradeView = kwargs.get('UpgradeView', base['UpgradeView'])
|
||||
UpgradeView.defaults(config)
|
||||
|
||||
|
||||
def includeme(config):
|
||||
defaults(config)
|
|
@ -10,7 +10,7 @@ from sqlalchemy import orm
|
|||
from wuttjamaican.conf import WuttaConfig
|
||||
from wuttaweb.forms import schema as mod
|
||||
from wuttaweb.forms import widgets
|
||||
from tests.util import DataTestCase
|
||||
from tests.util import DataTestCase, WebTestCase
|
||||
|
||||
|
||||
class TestObjectNode(DataTestCase):
|
||||
|
@ -47,6 +47,15 @@ class TestObjectNode(DataTestCase):
|
|||
self.assertIs(value, person)
|
||||
|
||||
|
||||
class TestWuttaEnum(WebTestCase):
|
||||
|
||||
def test_widget_maker(self):
|
||||
enum = self.app.enum
|
||||
typ = mod.WuttaEnum(self.request, enum.UpgradeStatus)
|
||||
widget = typ.widget_maker()
|
||||
self.assertIsInstance(widget, widgets.SelectWidget)
|
||||
|
||||
|
||||
class TestObjectRef(DataTestCase):
|
||||
|
||||
def setUp(self):
|
||||
|
@ -140,10 +149,17 @@ class TestObjectRef(DataTestCase):
|
|||
self.session.commit()
|
||||
self.assertIsNotNone(person.uuid)
|
||||
with patch.object(mod.ObjectRef, 'model_class', new=model.Person):
|
||||
|
||||
# can specify as uuid
|
||||
typ = mod.ObjectRef(self.request, session=self.session)
|
||||
value = typ.objectify(person.uuid)
|
||||
self.assertIs(value, person)
|
||||
|
||||
# or can specify object proper
|
||||
typ = mod.ObjectRef(self.request, session=self.session)
|
||||
value = typ.objectify(person)
|
||||
self.assertIs(value, person)
|
||||
|
||||
# error if not found
|
||||
with patch.object(mod.ObjectRef, 'model_class', new=model.Person):
|
||||
typ = mod.ObjectRef(self.request, session=self.session)
|
||||
|
@ -186,11 +202,7 @@ class TestObjectRef(DataTestCase):
|
|||
self.assertEqual(widget.values[1][1], "Betty Boop")
|
||||
|
||||
|
||||
class TestPersonRef(DataTestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.setup_db()
|
||||
self.request = testing.DummyRequest(wutta_config=self.config)
|
||||
class TestPersonRef(WebTestCase):
|
||||
|
||||
def test_sort_query(self):
|
||||
typ = mod.PersonRef(self.request, session=self.session)
|
||||
|
@ -200,6 +212,43 @@ class TestPersonRef(DataTestCase):
|
|||
self.assertIsInstance(sorted_query, orm.Query)
|
||||
self.assertIsNot(sorted_query, query)
|
||||
|
||||
def test_get_object_url(self):
|
||||
self.pyramid_config.add_route('people.view', '/people/{uuid}')
|
||||
model = self.app.model
|
||||
typ = mod.PersonRef(self.request, session=self.session)
|
||||
|
||||
person = model.Person(full_name="Barney Rubble")
|
||||
self.session.add(person)
|
||||
self.session.commit()
|
||||
|
||||
url = typ.get_object_url(person)
|
||||
self.assertIsNotNone(url)
|
||||
self.assertIn(f'/people/{person.uuid}', url)
|
||||
|
||||
|
||||
class TestUserRef(WebTestCase):
|
||||
|
||||
def test_sort_query(self):
|
||||
typ = mod.UserRef(self.request, session=self.session)
|
||||
query = typ.get_query()
|
||||
self.assertIsInstance(query, orm.Query)
|
||||
sorted_query = typ.sort_query(query)
|
||||
self.assertIsInstance(sorted_query, orm.Query)
|
||||
self.assertIsNot(sorted_query, query)
|
||||
|
||||
def test_get_object_url(self):
|
||||
self.pyramid_config.add_route('users.view', '/users/{uuid}')
|
||||
model = self.app.model
|
||||
typ = mod.UserRef(self.request, session=self.session)
|
||||
|
||||
user = model.User(username='barney')
|
||||
self.session.add(user)
|
||||
self.session.commit()
|
||||
|
||||
url = typ.get_object_url(user)
|
||||
self.assertIsNotNone(url)
|
||||
self.assertIn(f'/users/{user.uuid}', url)
|
||||
|
||||
|
||||
class TestUserRefs(DataTestCase):
|
||||
|
||||
|
|
|
@ -9,13 +9,13 @@ from fanstatic import Library, Resource
|
|||
from pyramid import testing
|
||||
|
||||
from wuttjamaican.conf import WuttaConfig
|
||||
from wuttaweb import util
|
||||
from wuttaweb import util as mod
|
||||
|
||||
|
||||
class TestFieldList(TestCase):
|
||||
|
||||
def test_insert_before(self):
|
||||
fields = util.FieldList(['f1', 'f2'])
|
||||
fields = mod.FieldList(['f1', 'f2'])
|
||||
self.assertEqual(fields, ['f1', 'f2'])
|
||||
|
||||
# typical
|
||||
|
@ -29,7 +29,7 @@ class TestFieldList(TestCase):
|
|||
self.assertEqual(fields, ['XXX', 'f1', 'YYY', 'f2', 'ZZZ'])
|
||||
|
||||
def test_insert_after(self):
|
||||
fields = util.FieldList(['f1', 'f2'])
|
||||
fields = mod.FieldList(['f1', 'f2'])
|
||||
self.assertEqual(fields, ['f1', 'f2'])
|
||||
|
||||
# typical
|
||||
|
@ -42,6 +42,14 @@ class TestFieldList(TestCase):
|
|||
fields.insert_after('f3', 'ZZZ')
|
||||
self.assertEqual(fields, ['f1', 'XXX', 'YYY', 'f2', 'ZZZ'])
|
||||
|
||||
def test_set_sequence(self):
|
||||
fields = mod.FieldList(['f5', 'f1', 'f3', 'f4', 'f2'])
|
||||
|
||||
# setting sequence will only "sort" for explicit fields.
|
||||
# other fields remain in original order, but at the end.
|
||||
fields.set_sequence(['f1', 'f2', 'f3'])
|
||||
self.assertEqual(fields, ['f1', 'f2', 'f3', 'f5', 'f4'])
|
||||
|
||||
|
||||
class TestGetLibVer(TestCase):
|
||||
|
||||
|
@ -51,153 +59,153 @@ class TestGetLibVer(TestCase):
|
|||
self.request.wutta_config = self.config
|
||||
|
||||
def test_buefy_default(self):
|
||||
version = util.get_libver(self.request, 'buefy')
|
||||
version = mod.get_libver(self.request, 'buefy')
|
||||
self.assertEqual(version, 'latest')
|
||||
|
||||
def test_buefy_custom_old(self):
|
||||
self.config.setdefault('wuttaweb.buefy_version', '0.9.29')
|
||||
version = util.get_libver(self.request, 'buefy')
|
||||
version = mod.get_libver(self.request, 'buefy')
|
||||
self.assertEqual(version, '0.9.29')
|
||||
|
||||
def test_buefy_custom_old_tailbone(self):
|
||||
self.config.setdefault('tailbone.libver.buefy', '0.9.28')
|
||||
version = util.get_libver(self.request, 'buefy', prefix='tailbone')
|
||||
version = mod.get_libver(self.request, 'buefy', prefix='tailbone')
|
||||
self.assertEqual(version, '0.9.28')
|
||||
|
||||
def test_buefy_custom_new(self):
|
||||
self.config.setdefault('wuttaweb.libver.buefy', '0.9.29')
|
||||
version = util.get_libver(self.request, 'buefy')
|
||||
version = mod.get_libver(self.request, 'buefy')
|
||||
self.assertEqual(version, '0.9.29')
|
||||
|
||||
def test_buefy_configured_only(self):
|
||||
version = util.get_libver(self.request, 'buefy', configured_only=True)
|
||||
version = mod.get_libver(self.request, 'buefy', configured_only=True)
|
||||
self.assertIsNone(version)
|
||||
|
||||
def test_buefy_default_only(self):
|
||||
self.config.setdefault('wuttaweb.libver.buefy', '0.9.29')
|
||||
version = util.get_libver(self.request, 'buefy', default_only=True)
|
||||
version = mod.get_libver(self.request, 'buefy', default_only=True)
|
||||
self.assertEqual(version, 'latest')
|
||||
|
||||
def test_buefy_css_default(self):
|
||||
version = util.get_libver(self.request, 'buefy.css')
|
||||
version = mod.get_libver(self.request, 'buefy.css')
|
||||
self.assertEqual(version, 'latest')
|
||||
|
||||
def test_buefy_css_custom_old(self):
|
||||
# nb. this uses same setting as buefy (js)
|
||||
self.config.setdefault('wuttaweb.buefy_version', '0.9.29')
|
||||
version = util.get_libver(self.request, 'buefy.css')
|
||||
version = mod.get_libver(self.request, 'buefy.css')
|
||||
self.assertEqual(version, '0.9.29')
|
||||
|
||||
def test_buefy_css_custom_new(self):
|
||||
# nb. this uses same setting as buefy (js)
|
||||
self.config.setdefault('wuttaweb.libver.buefy', '0.9.29')
|
||||
version = util.get_libver(self.request, 'buefy.css')
|
||||
version = mod.get_libver(self.request, 'buefy.css')
|
||||
self.assertEqual(version, '0.9.29')
|
||||
|
||||
def test_buefy_css_configured_only(self):
|
||||
version = util.get_libver(self.request, 'buefy.css', configured_only=True)
|
||||
version = mod.get_libver(self.request, 'buefy.css', configured_only=True)
|
||||
self.assertIsNone(version)
|
||||
|
||||
def test_buefy_css_default_only(self):
|
||||
self.config.setdefault('wuttaweb.libver.buefy', '0.9.29')
|
||||
version = util.get_libver(self.request, 'buefy.css', default_only=True)
|
||||
version = mod.get_libver(self.request, 'buefy.css', default_only=True)
|
||||
self.assertEqual(version, 'latest')
|
||||
|
||||
def test_vue_default(self):
|
||||
version = util.get_libver(self.request, 'vue')
|
||||
version = mod.get_libver(self.request, 'vue')
|
||||
self.assertEqual(version, '2.6.14')
|
||||
|
||||
def test_vue_custom_old(self):
|
||||
self.config.setdefault('wuttaweb.vue_version', '3.4.31')
|
||||
version = util.get_libver(self.request, 'vue')
|
||||
version = mod.get_libver(self.request, 'vue')
|
||||
self.assertEqual(version, '3.4.31')
|
||||
|
||||
def test_vue_custom_new(self):
|
||||
self.config.setdefault('wuttaweb.libver.vue', '3.4.31')
|
||||
version = util.get_libver(self.request, 'vue')
|
||||
version = mod.get_libver(self.request, 'vue')
|
||||
self.assertEqual(version, '3.4.31')
|
||||
|
||||
def test_vue_configured_only(self):
|
||||
version = util.get_libver(self.request, 'vue', configured_only=True)
|
||||
version = mod.get_libver(self.request, 'vue', configured_only=True)
|
||||
self.assertIsNone(version)
|
||||
|
||||
def test_vue_default_only(self):
|
||||
self.config.setdefault('wuttaweb.libver.vue', '3.4.31')
|
||||
version = util.get_libver(self.request, 'vue', default_only=True)
|
||||
version = mod.get_libver(self.request, 'vue', default_only=True)
|
||||
self.assertEqual(version, '2.6.14')
|
||||
|
||||
def test_vue_resource_default(self):
|
||||
version = util.get_libver(self.request, 'vue_resource')
|
||||
version = mod.get_libver(self.request, 'vue_resource')
|
||||
self.assertEqual(version, 'latest')
|
||||
|
||||
def test_vue_resource_custom(self):
|
||||
self.config.setdefault('wuttaweb.libver.vue_resource', '1.5.3')
|
||||
version = util.get_libver(self.request, 'vue_resource')
|
||||
version = mod.get_libver(self.request, 'vue_resource')
|
||||
self.assertEqual(version, '1.5.3')
|
||||
|
||||
def test_fontawesome_default(self):
|
||||
version = util.get_libver(self.request, 'fontawesome')
|
||||
version = mod.get_libver(self.request, 'fontawesome')
|
||||
self.assertEqual(version, '5.3.1')
|
||||
|
||||
def test_fontawesome_custom(self):
|
||||
self.config.setdefault('wuttaweb.libver.fontawesome', '5.6.3')
|
||||
version = util.get_libver(self.request, 'fontawesome')
|
||||
version = mod.get_libver(self.request, 'fontawesome')
|
||||
self.assertEqual(version, '5.6.3')
|
||||
|
||||
def test_bb_vue_default(self):
|
||||
version = util.get_libver(self.request, 'bb_vue')
|
||||
version = mod.get_libver(self.request, 'bb_vue')
|
||||
self.assertEqual(version, '3.4.31')
|
||||
|
||||
def test_bb_vue_custom(self):
|
||||
self.config.setdefault('wuttaweb.libver.bb_vue', '3.4.30')
|
||||
version = util.get_libver(self.request, 'bb_vue')
|
||||
version = mod.get_libver(self.request, 'bb_vue')
|
||||
self.assertEqual(version, '3.4.30')
|
||||
|
||||
def test_bb_oruga_default(self):
|
||||
version = util.get_libver(self.request, 'bb_oruga')
|
||||
version = mod.get_libver(self.request, 'bb_oruga')
|
||||
self.assertEqual(version, '0.8.12')
|
||||
|
||||
def test_bb_oruga_custom(self):
|
||||
self.config.setdefault('wuttaweb.libver.bb_oruga', '0.8.11')
|
||||
version = util.get_libver(self.request, 'bb_oruga')
|
||||
version = mod.get_libver(self.request, 'bb_oruga')
|
||||
self.assertEqual(version, '0.8.11')
|
||||
|
||||
def test_bb_oruga_bulma_default(self):
|
||||
version = util.get_libver(self.request, 'bb_oruga_bulma')
|
||||
version = mod.get_libver(self.request, 'bb_oruga_bulma')
|
||||
self.assertEqual(version, '0.3.0')
|
||||
version = util.get_libver(self.request, 'bb_oruga_bulma_css')
|
||||
version = mod.get_libver(self.request, 'bb_oruga_bulma_css')
|
||||
self.assertEqual(version, '0.3.0')
|
||||
|
||||
def test_bb_oruga_bulma_custom(self):
|
||||
self.config.setdefault('wuttaweb.libver.bb_oruga_bulma', '0.2.11')
|
||||
version = util.get_libver(self.request, 'bb_oruga_bulma')
|
||||
version = mod.get_libver(self.request, 'bb_oruga_bulma')
|
||||
self.assertEqual(version, '0.2.11')
|
||||
|
||||
def test_bb_fontawesome_svg_core_default(self):
|
||||
version = util.get_libver(self.request, 'bb_fontawesome_svg_core')
|
||||
version = mod.get_libver(self.request, 'bb_fontawesome_svg_core')
|
||||
self.assertEqual(version, '6.5.2')
|
||||
|
||||
def test_bb_fontawesome_svg_core_custom(self):
|
||||
self.config.setdefault('wuttaweb.libver.bb_fontawesome_svg_core', '6.5.1')
|
||||
version = util.get_libver(self.request, 'bb_fontawesome_svg_core')
|
||||
version = mod.get_libver(self.request, 'bb_fontawesome_svg_core')
|
||||
self.assertEqual(version, '6.5.1')
|
||||
|
||||
def test_bb_free_solid_svg_icons_default(self):
|
||||
version = util.get_libver(self.request, 'bb_free_solid_svg_icons')
|
||||
version = mod.get_libver(self.request, 'bb_free_solid_svg_icons')
|
||||
self.assertEqual(version, '6.5.2')
|
||||
|
||||
def test_bb_free_solid_svg_icons_custom(self):
|
||||
self.config.setdefault('wuttaweb.libver.bb_free_solid_svg_icons', '6.5.1')
|
||||
version = util.get_libver(self.request, 'bb_free_solid_svg_icons')
|
||||
version = mod.get_libver(self.request, 'bb_free_solid_svg_icons')
|
||||
self.assertEqual(version, '6.5.1')
|
||||
|
||||
def test_bb_vue_fontawesome_default(self):
|
||||
version = util.get_libver(self.request, 'bb_vue_fontawesome')
|
||||
version = mod.get_libver(self.request, 'bb_vue_fontawesome')
|
||||
self.assertEqual(version, '3.0.6')
|
||||
|
||||
def test_bb_vue_fontawesome_custom(self):
|
||||
self.config.setdefault('wuttaweb.libver.bb_vue_fontawesome', '3.0.8')
|
||||
version = util.get_libver(self.request, 'bb_vue_fontawesome')
|
||||
version = mod.get_libver(self.request, 'bb_vue_fontawesome')
|
||||
self.assertEqual(version, '3.0.8')
|
||||
|
||||
|
||||
|
@ -238,191 +246,191 @@ class TestGetLibUrl(TestCase):
|
|||
self.request.script_name = '/wutta'
|
||||
|
||||
def test_buefy_default(self):
|
||||
url = util.get_liburl(self.request, 'buefy')
|
||||
url = mod.get_liburl(self.request, 'buefy')
|
||||
self.assertEqual(url, 'https://unpkg.com/buefy@latest/dist/buefy.min.js')
|
||||
|
||||
def test_buefy_custom(self):
|
||||
self.config.setdefault('wuttaweb.liburl.buefy', '/lib/buefy.js')
|
||||
url = util.get_liburl(self.request, 'buefy')
|
||||
url = mod.get_liburl(self.request, 'buefy')
|
||||
self.assertEqual(url, '/lib/buefy.js')
|
||||
|
||||
def test_buefy_custom_tailbone(self):
|
||||
self.config.setdefault('tailbone.liburl.buefy', '/tailbone/buefy.js')
|
||||
url = util.get_liburl(self.request, 'buefy', prefix='tailbone')
|
||||
url = mod.get_liburl(self.request, 'buefy', prefix='tailbone')
|
||||
self.assertEqual(url, '/tailbone/buefy.js')
|
||||
|
||||
def test_buefy_default_only(self):
|
||||
self.config.setdefault('wuttaweb.liburl.buefy', '/lib/buefy.js')
|
||||
url = util.get_liburl(self.request, 'buefy', default_only=True)
|
||||
url = mod.get_liburl(self.request, 'buefy', default_only=True)
|
||||
self.assertEqual(url, 'https://unpkg.com/buefy@latest/dist/buefy.min.js')
|
||||
|
||||
def test_buefy_configured_only(self):
|
||||
url = util.get_liburl(self.request, 'buefy', configured_only=True)
|
||||
url = mod.get_liburl(self.request, 'buefy', configured_only=True)
|
||||
self.assertIsNone(url)
|
||||
|
||||
def test_buefy_fanstatic(self):
|
||||
self.setup_fanstatic()
|
||||
url = util.get_liburl(self.request, 'buefy')
|
||||
url = mod.get_liburl(self.request, 'buefy')
|
||||
self.assertEqual(url, '/wutta/fanstatic/buefy.js')
|
||||
|
||||
def test_buefy_fanstatic_tailbone(self):
|
||||
self.setup_fanstatic(register=False)
|
||||
self.config.setdefault('tailbone.static_libcache.module', 'tests.test_util')
|
||||
url = util.get_liburl(self.request, 'buefy', prefix='tailbone')
|
||||
url = mod.get_liburl(self.request, 'buefy', prefix='tailbone')
|
||||
self.assertEqual(url, '/wutta/fanstatic/buefy.js')
|
||||
|
||||
def test_buefy_css_default(self):
|
||||
url = util.get_liburl(self.request, 'buefy.css')
|
||||
url = mod.get_liburl(self.request, 'buefy.css')
|
||||
self.assertEqual(url, 'https://unpkg.com/buefy@latest/dist/buefy.min.css')
|
||||
|
||||
def test_buefy_css_custom(self):
|
||||
self.config.setdefault('wuttaweb.liburl.buefy.css', '/lib/buefy.css')
|
||||
url = util.get_liburl(self.request, 'buefy.css')
|
||||
url = mod.get_liburl(self.request, 'buefy.css')
|
||||
self.assertEqual(url, '/lib/buefy.css')
|
||||
|
||||
def test_buefy_css_fanstatic(self):
|
||||
self.setup_fanstatic()
|
||||
url = util.get_liburl(self.request, 'buefy.css')
|
||||
url = mod.get_liburl(self.request, 'buefy.css')
|
||||
self.assertEqual(url, '/wutta/fanstatic/buefy.css')
|
||||
|
||||
def test_vue_default(self):
|
||||
url = util.get_liburl(self.request, 'vue')
|
||||
url = mod.get_liburl(self.request, 'vue')
|
||||
self.assertEqual(url, 'https://unpkg.com/vue@2.6.14/dist/vue.min.js')
|
||||
|
||||
def test_vue_custom(self):
|
||||
self.config.setdefault('wuttaweb.liburl.vue', '/lib/vue.js')
|
||||
url = util.get_liburl(self.request, 'vue')
|
||||
url = mod.get_liburl(self.request, 'vue')
|
||||
self.assertEqual(url, '/lib/vue.js')
|
||||
|
||||
def test_vue_fanstatic(self):
|
||||
self.setup_fanstatic()
|
||||
url = util.get_liburl(self.request, 'vue')
|
||||
url = mod.get_liburl(self.request, 'vue')
|
||||
self.assertEqual(url, '/wutta/fanstatic/vue.js')
|
||||
|
||||
def test_vue_resource_default(self):
|
||||
url = util.get_liburl(self.request, 'vue_resource')
|
||||
url = mod.get_liburl(self.request, 'vue_resource')
|
||||
self.assertEqual(url, 'https://cdn.jsdelivr.net/npm/vue-resource@latest')
|
||||
|
||||
def test_vue_resource_custom(self):
|
||||
self.config.setdefault('wuttaweb.liburl.vue_resource', '/lib/vue-resource.js')
|
||||
url = util.get_liburl(self.request, 'vue_resource')
|
||||
url = mod.get_liburl(self.request, 'vue_resource')
|
||||
self.assertEqual(url, '/lib/vue-resource.js')
|
||||
|
||||
def test_vue_resource_fanstatic(self):
|
||||
self.setup_fanstatic()
|
||||
url = util.get_liburl(self.request, 'vue_resource')
|
||||
url = mod.get_liburl(self.request, 'vue_resource')
|
||||
self.assertEqual(url, '/wutta/fanstatic/vue_resource.js')
|
||||
|
||||
def test_fontawesome_default(self):
|
||||
url = util.get_liburl(self.request, 'fontawesome')
|
||||
url = mod.get_liburl(self.request, 'fontawesome')
|
||||
self.assertEqual(url, 'https://use.fontawesome.com/releases/v5.3.1/js/all.js')
|
||||
|
||||
def test_fontawesome_custom(self):
|
||||
self.config.setdefault('wuttaweb.liburl.fontawesome', '/lib/fontawesome.js')
|
||||
url = util.get_liburl(self.request, 'fontawesome')
|
||||
url = mod.get_liburl(self.request, 'fontawesome')
|
||||
self.assertEqual(url, '/lib/fontawesome.js')
|
||||
|
||||
def test_fontawesome_fanstatic(self):
|
||||
self.setup_fanstatic()
|
||||
url = util.get_liburl(self.request, 'fontawesome')
|
||||
url = mod.get_liburl(self.request, 'fontawesome')
|
||||
self.assertEqual(url, '/wutta/fanstatic/fontawesome.js')
|
||||
|
||||
def test_bb_vue_default(self):
|
||||
url = util.get_liburl(self.request, 'bb_vue')
|
||||
url = mod.get_liburl(self.request, 'bb_vue')
|
||||
self.assertEqual(url, 'https://unpkg.com/vue@3.4.31/dist/vue.esm-browser.prod.js')
|
||||
|
||||
def test_bb_vue_custom(self):
|
||||
self.config.setdefault('wuttaweb.liburl.bb_vue', '/lib/vue.js')
|
||||
url = util.get_liburl(self.request, 'bb_vue')
|
||||
url = mod.get_liburl(self.request, 'bb_vue')
|
||||
self.assertEqual(url, '/lib/vue.js')
|
||||
|
||||
def test_bb_vue_fanstatic(self):
|
||||
self.setup_fanstatic()
|
||||
url = util.get_liburl(self.request, 'bb_vue')
|
||||
url = mod.get_liburl(self.request, 'bb_vue')
|
||||
self.assertEqual(url, '/wutta/fanstatic/bb_vue.js')
|
||||
|
||||
def test_bb_oruga_default(self):
|
||||
url = util.get_liburl(self.request, 'bb_oruga')
|
||||
url = mod.get_liburl(self.request, 'bb_oruga')
|
||||
self.assertEqual(url, 'https://unpkg.com/@oruga-ui/oruga-next@0.8.12/dist/oruga.mjs')
|
||||
|
||||
def test_bb_oruga_custom(self):
|
||||
self.config.setdefault('wuttaweb.liburl.bb_oruga', '/lib/oruga.js')
|
||||
url = util.get_liburl(self.request, 'bb_oruga')
|
||||
url = mod.get_liburl(self.request, 'bb_oruga')
|
||||
self.assertEqual(url, '/lib/oruga.js')
|
||||
|
||||
def test_bb_oruga_fanstatic(self):
|
||||
self.setup_fanstatic()
|
||||
url = util.get_liburl(self.request, 'bb_oruga')
|
||||
url = mod.get_liburl(self.request, 'bb_oruga')
|
||||
self.assertEqual(url, '/wutta/fanstatic/bb_oruga.js')
|
||||
|
||||
def test_bb_oruga_bulma_default(self):
|
||||
url = util.get_liburl(self.request, 'bb_oruga_bulma')
|
||||
url = mod.get_liburl(self.request, 'bb_oruga_bulma')
|
||||
self.assertEqual(url, 'https://unpkg.com/@oruga-ui/theme-bulma@0.3.0/dist/bulma.mjs')
|
||||
|
||||
def test_bb_oruga_bulma_custom(self):
|
||||
self.config.setdefault('wuttaweb.liburl.bb_oruga_bulma', '/lib/oruga_bulma.js')
|
||||
url = util.get_liburl(self.request, 'bb_oruga_bulma')
|
||||
url = mod.get_liburl(self.request, 'bb_oruga_bulma')
|
||||
self.assertEqual(url, '/lib/oruga_bulma.js')
|
||||
|
||||
def test_bb_oruga_bulma_fanstatic(self):
|
||||
self.setup_fanstatic()
|
||||
url = util.get_liburl(self.request, 'bb_oruga_bulma')
|
||||
url = mod.get_liburl(self.request, 'bb_oruga_bulma')
|
||||
self.assertEqual(url, '/wutta/fanstatic/bb_oruga_bulma.js')
|
||||
|
||||
def test_bb_oruga_bulma_css_default(self):
|
||||
url = util.get_liburl(self.request, 'bb_oruga_bulma_css')
|
||||
url = mod.get_liburl(self.request, 'bb_oruga_bulma_css')
|
||||
self.assertEqual(url, 'https://unpkg.com/@oruga-ui/theme-bulma@0.3.0/dist/bulma.css')
|
||||
|
||||
def test_bb_oruga_bulma_css_custom(self):
|
||||
self.config.setdefault('wuttaweb.liburl.bb_oruga_bulma_css', '/lib/oruga-bulma.css')
|
||||
url = util.get_liburl(self.request, 'bb_oruga_bulma_css')
|
||||
url = mod.get_liburl(self.request, 'bb_oruga_bulma_css')
|
||||
self.assertEqual(url, '/lib/oruga-bulma.css')
|
||||
|
||||
def test_bb_oruga_bulma_css_fanstatic(self):
|
||||
self.setup_fanstatic()
|
||||
url = util.get_liburl(self.request, 'bb_oruga_bulma_css')
|
||||
url = mod.get_liburl(self.request, 'bb_oruga_bulma_css')
|
||||
self.assertEqual(url, '/wutta/fanstatic/bb_oruga_bulma.css')
|
||||
|
||||
def test_bb_fontawesome_svg_core_default(self):
|
||||
url = util.get_liburl(self.request, 'bb_fontawesome_svg_core')
|
||||
url = mod.get_liburl(self.request, 'bb_fontawesome_svg_core')
|
||||
self.assertEqual(url, 'https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-svg-core@6.5.2/+esm')
|
||||
|
||||
def test_bb_fontawesome_svg_core_custom(self):
|
||||
self.config.setdefault('wuttaweb.liburl.bb_fontawesome_svg_core', '/lib/fontawesome-svg-core.js')
|
||||
url = util.get_liburl(self.request, 'bb_fontawesome_svg_core')
|
||||
url = mod.get_liburl(self.request, 'bb_fontawesome_svg_core')
|
||||
self.assertEqual(url, '/lib/fontawesome-svg-core.js')
|
||||
|
||||
def test_bb_fontawesome_svg_core_fanstatic(self):
|
||||
self.setup_fanstatic()
|
||||
url = util.get_liburl(self.request, 'bb_fontawesome_svg_core')
|
||||
url = mod.get_liburl(self.request, 'bb_fontawesome_svg_core')
|
||||
self.assertEqual(url, '/wutta/fanstatic/bb_fontawesome_svg_core.js')
|
||||
|
||||
def test_bb_free_solid_svg_icons_default(self):
|
||||
url = util.get_liburl(self.request, 'bb_free_solid_svg_icons')
|
||||
url = mod.get_liburl(self.request, 'bb_free_solid_svg_icons')
|
||||
self.assertEqual(url, 'https://cdn.jsdelivr.net/npm/@fortawesome/free-solid-svg-icons@6.5.2/+esm')
|
||||
|
||||
def test_bb_free_solid_svg_icons_custom(self):
|
||||
self.config.setdefault('wuttaweb.liburl.bb_free_solid_svg_icons', '/lib/free-solid-svg-icons.js')
|
||||
url = util.get_liburl(self.request, 'bb_free_solid_svg_icons')
|
||||
url = mod.get_liburl(self.request, 'bb_free_solid_svg_icons')
|
||||
self.assertEqual(url, '/lib/free-solid-svg-icons.js')
|
||||
|
||||
def test_bb_free_solid_svg_icons_fanstatic(self):
|
||||
self.setup_fanstatic()
|
||||
url = util.get_liburl(self.request, 'bb_free_solid_svg_icons')
|
||||
url = mod.get_liburl(self.request, 'bb_free_solid_svg_icons')
|
||||
self.assertEqual(url, '/wutta/fanstatic/bb_free_solid_svg_icons.js')
|
||||
|
||||
def test_bb_vue_fontawesome_default(self):
|
||||
url = util.get_liburl(self.request, 'bb_vue_fontawesome')
|
||||
url = mod.get_liburl(self.request, 'bb_vue_fontawesome')
|
||||
self.assertEqual(url, 'https://cdn.jsdelivr.net/npm/@fortawesome/vue-fontawesome@3.0.6/+esm')
|
||||
|
||||
def test_bb_vue_fontawesome_custom(self):
|
||||
self.config.setdefault('wuttaweb.liburl.bb_vue_fontawesome', '/lib/vue-fontawesome.js')
|
||||
url = util.get_liburl(self.request, 'bb_vue_fontawesome')
|
||||
url = mod.get_liburl(self.request, 'bb_vue_fontawesome')
|
||||
self.assertEqual(url, '/lib/vue-fontawesome.js')
|
||||
|
||||
def test_bb_vue_fontawesome_fanstatic(self):
|
||||
self.setup_fanstatic()
|
||||
url = util.get_liburl(self.request, 'bb_vue_fontawesome')
|
||||
url = mod.get_liburl(self.request, 'bb_vue_fontawesome')
|
||||
self.assertEqual(url, '/wutta/fanstatic/bb_vue_fontawesome.js')
|
||||
|
||||
|
||||
|
@ -439,17 +447,17 @@ class TestGetFormData(TestCase):
|
|||
|
||||
def test_default(self):
|
||||
request = self.make_request()
|
||||
data = util.get_form_data(request)
|
||||
data = mod.get_form_data(request)
|
||||
self.assertEqual(data, {'foo1': 'bar'})
|
||||
|
||||
def test_is_xhr(self):
|
||||
request = self.make_request(POST=None, is_xhr=True)
|
||||
data = util.get_form_data(request)
|
||||
data = mod.get_form_data(request)
|
||||
self.assertEqual(data, {'foo2': 'baz'})
|
||||
|
||||
def test_content_type(self):
|
||||
request = self.make_request(POST=None, content_type='application/json')
|
||||
data = util.get_form_data(request)
|
||||
data = mod.get_form_data(request)
|
||||
self.assertEqual(data, {'foo2': 'baz'})
|
||||
|
||||
|
||||
|
@ -460,16 +468,16 @@ class TestGetModelFields(TestCase):
|
|||
self.app = self.config.get_app()
|
||||
|
||||
def test_empty_model_class(self):
|
||||
fields = util.get_model_fields(self.config)
|
||||
fields = mod.get_model_fields(self.config)
|
||||
self.assertIsNone(fields)
|
||||
|
||||
def test_unknown_model_class(self):
|
||||
fields = util.get_model_fields(self.config, TestCase)
|
||||
fields = mod.get_model_fields(self.config, TestCase)
|
||||
self.assertIsNone(fields)
|
||||
|
||||
def test_basic(self):
|
||||
model = self.app.model
|
||||
fields = util.get_model_fields(self.config, model.Setting)
|
||||
fields = mod.get_model_fields(self.config, model.Setting)
|
||||
self.assertEqual(fields, ['name', 'value'])
|
||||
|
||||
|
||||
|
@ -484,9 +492,9 @@ class TestGetCsrfToken(TestCase):
|
|||
# same token returned for same request
|
||||
# TODO: dummy request is always returning same token!
|
||||
# so this isn't really testing anything.. :(
|
||||
first = util.get_csrf_token(self.request)
|
||||
first = mod.get_csrf_token(self.request)
|
||||
self.assertIsNotNone(first)
|
||||
second = util.get_csrf_token(self.request)
|
||||
second = mod.get_csrf_token(self.request)
|
||||
self.assertEqual(first, second)
|
||||
|
||||
# TODO: ideally would make a new request here and confirm it
|
||||
|
@ -497,7 +505,7 @@ class TestGetCsrfToken(TestCase):
|
|||
# nb. dummy request always returns same token, so must
|
||||
# trick it into thinking it doesn't have one yet
|
||||
with patch.object(self.request.session, 'get_csrf_token', return_value=None):
|
||||
token = util.get_csrf_token(self.request)
|
||||
token = mod.get_csrf_token(self.request)
|
||||
self.assertIsNotNone(token)
|
||||
|
||||
|
||||
|
@ -508,10 +516,10 @@ class TestRenderCsrfToken(TestCase):
|
|||
self.request = testing.DummyRequest(wutta_config=self.config)
|
||||
|
||||
def test_basics(self):
|
||||
html = util.render_csrf_token(self.request)
|
||||
html = mod.render_csrf_token(self.request)
|
||||
self.assertIn('type="hidden"', html)
|
||||
self.assertIn('name="_csrf"', html)
|
||||
token = util.get_csrf_token(self.request)
|
||||
token = mod.get_csrf_token(self.request)
|
||||
self.assertIn(f'value="{token}"', html)
|
||||
|
||||
|
||||
|
@ -522,17 +530,17 @@ class TestMakeJsonSafe(TestCase):
|
|||
self.app = self.config.get_app()
|
||||
|
||||
def test_null(self):
|
||||
value = util.make_json_safe(colander.null)
|
||||
value = mod.make_json_safe(colander.null)
|
||||
self.assertIsNone(value)
|
||||
|
||||
value = util.make_json_safe(None)
|
||||
value = mod.make_json_safe(None)
|
||||
self.assertIsNone(value)
|
||||
|
||||
def test_invalid(self):
|
||||
model = self.app.model
|
||||
person = model.Person(full_name="Betty Boop")
|
||||
self.assertRaises(TypeError, json.dumps, person)
|
||||
value = util.make_json_safe(person, key='person')
|
||||
value = mod.make_json_safe(person, key='person')
|
||||
self.assertEqual(value, "Betty Boop")
|
||||
|
||||
def test_dict(self):
|
||||
|
@ -545,7 +553,7 @@ class TestMakeJsonSafe(TestCase):
|
|||
}
|
||||
|
||||
self.assertRaises(TypeError, json.dumps, data)
|
||||
value = util.make_json_safe(data)
|
||||
value = mod.make_json_safe(data)
|
||||
self.assertEqual(value, {
|
||||
'foo': 'bar',
|
||||
'person': "Betty Boop",
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
# -*- coding: utf-8; -*-
|
||||
|
||||
import datetime
|
||||
import decimal
|
||||
import functools
|
||||
from unittest import TestCase
|
||||
|
@ -579,7 +580,6 @@ class TestMasterView(WebTestCase):
|
|||
self.assertEqual(value, "No")
|
||||
|
||||
def test_grid_render_currency(self):
|
||||
model = self.app.model
|
||||
view = self.make_view()
|
||||
obj = {'amount': None}
|
||||
|
||||
|
@ -597,6 +597,33 @@ class TestMasterView(WebTestCase):
|
|||
value = view.grid_render_currency(obj, 'amount', '-100.42')
|
||||
self.assertEqual(value, "($100.42)")
|
||||
|
||||
def test_grid_render_datetime(self):
|
||||
view = self.make_view()
|
||||
obj = {'dt': None}
|
||||
|
||||
# null
|
||||
value = view.grid_render_datetime(obj, 'dt', None)
|
||||
self.assertIsNone(value)
|
||||
|
||||
# normal
|
||||
obj['dt'] = datetime.datetime(2024, 8, 24, 11)
|
||||
value = view.grid_render_datetime(obj, 'dt', '2024-08-24T11:00:00')
|
||||
self.assertEqual(value, '2024-08-24 11:00:00 AM')
|
||||
|
||||
def test_grid_render_enum(self):
|
||||
enum = self.app.enum
|
||||
view = self.make_view()
|
||||
obj = {'status': None}
|
||||
|
||||
# null
|
||||
value = view.grid_render_enum(obj, 'status', None, enum=enum.UpgradeStatus)
|
||||
self.assertIsNone(value)
|
||||
|
||||
# normal
|
||||
obj['status'] = enum.UpgradeStatus.SUCCESS
|
||||
value = view.grid_render_enum(obj, 'status', 'SUCCESS', enum=enum.UpgradeStatus)
|
||||
self.assertEqual(value, 'SUCCESS')
|
||||
|
||||
def test_grid_render_notes(self):
|
||||
model = self.app.model
|
||||
view = self.make_view()
|
||||
|
|
103
tests/views/test_upgrades.py
Normal file
103
tests/views/test_upgrades.py
Normal file
|
@ -0,0 +1,103 @@
|
|||
# -*- coding: utf-8; -*-
|
||||
|
||||
import datetime
|
||||
from unittest.mock import patch, MagicMock
|
||||
|
||||
from wuttaweb.views import upgrades as mod
|
||||
from tests.util import WebTestCase
|
||||
|
||||
|
||||
class TestUpgradeView(WebTestCase):
|
||||
|
||||
def make_view(self):
|
||||
return mod.UpgradeView(self.request)
|
||||
|
||||
def test_includeme(self):
|
||||
self.pyramid_config.include('wuttaweb.views.upgrades')
|
||||
|
||||
def test_configure_grid(self):
|
||||
model = self.app.model
|
||||
view = self.make_view()
|
||||
|
||||
# sanity / coverage check
|
||||
grid = view.make_grid(model_class=model.Upgrade)
|
||||
view.configure_grid(grid)
|
||||
|
||||
def test_grid_row_class(self):
|
||||
model = self.app.model
|
||||
enum = self.app.enum
|
||||
upgrade = model.Upgrade(description="test", status=enum.UpgradeStatus.PENDING)
|
||||
data = dict(upgrade)
|
||||
view = self.make_view()
|
||||
|
||||
self.assertIsNone(view.grid_row_class(upgrade, data, 1))
|
||||
|
||||
upgrade.status = enum.UpgradeStatus.EXECUTING
|
||||
self.assertEqual(view.grid_row_class(upgrade, data, 1), 'has-background-warning')
|
||||
|
||||
upgrade.status = enum.UpgradeStatus.SUCCESS
|
||||
self.assertIsNone(view.grid_row_class(upgrade, data, 1))
|
||||
|
||||
upgrade.status = enum.UpgradeStatus.FAILURE
|
||||
self.assertEqual(view.grid_row_class(upgrade, data, 1), 'has-background-warning')
|
||||
|
||||
def test_configure_form(self):
|
||||
model = self.app.model
|
||||
enum = self.app.enum
|
||||
user = model.User(username='barney')
|
||||
self.session.add(user)
|
||||
upgrade = model.Upgrade(description='test', created_by=user,
|
||||
status=enum.UpgradeStatus.PENDING)
|
||||
self.session.add(upgrade)
|
||||
self.session.commit()
|
||||
view = self.make_view()
|
||||
|
||||
# some fields exist when viewing
|
||||
with patch.object(view, 'viewing', new=True):
|
||||
form = view.make_form(model_class=model.Upgrade, model_instance=upgrade)
|
||||
self.assertIn('created', form)
|
||||
view.configure_form(form)
|
||||
self.assertIn('created', form)
|
||||
|
||||
# but then are removed when creating
|
||||
with patch.object(view, 'creating', new=True):
|
||||
form = view.make_form(model_class=model.Upgrade)
|
||||
self.assertIn('created', form)
|
||||
view.configure_form(form)
|
||||
self.assertNotIn('created', form)
|
||||
|
||||
# test executed field when viewing
|
||||
with patch.object(view, 'viewing', new=True):
|
||||
|
||||
# executed is *not* shown by default
|
||||
form = view.make_form(model_class=model.Upgrade, model_instance=upgrade)
|
||||
self.assertIn('executed', form)
|
||||
view.configure_form(form)
|
||||
self.assertNotIn('executed', form)
|
||||
|
||||
# but it *is* shown if upgrade is executed
|
||||
upgrade.executed = datetime.datetime.now()
|
||||
form = view.make_form(model_class=model.Upgrade, model_instance=upgrade)
|
||||
self.assertIn('executed', form)
|
||||
view.configure_form(form)
|
||||
self.assertIn('executed', form)
|
||||
|
||||
def test_objectify(self):
|
||||
model = self.app.model
|
||||
enum = self.app.enum
|
||||
user = model.User(username='barney')
|
||||
self.session.add(user)
|
||||
self.session.commit()
|
||||
view = self.make_view()
|
||||
|
||||
# user and status are auto-set when creating
|
||||
self.request.user = user
|
||||
self.request.method = 'POST'
|
||||
self.request.POST = {'description': "new one"}
|
||||
with patch.object(view, 'creating', new=True):
|
||||
form = view.make_model_form()
|
||||
self.assertTrue(form.validate())
|
||||
upgrade = view.objectify(form)
|
||||
self.assertEqual(upgrade.description, "new one")
|
||||
self.assertIs(upgrade.created_by, user)
|
||||
self.assertEqual(upgrade.status, enum.UpgradeStatus.PENDING)
|
Loading…
Reference in a new issue