Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/hcat #1591

Merged
merged 26 commits into from
Apr 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
2d06e55
Added 'Reference Assessment' tab in admin project settings, and stub …
jack-brinkman Jan 22, 2024
3a361c6
Added reference & assessment survey selection dropdowns to project admin
jack-brinkman Jan 24, 2024
8e9ba99
Fixed reference activity retrieval in requestRecords endpoint
jack-brinkman Jan 31, 2024
2e84938
Updated gradle.properties to change biocollectVersion
jack-brinkman Jan 31, 2024
ea531bc
Added queryParams
jack-brinkman Feb 1, 2024
0f55923
First-pass non functional image assessment view
jack-brinkman Mar 4, 2024
d34caef
First-pass interactive record requesting UI
jack-brinkman Mar 5, 2024
42d9259
Moved the requestAssessmentRecords controller view rendering from hub…
jack-brinkman Mar 5, 2024
04f8462
Removed bespoke implementation for assessment record request view, ad…
jack-brinkman Mar 14, 2024
9bb087b
First-pass working implementation of assessment record creation
jack-brinkman Mar 19, 2024
71732c1
Further refactoring to record creation process
jack-brinkman Mar 27, 2024
72c98cc
Fixed image uploading for assessment records, switched knockout-core …
jack-brinkman Mar 27, 2024
708c463
Included de-identify flag in record creation
jack-brinkman Apr 2, 2024
85734f6
Removed bespoke refAssess configuration from application.groovy, fixe…
jack-brinkman Apr 2, 2024
69b7de1
Fixed user hub admin check for static page saving
jack-brinkman Apr 2, 2024
cb84903
Switched to /ws/search endpoint for reference activities search
jack-brinkman Apr 3, 2024
2b2c8f3
Added additional data & documents check for reference records
jack-brinkman Apr 4, 2024
f40a30f
Fixed serverURL reference in image path generation
jack-brinkman Apr 4, 2024
eb0f3b4
Fixed baseUrl variable reference
jack-brinkman Apr 4, 2024
b251cfe
Added 'Hide Add new record button' in hub configuration
jack-brinkman Apr 18, 2024
4957f7c
Revert small changes for parity with develop
jack-brinkman Apr 22, 2024
ec5e42a
Removed pAssessmentActivitiesVM initialisation (no longer used)
jack-brinkman Apr 22, 2024
ef340df
Merge branch 'develop' into feature/hcat
jack-brinkman Apr 22, 2024
343aef2
Merge branch 'develop' into feature/hcat
temi Apr 22, 2024
df7e33b
6.8-REFASSESS-SNAPSHOT
temi Apr 22, 2024
242bb11
Refactored config retrieval
jack-brinkman Apr 26, 2024
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
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
biocollectVersion=6.8-LOGIN-SNAPSHOT
biocollectVersion=6.8-REFASSESS-SNAPSHOT
grailsVersion=5.1.9
grailsGradlePluginVersion=5.1.5
assetPipelineVersion=3.3.4
Expand Down
1 change: 1 addition & 0 deletions grails-app/assets/javascripts/hubs.js
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,7 @@ function ContentViewModel(config) {
self.hideBreadCrumbs = ko.observable(config.hideBreadCrumbs || false);
self.hideProjectAndSurvey = ko.observable(config.hideProjectAndSurvey || false);
self.hideCancelButtonOnForm = ko.observable(config.hideCancelButtonOnForm || false);
self.hideNewButtonOnRecordView = ko.observable(config.hideNewButtonOnRecordView || false);
self.showNote = ko.observable(config.showNote || false);
self.recordNote = ko.observable(config.recordNote || '');
self.industries = ko.observable(config.industries || false);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
package au.org.ala.biocollect

import au.org.ala.biocollect.merit.*
import grails.converters.JSON
import grails.web.servlet.mvc.GrailsParameterMap

import java.time.Instant

class ReferenceAssessmentController {
UserService userService
ProjectActivityService projectActivityService
ActivityService activityService


private def createAssessmentRecordFromReference(Object referenceActivity, Object assessProjectActivity, boolean deIdentify) {
def refDoc = referenceActivity.documents[0]

def baseUrl = ''
if (!refDoc["url"].startsWith('http')) {
baseUrl = grailsApplication.config.getProperty("grails.serverURL", String)
}

def assessPhoto = [
licence: refDoc["licence"],
notes: refDoc["notes"],
filesize: refDoc["filesize"],
staged: true,
url: baseUrl + refDoc["url"],
filename: refDoc["filename"],
attribution: referenceActivity.outputs[0].data["imageAttribution"],
name: refDoc["name"],
documentId: '',
contentType: refDoc["contentType"],
dateTaken: refDoc["dateTaken"],
formattedSize: refDoc["formattedSize"],
thumbnailUrl: baseUrl + refDoc["thumbnailUrl"],
status: "active"
]

def assessActivity = [
outputs: [
[
outputId: "",
outputNotCompleted: false,
data: [
recordedBy: userService.getCurrentUserDisplayName(),
upperConditionBound: "0",
lowerConditionBound: "0",
overallConditionBestEstimate: "0",
mvgGroup: referenceActivity.outputs[0].data.vegetationStructureGroup,
huchinsonGroup: referenceActivity.outputs[0].data.huchinsonGroup,
sitePhoto: [assessPhoto],
deIdentify: deIdentify ? "Yes" : "No"
],
name: assessProjectActivity["pActivityFormName"]
]
],
projectActivityId: assessProjectActivity["projectActivityId"],
userId: userService.getCurrentUserId(),
projectStage: "",
embargoed: false,
type: assessProjectActivity["pActivityFormName"],
projectId: assessProjectActivity["projectId"],
mainTheme: ""
]

// Create the new assessment activity record
activityService.update("", assessActivity)

// Update the numTimesReferenced field on the reference record
referenceActivity.outputs[0].data.numTimesReferenced =
referenceActivity.outputs[0].data.numTimesReferenced as Integer + 1
activityService.update(referenceActivity.activityId, referenceActivity)

// Return the assessment activity
assessActivity
}

def requestRecords() {
def config = grailsApplication.config.getProperty("refAssess", Map)
def body = request.JSON
def result

// Ensure BioCollect is configured for reference assessment projects
if (!config) {
response.status = 500
result = [message: 'The application is not configured for reference assessment projects']
render result as JSON
return
}

// Ensure the body of the request contains the required fields
if (!body['vegetationStructureGroups'] || !body['climateGroups'] || !body.keySet().contains('deIdentify')) {
response.status = 400
result = [message: 'Please ensure the assessment record request contains all relevant fields']
render result as JSON
return
}

// Ensure the user is authenticated
if (!userService.getCurrentUserId()) {
response.status = 403
result = [message: 'User is not authenticated']
render result as JSON
return
}

// Get the activity records for the reference survey
def refActivitiesSearch = activityService.search([
projectActivityId: config.reference.projectActivityId
])
def refActivities = refActivitiesSearch.resp.activities
def maxRecordsToCreate = config.assessment.maxRecordsToCreate as Integer

// Ensure the reference records exist
def numRefActivities = refActivities?.size()
if (numRefActivities == 0) {
response.status = 404
result = [message: 'No reference records found in reference survey']
render result as JSON
return
}

// Filter out any records without data or documents
refActivities = refActivities.findAll {
it.outputs[0].keySet().contains('data') &&
it.documents.size() > 0
}

// Filter out reference activities by the supplied vegetation structure groups & climate groups
refActivities = refActivities.findAll {
body["vegetationStructureGroups"].contains(it.outputs[0].data["vegetationStructureGroup"]) &&
body["climateGroups"].contains(it.outputs[0].data["huchinsonGroup"])
}

// Split & sort the reference activities into:
// Priority records (assessed <= 3 times), prioritising records assessed the MOST
// Other records (assessed > 3 times), prioritising records assessed the LEAST

def priorityRecords = refActivities
.findAll { it.outputs[0].data.numTimesReferenced as Integer <= 3 }
.sort{ -(it.outputs[0].data.numTimesReferenced as Integer) }
def otherRecords = refActivities
.findAll { it.outputs[0].data.numTimesReferenced as Integer > 3 }
.sort{ it.outputs[0].data.numTimesReferenced as Integer }

// Combine the two lists
refActivities = priorityRecords + otherRecords

// Ensure there are reference records after filtering
if (refActivities.size() == 0) {
response.status = 400
result = [message: "No reference images matching your criteria could be found."]
render result as JSON
return
}

def assessProjectActivity = projectActivityService.get(config.assessment.projectActivityId)
def assessActivities = []
for (
int projectIndex = 0;
projectIndex < Math.min(maxRecordsToCreate, refActivities.size());
projectIndex++
) {
assessActivities.push(
createAssessmentRecordFromReference(
refActivities[projectIndex],
assessProjectActivity,
body['deIdentify']
)
)
}

response.status = 200
result = [message: "Found ${assessActivities.size()} images for assessment, please standby..."]
render result as JSON
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package au.org.ala.biocollect

import au.org.ala.biocollect.merit.SettingService
import au.org.ala.web.AlaSecured
import au.org.ala.biocollect.merit.UserService
import au.org.ala.biocollect.merit.hub.HubSettings
import au.org.ala.web.NoSSO
import au.org.ala.web.SSO

@SSO
class StaticPageController {
SettingService settingService
UserService userService
@NoSSO
def index() {
String page = params.page;
Expand Down Expand Up @@ -44,13 +46,14 @@ class StaticPageController {
/**
* Save static page text
*/
@AlaSecured(value = ['ROLE_ADMIN'])
def saveTextAreaSetting() {
String text = params.textValue
String settingKey = params.settingKey
String returnUrl = params.returnUrl ?: g.createLink(controller: 'staticPage', action: 'index', absolute: true, params: [page: settingKey])

if (settingKey) {
if (!userService.doesUserHaveHubRole("admin")) {
flash.errorMessage = "You do not have correct permissions to perform this action"
} else if (settingKey) {
settingService.setSettingText(settingKey, text)
flash.message = "Successfully saved."
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,11 +167,14 @@ class UrlMappings {
format = 'json'
}

"/referenceAssessment/requestRecords"(controller: "referenceAssessment", action: [POST: "requestRecords"])

"500"(controller:'error', action:'response500')
"404"(controller:'error', action:'response404')


// Following api's are used by external mobile clients

"/ws/project/search"(controller: "project", action: 'search')
"/ws/survey/list/$id"(controller: "project", action: 'listSurveys')
"/ws/attachment/upload"(controller: "image", action: 'upload')
Expand Down
6 changes: 5 additions & 1 deletion grails-app/views/admin/editHub.gsp
Original file line number Diff line number Diff line change
Expand Up @@ -486,7 +486,11 @@

<h5>Data entry page</h5>
<div class="checkbox">
<input type="checkbox" data-bind="checked: hideCancelButtonOnForm"> Hide cancel button on form create page
<input type="checkbox" data-bind="checked: hideCancelButtonOnForm"> Hide 'Cancel' button on form create page
</div>
<h5>Record view page</h5>
<div class="checkbox">
<input type="checkbox" data-bind="checked: hideNewButtonOnRecordView"> Hide 'Add new record' button on form create page
</div>
<!-- /ko -->
<h3>Quick links</h3>
Expand Down
2 changes: 1 addition & 1 deletion grails-app/views/bioActivity/index.gsp
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@
<g:if test="${hasEditRights}">
<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>
</g:if>
<g:if test="${userIsProjectMember}">
<g:if test="${userIsProjectMember && (!hubConfig.content?.hideNewButtonOnRecordView)}">
<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>
</g:if>
</div>
Expand Down
1 change: 0 additions & 1 deletion grails-app/views/project/_CSAdmin.gsp
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@
</div>
</g:if>
</g:if>

</div>
</div>
</div>
Expand Down
1 change: 1 addition & 0 deletions grails-app/views/staticPage/index.gsp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
<head>
<meta name="layout" content="${mobile ? "mobile" : "bs4"}"/>
<title></title>
<asset:javascript src="common.js"/>
</head>

<body>
Expand Down
1 change: 1 addition & 0 deletions src/integration-test/resources/data/alaHub.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ var alaHub = {
"hideProjectSurveyDownloadXLSX" : false,
"hideBreadCrumbs" : false,
"hideCancelButtonOnForm" : false,
"hideNewButtonOnRecordView" : false,
"industries" : true,
"enablePartialSearch" : false,
"overriddenLabels" : [
Expand Down
Loading