diff --git a/gradle.properties b/gradle.properties index 5699c1c4..0cdd70e2 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -profileHubVersion=4.0-MANGROVE-SNAPSHOT +profileHubVersion=4.1-SNAPSHOT grailsVersion=5.2.4 grailsGradlePluginVersion=5.2.3 groovyVersion=3.0.11 diff --git a/grails-app/assets/javascripts/profileEditor/controllers/DoiController.js b/grails-app/assets/javascripts/profileEditor/controllers/DoiController.js index 5b3252fd..60eadcb3 100644 --- a/grails-app/assets/javascripts/profileEditor/controllers/DoiController.js +++ b/grails-app/assets/javascripts/profileEditor/controllers/DoiController.js @@ -37,4 +37,10 @@ profileEditor.controller('DoiController', function (util, $filter, profileServic } }); } + + self.trackDownload = function (context, opusId, profileId, publicationId) { + var url = context + '/opus/' + opusId + '/profile/' + profileId + '/publication/' + publicationId + '/file' + profileService.trackPageview(url); + } + }); \ No newline at end of file diff --git a/grails-app/assets/javascripts/profileEditor/controllers/ExportController.js b/grails-app/assets/javascripts/profileEditor/controllers/ExportController.js index 442c6f32..e0a5bcbd 100644 --- a/grails-app/assets/javascripts/profileEditor/controllers/ExportController.js +++ b/grails-app/assets/javascripts/profileEditor/controllers/ExportController.js @@ -1,7 +1,7 @@ /** * Export controller */ -profileEditor.controller('ExportController', function (util, $window, $modal, $http, config) { +profileEditor.controller('ExportController', function (util, $window, $modal, $http, config, profileService) { var self = this; self.profileId = util.getEntityId("profile"); @@ -49,6 +49,8 @@ profileEditor.controller('ExportController', function (util, $window, $modal, $h } else { $http.get(url); } + + profileService.trackPageview(url); }); } }); diff --git a/grails-app/assets/javascripts/profileEditor/directives/publication.js b/grails-app/assets/javascripts/profileEditor/directives/publication.js index 505c1abb..40aae4f5 100644 --- a/grails-app/assets/javascripts/profileEditor/directives/publication.js +++ b/grails-app/assets/javascripts/profileEditor/directives/publication.js @@ -12,8 +12,12 @@ profileEditor.directive('publication', function ($browser) { prefix: '@' }, templateUrl: '/profileEditor/publication.htm', - controller: ['$scope', 'config', function ($scope, config) { + controller: ['$scope', 'config', 'profileService', function ($scope, config, profileService) { $scope.context = config.contextPath; + $scope.trackDownload = function (context, opusId, profileId, publicationId) { + var url = context + '/opus/' + opusId + '/profile/' + profileId + '/publication/' + publicationId + '/file' + profileService.trackPageview(url); + } }], link: function (scope, element, attrs, ctrl) { diff --git a/grails-app/assets/javascripts/profileEditor/services/ProfileService.js b/grails-app/assets/javascripts/profileEditor/services/ProfileService.js index 5644bbb1..a90a57ac 100644 --- a/grails-app/assets/javascripts/profileEditor/services/ProfileService.js +++ b/grails-app/assets/javascripts/profileEditor/services/ProfileService.js @@ -1277,6 +1277,22 @@ profileEditor.service('profileService', function ($http, util, $cacheFactory, co loadMasterListItems: function(opus) { var future = $http.get(util.contextRoot() + '/opus/' + opus.uuid + '/masterList/keybaseItems', {disableAlertOnFailure: true }); return util.toStandardPromise(future); + }, + + trackPageview: function (url, referrer) { + if ((typeof fathom !== 'undefined') && fathom.trackPageview) { + var payload = { }; + if (url) { + payload.url = url; + } + + if (referrer) { + payload.referrer = referrer; + } + + console.debug("Tracking pageview with payload: " + JSON.stringify(payload)); + fathom.trackPageview(payload); + } } } }); diff --git a/grails-app/assets/javascripts/profileEditor/templates/publication.tpl.htm b/grails-app/assets/javascripts/profileEditor/templates/publication.tpl.htm index 0609c189..13a5eab1 100644 --- a/grails-app/assets/javascripts/profileEditor/templates/publication.tpl.htm +++ b/grails-app/assets/javascripts/profileEditor/templates/publication.tpl.htm @@ -17,7 +17,7 @@
-  Download
\ No newline at end of file diff --git a/grails-app/conf/spring/resources.groovy b/grails-app/conf/spring/resources.groovy index 876fefb3..fa950068 100644 --- a/grails-app/conf/spring/resources.groovy +++ b/grails-app/conf/spring/resources.groovy @@ -1,11 +1,3 @@ -import au.org.ala.profile.analytics.GoogleAnalyticsClientFactory - // Place your Spring DSL code here beans = { - - googleAnalyticsClientFactory(GoogleAnalyticsClientFactory) { - // override with beans.googleAnalyticsClientFactory.baseUrl property - baseUrl = 'https://ssl.google-analytics.com' - } - googleAnalyticsClient(googleAnalyticsClientFactory: 'getInstance') { } } diff --git a/grails-app/controllers/au/org/ala/profile/api/ApiController.groovy b/grails-app/controllers/au/org/ala/profile/api/ApiController.groovy index f430b28f..7b9951d2 100644 --- a/grails-app/controllers/au/org/ala/profile/api/ApiController.groovy +++ b/grails-app/controllers/au/org/ala/profile/api/ApiController.groovy @@ -1,7 +1,6 @@ package au.org.ala.profile.api import au.ala.org.ws.security.RequireApiKey -import au.org.ala.profile.analytics.Analytics import au.org.ala.profile.hub.BaseController import au.org.ala.profile.hub.MapService import au.org.ala.profile.hub.ProfileService @@ -21,7 +20,6 @@ import io.swagger.v3.oas.annotations.security.SecurityRequirement import io.swagger.v3.oas.annotations.security.SecurityScheme import au.org.ala.plugins.openapi.Path -@Analytics @SecurityScheme(name = "auth", type = SecuritySchemeType.HTTP, scheme = "bearer" @@ -36,6 +34,78 @@ class ApiController extends BaseController { MapService mapService ApiService apiService + @Path("/api/opus/{opusId}") + @Operation( + summary = "Get collection (opus) details", + operationId = "/api/opus/{opusId}", + method = "GET", + responses = [ + @ApiResponse( + responseCode = "200", + content = @Content( + mediaType = "application/json", + array = @ArraySchema( + schema = @Schema( + implementation = OpusResponse.class + ) + ) + ), + headers = [ + @Header(name = 'Access-Control-Allow-Headers', description = "CORS header", schema = @Schema(type = "String")), + @Header(name = 'Access-Control-Allow-Methods', description = "CORS header", schema = @Schema(type = "String")), + @Header(name = 'Access-Control-Allow-Origin', description = "CORS header", schema = @Schema(type = "String")) + ] + ), + @ApiResponse(responseCode = "400", + description = "opusId is a required parameter"), + @ApiResponse(responseCode = "403", + description = "You do not have the necessary permissions to perform this action."), + @ApiResponse(responseCode = "405", + description = "An unexpected error has occurred while processing your request."), + @ApiResponse(responseCode = "404", + description = "Collection not found"), + @ApiResponse(responseCode = "500", + description = "An unexpected error has occurred while processing your request.") + ], + parameters = [ + @Parameter( + name = "opusId", + in = ParameterIn.PATH, + required = true, + description = "Collection id" + ), + @Parameter(name = "Access-Token", + in = ParameterIn.HEADER, + required = false, + description = "Access token to read private collection"), + @Parameter(name = "Accept-Version", + in = ParameterIn.HEADER, + required = true, + description = "The API version", + schema = @Schema( + name = "Accept-Version", + type = "string", + defaultValue = '1.0', + allowableValues = ["1.0"] + ) + ) + ], + security = [@SecurityRequirement(name="auth"), @SecurityRequirement(name = "oauth")] + ) + def getOpus () { + if (!params.opusId) { + badRequest "opusId is a required parameter" + } else { + Map opus = profileService.getOpus(params.opusId) + if (!opus) { + notFound() + } else { + opus.remove('accessToken') + render opus as JSON + } + } + } + @Path("/api/opus/{opusId}/profile") @Operation( summary = "List profiles in a collection", diff --git a/grails-app/controllers/au/org/ala/profile/api/ApiInterceptor.groovy b/grails-app/controllers/au/org/ala/profile/api/ApiInterceptor.groovy index 44c79df7..00220bff 100644 --- a/grails-app/controllers/au/org/ala/profile/api/ApiInterceptor.groovy +++ b/grails-app/controllers/au/org/ala/profile/api/ApiInterceptor.groovy @@ -27,19 +27,16 @@ class ApiInterceptor { def method = controllerClass?.getMethod(actionName, [] as Class[]) if (authorization) { - def user = authService.userDetails() - if (user) { - if (params.opusId && (opus = profileService.getOpus(params.opusId))) { - params.isOpusPrivate = opus.privateCollection - if ((params.isOpusPrivate - || controllerClass?.isAnnotationPresent(RequiresAccessToken) - || method?.isAnnotationPresent(RequiresAccessToken) - ) && (token != opus.accessToken)) { - log.warn("No valid access token for opus ${opus.uuid} when calling ${controllerName}/${actionName}") - authorised = false - } else { - authorised = true - } + if (params.opusId && (opus = profileService.getOpus(params.opusId))) { + params.isOpusPrivate = opus.privateCollection + if ((params.isOpusPrivate + || controllerClass?.isAnnotationPresent(RequiresAccessToken) + || method?.isAnnotationPresent(RequiresAccessToken) + ) && (token != opus.accessToken)) { + log.warn("No valid access token for opus ${opus.uuid} when calling ${controllerName}/${actionName}") + authorised = false + } else { + authorised = true } } } diff --git a/grails-app/controllers/au/org/ala/profile/hub/AnalyticsInterceptor.groovy b/grails-app/controllers/au/org/ala/profile/hub/AnalyticsInterceptor.groovy deleted file mode 100644 index e7fed1dd..00000000 --- a/grails-app/controllers/au/org/ala/profile/hub/AnalyticsInterceptor.groovy +++ /dev/null @@ -1,136 +0,0 @@ -package au.org.ala.profile.hub - -import au.org.ala.profile.analytics.Analytics -import au.org.ala.web.AuthService -import grails.core.GrailsApplication -import io.swagger.v3.oas.annotations.Operation -import au.org.ala.grails.AnnotationMatcher -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.http.HttpHeaders - -import javax.annotation.PostConstruct -import javax.servlet.http.Cookie - -import static com.google.common.net.HttpHeaders.REFERER -import static com.google.common.net.HttpHeaders.USER_AGENT - -class AnalyticsInterceptor { - - @Autowired - GrailsApplication grailsApplication - @Autowired(required = false) - AnalyticsService analyticsService - @Autowired - AuthService authService - @Autowired - WebServiceWrapperService webServiceWrapperService - - // Code runs after controller action is called. Ordering it such that it is called last. - int order = HIGHEST_PRECEDENCE - - AnalyticsInterceptor () { - - } - - @PostConstruct - void init () { - AnnotationMatcher.matchAnnotation(this, grailsApplication, Analytics) - } - - boolean before () { - true - } - - boolean after () { - try { - if (response.getStatus() in 200..299) { // only care about successful HTTP responses - final artefact = grailsApplication.getArtefactByLogicalPropertyName('Controller', controllerName) - final annotation = artefact?.clazz.with { clazz -> - (clazz?.methods.find { it.name == actionName }?.getAnnotation(Analytics) ?: clazz?.declaredFields.find { it.name == actionName }?.getAnnotation(Analytics)) ?: clazz?.getAnnotation(Analytics) - } - if (annotation) { - final clientId = extractClientIdFromGoogleAnalyticsCookie(request.cookies) - final path = URLDecoder.decode(request.forwardURI, 'utf-8') - Map payload = [:] - def classAction = artefact.getClazz().methods.find {it.name == actionName} - Operation operation = classAction.getAnnotation(Operation) - if (operation) { - // page title - payload.dt = operation.summary() ?: "" - payload[grailsApplication.config.app.analytics.apiid] = operation.operationId() ?: "" - if (params.opusId) payload[grailsApplication.config.app.analytics.collectionid] = params.opusId - if (params.profileId) payload[grailsApplication.config.app.analytics.profileid] = params.profileId - - def userId = authService.getUserId() - if (userId) payload[grailsApplication.config.app.analytics.userid] = userId - else { - String authorization = request.getHeader(HttpHeaders.AUTHORIZATION) - if (authorization) { - payload[grailsApplication.config.app.analytics.userid] = Utils.getClientId(authorization) - } - } - } - - log.debug("Sending pageview to analytics for ${request.serverName}, $path, $clientId, ${request.remoteAddr}") - analyticsService?.pageView(request.serverName, path, clientId, request.remoteAddr, request.getHeader(USER_AGENT), request.getHeader(REFERER), payload) - } - } - } catch (e) { - log.error("Caught exception in analytics filter", e) - } - - true - } - - void afterView () { - } - - /** - * 1. Under Measurement Protocol it's recommended that you use UUID v4 format to produce standard, unique client - * IDs. However, it also supports the old X.Y 32-bit IDs used in the previous generation of GA. - - * 2. Universal Analytics analytics.js creates a cookie called _ga. There's just one cookie, not several as there used - * to be in ye olde GA. The cookie contains four values: GA1.2.299259584.1357814039257. - * (There are no longer two underscores as there were on old GA cookies). - * - * GA1 = The cookie format version - * 2 = The domain depth on which the cookie is written - * 299259584.1357814039257 = The client id (cid) - * - * Using this CID will ensure server side analytics events match to the same user as the client side events. - * - * Source: https://plus.google.com/110147996971766876369/posts/Mz1ksPoBGHx - * - * If the CID can't be extracted from the cookie, a random UUID is used instead. A CID may not be available in - * the case that a download or PDF link has been given directly to a user. - * TODO use a persistent UUID per user. - * - * @param cookies The cookies from a request - * @return The Google Analytics CID parameter - */ - private String extractClientIdFromGoogleAnalyticsCookie(Cookie[] cookies) { - final GA_VERSION_INDEX = 0 - final GA_CLIENT_ID_PART_1_INDEX = 2 - final GA_CLIENT_ID_PART_2_INDEX = 3 - final GA_COOKIE_PARTS_EXPECTED_LENGTH = 4 - final GA_EXPECTED_VERSION = 'GA1' - final cookie = cookies.find { it.name == '_ga' } - String clientId = '' - if (cookie) { - final analyticsCookieComponents = cookie.value.split('\\.') - if (analyticsCookieComponents.length > 1 - && analyticsCookieComponents[GA_VERSION_INDEX] == GA_EXPECTED_VERSION - && analyticsCookieComponents.length == GA_COOKIE_PARTS_EXPECTED_LENGTH) { - clientId = analyticsCookieComponents[GA_CLIENT_ID_PART_1_INDEX] + '.' + analyticsCookieComponents[GA_CLIENT_ID_PART_2_INDEX] - } else { - log.warn("Got Google Analytics cookie but not of a known version: ${cookie.value}") - } - } - - if (!clientId) { - clientId = UUID.randomUUID().toString() - } - - return clientId - } -} diff --git a/grails-app/controllers/au/org/ala/profile/hub/ExportController.groovy b/grails-app/controllers/au/org/ala/profile/hub/ExportController.groovy index f4b81186..a11b92ea 100644 --- a/grails-app/controllers/au/org/ala/profile/hub/ExportController.groovy +++ b/grails-app/controllers/au/org/ala/profile/hub/ExportController.groovy @@ -1,6 +1,5 @@ package au.org.ala.profile.hub -import au.org.ala.profile.analytics.Analytics import grails.converters.JSON import org.springframework.web.context.request.RequestContextHolder @@ -9,7 +8,6 @@ class ExportController extends BaseController { ProfileService profileService ExportService exportService - @Analytics def getPdf() { if (!params.profileId || !params.opusId) { badRequest "profileId and opusId are required parameters" diff --git a/grails-app/controllers/au/org/ala/profile/hub/ProfileController.groovy b/grails-app/controllers/au/org/ala/profile/hub/ProfileController.groovy index b80171a9..f66566cf 100644 --- a/grails-app/controllers/au/org/ala/profile/hub/ProfileController.groovy +++ b/grails-app/controllers/au/org/ala/profile/hub/ProfileController.groovy @@ -1,6 +1,5 @@ package au.org.ala.profile.hub -import au.org.ala.profile.analytics.Analytics import au.org.ala.profile.security.PrivateCollectionSecurityExempt import au.org.ala.profile.security.Secured import au.org.ala.web.AuthService @@ -532,7 +531,6 @@ class ProfileController extends BaseController { } } - @Analytics def proxyPublicationDownload() { final pubId = params.publicationId as String if (!pubId) { diff --git a/grails-app/controllers/au/org/ala/profile/hub/UrlMappings.groovy b/grails-app/controllers/au/org/ala/profile/hub/UrlMappings.groovy index 67608965..971755e6 100644 --- a/grails-app/controllers/au/org/ala/profile/hub/UrlMappings.groovy +++ b/grails-app/controllers/au/org/ala/profile/hub/UrlMappings.groovy @@ -257,6 +257,7 @@ class UrlMappings { // The following are APIs. group("/api") { + get "/opus/$opusId" (version: "1.0", controller: "api", action: "getOpus", namespace: "v1") get "/opus/$opusId/profile" (version: "1.0", controller: "api", action: "getProfiles", namespace: "v1") get "/opus/$opusId/profile/$profileId" (version: "1.0", controller: "api", action: "get", namespace: "v1") get "/opus/$opusId/profile/$profileId/image" (version: "1.0", controller: "api", action: "getImages", namespace: "v1") diff --git a/grails-app/services/au/org/ala/profile/hub/AnalyticsService.groovy b/grails-app/services/au/org/ala/profile/hub/AnalyticsService.groovy deleted file mode 100644 index d04465d0..00000000 --- a/grails-app/services/au/org/ala/profile/hub/AnalyticsService.groovy +++ /dev/null @@ -1,47 +0,0 @@ -package au.org.ala.profile.hub - -import au.org.ala.profile.analytics.GoogleAnalyticsClient - -import static grails.async.Promises.task - -class AnalyticsService { - - static transactional = false - - def grailsApplication - GoogleAnalyticsClient googleAnalyticsClient - - /** - * Asynchronously send a page view to the analytics end point. - * @param hostname The hostname of the page view - * @param path The path of the page view - * @param clientId The client id of the page view - * @param userIp The originating ip of the page view - * @param userAgent The user agent for the page view - * @param referrer The 'referer' for the page view - */ - void pageView(String hostname, String path, String clientId, String userIp, String userAgent, String referrer, Map payload = [:]) { - final String googleAnalyticsId = grailsApplication.config.googleAnalyticsId - if (googleAnalyticsId) { - task { - final data = [ - dh : hostname, // Document hostname. - dp : path, // Page. - uip: userIp, // User IP - ua : userAgent ?: '', // User Agent - dr : referrer ?: '', // Document referrer - ] + payload - final call = googleAnalyticsClient.collect('1', googleAnalyticsId, clientId, 'pageview', data) - try { - final resp = call.execute() - if (!resp.successful) { - log.warn("Analytics pageview for $clientId with data: $data failed") - } - } catch(e) { - log.error("Caught exception while sending pageview to analytics", e) - } - } - } - } - -} diff --git a/grails-app/views/layouts/_custom-top.gsp b/grails-app/views/layouts/_custom-top.gsp index 928a4566..2411247a 100644 --- a/grails-app/views/layouts/_custom-top.gsp +++ b/grails-app/views/layouts/_custom-top.gsp @@ -21,14 +21,9 @@ - %{-- Google Analytics --}% - - - %{--End Google Analytics--}% + %{-- Fathom analytics --}% + + %{-- End Fathom analytics --}% diff --git a/grails-app/views/profile/publication.gsp b/grails-app/views/profile/publication.gsp index 5136fa74..a1542adf 100644 --- a/grails-app/views/profile/publication.gsp +++ b/grails-app/views/profile/publication.gsp @@ -36,6 +36,7 @@
Download PDF View Profile diff --git a/package-lock.json b/package-lock.json index 1b5ddec1..5ff9acf9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5459,10 +5459,9 @@ } }, "body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", - + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz", + "integrity": "sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==", "dev": true, "requires": { "bytes": "3.1.2", @@ -5473,91 +5472,10 @@ "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", - "qs": "6.11.0", + "qs": "6.10.3", "raw-body": "2.5.1", "type-is": "~1.6.18", "unpipe": "1.0.0" - }, - "dependencies": { - "bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "dev": true - }, - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true - }, - "http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "dev": true, - "requires": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "dev": true, - "requires": { - "ee-first": "1.1.1" - } - }, - "qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "dev": true, - "requires": { - "side-channel": "^1.0.4" - } - }, - "raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", - "dev": true, - "requires": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - } - }, - "setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true - }, - "statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "dev": true - }, - "toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "dev": true - } } }, "boom": { @@ -6018,15 +5936,11 @@ "integrity": "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==", "dev": true }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true }, "call-bind": { "version": "1.0.2", @@ -6074,40 +5988,9 @@ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "requires": { - "ansi-styles": "^1.1.0", - "escape-string-regexp": "^1.0.0", - "has-ansi": "^0.1.0", - "strip-ansi": "^0.3.0", - "supports-color": "^0.2.0" - }, - "dependencies": { - "ansi-regex": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-0.2.1.tgz", - "integrity": "sha512-sGwIGMjhYdW26/IhwK2gkWWI8DRCVO6uj3hYgHT+zD+QL1pa37tM3ujhyfcJIYSbsxp7Gxhy7zrRW/1AHm4BmA==", - "dev": true - }, - "ansi-styles": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.1.0.tgz", - "integrity": "sha1-6uy/Zs1waIJ2Cy9GkVgrj1XXp94=", - "dev": true - }, - "strip-ansi": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.3.0.tgz", - "integrity": "sha1-JfSOoiynkYfzF0pNuHWTR7sSYiA=", - "dev": true, - "requires": { - "ansi-regex": "^0.2.1" - } - }, - "supports-color": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-0.2.0.tgz", - "integrity": "sha1-2S3iaU6z9nMjlz1649i1W0wiGQo=", - "dev": true - } + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, "chmodr": { @@ -6381,6 +6264,12 @@ "integrity": "sha512-v+7uBd1pqe5YtgPacIIbZ8HuHeLFVNe4mUEyFDXL6KiqzEykjbw+5mXZXpGFgNVasdL4jWKgaKIXrEHiynN1LA==", "dev": true }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true + }, "destroy": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", @@ -6840,9 +6729,9 @@ "dev": true }, "get-intrinsic": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", - "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz", + "integrity": "sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==", "dev": true, "requires": { "function-bind": "^1.1.1", @@ -6961,12 +6850,6 @@ "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", "dev": true }, - "has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true - }, "hawk": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/hawk/-/hawk-1.1.1.tgz", @@ -6991,6 +6874,27 @@ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true }, + "http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "requires": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "dependencies": { + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true + } + } + }, "http-proxy": { "version": "1.18.1", "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", @@ -7090,6 +6994,21 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz", "integrity": "sha512-Kak1hi6/hYHGVPmdyiZijoQyz5x2iGVzs6w9GYB/HiXEtylY7tIoYEROMjvM1d9nXJqPOrG2MNPMn01bJ+S0Rw==", "dev": true + }, + "strip-ansi": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.3.0.tgz", + "integrity": "sha512-DerhZL7j6i6/nEnVG0qViKXI0OKouvvpsAiaj7c+LfqZZZxdwZtv8+UiA/w4VUJpT8UzX0pR1dcHOii1GbmruQ==", + "dev": true, + "requires": { + "ansi-regex": "^0.2.1" + } + }, + "supports-color": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-0.2.0.tgz", + "integrity": "sha512-tdCZ28MnM7k7cJDJc7Eq80A9CsRFAAOZUy41npOZCs++qSjfIy7o5Rh46CBk+Dk5FbKJ33X3Tqg4YrV07N5RaA==", + "dev": true } } }, @@ -7386,9 +7305,9 @@ "dev": true }, "json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", "dev": true }, "jsonfile": { @@ -7851,12 +7770,6 @@ "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", "dev": true }, - "object-inspect": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", - "dev": true - }, "on-finished": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", @@ -8026,12 +7939,33 @@ "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", "dev": true }, + "qs": { + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", + "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "dev": true, + "requires": { + "side-channel": "^1.0.4" + } + }, "range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", "dev": true }, + "raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dev": true, + "requires": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, "read": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", @@ -8244,6 +8178,12 @@ } } }, + "setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, "shell-quote": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.4.3.tgz", @@ -8541,6 +8481,12 @@ "is-number": "^7.0.0" } }, + "toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true + }, "touch": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/touch/-/touch-0.0.2.tgz", @@ -8599,9 +8545,9 @@ } }, "ua-parser-js": { - "version": "0.7.33", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.33.tgz", - "integrity": "sha512-s8ax/CeZdK9R/56Sui0WM6y9OFREJarMRHqLB2EwkovemBxNQ+Bqu8GAsUnVcXKgphb++ghr/B2BZx4mahujPw==", + "version": "0.7.31", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.31.tgz", + "integrity": "sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ==", "dev": true }, "uglify-js": { diff --git a/src/main/groovy/au/org/ala/profile/analytics/Analytics.java b/src/main/groovy/au/org/ala/profile/analytics/Analytics.java deleted file mode 100644 index 96d4aaae..00000000 --- a/src/main/groovy/au/org/ala/profile/analytics/Analytics.java +++ /dev/null @@ -1,13 +0,0 @@ -package au.org.ala.profile.analytics; - -import java.lang.annotation.*; - -/** - * Indicates that a controller action (or entire controller) requires - * reporting pageviews to the analytics service from the server side. - */ -@Target({ElementType.FIELD, ElementType.METHOD, ElementType.TYPE}) -@Retention(RetentionPolicy.RUNTIME) -@Documented -public @interface Analytics { -} diff --git a/src/main/groovy/au/org/ala/profile/analytics/GoogleAnalyticsClient.java b/src/main/groovy/au/org/ala/profile/analytics/GoogleAnalyticsClient.java deleted file mode 100644 index b7e6d255..00000000 --- a/src/main/groovy/au/org/ala/profile/analytics/GoogleAnalyticsClient.java +++ /dev/null @@ -1,23 +0,0 @@ -package au.org.ala.profile.analytics; - -import retrofit2.Call; -import retrofit2.http.Field; -import retrofit2.http.FieldMap; -import retrofit2.http.FormUrlEncoded; -import retrofit2.http.POST; - -import java.util.Map; - -public interface GoogleAnalyticsClient { - - @FormUrlEncoded - @POST("collect") - Call collect( - @Field("v") String version, - @Field("tid") String trackingId, - @Field("cid") String clientId, - @Field("t") String hitType, - @FieldMap Map otherParams - ); - -} diff --git a/src/main/groovy/au/org/ala/profile/analytics/GoogleAnalyticsClientFactory.java b/src/main/groovy/au/org/ala/profile/analytics/GoogleAnalyticsClientFactory.java deleted file mode 100644 index d6c653e2..00000000 --- a/src/main/groovy/au/org/ala/profile/analytics/GoogleAnalyticsClientFactory.java +++ /dev/null @@ -1,22 +0,0 @@ -package au.org.ala.profile.analytics; - -import retrofit2.Retrofit; - -/** - * Factory bean for generating a GoogleAnalyticsClient instance for Spring - */ -public class GoogleAnalyticsClientFactory { - - private String baseUrl; - - public GoogleAnalyticsClientFactory() {} - - public GoogleAnalyticsClient getInstance() { - Retrofit retrofit = new Retrofit.Builder().baseUrl(baseUrl).build(); - return retrofit.create(GoogleAnalyticsClient.class); - } - - public void setBaseUrl(String baseUrl) { - this.baseUrl = baseUrl; - } -} diff --git a/src/main/groovy/au/org/ala/profile/api/OpusResponse.groovy b/src/main/groovy/au/org/ala/profile/api/OpusResponse.groovy new file mode 100644 index 00000000..b1c5a1e4 --- /dev/null +++ b/src/main/groovy/au/org/ala/profile/api/OpusResponse.groovy @@ -0,0 +1,62 @@ +package au.org.ala.profile.api + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties +import groovy.transform.Canonical + +@Canonical +@JsonIgnoreProperties('metaClass') +class OpusResponse { + String uuid + String dataResourceUid + String title + String shortName + String description + String masterListUid + Map dataResourceConfig + String approvedImageOption + List approvedLists + List featureLists + String featureListSectionName + Map brandingConfig + Map profileLayoutConfig + Map opusLayoutConfig + Map theme + Map help + String keybaseProjectId + String keybaseKeyId + String attributeVocabUuid + String authorshipVocabUuid + String groupVocabUuid + boolean autoDraftProfiles + String glossaryUuid + List attachments + boolean enablePhyloUpload + boolean enableOccurrenceUpload + boolean enableTaxaUpload + boolean enableKeyUpload + boolean privateCollection + boolean keepImagesPrivate + boolean usePrivateRecordData + Map mapConfig + List supportingOpuses + List requestedSupportingOpuses + List sharingDataWith + boolean autoApproveShareRequests + boolean allowCopyFromLinkedOpus + boolean showLinkedOpusAttributes + boolean allowFineGrainedAttribution + List authorities + String copyrightText + String footerText + Map contact + boolean hasAboutPage + int profileCount + String florulaListId + String aboutHtml + String citationHtml + String citationProfile + List tags + List additionalStatuses + Long dateCreated + Long lastUpdated +} diff --git a/src/test/groovy/au/org/ala/profile/api/ApiControllerSpec.groovy b/src/test/groovy/au/org/ala/profile/api/ApiControllerSpec.groovy index 5d01467c..ee560ec6 100644 --- a/src/test/groovy/au/org/ala/profile/api/ApiControllerSpec.groovy +++ b/src/test/groovy/au/org/ala/profile/api/ApiControllerSpec.groovy @@ -17,6 +17,36 @@ class ApiControllerSpec extends Specification implements ControllerUnitTest> [uuid: 'abc'] + + when: + params.opusId = opusId + controller.getOpus() + + then: + response.status == responseCode + + where: + opusId | responseCode + null | 400 + 'abc' | 404 + 'opus1' | 200 + } + + void "getOpus output should not contain access token"() { + setup: + profileService.getOpus('opus1') >> [uuid: 'abc', accessToken: 'test1'] + + when: + params.opusId = "opus1" + controller.getOpus() + + then: + response.json.accessToken == null + } + void "getProfiles should be provided with opus id parameter"() { setup: profileService.getOpus('opus1') >> [uuid: 'abc'] diff --git a/src/test/groovy/au/org/ala/profile/hub/AnalyticsInterceptorSpec.groovy b/src/test/groovy/au/org/ala/profile/hub/AnalyticsInterceptorSpec.groovy deleted file mode 100644 index 56289015..00000000 --- a/src/test/groovy/au/org/ala/profile/hub/AnalyticsInterceptorSpec.groovy +++ /dev/null @@ -1,156 +0,0 @@ -package au.org.ala.profile.hub - -import au.org.ala.plugins.openapi.Path -import au.org.ala.profile.analytics.Analytics -import au.org.ala.profile.api.ProfileBriefResponse -import au.org.ala.web.AuthService -import au.org.ala.web.UserDetails -import grails.converters.JSON -import grails.events.Events -import grails.testing.web.interceptor.InterceptorUnitTest -import groovy.util.logging.Slf4j -import org.grails.web.servlet.mvc.GrailsWebRequest -import org.grails.web.util.GrailsApplicationAttributes -import spock.lang.Specification - -import javax.servlet.http.Cookie -import java.security.Principal - -/* - * Copyright (C) 2021 Atlas of Living Australia - * All Rights Reserved. - * - * The contents of this file are subject to the Mozilla Public - * License Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * Created by Temi on 23/8/21. - */ -@Slf4j -class AnalyticsInterceptorSpec extends Specification implements InterceptorUnitTest { - - def controller - - def setup() { - defineBeans { - authService(MockAuthService) - webServiceWrapperService(WebServiceWrapperService) - } - - grailsApplication.addArtefact("Controller", ExampleController) - grailsApplication.config.security.authorisation.disable = false - grailsApplication.config.lists.base.url = "http://lists.ala.org.au" - grailsApplication.config.image.staging.dir = "/data/profile-hub/" - grailsApplication.config.app.analytics = [apiid: "cd1", collectionid: "cd3", profileid: "cd4", userid: "cd2"] - } - - void "Send appropriate data to GA depending on called controller action"() { - setup: - - interceptor.analyticsService = Mock(AnalyticsService) - controller = (ExampleController) mockController(ExampleController) - interceptor.match(controller: "example") - - when: - params.opusId = "public1" - request.method = "GET" - request.addHeader(MockAuthService.DEFAULT_AUTH_HEADER, userId) - request.cookies = [new Cookie('_ga', 'GA1.1.abc.123')].toArray() - request.requestURI = "/opus/public1/profile" - request.setAttribute(GrailsApplicationAttributes.CONTROLLER_NAME_ATTRIBUTE, 'example') - request.setAttribute(GrailsApplicationAttributes.ACTION_NAME_ATTRIBUTE, 'publicAction') - withInterceptors(controller: "example", action: "publicAction") { - controller.publicAction() - } - - then: - response.status == responseCode - 1 * interceptor.analyticsService.pageView("localhost", "/opus/public1/profile", 'abc.123', "127.0.0.1", null, null, payload) - - where: - userId | responseCode | payload - "" | 200 | [dt: "List profiles in a collection", cd1: "/opus/{opusId}/profile", cd3: "public1"] - "123" | 200 | [dt: "List profiles in a collection", cd1: "/opus/{opusId}/profile", cd3: "public1", cd2: "123"] - - } -} - - -class User implements Principal { - - Map attributes - - User(Map attributes) { - this.attributes = attributes - } - - @Override - String getName() { - return "Fred" - } - - Map getAttributes() { - return attributes - } -} - -@Analytics -class ExampleController { - MockAnalyticsService analyticsService - @Path("/opus/{opusId}/profile") - @io.swagger.v3.oas.annotations.Operation( - summary = "List profiles in a collection", - operationId = "/opus/{opusId}/profile", - method = "GET", - responses = [ - @io.swagger.v3.oas.annotations.responses.ApiResponse( - responseCode = "200", - content = @io.swagger.v3.oas.annotations.media.Content( - mediaType = "application/json", - array = @io.swagger.v3.oas.annotations.media.ArraySchema( - schema = @io.swagger.v3.oas.annotations.media.Schema( - implementation = ProfileBriefResponse.class - ) - ) - ), - headers = [ - @io.swagger.v3.oas.annotations.headers.Header(name = 'X-Total-Count', description = "Total number of profiles", schema = @io.swagger.v3.oas.annotations.media.Schema(type = "integer")), - @io.swagger.v3.oas.annotations.headers.Header(name = 'Access-Control-Allow-Headers', description = "CORS header", schema = @io.swagger.v3.oas.annotations.media.Schema(type = "String")), - @io.swagger.v3.oas.annotations.headers.Header(name = 'Access-Control-Allow-Methods', description = "CORS header", schema = @io.swagger.v3.oas.annotations.media.Schema(type = "String")), - @io.swagger.v3.oas.annotations.headers.Header(name = 'Access-Control-Allow-Origin', description = "CORS header", schema = @io.swagger.v3.oas.annotations.media.Schema(type = "String")) - ] - ) - ] - ) - def publicAction() { - [:] as JSON - } -} - -class MockAuthService extends AuthService implements Events { - static final String DEFAULT_AUTH_HEADER = "X-ALA-userId" - @Override - UserDetails getUserForEmailAddress(String emailAddress) { - if (emailAddress) { - new UserDetails(userId: "123") - } - } - - @Override - String getUserId(){ - def userId = GrailsWebRequest.lookup()?.getHeader(DEFAULT_AUTH_HEADER) - userId - } -} - -class MockAnalyticsService extends AnalyticsService implements Events { - @Override - void pageView(String hostname, String path, String clientId, String userIp, String userAgent, String referrer, Map payload = [:]) { - } -} \ No newline at end of file diff --git a/src/test/js/specs/services/ProfileServiceSpec.js b/src/test/js/specs/services/ProfileServiceSpec.js index 7cd2a2c8..5eab2231 100644 --- a/src/test/js/specs/services/ProfileServiceSpec.js +++ b/src/test/js/specs/services/ProfileServiceSpec.js @@ -438,4 +438,23 @@ describe("ProfileService tests", function () { http.expectGET("/someContext/ws/image/abcdefghijlkmnop").respond("bla"); }); + + it("should invoke GET request when trackService is called", function() { + window.fathom = { + trackPageview: function(payload) { + + http.get(payload.url); + } + }; + + spyOn(window.fathom, 'trackPageview'); + service.trackPageview('/opus/xyz/profile/abc/pdf'); + + expect(window.fathom.trackPageview).toHaveBeenCalledWith({url: '/opus/xyz/profile/abc/pdf'}); + + // Ignore below lines. added to prevent call to http.flush from throwing an error + service.getImageMetadata('abcdefghijlkmnop', true); + http.expectGET("/someContext/ws/image/abcdefghijlkmnop").respond("bla"); + // end ignore + }); }); \ No newline at end of file