Skip to main content

C. Searching SDK Authentications

The Entrupy iOS SDK provides functionality to search for past authentications initiated by the currently authorized user. This allows you to build features like a submission history screen within your application.

Backend Search Alternative

If you need to search authentications across all users within your organization or require more complex server-side filtering and data aggregation, you should use the Entrupy API from your backend server. The SDK search is scoped to the logged-in SDK user.

To search for submissions, use the searchSubmissions method. This method supports pagination and filtering.

Key Parameters:

  • pageCursor: An array (often of strings or a specific cursor object type defined by the SDK) that determines which page of results to fetch. For the first page, pass an empty array or nil as appropriate based on the SDK's exact method signature.
  • filters: An array of dictionaries to filter search results. Each dictionary typically contains a key (the field to filter on) and a value or values (the criteria).
  • startDate, endDate: Unix epoch timestamps (as TimeInterval or Double) to filter submissions within a specific date range. Use 0 if a date boundary is not needed.
  • paginationLimit: An integer specifying the maximum number of items per page (e.g., 20). The maximum allowed by the SDK is typically 25.

Ensure your class conforms to the EntrupySearchDelegate protocol.

// Swift
import EntrupySDK

// Ensure your class conforms to EntrupySearchDelegate
// class YourViewController: UIViewController, EntrupySearchDelegate { ... }

class SubmissionSearchManager {
weak var delegate: EntrupySearchDelegate? // Assign your delegate here

private var nextPageCursor: [AnyHashable]? = [] // Store cursor for pagination. Type based on SDK.
private var isLoading = false
var allItemsLoaded = false

let perPage = 20

init(delegate: EntrupySearchDelegate) {
self.delegate = delegate
}

func fetchInitialSubmissions(filters: [[String: Any]] = [], startDate: TimeInterval = 0, endDate: TimeInterval = 0) {
nextPageCursor = [] // Reset for a new initial search
allItemsLoaded = false
fetchNextPage(filters: filters, startDate: startDate, endDate: endDate)
}

func fetchNextPage(filters: [[String: Any]] = [], startDate: TimeInterval = 0, endDate: TimeInterval = 0) {
guard !isLoading, !allItemsLoaded else {
if isLoading { print("Search already in progress.") }
if allItemsLoaded { print("All items already loaded.") }
return
}

guard EntrupyApp.sharedInstance().isAuthorizationValid() else {
print("User not authorized. Cannot perform search.")
// Handle re-authorization if needed
// Potentially call a delegate method to indicate auth error
return
}

isLoading = true
EntrupyApp.sharedInstance().searchDelegate = self.delegate

// The type for pageCursor (nextPageCursor) needs to match what the SDK expects.
// sdk-v1-legacy used [AnyHashable]? but modern SDKs might use [String]?, String?, or a custom object.
// Casting to [AnyHashable] if your nextPageCursor is, for example, [String]. Adjust as needed.
let cursorForSDK = nextPageCursor as [AnyHashable]? ?? []

EntrupyApp.sharedInstance().searchSubmissions(
at: cursorForSDK, // Or just nextPageCursor if its type matches
filters: filters,
startDate: startDate,
endDate: endDate,
paginationLimit: perPage
)
}

// Call this method from your delegate's success callback
func searchCompletedSuccessfully(nextCursorFromSDK: [AnyHashable]?) {
isLoading = false
self.nextPageCursor = nextCursorFromSDK
if nextCursorFromSDK == nil || nextCursorFromSDK?.isEmpty == true {
allItemsLoaded = true
print("All submissions loaded.")
}
}

// Call this method from your delegate's failure callback
func searchFailed() {
isLoading = false
// Potentially allow retry
}
}

2. Search Filters

You can apply various filters to narrow down your search results.

Filtering by Brand(s):

// Filter by a single brand
let brandFilter: [[String: Any]] = [["key": "properties.brand.id", "value": "nike"]]

// Filter by multiple brands
let multiBrandFilter: [[String: Any]] = [["key": "properties.brand.id", "values": ["nike", "adidas"]]]

Supported brand values: Refer to SDK documentation or sdk-v1-legacy.md (Section 12) for a list of accepted brand ID strings (e.g., adidas, alexander_mcqueen, balenciaga).

Filtering by Result Type(s):

// Filter by a single result type
let resultFilter: [[String: Any]] = [["key": "status.result.id", "value": "authentic"]]

// Filter by multiple result types
let multiResultFilter: [[String: Any]] = [["key": "status.result.id", "values": ["unknown", "authentic"]]]

Supported result values: authentic, unknown, not_supported, needs_review, invalid.

Filtering by Flag Status:

let flagFilter: [[String: Any]] = [["key": "status.flag", "value": "flagged"]]

Supported flag values: none, flagged, resolved.

Filtering by Your customer_item_id:

// Assuming your customer_item_id was stored using the key "text_fields.sku" as in sdk-v1-legacy
let customerIdFilter: [[String: Any]] = [["key": "text_fields.sku", "value": "YOUR_UNIQUE_ITEM_ID_123"]]
Key for customer_item_id

The exact filter key for customer_item_id (e.g., "text_fields.sku" or a more direct field like "customer_item_id") should be verified with the current SDK specifications.

Combining Filters (Cascading):

To apply multiple filter criteria, include multiple filter dictionaries in the filters array:

let combinedFilter: [[String: Any]] = [
["key": "properties.brand.id", "values": ["nike", "adidas"]],
["key": "status.result.id", "value": "authentic"]
]

3. Handling Search Delegate Callbacks

Implement the EntrupySearchDelegate methods to process the search results or handle errors.

// Swift
// extension YourViewController: EntrupySearchDelegate {

func didSearchSubmissionsCompleteSuccessfully(_ result: [AnyHashable: Any]) {
// searchManager.searchCompletedSuccessfully(nextCursorFromSDK: nextCursor) // Update your search manager
print("Search completed successfully.")
do {
let jsonData = try JSONSerialization.data(withJSONObject: result)
// Assuming a decodable struct EntrupySearchResult exists (as per sdk-v1-legacy.md)
// Adapt this based on the actual structure provided by the current SDK.
// struct EntrupySearchResult: Decodable {
// let items: [EntrupySearchedItem] // Define EntrupySearchedItem based on SDK
// let next_cursor: [AnyHashable]?
// }
// let searchResult = try JSONDecoder().decode(EntrupySearchResult.self, from: jsonData)

// ---- Conceptual interpretation based on legacy structure ----
let items = result["items"] as? [[AnyHashable: Any]] ?? []
let nextCursor = result["next_cursor"] as? [AnyHashable]
// ---- End conceptual interpretation ----

// Pass nextCursor to your SubmissionSearchManager or pagination handler
// self.submissionSearchManager.searchCompletedSuccessfully(nextCursorFromSDK: nextCursor)

if !items.isEmpty {
print("Found \(items.count) items.")
// Process items: update your UITableView, UICollectionView, or data models
// For example, append to an array and reload UI
} else {
print("No items found for this page/filter.")
// Handle empty state if it's the first page
}

if nextCursor == nil || nextCursor?.isEmpty == true {
print("This is the last page of results.")
// self.submissionSearchManager.allItemsLoaded = true (if using a manager)
// Disable further pagination calls
}

} catch {
print("Error decoding search result: \(error)")
// self.submissionSearchManager.searchFailed() (if using a manager)
}
}

func didSearchSubmissionsFailWithError(_ errorCode: EntrupyErrorCode, description: String, localizedDescription: String) {
// searchManager.searchFailed() // Update your search manager
print("Search submissions failed. Error: \(localizedDescription) (Code: \(errorCode))")
// Handle error: inform user, log, allow retry.
// Refer to Error Code Reference for specific error codes.
}
// }

By using the search functionality with appropriate filters and pagination, you can provide users with a comprehensive history of their authentications directly within your app.