Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
c22fd6c
9.1-SNAPSHOT
chrisala Feb 23, 2026
0b0dd98
Feature/issue333 (#337)
chrisala Feb 27, 2026
503ea60
Bump basic-ftp from 5.0.5 to 5.2.0 (#336)
dependabot[bot] Mar 2, 2026
2f0e589
Revert "Bump basic-ftp from 5.0.5 to 5.2.0 (#336)" (#338)
temi Mar 2, 2026
250917a
Updated ala-security-project AtlasOfLivingAustralia/ecodata#1196
chrisala Mar 10, 2026
84fdede
Workaround discoveryUri eager fetch in integration tests AtlasOfLivin…
chrisala Mar 10, 2026
e3ef18f
Feature/issue1196 (#339)
temi Mar 11, 2026
9b7c120
virus detection error message should not appear if failure is due to …
temi Mar 13, 2026
305547f
added test case and updated logic AtlasOfLivingAustralia/fieldcapture…
temi Mar 13, 2026
c1501a5
handle file upload error message correctly - AtlasOfLivingAustralia/f…
temi Mar 13, 2026
370ec55
removing used variable
temi Mar 15, 2026
0422e96
code review suggestions
temi Mar 15, 2026
bc3dbd2
Merge branch 'feature/3711-fieldcapture' of https://github.com/AtlasO…
temi Mar 15, 2026
1f615de
Added file download support to EcpWebService, fixed a bug with non-au…
chrisala Mar 17, 2026
d5391bd
Merge pull request #340 from AtlasOfLivingAustralia/feature/3711-fiel…
chrisala Mar 17, 2026
ed3c9bb
Merge remote-tracking branch 'origin/dev' into feature/issue3715
chrisala Mar 17, 2026
bbd8647
Updated error messages fieldcapture#3715
chrisala Mar 17, 2026
8d5346f
Don't return empty strings as status codes
chrisala Mar 17, 2026
97bdad4
Bumped actions node version to 24 to resolve build warning fieldcaptu…
chrisala Mar 17, 2026
6563c53
Bumped actions node version to 24 to resolve build warning fieldcaptu…
chrisala Mar 17, 2026
7d1c8cc
Bumped actions node version to 24 to resolve build warning fieldcaptu…
chrisala Mar 17, 2026
1f03077
Merge pull request #341 from AtlasOfLivingAustralia/feature/issue3715
chrisala Mar 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
- name: Install nodejs
uses: actions/setup-node@v4
with:
node-version: '16.x'
node-version: '24.x'
registry-url: 'https://npm.pkg.github.com'
scope: 'AtlasOfLivingAustralia'

Expand All @@ -40,19 +40,24 @@ jobs:
id: pre-release-version
uses: adobe/update-prerelease-npm-version@4dea8f295023f5b18126afd79bae1057a5b92d6e #v1.2.0

- run: npm publish
- run: npm publish --tag=snapshot
env:
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Setup Gradle
uses: gradle/actions/setup-gradle@af1da67850ed9a4cedd57bfd976089dd991e2582 # v4.0.0

- name: Check chromedriver is available
run: echo $CHROMEWEBDRIVER

- name: Check chromedriver version
run: $CHROMEWEBDRIVER/chromedriver --version

- name: Run tests and jacoco coverage report with Gradle
run: ./gradlew -PenableJacoco=true check
run: ./gradlew -PenableJacoco=true -Dwebdriver.chrome.driver=$CHROMEWEBDRIVER/chromedriver check

- name: Run javascript unit tests
run: node_modules/karma/bin/karma start karma.conf.js --single-run --browsers ChromeHeadless
run: npm run test

- name: Clean to remove clover instrumentation
run: ./gradlew clean
Expand Down
3 changes: 2 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ plugins {
id 'jacoco'
}

version "9.0"
version "9.1-SNAPSHOT"
group "org.grails.plugins"

apply plugin:"eclipse"
Expand Down Expand Up @@ -108,6 +108,7 @@ dependencies {
tasks.withType(Test) {
systemProperty 'geb.env', System.getProperty('geb.env') ?: 'chromeHeadless'
systemProperty "geb.build.reportsDir", reporting.file("geb/integrationTest")
systemProperty "webdriver.chrome.driver", System.getProperty('webdriver.chrome.driver')

testLogging {
events "passed", "skipped", "failed"
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ org.gradle.jvmargs=-Dfile.encoding=UTF-8 -Xss2048k -Xmx1024M
exploded=true
enableClover=false
enableJacoco=true
alaSecurityLibsVersion=7.0.0
alaSecurityLibsVersion=7.1.0-SNAPSHOT
12 changes: 6 additions & 6 deletions grails-app/assets/javascripts/forms-knockout-bindings.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,9 @@

}).on('fileuploadfail', function(e, data) {
var jqXHR = data.jqXHR;
if (jqXHR && jqXHR.status === 422) {
var resp = jqXHR.responseJSON || {message: "File upload could not be processed. Possible virus detected."};
error(resp.message);
if (jqXHR && (jqXHR.status === 422 || jqXHR.status === 500)) {
var resp = jqXHR.responseJSON || {};
error(resp.message || jqXHR.responseText || 'File upload failed');
}
else {
error(data.errorThrown);
Expand Down Expand Up @@ -228,9 +228,9 @@

}).on(eventPrefix+'fail', function(e, data) {
var jqXHR = data.jqXHR;
if (jqXHR && jqXHR.status === 422) {
var resp = jqXHR.responseJSON || {message: "File upload could not be processed. Possible virus detected."};
error(resp.message);
if (jqXHR && (jqXHR.status === 422 || jqXHR.status === 500)) {
var resp = jqXHR.responseJSON || {};
error(resp.message || jqXHR.responseText || 'File upload failed');
}
else {
error(data.errorThrown);
Expand Down
5 changes: 4 additions & 1 deletion grails-app/conf/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,10 @@ environments:
appServerName: 'n/a'
oidc:
enabled: true
discoveryUri: 'http://localhost:8080'
discoveryUri: 'file://${user.dir}/src/integration-test/resources/oidcDiscovery.json'
clientId: 'testClientId'
secret: 'testSecret'
allowUnsignedIdTokens: true
jwt:
enabled: false

Expand Down
15 changes: 11 additions & 4 deletions grails-app/controllers/au/org/ala/merit/FileScanInterceptor.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,29 @@ class FileScanInterceptor {

boolean before() {
if (request.respondsTo('getFile')) {
boolean clean = true
List statusCodes = []
def files = request.getFileNames()
while(files.hasNext()) {
def fileName = files.next()
def file = request.getFile(fileName)
if (file) {
boolean isClean = scanService.isDocumentClean(file)
clean &= isClean
statusCodes << scanService.getDocumentScanStatus(file)
}
}

if (!clean) {
if (statusCodes.any { it == HttpStatus.SC_UNPROCESSABLE_ENTITY }) {
response.status = HttpStatus.SC_UNPROCESSABLE_ENTITY
render contentType: 'application/json', text: [success: false, message: "File upload rejected: virus detected"] as JSON, status: HttpStatus.SC_UNPROCESSABLE_ENTITY
return false
}
else if (statusCodes.every { it == HttpStatus.SC_OK }) {
return true
}
else {
response.status = HttpStatus.SC_INTERNAL_SERVER_ERROR
render contentType: 'application/json', text: [success: false, message: "File upload failed during scanning"] as JSON, status: HttpStatus.SC_INTERNAL_SERVER_ERROR
return false
}
}

true
Expand Down
42 changes: 39 additions & 3 deletions grails-app/services/au/org/ala/ecodata/forms/EcpWebService.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,41 @@ class EcpWebService {
}
}

/**
* This method is used when the response is expected to be a stream, e.g. for downloading files.
* It returns a Map with keys [statusCode: <http status code>, error: <error message if applicable>]
* The supplied outputStream will be written to with the response from the web service if the call is successful.
* The caller is responsible for closing the outputStream.
*/
Map readToStream(String url, OutputStream outputStream, boolean includeUserId = true, Integer timeout = null) {
HttpURLConnection conn = null
Map resp = [:]
try {
conn = configureConnection(url, includeUserId, timeout)
try (InputStream inputStream = conn.inputStream) {
outputStream << inputStream
}
resp = [statusCode: conn.responseCode]

} catch (SocketTimeoutException e) {
int statusCode = conn ? (conn.responseCode ?: HttpStatus.SC_GATEWAY_TIMEOUT) : HttpStatus.SC_GATEWAY_TIMEOUT
resp = [error: "Timed out calling web service. URL= ${url}.", statusCode: statusCode]
log.error "Timed out calling web service. URL= ${url}.", e
} catch (SocketException se) {
int statusCode = conn ? (conn.responseCode ?: HttpStatus.SC_GATEWAY_TIMEOUT) : HttpStatus.SC_GATEWAY_TIMEOUT
resp = [error: "Timed out calling web service. URL= ${url}.", statusCode: statusCode]

log.warn "Socket connection closed. ${se.getMessage()} URL= ${url}.", se
} catch (Exception e) {
int statusCode = conn ? (conn.responseCode ?: HttpStatus.SC_INTERNAL_SERVER_ERROR) : HttpStatus.SC_INTERNAL_SERVER_ERROR
resp = [error: "Timed out calling web service. URL= ${url}.", statusCode: statusCode]

log.error "Failed calling web service. ${e.getClass()} ${e.getMessage()} URL= ${url}.", e
}

resp
}

Map getString(String url, boolean includeAuth) {
URLConnection conn = null
Map resp = [:]
Expand All @@ -104,7 +139,7 @@ class EcpWebService {
resp.statusCode = conn.responseCode
} catch (SocketTimeoutException e) {
resp.error = "Timed out calling web service. URL= ${url}."
resp.statusCode = HttpStatus.CONNECTION_TIMED_OUT
resp.statusCode = HttpStatus.SC_GATEWAY_TIMEOUT
log.warn resp.error
} catch (SocketException se) {
resp.error = "Socket connection closed. ${se.getMessage()} URL= ${url}."
Expand Down Expand Up @@ -607,9 +642,10 @@ class EcpWebService {
}

def user = userService.getUser()
String userId = user.userId
String userIdHeader = grailsApplication.config.getProperty('app.http.header.userId')

if (user) {
String userIdHeader = grailsApplication.config.getProperty('app.http.header.userId')
String userId = user.userId
requestBuilder.addHeader(userIdHeader, userId)
} else {
log.warn("No user associated with request: ${url}")
Expand Down
10 changes: 5 additions & 5 deletions grails-app/services/au/org/ala/ecodata/forms/ScanService.groovy
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
package au.org.ala.ecodata.forms


import org.springframework.http.HttpStatus
import org.springframework.web.multipart.MultipartFile

class ScanService {
EcpWebService ecpWebService
def grailsApplication

boolean isDocumentClean(MultipartFile file) {
int getDocumentScanStatus(MultipartFile file) {
if (file == null) {
return true
return HttpStatus.OK.value()
}

if (grailsApplication.config.getProperty('scanFile.enabled', Boolean, true)) {
Expand All @@ -20,9 +20,9 @@ class ScanService {

baseUrl = baseUrl.replaceAll("/ws", '/reporting/ws')
def result = ecpWebService.postMultipart("${baseUrl}/document/scanDocument", [:], file, "fileToScan", true)
return result.statusCode == org.springframework.http.HttpStatus.OK.value()
return result.statusCode
}

return true
return HttpStatus.OK.value()
}
}
111 changes: 0 additions & 111 deletions karma.conf.js

This file was deleted.

Loading
Loading