Skip to content
This repository was archived by the owner on Mar 10, 2025. It is now read-only.

Commit 8ff774d

Browse files
authored
Merge pull request #394 from codeconsole/6.0.x-customizable-blacklist
Allow setting the default blacklist via properties
2 parents 9401cdd + 9061d84 commit 8ff774d

7 files changed

Lines changed: 79 additions & 9 deletions

File tree

grails-app/taglib/grails/plugin/formfields/FormFieldsTagLib.groovy

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,17 @@ class FormFieldsTagLib {
6565
@Value('${grails.plugin.fields.localizeNumbers:true}')
6666
Boolean localizeNumbers
6767

68+
@Value('${grails.plugin.fields.exclusions.list:#{T(java.util.Arrays).asList("id", "dateCreated", "lastUpdated")}}')
69+
List<String> exclusionsList
70+
@Value('${grails.plugin.fields.exclusions.input:#{T(java.util.Arrays).asList("version", "dateCreated", "lastUpdated")}}')
71+
List<String> exclusionsInput
72+
@Value('${grails.plugin.fields.exclusions.display:#{T(java.util.Arrays).asList("version", "dateCreated", "lastUpdated")}}')
73+
List<String> exclusionsDisplay
74+
75+
enum ExclusionType {
76+
List, Display, Input
77+
}
78+
6879
FormFieldsTemplateService formFieldsTemplateService
6980
BeanPropertyAccessorFactory beanPropertyAccessorFactory
7081
DomainPropertyFactory fieldsDomainPropertyFactory
@@ -355,7 +366,7 @@ class FormFieldsTagLib {
355366
if (domainClass) {
356367
String template = attrs.remove('template') ?: 'list'
357368

358-
List properties = resolvePersistentProperties(domainClass, attrs)
369+
List properties = resolvePersistentProperties(domainClass, attrs, ExclusionType.Display)
359370
out << render(template: "/templates/_fields/$template", model: attrs + [domainClass: domainClass, domainProperties: properties]) { prop ->
360371
BeanPropertyAccessor propertyAccessor = resolveProperty(bean, prop.name)
361372
Map model = buildModel(propertyAccessor, attrs, 'HTML')
@@ -448,7 +459,7 @@ class FormFieldsTagLib {
448459
} else if (attrs.containsKey('properties')) {
449460
return getList(attrs.remove('properties'))
450461
} else {
451-
List<String> properties = resolvePersistentProperties(domainClass, attrs, true)*.name
462+
List<String> properties = resolvePersistentProperties(domainClass, attrs, ExclusionType.List)*.name
452463
int maxProperties = attrs.containsKey('maxProperties') ? attrs.remove('maxProperties').toInteger() : 7
453464
if (maxProperties && properties.size() > maxProperties) {
454465
properties = properties[0..<maxProperties]
@@ -578,9 +589,10 @@ class FormFieldsTagLib {
578589
}
579590
}
580591

581-
private List<PersistentProperty> resolvePersistentProperties(PersistentEntity domainClass, Map attrs, boolean list = false) {
592+
private List<PersistentProperty> resolvePersistentProperties(PersistentEntity domainClass, Map attrs, ExclusionType exclusionType = ExclusionType.Input) {
582593
List<PersistentProperty> properties
583594

595+
boolean list = exclusionType == ExclusionType.List
584596
if (attrs.order) {
585597
def orderBy = getList(attrs.order)
586598
if (attrs.except) {
@@ -590,9 +602,10 @@ class FormFieldsTagLib {
590602
fieldsDomainPropertyFactory.build(domainClass.getPropertyByName(propertyName))
591603
}
592604
} else {
593-
properties = list ? domainModelService.getListOutputProperties(domainClass) : domainModelService.getInputProperties(domainClass)
605+
properties = list ? domainModelService.getListOutputProperties(domainClass) : domainModelService.getInputProperties(domainClass,
606+
exclusionType == ExclusionType.Input? exclusionsInput : exclusionsDisplay)
594607
// If 'except' is not set, but 'list' is, exclude 'id', 'dateCreated' and 'lastUpdated' by default
595-
List<String> blacklist = attrs.containsKey('except') ? getList(attrs.except) : (list ? ['id', 'dateCreated', 'lastUpdated'] : [])
608+
List<String> blacklist = attrs.containsKey('except') ? getList(attrs.except) : (list ? exclusionsList : [])
596609

597610
properties.removeAll { it.name in blacklist }
598611
}

src/main/groovy/org/grails/scaffolding/model/DomainModelService.groovy

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ interface DomainModelService {
1616
* @param domainClass The persistent entity
1717
*/
1818
List<DomainProperty> getInputProperties(PersistentEntity domainClass)
19+
List<DomainProperty> getInputProperties(PersistentEntity domainClass, List blackList)
1920

2021
/**
2122
* The list of {@link DomainProperty} instances that are to be visible

src/main/groovy/org/grails/scaffolding/model/DomainModelServiceImpl.groovy

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,8 @@ class DomainModelServiceImpl implements DomainModelService {
9191
* @see {@link DomainModelServiceImpl#getProperties}
9292
* @param domainClass The persistent entity
9393
*/
94-
List<DomainProperty> getInputProperties(PersistentEntity domainClass) {
95-
getProperties(domainClass, ['version', 'dateCreated', 'lastUpdated'])
94+
List<DomainProperty> getInputProperties(PersistentEntity domainClass, List<String> blackList = null) {
95+
getProperties(domainClass, new ArrayList<>(blackList ?: ['version', 'dateCreated', 'lastUpdated']))
9696
}
9797

9898
/**

src/test/groovy/grails/plugin/formfields/mock/Person.groovy

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
package grails.plugin.formfields.mock
22

3+
import grails.gorm.annotation.AutoTimestamp
34
import grails.persistence.Entity
45

6+
@Entity
7+
class Cyborg extends HomoSapiens {
8+
@AutoTimestamp(AutoTimestamp.EventType.CREATED) Date created
9+
@AutoTimestamp Date modified
10+
}
11+
512
@Entity
613
class Person extends HomoSapiens {}
714

src/test/groovy/grails/plugin/formfields/taglib/AbstractFormFieldsTagLibSpec.groovy

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,15 @@ import grails.plugin.formfields.mock.*
1818
abstract class AbstractFormFieldsTagLibSpec extends Specification implements GrailsWebUnitTest, DataTest {
1919

2020
Person personInstance
21+
Cyborg cyborgInstance
2122
Product productInstance
2223

2324
def setup() {
2425
personInstance = new Person(name: "Bart Simpson", password: "bartman", gender: Gender.Male, dateOfBirth: new Date(87, 3, 19), minor: true)
2526
personInstance.address = new Address(street: "94 Evergreen Terrace", city: "Springfield", country: "USA")
2627
personInstance.emails = [home: "bart@thesimpsons.net", school: "bart.simpson@springfieldelementary.edu"]
2728
productInstance = new Product(netPrice: 12.33, name: "<script>alert('XSS');</script>")
29+
cyborgInstance = new Cyborg(name: "Hal", password: "monolith", gender: null)
2830
}
2931

3032
def cleanup() {

src/test/groovy/grails/plugin/formfields/taglib/AllTagSpec.groovy

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
package grails.plugin.formfields.taglib
22

3+
import grails.plugin.formfields.mock.Cyborg
34
import grails.plugin.formfields.mock.Person
45
import grails.plugin.formfields.*
56
import grails.testing.web.taglib.TagLibUnitTest
6-
import org.grails.taglib.GrailsTagException
77
import spock.lang.*
88

99
@Unroll
@@ -13,6 +13,7 @@ class AllTagSpec extends AbstractFormFieldsTagLibSpec implements TagLibUnitTest<
1313

1414
def setupSpec() {
1515
mockDomain(Person)
16+
mockDomain(Cyborg)
1617
}
1718

1819
def setup() {
@@ -58,6 +59,24 @@ class AllTagSpec extends AbstractFormFieldsTagLibSpec implements TagLibUnitTest<
5859
included << ['salutation', 'name', 'password', 'gender', 'dateOfBirth', 'address.street']
5960
}
6061

62+
void 'all tag skips custom #excluded property and includes #included property'() {
63+
given:
64+
views["/_fields/default/_field.gsp"] = '${property} '
65+
views["/_fields/default/_wrapper.gsp"] = '${widget}'
66+
tagLib.exclusionsInput = ['id', 'created', 'modified', 'version']
67+
68+
when:
69+
def output = applyTemplate('<f:all bean="cyborgInstance"/>', [cyborgInstance: cyborgInstance])
70+
71+
then:
72+
!output.contains(excluded)
73+
output.contains(included)
74+
75+
where:
76+
excluded << ['id', 'created', 'modified', 'version', 'onLoad', 'excludedProperty', 'displayFalseProperty']
77+
included << ['salutation', 'name', 'password', 'gender', 'dateOfBirth', 'address.street', 'minor']
78+
}
79+
6180
@Issue('https://github.com/grails-fields-plugin/grails-fields/issues/12')
6281
void 'all tag skips properties listed with the except attribute'() {
6382
given:

src/test/groovy/org/grails/scaffolding/model/DomainModelServiceSpec.groovy

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ class DomainModelServiceSpec extends Specification implements MocksDomain {
9090
1 * getName() >> "lastUpdated"
9191
}
9292
DomainProperty version = Mock(DomainProperty) {
93-
1 * getName() >> "lastUpdated"
93+
1 * getName() >> "version"
9494
}
9595
domainModelService.domainPropertyFactory = Mock(DomainPropertyFactoryImpl) {
9696
1 * build(persistentProperty1) >> dateCreated
@@ -106,6 +106,34 @@ class DomainModelServiceSpec extends Specification implements MocksDomain {
106106
properties.empty
107107
}
108108

109+
void "test getEditableProperties excluded by overriding default exclusions"() {
110+
given:
111+
PersistentProperty persistentProperty1 = Mock(PersistentProperty)
112+
PersistentProperty persistentProperty2 = Mock(PersistentProperty)
113+
PersistentProperty persistentProperty3 = Mock(PersistentProperty)
114+
DomainProperty created = Mock(DomainProperty) {
115+
1 * getName() >> "created"
116+
}
117+
DomainProperty modified = Mock(DomainProperty) {
118+
1 * getName() >> "modified"
119+
}
120+
DomainProperty version = Mock(DomainProperty) {
121+
1 * getName() >> "version"
122+
}
123+
domainModelService.domainPropertyFactory = Mock(DomainPropertyFactoryImpl) {
124+
1 * build(persistentProperty1) >> created
125+
1 * build(persistentProperty2) >> modified
126+
1 * build(persistentProperty3) >> version
127+
}
128+
1 * domainClass.getPersistentProperties() >> [persistentProperty1, persistentProperty2, persistentProperty3]
129+
130+
when:
131+
List<DomainProperty> properties = domainModelService.getInputProperties(domainClass, ['created', 'modified', 'version']).toList()
132+
133+
then: "properties that are excluded by overriding default exclusion are excluded"
134+
properties.empty
135+
}
136+
109137
void "test getEditableProperties constraints display false"() {
110138
given:
111139
PersistentProperty bar = Mock()

0 commit comments

Comments
 (0)