fix: make master view auto-detect continuum versioning for model class
This commit is contained in:
		
							parent
							
								
									f33448f64a
								
							
						
					
					
						commit
						910ddca96f
					
				
					 2 changed files with 52 additions and 21 deletions
				
			
		|  | @ -350,14 +350,6 @@ class MasterView(View):  # pylint: disable=too-many-public-methods | ||||||
|        "configuring" - i.e. it should have a :meth:`configure()` view. |        "configuring" - i.e. it should have a :meth:`configure()` view. | ||||||
|        Default value is ``False``. |        Default value is ``False``. | ||||||
| 
 | 
 | ||||||
|     .. attribute:: has_versions |  | ||||||
| 
 |  | ||||||
|        Boolean indicating whether the master view should expose |  | ||||||
|        version history for its data records - i.e. it should have a |  | ||||||
|        :meth:`view_versions()` view.  Default value is ``False``. |  | ||||||
| 
 |  | ||||||
|        See also :meth:`should_expose_versions()`. |  | ||||||
| 
 |  | ||||||
|     .. attribute:: version_grid_columns |     .. attribute:: version_grid_columns | ||||||
| 
 | 
 | ||||||
|        List of columns for the :meth:`view_versions()` view grid. |        List of columns for the :meth:`view_versions()` view grid. | ||||||
|  | @ -451,9 +443,6 @@ class MasterView(View):  # pylint: disable=too-many-public-methods | ||||||
|     rows_paginate_on_backend = True |     rows_paginate_on_backend = True | ||||||
|     rows_viewable = False |     rows_viewable = False | ||||||
| 
 | 
 | ||||||
|     # versioning features |  | ||||||
|     has_versions = False |  | ||||||
| 
 |  | ||||||
|     # current action |     # current action | ||||||
|     listing = False |     listing = False | ||||||
|     creating = False |     creating = False | ||||||
|  | @ -914,12 +903,40 @@ class MasterView(View):  # pylint: disable=too-many-public-methods | ||||||
|     # version history methods |     # version history methods | ||||||
|     ############################## |     ############################## | ||||||
| 
 | 
 | ||||||
|  |     @classmethod | ||||||
|  |     def is_versioned(cls): | ||||||
|  |         """ | ||||||
|  |         Returns boolean indicating whether the model class is | ||||||
|  |         configured for SQLAlchemy-Continuum versioning. | ||||||
|  | 
 | ||||||
|  |         The default logic will directly inspect the model class, as | ||||||
|  |         returned by :meth:`get_model_class()`.  Or you can override by | ||||||
|  |         setting the ``model_is_versioned`` attribute:: | ||||||
|  | 
 | ||||||
|  |            class WidgetView(MasterView): | ||||||
|  |                model_class = Widget | ||||||
|  |                model_is_versioned = False | ||||||
|  | 
 | ||||||
|  |         See also :meth:`should_expose_versions()`. | ||||||
|  | 
 | ||||||
|  |         :returns: ``True`` if the model class is versioned; else | ||||||
|  |            ``False``. | ||||||
|  |         """ | ||||||
|  |         if hasattr(cls, "model_is_versioned"): | ||||||
|  |             return cls.model_is_versioned | ||||||
|  | 
 | ||||||
|  |         model_class = cls.get_model_class() | ||||||
|  |         if hasattr(model_class, "__versioned__"): | ||||||
|  |             return True | ||||||
|  | 
 | ||||||
|  |         return False | ||||||
|  | 
 | ||||||
|     @classmethod |     @classmethod | ||||||
|     def get_model_version_class(cls): |     def get_model_version_class(cls): | ||||||
|         """ |         """ | ||||||
|         Returns the version class for the master model class. |         Returns the version class for the master model class. | ||||||
| 
 | 
 | ||||||
|         Should only be relevant if :attr:`has_versions` is true. |         Should only be relevant if :meth:`is_versioned()` is true. | ||||||
|         """ |         """ | ||||||
|         import sqlalchemy_continuum as continuum  # pylint: disable=import-outside-toplevel |         import sqlalchemy_continuum as continuum  # pylint: disable=import-outside-toplevel | ||||||
| 
 | 
 | ||||||
|  | @ -931,14 +948,14 @@ class MasterView(View):  # pylint: disable=too-many-public-methods | ||||||
|         be exposed for the current user.  This will return ``True`` |         be exposed for the current user.  This will return ``True`` | ||||||
|         unless any of the following are ``False``: |         unless any of the following are ``False``: | ||||||
| 
 | 
 | ||||||
|         * :attr:`has_versions` |         * :meth:`is_versioned()` | ||||||
|         * :meth:`wuttjamaican:wuttjamaican.app.AppHandler.continuum_is_enabled()` |         * :meth:`wuttjamaican:wuttjamaican.app.AppHandler.continuum_is_enabled()` | ||||||
|         * ``self.has_perm("versions")`` - cf. :meth:`has_perm()` |         * ``self.has_perm("versions")`` - cf. :meth:`has_perm()` | ||||||
| 
 | 
 | ||||||
|         :returns: ``True`` if versioning should be exposed for current |         :returns: ``True`` if versioning should be exposed for current | ||||||
|            user; else ``False``. |            user; else ``False``. | ||||||
|         """ |         """ | ||||||
|         if not self.has_versions: |         if not self.is_versioned(): | ||||||
|             return False |             return False | ||||||
| 
 | 
 | ||||||
|         if not self.app.continuum_is_enabled(): |         if not self.app.continuum_is_enabled(): | ||||||
|  | @ -958,8 +975,8 @@ class MasterView(View):  # pylint: disable=too-many-public-methods | ||||||
|         ``/widgets/XXX/versions/`` where ``XXX`` represents the key/ID |         ``/widgets/XXX/versions/`` where ``XXX`` represents the key/ID | ||||||
|         for the record. |         for the record. | ||||||
| 
 | 
 | ||||||
|         By default, this view is included only if :attr:`has_versions` |         By default, this view is included only if | ||||||
|         is true. |         :meth:`is_versioned()` is true. | ||||||
| 
 | 
 | ||||||
|         The default view logic will show a "grid" (table) with the |         The default view logic will show a "grid" (table) with the | ||||||
|         record's version history. |         record's version history. | ||||||
|  | @ -1147,8 +1164,8 @@ class MasterView(View):  # pylint: disable=too-many-public-methods | ||||||
|         key/ID for the record and YYY represents a |         key/ID for the record and YYY represents a | ||||||
|         SQLAlchemy-Continuum ``transaction.id``. |         SQLAlchemy-Continuum ``transaction.id``. | ||||||
| 
 | 
 | ||||||
|         By default, this view is included only if :attr:`has_versions` |         By default, this view is included only if | ||||||
|         is true. |         :meth:`is_versioned()` is true. | ||||||
| 
 | 
 | ||||||
|         The default view logic will display a "diff" table showing how |         The default view logic will display a "diff" table showing how | ||||||
|         the record's values were changed within a transaction. |         the record's values were changed within a transaction. | ||||||
|  | @ -3618,7 +3635,7 @@ class MasterView(View):  # pylint: disable=too-many-public-methods | ||||||
|             ) |             ) | ||||||
| 
 | 
 | ||||||
|         # version history |         # version history | ||||||
|         if cls.has_versions and app.continuum_is_enabled(): |         if cls.is_versioned() and app.continuum_is_enabled(): | ||||||
|             instance_url_prefix = cls.get_instance_url_prefix() |             instance_url_prefix = cls.get_instance_url_prefix() | ||||||
|             config.add_wutta_permission( |             config.add_wutta_permission( | ||||||
|                 permission_prefix, |                 permission_prefix, | ||||||
|  |  | ||||||
|  | @ -1849,10 +1849,24 @@ class TestVersionedMasterView(VersionWebTestCase): | ||||||
|     def make_view(self): |     def make_view(self): | ||||||
|         return mod.MasterView(self.request) |         return mod.MasterView(self.request) | ||||||
| 
 | 
 | ||||||
|  |     def test_is_versioned(self): | ||||||
|  |         model = self.app.model | ||||||
|  | 
 | ||||||
|  |         with patch.object(mod.MasterView, "model_class", new=model.User): | ||||||
|  | 
 | ||||||
|  |             # User is versioned by default | ||||||
|  |             self.assertTrue(mod.MasterView.is_versioned()) | ||||||
|  | 
 | ||||||
|  |             # but view can override w/ attr | ||||||
|  |             with patch.object( | ||||||
|  |                 mod.MasterView, "model_is_versioned", new=False, create=True | ||||||
|  |             ): | ||||||
|  |                 self.assertFalse(mod.MasterView.is_versioned()) | ||||||
|  | 
 | ||||||
|     def test_defaults(self): |     def test_defaults(self): | ||||||
|         model = self.app.model |         model = self.app.model | ||||||
| 
 | 
 | ||||||
|         with patch.multiple(mod.MasterView, model_class=model.User, has_versions=True): |         with patch.object(mod.MasterView, "model_class", new=model.User): | ||||||
|             mod.MasterView.defaults(self.pyramid_config) |             mod.MasterView.defaults(self.pyramid_config) | ||||||
| 
 | 
 | ||||||
|     def test_get_model_version_class(self): |     def test_get_model_version_class(self): | ||||||
|  | @ -1864,7 +1878,7 @@ class TestVersionedMasterView(VersionWebTestCase): | ||||||
| 
 | 
 | ||||||
|     def test_should_expose_versions(self): |     def test_should_expose_versions(self): | ||||||
|         model = self.app.model |         model = self.app.model | ||||||
|         with patch.multiple(mod.MasterView, model_class=model.User, has_versions=True): |         with patch.object(mod.MasterView, "model_class", new=model.User): | ||||||
| 
 | 
 | ||||||
|             # fully enabled for root user |             # fully enabled for root user | ||||||
|             with patch.object(self.request, "is_root", new=True): |             with patch.object(self.request, "is_root", new=True): | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue