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

RCS org changes #1042

Merged
merged 17 commits into from
Dec 12, 2024
Merged
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -105,6 +105,7 @@ dependencies {

implementation 'org.apache.poi:poi:5.2.2'
implementation 'org.apache.poi:poi-ooxml:5.2.2'
implementation 'org.apache.poi:poi-ooxml-full:5.2.2'
implementation 'org.codehaus.groovy:groovy-dateutil:3.0.8'

implementation "org.grails.plugins:ala-auth:$alaSecurityLibsVersion"
3 changes: 2 additions & 1 deletion grails-app/conf/application.groovy
Original file line number Diff line number Diff line change
@@ -671,7 +671,7 @@ environments {
ecodata.use.uuids = false
app.external.model.dir = "./models/"
grails.serverURL = "http://localhost:8080"
app.uploads.url = "${grails.serverURL}/document/download?filename="
app.uploads.url = "/document/download/"

app.elasticsearch.indexOnGormEvents = true
app.elasticsearch.indexAllOnStartup = true
@@ -700,6 +700,7 @@ environments {
audit.thread.schedule.interval = 500l;

paratoo.core.baseUrl = "http://localhost:${wiremock.port}/monitor"
spatial.baseUrl = "http://localhost:${wiremock.port}"
}
production {
grails.logging.jul.usebridge = false
11 changes: 11 additions & 0 deletions grails-app/conf/data/mapping.json
Original file line number Diff line number Diff line change
@@ -88,6 +88,17 @@
"dateCreatedSort" : {
"type" : "keyword", "normalizer" : "case_insensitive_sort"
},
"serviceProviderName": {
"type" : "text",
"copy_to": ["organisationName","organisationFacet", "organisationSort"]
},
"lastUpdated": {
"type" : "date",
"copy_to" : "lastUpdatedSort"
},
"lastUpdatedSort" : {
"type" : "keyword", "normalizer" : "case_insensitive_sort"
},
"associatedOrgs": {
"properties" : {
"name" : {
Original file line number Diff line number Diff line change
@@ -41,7 +41,7 @@ class ApiKeyInterceptor {
PreAuthorise pa = method.getAnnotation(PreAuthorise) ?: controllerClass.getAnnotation(PreAuthorise)

if (pa.basicAuth()) {
au.org.ala.web.UserDetails user = userService.getUserFromJWT()
def user = userService.setUser()
request.userId = user?.userId
if(permissionService.isUserAlaAdmin(request.userId)) {
/* Don't enforce check for ALA admin.*/
18 changes: 2 additions & 16 deletions grails-app/controllers/au/org/ala/ecodata/AuditInterceptor.groovy
Original file line number Diff line number Diff line change
@@ -7,7 +7,7 @@ import grails.config.Config
class AuditInterceptor implements GrailsConfigurationAware {

int order = 100 // This needs to be after the @RequireApiKey interceptor which makes the userId available via the authService
String httpRequestHeaderForUserId
static String httpRequestHeaderForUserId
UserService userService
AuthService authService

@@ -16,21 +16,7 @@ class AuditInterceptor implements GrailsConfigurationAware {
}

boolean before() {
// userId is set from either the request param userId or failing that it tries to get it from
// the UserPrincipal (assumes ecodata is being accessed directly via admin page)
def userId = authService.getUserId() ?: request.getHeader(httpRequestHeaderForUserId)
if (userId) {
def userDetails = userService.setCurrentUser(userId)
if (userDetails) {
// We set the current user details in the request scope because
// the 'afterView' hook can be called prior to the actual rendering (despite the name)
// and the thread local can get clobbered before it is actually required.
// Consumers who have access to the request can simply extract current user details
// from there rather than use the service.
request.setAttribute(UserDetails.REQUEST_USER_DETAILS_KEY, userDetails)
}
}

userService.setUser()
true
}

Original file line number Diff line number Diff line change
@@ -52,7 +52,8 @@ class ProjectActivityController {
}

if (!result) {
result = [status: 404, text: 'Invalid id'];
render status: 404, text: [message: 'Invalid id', status: 404] as JSON
return
}
}

5 changes: 3 additions & 2 deletions grails-app/domain/au/org/ala/ecodata/Organisation.groovy
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
package au.org.ala.ecodata

import au.org.ala.ecodata.graphql.mappers.OrganisationGraphQLMapper
import au.org.ala.ecodata.graphql.mappers.ProjectGraphQLMapper
import org.bson.types.ObjectId
import org.springframework.validation.Errors

/**
* Represents an organisation that manages projects in MERIT and BioCollect.
* Allows some branding as well as grouping / ownership of projects.
@@ -39,6 +37,8 @@ class Organisation {

/** Stores configuration information for how reports should be generated for this organisation (if applicable) */
Map config
/** Stores service target details like MeriPlan in projects */
Map custom

String collectoryInstitutionId // Reference to the Collectory

@@ -74,6 +74,7 @@ class Organisation {
config nullable: true
sourceSystem nullable: true
externalIds nullable: true
custom nullable: true
hubId nullable: true, validator: { String hubId, Organisation organisation, Errors errors ->
GormMongoUtil.validateWriteOnceProperty(organisation, 'organisationId', 'hubId', errors)
}
7 changes: 6 additions & 1 deletion grails-app/domain/au/org/ala/ecodata/Score.groovy
Original file line number Diff line number Diff line change
@@ -13,6 +13,9 @@ class Score {
/** The label for this score when displayed */
String label

/** Unique human name for this score to be used as a more descriptive alternative to the scoreId in forms/configuration. Must be unique if present */
String name

/** A more detailed description of the score and how it should be interpreted */
String description

@@ -53,6 +56,7 @@ class Score {
tags: nullable:true
label unique: true
scoreId unique: true
name nullable: true, unique: true
}

static mapping = {
@@ -88,7 +92,8 @@ class Score {
entity:entity,
externalId:externalId,
entityTypes:entityTypes,
tags:tags
tags:tags,
name:name
]
if (includeConfig) {
scoreMap.configuration = configuration
34 changes: 32 additions & 2 deletions grails-app/services/au/org/ala/ecodata/ElasticSearchService.groovy
Original file line number Diff line number Diff line change
@@ -111,7 +111,7 @@ class ElasticSearchService {
RestHighLevelClient client
ElasticSearchIndexManager indexManager
def indexingTempInactive = false // can be set to true for loading of dump files, etc
def ALLOWED_DOC_TYPES = [Project.class.name, Site.class.name, Document.class.name, Activity.class.name, Record.class.name, Organisation.class.name, UserPermission.class.name, Program.class.name, Output.class.name]
def ALLOWED_DOC_TYPES = [Project.class.name, Site.class.name, Document.class.name, Activity.class.name, Record.class.name, Organisation.class.name, UserPermission.class.name, Program.class.name, Output.class.name, ProjectActivity.class.name]
def DEFAULT_FACETS = 10
private static Queue<IndexDocMsg> _messageQueue = new ConcurrentLinkedQueue<IndexDocMsg>()

@@ -642,6 +642,14 @@ class ElasticSearchService {
indexHomePage(doc, Project.class.name)
}
break
case ProjectActivity.class.name:
// make sure updates to project activity updates project object.
// helps BioCollect mobile app show correct surveys.
ProjectActivity projectActivity = ProjectActivity.findByProjectActivityId(docId)
if (projectActivity?.projectId) {
indexDocType(projectActivity.projectId, Project.class.name)
}
break
}
}

@@ -1129,7 +1137,7 @@ class ElasticSearchService {
// MERIT project needs private sites to be indexed for faceting purposes but Biocollect does not require private sites.
// Some Biocollect project have huge numbers of private sites. This will significantly hurt performance.
// Hence the if condition.
if(projectMap.isMERIT){
if (projectMap.isMERIT) {

// Allow ESP sites to be hidden, even on the project explorer. Needs to be tided up a bit as MERIT sites were
// already marked as private to avoid discovery via BioCollect
@@ -1166,6 +1174,17 @@ class ElasticSearchService {
// todo: Check if BioCollect requires all sites in `sites` property. If no, merge `projectArea` with `sites`.
projectMap.projectArea = siteService.getSimpleProjectArea(projectMap.projectSiteId)
projectMap.containsActivity = activityService.searchAndListActivityDomainObjects([projectId: projectMap.projectId], null, null, null, [max: 1, offset: 0])?.totalCount > 0
projectMap.projectActivities = projectActivityService.getAllByProject(project.projectId).collect({
[
id: it.id,
projectId: it.projectId,
projectActivityId: it.projectActivityId,
name: it.name,
startDate: it.startDate,
endDate: it.endDate,
published: it.published
]
})
}
projectMap.sites?.each { site ->
// Not useful for the search index and there is a bug right now that can result in invalid POI
@@ -1660,6 +1679,17 @@ class ElasticSearchService {
}
break

case 'projectactivityrecords':
if (projectActivityId) {
if (userId && (permissionService.isUserAlaAdmin(userId) || permissionService.isUserAdminForProject(userId, projectId) || permissionService.isUserEditorForProject(userId, projectId))) {
forcedQuery = '(docType:activity AND projectActivity.projectActivityId:' + projectActivityId + ')'
}
else {
forcedQuery = '(docType:activity AND projectActivity.projectActivityId:' + projectActivityId + ' AND projectActivity.embargoed:false AND (verificationStatusFacet:approved OR verificationStatusFacet:\"not applicable\" OR (NOT _exists_:verificationStatus)))'
}
}
break

case 'myprojectrecords':
if (projectId) {
if (userId) {
27 changes: 27 additions & 0 deletions grails-app/services/au/org/ala/ecodata/UserService.groovy
Original file line number Diff line number Diff line change
@@ -213,4 +213,31 @@ class UserService {
return null
}
}

def setUser() {
String userId
GrailsWebRequest grailsWebRequest = GrailsWebRequest.lookup()
HttpServletRequest request = grailsWebRequest.getCurrentRequest()
def userDetails = request.getAttribute(UserDetails.REQUEST_USER_DETAILS_KEY)

if (userDetails)
return userDetails

// userId is set from either the request param userId or failing that it tries to get it from
// the UserPrincipal (assumes ecodata is being accessed directly via admin page)
userId = getUserFromJWT()?.userId ?: authService.getUserId() ?: request.getHeader(AuditInterceptor.httpRequestHeaderForUserId)

if (userId) {
userDetails = setCurrentUser(userId)
if (userDetails) {
// We set the current user details in the request scope because
// the 'afterView' hook can be called prior to the actual rendering (despite the name)
// and the thread local can get clobbered before it is actually required.
// Consumers who have access to the request can simply extract current user details
// from there rather than use the service.
request.setAttribute(UserDetails.REQUEST_USER_DETAILS_KEY, userDetails)
return userDetails
}
}
}
}
Loading
Loading