Skip to content

Commit 4e0fcf0

Browse files
authoredApr 26, 2024
Merge pull request #1592 from AtlasOfLivingAustralia/feature/hcat-cas
Feature/hcat CAS Implementation
2 parents 582dd09 + 2dd86f0 commit 4e0fcf0

File tree

12 files changed

+922
-51
lines changed

12 files changed

+922
-51
lines changed
 

‎gradle.properties

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
biocollectVersion=6.7
1+
biocollectVersion=6.6.6-REFASSESS-SNAPSHOT
22
grailsVersion=5.1.9
33
grailsGradlePluginVersion=5.1.5
44
assetPipelineVersion=3.3.4

‎grails-app/assets/javascripts/hubs.js

+1
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,7 @@ function ContentViewModel(config) {
480480
self.hideBreadCrumbs = ko.observable(config.hideBreadCrumbs || false);
481481
self.hideProjectAndSurvey = ko.observable(config.hideProjectAndSurvey || false);
482482
self.hideCancelButtonOnForm = ko.observable(config.hideCancelButtonOnForm || false);
483+
self.hideNewButtonOnRecordView = ko.observable(config.hideNewButtonOnRecordView || false);
483484
self.showNote = ko.observable(config.showNote || false);
484485
self.recordNote = ko.observable(config.recordNote || '');
485486
self.industries = ko.observable(config.industries || false);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
package au.org.ala.biocollect
2+
3+
import au.org.ala.biocollect.merit.*
4+
import grails.converters.JSON
5+
import grails.web.servlet.mvc.GrailsParameterMap
6+
7+
import java.time.Instant
8+
9+
class ReferenceAssessmentController {
10+
UserService userService
11+
ProjectActivityService projectActivityService
12+
ActivityService activityService
13+
14+
15+
private def createAssessmentRecordFromReference(Object referenceActivity, Object assessProjectActivity, boolean deIdentify) {
16+
def refDoc = referenceActivity.documents[0]
17+
18+
def baseUrl = ''
19+
if (!refDoc["url"].startsWith('http')) {
20+
baseUrl = grailsApplication.config.getProperty("grails.serverURL", String)
21+
}
22+
23+
def assessPhoto = [
24+
licence: refDoc["licence"],
25+
notes: refDoc["notes"],
26+
filesize: refDoc["filesize"],
27+
staged: true,
28+
url: baseUrl + refDoc["url"],
29+
filename: refDoc["filename"],
30+
attribution: referenceActivity.outputs[0].data["imageAttribution"],
31+
name: refDoc["name"],
32+
documentId: '',
33+
contentType: refDoc["contentType"],
34+
dateTaken: refDoc["dateTaken"],
35+
formattedSize: refDoc["formattedSize"],
36+
thumbnailUrl: baseUrl + refDoc["thumbnailUrl"],
37+
status: "active"
38+
]
39+
40+
def assessActivity = [
41+
outputs: [
42+
[
43+
outputId: "",
44+
outputNotCompleted: false,
45+
data: [
46+
recordedBy: userService.getCurrentUserDisplayName(),
47+
upperConditionBound: "0",
48+
lowerConditionBound: "0",
49+
overallConditionBestEstimate: "0",
50+
mvgGroup: referenceActivity.outputs[0].data.vegetationStructureGroup,
51+
huchinsonGroup: referenceActivity.outputs[0].data.huchinsonGroup,
52+
sitePhoto: [assessPhoto],
53+
deIdentify: deIdentify ? "Yes" : "No"
54+
],
55+
name: assessProjectActivity["pActivityFormName"]
56+
]
57+
],
58+
projectActivityId: assessProjectActivity["projectActivityId"],
59+
userId: userService.getCurrentUserId(),
60+
projectStage: "",
61+
embargoed: false,
62+
type: assessProjectActivity["pActivityFormName"],
63+
projectId: assessProjectActivity["projectId"],
64+
mainTheme: ""
65+
]
66+
67+
// Create the new assessment activity record
68+
activityService.update("", assessActivity)
69+
70+
// Update the numTimesReferenced field on the reference record
71+
referenceActivity.outputs[0].data.numTimesReferenced =
72+
referenceActivity.outputs[0].data.numTimesReferenced as Integer + 1
73+
activityService.update(referenceActivity.activityId, referenceActivity)
74+
75+
// Return the assessment activity
76+
assessActivity
77+
}
78+
79+
def requestRecords() {
80+
def config = grailsApplication.config.getProperty("refAssess", Map)
81+
def body = request.JSON
82+
def result
83+
84+
// Ensure BioCollect is configured for reference assessment projects
85+
if (!config) {
86+
response.status = 500
87+
result = [message: 'The application is not configured for reference assessment projects']
88+
render result as JSON
89+
return
90+
}
91+
92+
// Ensure the body of the request contains the required fields
93+
if (!body['vegetationStructureGroups'] || !body['climateGroups'] || !body.keySet().contains('deIdentify')) {
94+
response.status = 400
95+
result = [message: 'Please ensure the assessment record request contains all relevant fields']
96+
render result as JSON
97+
return
98+
}
99+
100+
// Ensure the user is authenticated
101+
if (!userService.getCurrentUserId()) {
102+
response.status = 403
103+
result = [message: 'User is not authenticated']
104+
render result as JSON
105+
return
106+
}
107+
108+
// Get the activity records for the reference survey
109+
def refActivitiesSearch = activityService.search([
110+
projectActivityId: config.reference.projectActivityId
111+
])
112+
def refActivities = refActivitiesSearch.resp.activities
113+
def maxRecordsToCreate = config.assessment.maxRecordsToCreate as Integer
114+
115+
// Ensure the reference records exist
116+
def numRefActivities = refActivities?.size()
117+
if (numRefActivities == 0) {
118+
response.status = 404
119+
result = [message: 'No reference records found in reference survey']
120+
render result as JSON
121+
return
122+
}
123+
124+
// Filter out any records without data or documents
125+
refActivities = refActivities.findAll {
126+
it.outputs[0].keySet().contains('data') &&
127+
it.documents.size() > 0
128+
}
129+
130+
// Filter out reference activities by the supplied vegetation structure groups & climate groups
131+
refActivities = refActivities.findAll {
132+
body["vegetationStructureGroups"].contains(it.outputs[0].data["vegetationStructureGroup"]) &&
133+
body["climateGroups"].contains(it.outputs[0].data["huchinsonGroup"])
134+
}
135+
136+
// Split & sort the reference activities into:
137+
// Priority records (assessed <= 3 times), prioritising records assessed the MOST
138+
// Other records (assessed > 3 times), prioritising records assessed the LEAST
139+
140+
def priorityRecords = refActivities
141+
.findAll { it.outputs[0].data.numTimesReferenced as Integer <= 3 }
142+
.sort{ -(it.outputs[0].data.numTimesReferenced as Integer) }
143+
def otherRecords = refActivities
144+
.findAll { it.outputs[0].data.numTimesReferenced as Integer > 3 }
145+
.sort{ it.outputs[0].data.numTimesReferenced as Integer }
146+
147+
// Combine the two lists
148+
refActivities = priorityRecords + otherRecords
149+
150+
// Ensure there are reference records after filtering
151+
if (refActivities.size() == 0) {
152+
response.status = 400
153+
result = [message: "No reference images matching your criteria could be found."]
154+
render result as JSON
155+
return
156+
}
157+
158+
def assessProjectActivity = projectActivityService.get(config.assessment.projectActivityId)
159+
def assessActivities = []
160+
for (
161+
int projectIndex = 0;
162+
projectIndex < Math.min(maxRecordsToCreate, refActivities.size());
163+
projectIndex++
164+
) {
165+
assessActivities.push(
166+
createAssessmentRecordFromReference(
167+
refActivities[projectIndex],
168+
assessProjectActivity,
169+
body['deIdentify']
170+
)
171+
)
172+
}
173+
174+
response.status = 200
175+
result = [message: "Found ${assessActivities.size()} images for assessment, please standby..."]
176+
render result as JSON
177+
}
178+
}

‎grails-app/controllers/au/org/ala/biocollect/StaticPageController.groovy

+6-3
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
package au.org.ala.biocollect
22

33
import au.org.ala.biocollect.merit.SettingService
4-
import au.org.ala.web.AlaSecured
4+
import au.org.ala.biocollect.merit.UserService
5+
import au.org.ala.biocollect.merit.hub.HubSettings
56
import au.org.ala.web.NoSSO
67
import au.org.ala.web.SSO
78

89
@SSO
910
class StaticPageController {
1011
SettingService settingService
12+
UserService userService
1113
@NoSSO
1214
def index() {
1315
String page = params.page;
@@ -44,13 +46,14 @@ class StaticPageController {
4446
/**
4547
* Save static page text
4648
*/
47-
@AlaSecured(value = ['ROLE_ADMIN'])
4849
def saveTextAreaSetting() {
4950
String text = params.textValue
5051
String settingKey = params.settingKey
5152
String returnUrl = params.returnUrl ?: g.createLink(controller: 'staticPage', action: 'index', absolute: true, params: [page: settingKey])
5253

53-
if (settingKey) {
54+
if (!userService.doesUserHaveHubRole("admin")) {
55+
flash.errorMessage = "You do not have correct permissions to perform this action"
56+
} else if (settingKey) {
5457
settingService.setSettingText(settingKey, text)
5558
flash.message = "Successfully saved."
5659
} else {

‎grails-app/controllers/au/org/ala/biocollect/UrlMappings.groovy

+3
Original file line numberDiff line numberDiff line change
@@ -167,11 +167,14 @@ class UrlMappings {
167167
format = 'json'
168168
}
169169

170+
"/referenceAssessment/requestRecords"(controller: "referenceAssessment", action: [POST: "requestRecords"])
171+
170172
"500"(controller:'error', action:'response500')
171173
"404"(controller:'error', action:'response404')
172174

173175

174176
// Following api's are used by external mobile clients
177+
175178
"/ws/project/search"(controller: "project", action: 'search')
176179
"/ws/survey/list/$id"(controller: "project", action: 'listSurveys')
177180
"/ws/attachment/upload"(controller: "image", action: 'upload')

‎grails-app/views/admin/editHub.gsp

+5-1
Original file line numberDiff line numberDiff line change
@@ -486,7 +486,11 @@
486486

487487
<h5>Data entry page</h5>
488488
<div class="checkbox">
489-
<input type="checkbox" data-bind="checked: hideCancelButtonOnForm"> Hide cancel button on form create page
489+
<input type="checkbox" data-bind="checked: hideCancelButtonOnForm"> Hide 'Cancel' button on form create page
490+
</div>
491+
<h5>Record view page</h5>
492+
<div class="checkbox">
493+
<input type="checkbox" data-bind="checked: hideNewButtonOnRecordView"> Hide 'Add new record' button on form create page
490494
</div>
491495
<!-- /ko -->
492496
<h3>Quick links</h3>

‎grails-app/views/bioActivity/index.gsp

+1-1
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@
175175
<g:if test="${hasEditRights}">
176176
<a class="btn btn-primary-dark btn-lg" href="${createLink(controller: 'bioActivity', action: 'edit')}/${activity.activityId}"><span class="fas fa-pencil-alt"></span> Edit</a>
177177
</g:if>
178-
<g:if test="${userIsProjectMember}">
178+
<g:if test="${userIsProjectMember && (!hubConfig.content?.hideNewButtonOnRecordView)}">
179179
<a class="btn btn-primary-dark btn-lg" href="${createLink(controller: 'bioActivity', action: 'create')}/${pActivity.projectActivityId}"><span class="fas fa-plus"></span> Add new record</a>
180180
</g:if>
181181
</div>

‎grails-app/views/project/_CSAdmin.gsp

-1
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,6 @@
8686
</div>
8787
</g:if>
8888
</g:if>
89-
9089
</div>
9190
</div>
9291
</div>

‎grails-app/views/staticPage/index.gsp

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
<head>
2222
<meta name="layout" content="${mobile ? "mobile" : "bs4"}"/>
2323
<title></title>
24+
<asset:javascript src="common.js"/>
2425
</head>
2526

2627
<body>

0 commit comments

Comments
 (0)