From aa7abb3d744c5a811efb41191cfdc58d0f00192f Mon Sep 17 00:00:00 2001
From: Scott Murphy Heiberg <scott@alwaysvip.com>
Date: Sun, 12 Jan 2025 16:54:41 -0800
Subject: [PATCH] Allow setting the default blacklist via properties

---
 .../plugin/formfields/FormFieldsTagLib.groovy | 23 +++++++++++++++----
 .../model/DomainModelService.groovy           |  1 +
 .../model/DomainModelServiceImpl.groovy       |  4 ++--
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/grails-app/taglib/grails/plugin/formfields/FormFieldsTagLib.groovy b/grails-app/taglib/grails/plugin/formfields/FormFieldsTagLib.groovy
index aeb8cf8d..50148a3d 100644
--- a/grails-app/taglib/grails/plugin/formfields/FormFieldsTagLib.groovy
+++ b/grails-app/taglib/grails/plugin/formfields/FormFieldsTagLib.groovy
@@ -65,6 +65,17 @@ class FormFieldsTagLib {
 	@Value('${grails.plugin.fields.localizeNumbers:true}')
 	Boolean localizeNumbers
 
+	@Value('${grails.plugin.fields.exclusions.list:#{T(java.util.Arrays).asList("id", "dateCreated", "lastUpdated")}}')
+	List<String> exclusionsList
+	@Value('${grails.plugin.fields.exclusions.input:#{T(java.util.Arrays).asList("version", "dateCreated", "lastUpdated")}}')
+	List<String> exclusionsInput
+	@Value('${grails.plugin.fields.exclusions.display:#{T(java.util.Arrays).asList("version", "dateCreated", "lastUpdated")}}')
+	List<String> exclusionsDisplay
+
+	enum ExclusionType {
+		List, Display, Inout
+	}
+
 	FormFieldsTemplateService formFieldsTemplateService
 	BeanPropertyAccessorFactory beanPropertyAccessorFactory
 	DomainPropertyFactory fieldsDomainPropertyFactory
@@ -355,7 +366,7 @@ class FormFieldsTagLib {
 			if (domainClass) {
 				String template = attrs.remove('template') ?: 'list'
 
-				List properties = resolvePersistentProperties(domainClass, attrs)
+				List properties = resolvePersistentProperties(domainClass, attrs, ExclusionType.Display)
 				out << render(template: "/templates/_fields/$template", model: attrs + [domainClass: domainClass, domainProperties: properties]) { prop ->
 					BeanPropertyAccessor propertyAccessor = resolveProperty(bean, prop.name)
 					Map model = buildModel(propertyAccessor, attrs, 'HTML')
@@ -448,7 +459,7 @@ class FormFieldsTagLib {
 		} else if (attrs.containsKey('properties')) {
 			return getList(attrs.remove('properties'))
 		} else {
-			List<String> properties = resolvePersistentProperties(domainClass, attrs, true)*.name
+			List<String> properties = resolvePersistentProperties(domainClass, attrs, ExclusionType.List)*.name
 			int maxProperties = attrs.containsKey('maxProperties') ? attrs.remove('maxProperties').toInteger() : 7
 			if (maxProperties && properties.size() > maxProperties) {
 				properties = properties[0..<maxProperties]
@@ -578,9 +589,10 @@ class FormFieldsTagLib {
 		}
 	}
 
-	private List<PersistentProperty> resolvePersistentProperties(PersistentEntity domainClass, Map attrs, boolean list = false) {
+	private List<PersistentProperty> resolvePersistentProperties(PersistentEntity domainClass, Map attrs, ExclusionType exclusionType = ExclusionType.Inout) {
 		List<PersistentProperty> properties
 
+		boolean list = exclusionType == ExclusionType.List
 		if (attrs.order) {
 			def orderBy = getList(attrs.order)
 			if (attrs.except) {
@@ -590,9 +602,10 @@ class FormFieldsTagLib {
 				fieldsDomainPropertyFactory.build(domainClass.getPropertyByName(propertyName))
 			}
 		} else {
-			properties = list ? domainModelService.getListOutputProperties(domainClass) : domainModelService.getInputProperties(domainClass)
+			properties = list ? domainModelService.getListOutputProperties(domainClass) : domainModelService.getInputProperties(domainClass,
+					exclusionType == ExclusionType.Inout? exclusionsInput : exclusionsDisplay)
 			// If 'except' is not set, but 'list' is, exclude 'id', 'dateCreated' and 'lastUpdated' by default
-			List<String> blacklist = attrs.containsKey('except') ? getList(attrs.except) : (list ? ['id', 'dateCreated', 'lastUpdated'] : [])
+			List<String> blacklist = attrs.containsKey('except') ? getList(attrs.except) : (list ? exclusionsList : [])
 
 			properties.removeAll { it.name in blacklist }
 		}
diff --git a/src/main/groovy/org/grails/scaffolding/model/DomainModelService.groovy b/src/main/groovy/org/grails/scaffolding/model/DomainModelService.groovy
index 079ba48f..6d592bba 100644
--- a/src/main/groovy/org/grails/scaffolding/model/DomainModelService.groovy
+++ b/src/main/groovy/org/grails/scaffolding/model/DomainModelService.groovy
@@ -16,6 +16,7 @@ interface DomainModelService {
      * @param domainClass The persistent entity
      */
     List<DomainProperty> getInputProperties(PersistentEntity domainClass)
+    List<DomainProperty> getInputProperties(PersistentEntity domainClass, List blackList)
 
     /**
      * The list of {@link DomainProperty} instances that are to be visible
diff --git a/src/main/groovy/org/grails/scaffolding/model/DomainModelServiceImpl.groovy b/src/main/groovy/org/grails/scaffolding/model/DomainModelServiceImpl.groovy
index 4feb6438..3f8ed0e9 100644
--- a/src/main/groovy/org/grails/scaffolding/model/DomainModelServiceImpl.groovy
+++ b/src/main/groovy/org/grails/scaffolding/model/DomainModelServiceImpl.groovy
@@ -91,8 +91,8 @@ class DomainModelServiceImpl implements DomainModelService {
      * @see {@link DomainModelServiceImpl#getProperties}
      * @param domainClass The persistent entity
      */
-    List<DomainProperty> getInputProperties(PersistentEntity domainClass) {
-        getProperties(domainClass, ['version', 'dateCreated', 'lastUpdated'])
+    List<DomainProperty> getInputProperties(PersistentEntity domainClass, List blackList = ['version', 'dateCreated', 'lastUpdated']) {
+        getProperties(domainClass, blackList)
     }
 
     /**