diff --git a/grails-app/assets/javascripts/show.js b/grails-app/assets/javascripts/show.js index 6ebac7dc4..03597f2ce 100644 --- a/grails-app/assets/javascripts/show.js +++ b/grails-app/assets/javascripts/show.js @@ -152,7 +152,6 @@ $(document).ready(function() { alert("You can't mark a record as a duplicate of itself"); return; } else { - $.post(OCC_REC.contextPath + "/occurrences/assertions/add", { recordUuid: recordUuid, @@ -165,6 +164,18 @@ $(document).ready(function() { relatedRecordReason: relatedRecordReason, }, function (data) { + // when add assertion succeeds, we update alert settings + if (myAnnotationQueryId) { + var orig_state = $('#notifyChangeCheckbox').prop('data-origstate'); + var new_state = $('#notifyChangeCheckbox').prop('checked'); + + // only update when user changed preference + if (orig_state !== new_state) { + var actionpath = new_state ? ("/occurrences/addAlert?queryId=" + myAnnotationQueryId) : ("/occurrences/deleteAlert?queryId=" + myAnnotationQueryId) + $.post(OCC_REC.contextPath + actionpath) + } + } + $('#assertionSubmitProgress').css({'display': 'none'}); $("#submitSuccess").html("Thanks for flagging the problem!"); $("#issueFormSubmit").hide(); @@ -197,6 +208,43 @@ $(document).ready(function() { $(el).html(replaceURLWithHTMLLinks(html)); // convert it }); + var myAnnotationQueryId = null + + $('#assertionButton').click(function (e) { + var getAlerts = OCC_REC.contextPath + "/occurrences/alerts"; + // hide check box until we get user alerts settings + $("#notifyChange").hide(); + + $.getJSON(getAlerts, function (data) { + // init status + myAnnotationQueryId = null + var myAnnotationEnabled = false + if (data.enabledQueries) { + for (var i = 0; i < data.enabledQueries.length; i++) { + if (data.enabledQueries[i].name.indexOf(OCC_REC.alertName) !== -1) { + myAnnotationEnabled = true; + myAnnotationQueryId = data.enabledQueries[i].id + } + } + } + + if (data.disabledQueries) { + for (var i = 0; i < data.disabledQueries.length; i++) { + if (data.disabledQueries[i].name.indexOf(OCC_REC.alertName) !== -1) { + myAnnotationEnabled = false; + myAnnotationQueryId = data.disabledQueries[i].id + } + } + } + + // if find 'my annotation' show the check box + if (myAnnotationQueryId !== null) { + $("#notifyChange").show(); + $("#notifyChangeCheckbox").prop('checked', myAnnotationEnabled); + $("#notifyChangeCheckbox").prop('data-origstate', myAnnotationEnabled); + } + }) + }) // bind to form "close" button TODO $("input#close").on("click", function(e) { @@ -598,7 +646,6 @@ function updateConfirmVerificationEvents(occUuid, assertionUuid, userDisplayName } console.log("Submitting an assertion with userAssertionStatus: " + userAssertionStatus) - $.post(OCC_REC.contextPath + "/occurrences/assertions/add", { recordUuid: occUuid, code: code, diff --git a/grails-app/conf/plugin.groovy b/grails-app/conf/plugin.groovy index 3446b61da..4b3575609 100644 --- a/grails-app/conf/plugin.groovy +++ b/grails-app/conf/plugin.groovy @@ -143,6 +143,7 @@ alwaysshow.imagetab = false facets.defaultSelected = "data_resource_uid,taxon_name,year,multimedia" +myannotation.name="My Annotations" mapdownloads { baseLayers { default_layer { diff --git a/grails-app/controllers/au/org/ala/biocache/hubs/BiocacheHubsUrlMappings.groovy b/grails-app/controllers/au/org/ala/biocache/hubs/BiocacheHubsUrlMappings.groovy index 49f0f4e23..2e9b8b646 100644 --- a/grails-app/controllers/au/org/ala/biocache/hubs/BiocacheHubsUrlMappings.groovy +++ b/grails-app/controllers/au/org/ala/biocache/hubs/BiocacheHubsUrlMappings.groovy @@ -24,6 +24,9 @@ class BiocacheHubsUrlMappings { "/occurrences/next"(controller: 'occurrence', action: 'next') "/occurrences/previous"(controller: 'occurrence', action: 'previous') "/occurrences/dataQualityExcludeCounts"(controller: 'occurrence', action: 'dataQualityExcludeCounts') + "/occurrences/alerts"(controller: 'occurrence', action: [GET: 'getAlerts']) + "/occurrences/addAlert"(controller: 'occurrence', action: [POST: 'addAlert']) + "/occurrences/deleteAlert"(controller: 'occurrence', action: [POST: 'deleteAlert']) "/occurrences/$id"(controller: 'occurrence', action: 'show') "/occurrence/$id"(controller: 'occurrence', action: 'show') "/assertions/$id"(controller: 'assertions', action: 'assertions') diff --git a/grails-app/controllers/au/org/ala/biocache/hubs/OccurrenceController.groovy b/grails-app/controllers/au/org/ala/biocache/hubs/OccurrenceController.groovy index 4452b5db5..b31c993f6 100644 --- a/grails-app/controllers/au/org/ala/biocache/hubs/OccurrenceController.groovy +++ b/grails-app/controllers/au/org/ala/biocache/hubs/OccurrenceController.groovy @@ -17,7 +17,6 @@ package au.org.ala.biocache.hubs import au.org.ala.dataquality.model.QualityProfile import au.org.ala.web.CASRoles -import com.google.common.base.Stopwatch import com.maxmind.geoip2.record.Location import grails.converters.JSON import groovy.util.logging.Slf4j @@ -639,4 +638,34 @@ class OccurrenceController { data.count = qualityService.getExcludeCount(params.categoryLabel, profile.getCategories(), requestParams) render data as JSON } + + def getAlerts() { + String userId = authService?.getUserId() + if (userId == null) { + response.status = 404 + render ([error: 'userId must be supplied to get alerts'] as JSON) + } else { + render webServicesService.getAlerts(userId) as JSON + } + } + + def addAlert() { + String userId = authService?.getUserId() + if (userId == null) { + response.status = 404 + render ([error: 'userId must be supplied to add alert'] as JSON) + } else { + render webServicesService.addAlert(userId, params.queryId) as JSON + } + } + + def deleteAlert() { + String userId = authService?.getUserId() + if (userId == null) { + response.status = 404 + render ([error: 'userId must be supplied to delete alert'] as JSON) + } else { + render webServicesService.deleteAlert(userId, params.queryId) as JSON + } + } } diff --git a/grails-app/i18n/messages_en.properties b/grails-app/i18n/messages_en.properties index 1c8d74379..8f6509d65 100644 --- a/grails-app/i18n/messages_en.properties +++ b/grails-app/i18n/messages_en.properties @@ -135,6 +135,7 @@ show.issueform.label01 = Issue type: show.issueform.label02 = Comment: show.issueform.label03 = Duplicate Record ID: show.issueform.label04 = Duplicate Reason: +show.issueform.notifyme = Notify me when records I have annotated are updated show.issueform.relatedrecord.found.this = You are indicating this record (the one you are viewing): show.issueform.relatedrecord.found.other = is a duplicate of this record (the id you provided): show.issueform.button.submit = Submit diff --git a/grails-app/services/au/org/ala/biocache/hubs/WebServicesService.groovy b/grails-app/services/au/org/ala/biocache/hubs/WebServicesService.groovy index 1dcb6b42c..7034056c9 100644 --- a/grails-app/services/au/org/ala/biocache/hubs/WebServicesService.groovy +++ b/grails-app/services/au/org/ala/biocache/hubs/WebServicesService.groovy @@ -100,6 +100,21 @@ class WebServicesService { getJsonElements(url) } + def getAlerts(String userId) { + def url = "${grailsApplication.config.alerts.baseURL}" + "/api/alerts/user/" + userId + return getJsonElements(url, "${grailsApplication.config.alerts.apiKey}") + } + + def addAlert(String userId, String queryId) { + String url = "${grailsApplication.config.alerts.baseURL}" + "/api/alerts/user/" + userId + "/subscribe/" + queryId + postFormData(url, [:], grailsApplication.config.alerts.apiKey as String) + } + + def deleteAlert(String userId, String queryId) { + String url = "${grailsApplication.config.alerts.baseURL}" + "/api/alerts/user/" + userId + "/unsubscribe/" + queryId + postFormData(url, [:], grailsApplication.config.alerts.apiKey as String) + } + def JSONObject getDuplicateRecordDetails(JSONObject record) { log.debug "getDuplicateRecordDetails -> ${record?.processed?.occurrence?.associatedOccurrences}" if (record?.processed?.occurrence?.associatedOccurrences) { @@ -401,12 +416,15 @@ class WebServicesService { * @param url * @return */ - JSONElement getJsonElements(String url) { + JSONElement getJsonElements(String url, String apiKey = null) { log.debug "(internal) getJson URL = " + url def conn = new URL(url).openConnection() try { conn.setConnectTimeout(10000) conn.setReadTimeout(50000) + if (apiKey != null) { + conn.setRequestProperty('apiKey', apiKey) + } return JSON.parse(conn.getInputStream(), "UTF-8") } catch (Exception e) { def error = "Failed to get json from web service (${url}). ${e.getClass()} ${e.getMessage()}, ${e}" @@ -445,13 +463,17 @@ class WebServicesService { * @param postParams * @return postResponse (Map with keys: statusCode (int) and statusMsg (String) */ - def Map postFormData(String uri, Map postParams) { + def Map postFormData(String uri, Map postParams, String apiKey = null) { HTTPBuilder http = new HTTPBuilder(uri) log.debug "POST (form encoded) to ${http.uri}" Map postResponse = [:] http.request( Method.POST ) { + if (apiKey != null) { + headers.'apiKey' = apiKey + } + send ContentType.URLENC, postParams response.success = { resp -> diff --git a/grails-app/views/occurrence/_recordSidebar.gsp b/grails-app/views/occurrence/_recordSidebar.gsp index 36479f7f2..5a2565613 100644 --- a/grails-app/views/occurrence/_recordSidebar.gsp +++ b/grails-app/views/occurrence/_recordSidebar.gsp @@ -351,6 +351,11 @@

+ +

+ +

+

" class="btn btn-primary" /> " class="btn btn-default" onClick="$('#loginOrFlag').modal('hide');"/> diff --git a/grails-app/views/occurrence/show.gsp b/grails-app/views/occurrence/show.gsp index e385bf0da..e85deb52f 100644 --- a/grails-app/views/occurrence/show.gsp +++ b/grails-app/views/occurrence/show.gsp @@ -59,7 +59,8 @@ status="s">'${sds}': '${grailsApplication.config.sensitiveDatasets[sds]}'${s < (sensitiveDatasets.size() - 1) ? ',' : ''} }, - hasGoogleKey: ${grailsApplication.config.google.apikey as Boolean} + hasGoogleKey: ${grailsApplication.config.google.apikey as Boolean}, + alertName: "${grailsApplication.config.myannotation.name}" } // Google charts