Skip to content

Commit

Permalink
Add API to decorate link with user/session info
Browse files Browse the repository at this point in the history
  • Loading branch information
greg-el committed Sep 13, 2023
1 parent 1f76199 commit 7b8912d
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 1 deletion.
39 changes: 38 additions & 1 deletion Sources/Core/Tracker/Tracker.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ class Tracker: NSObject {

private var builderFinished = false


/// The object used for sessionization, i.e. it characterizes user activity.
private(set) var session: Session?
/// Previous screen view state.
Expand Down Expand Up @@ -385,6 +384,44 @@ class Tracker: NSObject {
emitter.resumeTimer()
session?.startChecker()
}

@objc func decorateLink(_ url: URL, extendedParameters: CrossDeviceParameterConfiguration? = nil) -> URL? {
var userId: String
switch self.session {
case .none:
logError(message: "\(url) could not be decorated as session.userId is nil")
return nil
case .some(let s):
userId = s.userId
}

let extendedParameters = extendedParameters ?? CrossDeviceParameterConfiguration()
let sessionId = extendedParameters.sessionId ? self.session?.state?.sessionId ?? "" : ""
let sourceId = extendedParameters.sourceId ? self.appId : ""
let sourcePlatform = extendedParameters.sourcePlatform ? devicePlatformToString(self.devicePlatform) ?? "" : ""
let subjectUserId = extendedParameters.subjectUserId ? self.subject?.domainUserId ?? "" : ""
let reason = extendedParameters.reason ?? ""

let spParameters = [
userId,
String(Date().timeIntervalSince1970),
sessionId,
subjectUserId,
sourceId,
sourcePlatform,
reason
].joined(separator: ".")

var components = URLComponents(url: url, resolvingAgainstBaseURL: false)
if var existingSp = components?.queryItems?.first(where: { $0.name == "_sp" }) {
existingSp.value = spParameters
} else {
components?.queryItems?.append(URLQueryItem(name: "_sp", value: spParameters))
}

return components?.url
}


// MARK: - Notifications management

Expand Down
4 changes: 4 additions & 0 deletions Sources/Core/Tracker/TrackerControllerImpl.swift
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ class TrackerControllerImpl: Controller, TrackerController {
func track(_ event: Event) -> UUID? {
return tracker.track(event)
}

func decorateLink(_ url: URL, extendedParameters: CrossDeviceParameterConfiguration? = nil) -> URL? {
return tracker.decorateLink(url, extendedParameters: extendedParameters)
}

// MARK: - Properties' setters and getters

Expand Down
3 changes: 3 additions & 0 deletions Sources/Snowplow/Controllers/TrackerController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,7 @@ public protocol TrackerController: TrackerConfigurationProtocol {
/// The tracker will start tracking again.
@objc
func resume()

@objc
func decorateLink(_ url: URL, extendedParameters: CrossDeviceParameterConfiguration?) -> URL?
}
36 changes: 36 additions & 0 deletions Sources/Snowplow/Tracker/CrossDeviceParameterConfiguration.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright (c) 2013-2023 Snowplow Analytics Ltd. All rights reserved.
//
// This program is licensed to you under the Apache License Version 2.0,
// and you may not use this file except in compliance with the Apache License
// Version 2.0. You may obtain a copy of the Apache License Version 2.0 at
// http://www.apache.org/licenses/LICENSE-2.0.
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the Apache License Version 2.0 is distributed on
// an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
// express or implied. See the Apache License Version 2.0 for the specific
// language governing permissions and limitations there under.

import Foundation

public class CrossDeviceParameterConfiguration : NSObject {
var sessionId: Bool
var subjectUserId: Bool
var sourceId: Bool
var sourcePlatform: Bool
var reason: String?

init(
sessionId: Bool = true,
subjectUserId: Bool = false,
sourceId: Bool = false,
sourcePlatform: Bool = false,
reason: String? = nil
) {
self.sessionId = sessionId
self.subjectUserId = subjectUserId
self.sourceId = sourceId
self.sourcePlatform = sourcePlatform
self.reason = reason
}
}
46 changes: 46 additions & 0 deletions Tests/TestLinkDecorator.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright (c) 2013-2023 Snowplow Analytics Ltd. All rights reserved.
//
// This program is licensed to you under the Apache License Version 2.0,
// and you may not use this file except in compliance with the Apache License
// Version 2.0. You may obtain a copy of the Apache License Version 2.0 at
// http://www.apache.org/licenses/LICENSE-2.0.
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the Apache License Version 2.0 is distributed on
// an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
// express or implied. See the Apache License Version 2.0 for the specific
// language governing permissions and limitations there under.

import XCTest
@testable import SnowplowTracker

class TestLinkDecorator : XCTest {

func testTest() {
let tracker = getTracker()

let test = URL(string: "https://example.com")!
let result = tracker.decorateLink(test)
}

func getTracker() -> TrackerController {
let networkConnection = MockNetworkConnection(requestOption: .post, statusCode: 200)
let emitterConfig = EmitterConfiguration()
emitterConfig.eventStore = MockEventStore()
emitterConfig.bufferOption = .single
let networkConfig = NetworkConfiguration(networkConnection: networkConnection)

return createTracker(networkConfig: networkConfig, emitterConfig: emitterConfig)
}

private func createTracker(networkConfig: NetworkConfiguration, emitterConfig: EmitterConfiguration) -> TrackerController {
let trackerConfig = TrackerConfiguration()
trackerConfig.installAutotracking = false
trackerConfig.screenViewAutotracking = false
trackerConfig.lifecycleAutotracking = false
let namespace = "testEmitter" + String(describing: Int.random(in: 0..<100))
return Snowplow.createTracker(namespace: namespace,
network: networkConfig,
configurations: [trackerConfig, emitterConfig])!
}
}

0 comments on commit 7b8912d

Please sign in to comment.