Skip to content

Commit

Permalink
Merge pull request #173 from TelemetryDeck/Ticket-170
Browse files Browse the repository at this point in the history
Update DataObjects and API Versions
  • Loading branch information
Black-Fox-2022 authored May 22, 2024
2 parents f60fd8c + 2907e02 commit 5ed2c89
Show file tree
Hide file tree
Showing 20 changed files with 204 additions and 956 deletions.
43 changes: 4 additions & 39 deletions APIClient/APIClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ final class APIClient: ObservableObject {
/// The end of the currently displayed time window. If nil, defaults to date()
@Published var timeWindowEnd: Date?

@Published var user: DTOv1.UserDTO?
@Published var user: UserInfoDTO?
@Published var userNotLoggedIn: Bool = true
@Published var userLoginFailed: Bool = false
var userLoginErrorMessage: String?
Expand Down Expand Up @@ -197,12 +197,12 @@ extension APIClient {
}
}

func getUserInformation(callback: ((Result<DTOv1.UserDTO, TransferError>) -> Void)? = nil) {
func getUserInformation(callback: ((Result<UserInfoDTO, TransferError>) -> Void)? = nil) {
userLoginFailed = false

let url = urlForPath("users", "me")
let url = urlForPath(apiVersion: .v3, "users", "info")

get(url) { (result: Result<DTOv1.UserDTO, TransferError>) in
get(url) { (result: Result<UserInfoDTO, TransferError>) in
switch result {
case let .success(userDTO):
#if canImport(TelemetryClient)
Expand All @@ -228,41 +228,6 @@ extension APIClient {
}
}

func updatePassword(with passwordChangeRequest: PasswordChangeRequestBody, callback: ((Result<DTOv1.UserDTO, TransferError>) -> Void)? = nil) {
let url = urlForPath("users", "updatePassword")

post(passwordChangeRequest, to: url) { [unowned self] (result: Result<DTOv1.UserDTO, TransferError>) in
switch result {
case let .success(userDTO):
DispatchQueue.main.async {
self.user = userDTO
self.logout()
}
case let .failure(error):
self.handleError(error)
}

callback?(result)
}
}

func updateUser(with dto: DTOv1.UserDTO, callback: ((Result<DTOv1.UserDTO, TransferError>) -> Void)? = nil) {
let url = urlForPath("users", "updateUser")

post(dto, to: url) { [unowned self] (result: Result<DTOv1.UserDTO, TransferError>) in
switch result {
case let .success(userDTO):
DispatchQueue.main.async {
self.user = userDTO
}
case let .failure(error):
self.handleError(error)
}

callback?(result)
}
}

func getOrganizationAdminEntries(callback: ((Result<[OrganizationAdminListEntry], TransferError>) -> Void)? = nil) {
let url = urlForPath("organizationadmin")

Expand Down
24 changes: 24 additions & 0 deletions APIClient/DTOs/AppInfo.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//
// AppInfo.swift
// Telemetry Viewer (iOS)
//
// Created by Lukas on 21.05.24.
//

import Foundation
import DataTransferObjects
import SwiftUI

public struct AppInfo: Codable, Hashable, Identifiable {
public var id: UUID
public var name: String
public var organizationID: UUID
public var insightGroups: [InsightGroupInfo]
public var settings: DTOv2.AppSettings
public var insightGroupIDs: [UUID] {
insightGroups.map { group in
group.id
}
}

}
31 changes: 31 additions & 0 deletions APIClient/DTOs/InsightGroupInfo.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//
// InsightGroupInfo.swift
// Telemetry Viewer (iOS)
//
// Created by Lukas on 21.05.24.
//

import Foundation

public struct InsightGroupInfo: Codable, Hashable, Identifiable {
public init(id: UUID, title: String, order: Double? = nil, appID: UUID, insights: [InsightInfo]) {
self.id = id
self.title = title
self.order = order
self.appID = appID
self.insights = insights
}

public var id: UUID
public var title: String
public var order: Double?
public var appID: UUID
public var insights: [InsightInfo]

public var insightIDs: [UUID] {
insights.map { insight in
insight.id
}
}

}
94 changes: 94 additions & 0 deletions APIClient/DTOs/InsightInfo.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
//
// InsightInfo.swift
// Telemetry Viewer (iOS)
//
// Created by Lukas on 21.05.24.
//

import Foundation
import DataTransferObjects

public struct InsightInfo: Codable, Hashable, Identifiable {
public enum InsightType: String, Codable, Hashable {
case timeseries
case topN
case customQuery
case funnel
case experiment
}

public var id: UUID
public var groupID: UUID

/// order in which insights appear in the apps (if not expanded)
public var order: Double?
public var title: String

/// What kind of insight is this?
public var type: InsightType

/// If set, display the chart with this accent color, otherwise fall back to default color
public var accentColor: String?

/// If set, use the custom query in this property instead of constructing a query out of the options below
public var customQuery: CustomQuery?

/// Which signal types are we interested in? If nil, do not filter by signal type
public var signalType: String?

/// If true, only include at the newest signal from each user
public var uniqueUser: Bool

/// If set, break down the values in this key
public var breakdownKey: String?

/// If set, group and count found signals by this time interval. Incompatible with breakdownKey
public var groupBy: QueryGranularity?

/// How should this insight's data be displayed?
public var displayMode: InsightDisplayMode

/// If true, the insight will be displayed bigger
public var isExpanded: Bool

/// The amount of time (in seconds) this query took to calculate last time
public var lastRunTime: TimeInterval?

/// The date this query was last run
public var lastRunAt: Date?

public init(
id: UUID,
groupID: UUID,
order: Double?,
title: String,
type: InsightType,
accentColor: String? = nil,
widgetable _: Bool? = false,
customQuery: CustomQuery? = nil,
signalType: String?,
uniqueUser: Bool,
breakdownKey: String?,
groupBy: QueryGranularity?,
displayMode: InsightDisplayMode,
isExpanded: Bool,
lastRunTime: TimeInterval?,
lastRunAt: Date?
) {
self.id = id
self.groupID = groupID
self.order = order
self.title = title
self.type = type
self.accentColor = accentColor
self.customQuery = customQuery
self.signalType = signalType
self.uniqueUser = uniqueUser
self.breakdownKey = breakdownKey
self.groupBy = groupBy
self.displayMode = displayMode
self.isExpanded = isExpanded
self.lastRunTime = lastRunTime
self.lastRunAt = lastRunAt
}
}
20 changes: 20 additions & 0 deletions APIClient/DTOs/UserInfo.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// UserInfo.swift
// Telemetry Viewer (iOS)
//
// Created by Lukas on 21.05.24.
//

import Foundation
import DataTransferObjects

struct UserInfoDTO: Identifiable, Codable {
public let id: UUID
public var firstName: String
public var lastName: String
public var email: String
public let emailIsVerified: Bool
public var receiveMarketingEmails: Bool?
public var receiveReports: ReportSendingRate

}
28 changes: 14 additions & 14 deletions Services/AppService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ class AppService: ObservableObject {

var loadingCancellable: AnyCancellable?

@Published var appDictionary: [DTOv2.App.ID: DTOv2.App] = [:]
@Published var loadingStateDictionary: [DTOv2.App.ID: LoadingState] = [:]
@Published var appDictionary: [AppInfo.ID: AppInfo] = [:]
@Published var loadingStateDictionary: [AppInfo.ID: LoadingState] = [:]

init(api: APIClient, errors: ErrorService, orgService: OrgService) {
self.api = api
Expand All @@ -46,23 +46,23 @@ class AppService: ObservableObject {
return loadingState
}

func app(withID appID: DTOv2.App.ID) -> DTOv2.App? {
func app(withID appID: AppInfo.ID) -> AppInfo? {
return appDictionary[appID]
}

func retrieveApp(with appID: DTOv2.App.ID, callback: ((Result<DTOv2.App, TransferError>) -> Void)? = nil) {
let url = api.urlForPath(apiVersion: .v2, "apps", appID.uuidString)
let url = api.urlForPath(apiVersion: .v3, "apps", appID.uuidString)
api.get(url) { (result: Result<DTOv2.App, TransferError>) in
callback?(result)
}
}

func retrieveApp(withID appID: DTOv2.App.ID) async throws -> DTOv2.App {
func retrieveApp(withID appID: DTOv2.App.ID) async throws -> AppInfo {
// guard loadingStateDictionary[appID] != .loading else { let error: TransferError = .transferFailed; throw error }
// loadingStateDictionary[appID] = .loading
return try await withCheckedThrowingContinuation { (continuation: CheckedContinuation<DTOv2.App, Error>) in
let url = api.urlForPath(apiVersion: .v2, "apps", appID.uuidString)
api.get(url) { (result: Result<DTOv2.App, TransferError>) in
return try await withCheckedThrowingContinuation { (continuation: CheckedContinuation<AppInfo, Error>) in
let url = api.urlForPath(apiVersion: .v3, "apps", appID.uuidString)
api.get(url) { (result: Result<AppInfo, TransferError>) in
switch result {
case let .success(app):

Expand All @@ -76,10 +76,10 @@ class AppService: ObservableObject {
}
}

func create(appNamed name: String, callback: ((Result<DTOv2.App, TransferError>) -> Void)? = nil) {
let url = api.urlForPath(apiVersion: .v2, "apps")
func create(appNamed name: String, callback: ((Result<AppInfo, TransferError>) -> Void)? = nil) {
let url = api.urlForPath(apiVersion: .v3, "apps")

api.post(["name": name], to: url) { [unowned self] (result: Result<DTOv2.App, TransferError>) in
api.post(["name": name], to: url) { [unowned self] (result: Result<AppInfo, TransferError>) in

if let app = try? result.get() {
appDictionary[app.id] = app
Expand All @@ -90,10 +90,10 @@ class AppService: ObservableObject {
}
}

func update(appID: UUID, newName: String, callback: ((Result<DTOv2.App, TransferError>) -> Void)? = nil) {
let url = api.urlForPath(apiVersion: .v2, "apps", appID.uuidString)
func update(appID: UUID, newName: String, callback: ((Result<AppInfo, TransferError>) -> Void)? = nil) {
let url = api.urlForPath(apiVersion: .v3, "apps", appID.uuidString)

api.patch(["name": newName], to: url) { [unowned self] (result: Result<DTOv2.App, TransferError>) in
api.patch(["name": newName], to: url) { [unowned self] (result: Result<AppInfo, TransferError>) in

if let app = try? result.get() {
appDictionary[app.id] = app
Expand Down
26 changes: 13 additions & 13 deletions Services/GroupService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ class GroupService: ObservableObject {
private let api: APIClient
private let errorService: ErrorService

private let loadingState = Cache<DTOv2.Group.ID, LoadingState>()
private let loadingState = Cache<InsightGroupInfo.ID, LoadingState>()

var loadingCancellable: AnyCancellable?

@Published var groupsDictionary = [DTOv2.Group.ID: DTOv2.Group]()
@Published var groupsDictionary = [InsightGroupInfo.ID: InsightGroupInfo]()

init(api: APIClient, errors: ErrorService) {
self.api = api
Expand All @@ -43,26 +43,26 @@ class GroupService: ObservableObject {
return loadingState
}

func group(withID groupID: DTOv2.Group.ID) -> DTOv2.Group? {
func group(withID groupID: InsightGroupInfo.ID) -> InsightGroupInfo? {
return groupsDictionary[groupID]
}

func retrieveGroup(with groupID: DTOv2.Group.ID) {
func retrieveGroup(with groupID: InsightGroupInfo.ID) {
performRetrieval(ofGroupWithID: groupID)
}

func create(insightGroupNamed: String, for appID: UUID, callback: ((Result<DTOv2.Group, TransferError>) -> Void)? = nil) {
let url = api.urlForPath(apiVersion: .v2, "groups")
func create(insightGroupNamed: String, for appID: UUID, callback: ((Result<InsightGroupInfo, TransferError>) -> Void)? = nil) {
let url = api.urlForPath(apiVersion: .v3, "groups")

api.post(["title": insightGroupNamed, "appID": appID.uuidString], to: url) { (result: Result<DTOv2.Group, TransferError>) in
api.post(["title": insightGroupNamed, "appID": appID.uuidString], to: url) { (result: Result<InsightGroupInfo, TransferError>) in
callback?(result)
}
}

func update(insightGroup: DTOv2.Group, in appID: UUID, callback: ((Result<DTOv2.Group, TransferError>) -> Void)? = nil) {
let url = api.urlForPath(apiVersion: .v2, "groups", insightGroup.id.uuidString)
func update(insightGroup: InsightGroupInfo, in appID: UUID, callback: ((Result<InsightGroupInfo, TransferError>) -> Void)? = nil) {
let url = api.urlForPath(apiVersion: .v3, "groups", insightGroup.id.uuidString)

api.patch(insightGroup, to: url) { (result: Result<DTOv2.Group, TransferError>) in
api.patch(insightGroup, to: url) { (result: Result<InsightGroupInfo, TransferError>) in
callback?(result)
}
}
Expand All @@ -78,7 +78,7 @@ class GroupService: ObservableObject {
}

private extension GroupService {
func performRetrieval(ofGroupWithID groupID: DTOv2.Group.ID) {
func performRetrieval(ofGroupWithID groupID: InsightGroupInfo.ID) {
switch loadingState(for: groupID) {
case .loading, .error:
return
Expand All @@ -88,9 +88,9 @@ private extension GroupService {

loadingState[groupID] = .loading

let url = api.urlForPath(apiVersion: .v2, "groups", groupID.uuidString)
let url = api.urlForPath(apiVersion: .v3, "groups", groupID.uuidString)

api.get(url) { [weak self] (result: Result<DTOv2.Group, TransferError>) in
api.get(url) { [weak self] (result: Result<InsightGroupInfo, TransferError>) in

switch result {
case let .success(group):
Expand Down
Loading

0 comments on commit 5ed2c89

Please sign in to comment.