Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions PayForMe.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
BF4D7AF265FC4A90B1AC5AEB /* JSONDecodingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F4D55C3EF5EFCD925428041 /* JSONDecodingTests.swift */; };
D279295CFA25D9CC69C6F27C /* BillTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7EED3194A2342518B0E74079 /* BillTests.swift */; };
DBBD86EF399BCF232C021935 /* NetworkRequestTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 316FBA7C0CE4ABB51EC2A121 /* NetworkRequestTests.swift */; };
65AF00022F1A000100000002 /* StorageMigrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65AF00012F1A000100000001 /* StorageMigrationTests.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -106,6 +107,7 @@
6514934B26CFC71000F00851 /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cs; path = cs.lproj/LaunchScreen.strings; sourceTree = "<group>"; };
6514934C26CFC71000F00851 /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cs; path = cs.lproj/Localizable.strings; sourceTree = "<group>"; };
6523FC4B25580EEF00BCD843 /* UrlExtensionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UrlExtensionsTests.swift; sourceTree = "<group>"; };
65AF00012F1A000100000001 /* StorageMigrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StorageMigrationTests.swift; sourceTree = "<group>"; };
6523FC502558153600BCD843 /* AddPasswordView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddPasswordView.swift; sourceTree = "<group>"; };
6533A02A23D888B100FF822B /* BillCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BillCell.swift; sourceTree = "<group>"; };
654754B72528736F00A82EB6 /* Views+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Views+Extensions.swift"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -236,6 +238,7 @@
143F41EE78329905894C8A29 /* BalanceCalculationTests.swift */,
92ABB02BEA28BEA7C8C64841 /* BillSortingTests.swift */,
316FBA7C0CE4ABB51EC2A121 /* NetworkRequestTests.swift */,
65AF00012F1A000100000001 /* StorageMigrationTests.swift */,
);
path = PayForMeTests;
sourceTree = "<group>";
Expand Down Expand Up @@ -551,6 +554,7 @@
56E7DB46FDCDC5B46C475020 /* BalanceCalculationTests.swift in Sources */,
62C73597878BA5AD4572FE90 /* BillSortingTests.swift in Sources */,
DBBD86EF399BCF232C021935 /* NetworkRequestTests.swift in Sources */,
65AF00022F1A000100000002 /* StorageMigrationTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
24 changes: 15 additions & 9 deletions PayForMe/Model/Project.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@ class Project: Codable, Identifiable {
var bills: [Bill]
var me: Int?

convenience init(name: String, password: String, token: String, backend: ProjectBackend, url: URL) {
self.init(name: name, password: password, token: token, backend: backend, url: url, id: nil)
let projectId: String

convenience init(name: String, password: String, token: String, backend: ProjectBackend, url: URL, projectId: String) {
self.init(name: name, password: password, token: token, backend: backend, url: url, id: nil, projectId: projectId)
}

fileprivate init(name: String, password: String, token: String, backend: ProjectBackend, url: URL, id: Int?, me: Int? = nil) {
fileprivate init(name: String, password: String, token: String, backend: ProjectBackend, url: URL, id: Int?, me: Int? = nil, projectId: String) {
self.name = name
self.password = password
self.token = token
Expand All @@ -33,6 +35,7 @@ class Project: Codable, Identifiable {
members = [:]
bills = []
self.me = me
self.projectId = projectId
}
}

Expand All @@ -49,15 +52,17 @@ struct StoredProject: Codable {
let backend: ProjectBackend
var id: Int?
let me: Int?
let projectId: String

init(name: String, password: String, token: String, url: URL, backend: ProjectBackend) {
init(name: String, password: String, token: String, url: URL, backend: ProjectBackend, projectId: String) {
self.name = name
self.password = password
self.token = token
self.url = url
self.backend = backend
id = nil
me = nil
self.projectId = projectId
}

init(project: Project) {
Expand All @@ -68,10 +73,11 @@ struct StoredProject: Codable {
backend = project.backend
id = project.id
me = project.me
projectId = project.projectId
}

func toProject() -> Project {
Project(name: name, password: password, token: token, backend: backend, url: url, id: id!, me: me)
Project(name: name, password: password, token: token, backend: backend, url: url, id: id!, me: me, projectId: projectId)
}
}

Expand Down Expand Up @@ -101,10 +107,10 @@ enum ProjectBackend: Int, Codable {
}
}

let previewProject = Project(name: "TestProject", password: "TestPassword", token: "asdasdas", backend: .cospend, url: URL(string: "https://testserver.de")!, id: 0)
let previewProject = Project(name: "TestProject", password: "TestPassword", token: "asdasdas", backend: .cospend, url: URL(string: "https://testserver.de")!, id: 0, projectId: "TestProject")
let previewProjects = [
previewProject,
Project(name: "test1", password: "test23", token: "dasdasa", backend: .cospend, url: URL(string: "https://testserver.de")!, id: 1),
Project(name: "test2", password: "test45", token: "123123122", backend: .cospend, url: URL(string: "https://testserver.de")!, id: 2),
Project(name: "test1", password: "test23", token: "dasdasa", backend: .cospend, url: URL(string: "https://testserver.de")!, id: 1, projectId: "test1"),
Project(name: "test2", password: "test45", token: "123123122", backend: .cospend, url: URL(string: "https://testserver.de")!, id: 2, projectId: "test2"),
]
let demoProject = Project(name: "study-group", password: "no-pass", token: "9da50e410157dc1ca63e594af022f3a2", backend: .cospend, url: URL(string: "https://intranet.mayflower.de")!, id: 1)
let demoProject = Project(name: "study-group", password: "no-pass", token: "9da50e410157dc1ca63e594af022f3a2", backend: .cospend, url: URL(string: "https://intranet.mayflower.de")!, id: 1, projectId: "study-group")
2 changes: 1 addition & 1 deletion PayForMe/SceneDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
func scene(_: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
guard let context = URLContexts.first,
let scheme = context.url.scheme,
scheme.localizedCaseInsensitiveContains("cospend")
scheme.localizedCaseInsensitiveContains("cospend") || scheme.localizedCaseInsensitiveContains("ihatemoney")
else {
return
}
Expand Down
49 changes: 44 additions & 5 deletions PayForMe/Services/NetworkService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,32 @@ class NetworkService {
}
let apiProject = try JSONDecoder().decode(APIProject.self, from: data)

return Project(name: apiProject.name, password: project.password, token: project.token, backend: project.backend, url: project.url)
return Project(name: apiProject.name, password: project.password, token: project.token, backend: project.backend, url: project.url, projectId: apiProject.id)
}

func getProjectName(invite: InviteData) async throws -> Project {
guard var components = URLComponents(string: invite.baseUrl),
let baseURL = components.url else {
throw URLError(.badURL)
}
components.path += iHateMoneyStaticPath + "/" + invite.project
guard let url = components.url else {
throw URLError(.badURL)
}
var request = URLRequest(url: url)
request.httpMethod = "GET"
request.setValue(
"Bearer \(invite.token)",
forHTTPHeaderField: "Authorization"
)

let (data, response) = try await URLSession.shared.data(for: request)
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode / 100 == 2 else {
throw HTTPError.statuscode
}
let apiProject = try JSONDecoder().decode(APIProject.self, from: data)

return Project(name: apiProject.name, password: "", token: invite.token, backend: ProjectBackend.iHateMoney, url: baseURL, projectId: apiProject.id)
}

func postBillPublisher(bill: Bill) -> AnyPublisher<Bool, Never> {
Expand Down Expand Up @@ -147,13 +172,21 @@ class NetworkService {
.replaceError(with: false)
.eraseToAnyPublisher()
}


private func baseURLFor(_ project: Project, suffix: String) -> URL {
var url = project.url
.appendingPathComponent(project.backend.staticPath)
.appendingPathComponent(project.token)

if project.backend == .cospend {
url = url.appendingPathComponent(project.password)
url = url
.appendingPathComponent(project.token)
.appendingPathComponent(project.password)
}

if project.backend == .iHateMoney {
url = url
.appendingPathComponent(project.projectId)
}
if suffix.isEmpty {
return url
Expand Down Expand Up @@ -181,8 +214,14 @@ class NetworkService {
request = URLRequest(url: requestURL)

if project.backend == .iHateMoney {
guard let authString = "\(project.token):\(project.password)".data(using: .utf8)?.base64EncodedString() else { fatalError("error generating authString. THIS SHOULD NOT HAPPEN") }
request.setValue("Basic \(authString)", forHTTPHeaderField: "Authorization")
if project.password.isEmpty {
request.setValue("Bearer \(project.token)", forHTTPHeaderField: "Authorization")
} else {
guard let authString = "\(project.token):\(project.password)".data(using: .utf8)?.base64EncodedString() else {
fatalError("error generating authString. THIS SHOULD NOT HAPPEN")
}
request.setValue("Basic \(authString)", forHTTPHeaderField: "Authorization")
}

if !params.isEmpty {
request.httpBody = try? JSONSerialization.data(withJSONObject: params)
Expand Down
7 changes: 1 addition & 6 deletions PayForMe/Services/ProjectManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,7 @@ class ProjectManager: ObservableObject {
}

func openedByURL(url: URL) {
let data = url.decodeCospendString()
guard let _ = data.server,
let _ = data.project
else {
return
}
guard url.decodeCospendString() != nil || url.decodeIHateMoneyString() != nil else { return }
openedByURL = url
}

Expand Down
66 changes: 38 additions & 28 deletions PayForMe/Services/StorageService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,37 +19,47 @@ class StorageService {

private let dbQueue: DatabaseQueue

init() {
do {
var migrator = DatabaseMigrator()

migrator.registerMigration("v1", migrate: { db in
try db.create(table: "storedProject", ifNotExists: true) { table in
table.autoIncrementedPrimaryKey("id")
table.column("name")
table.column("password")
table.column("url")
table.column("backend")
}
static func makeMigrator() -> DatabaseMigrator {
var migrator = DatabaseMigrator()

migrator.registerMigration("v1", migrate: { db in
try db.create(table: "storedProject", ifNotExists: true) { table in
table.autoIncrementedPrimaryKey("id")
table.column("name")
table.column("password")
table.column("url")
table.column("backend")
}
})
migrator.registerMigration("v2", migrate: { db in
try db.alter(table: "storedProject", body: { table in
table.add(column: "token")
})
migrator.registerMigration("v2", migrate: { db in
try db.alter(table: "storedProject", body: { table in
table.add(column: "token")
})
try db.execute(sql: "UPDATE storedProject SET token = name;")
try db.execute(sql: "UPDATE storedProject SET token = name;")

})
migrator.registerMigration("v3") { db in
try db.alter(table: "storedProject", body: { table in
table.add(column: "me")
})
migrator.registerMigration("v3") { db in
try db.alter(table: "storedProject", body: { table in
table.add(column: "me")
})
}
// #if DEBUG
//// Speed up development by nuking the database when migrations change
// migrator.eraseDatabaseOnSchemaChange = true
// #endif
}
migrator.registerMigration("v4") { db in
try db.alter(table: "storedProject", body: { table in
table.add(column: "projectId")
})
try db.execute(sql: "UPDATE storedProject SET projectId = token;")
}
// #if DEBUG
//// Speed up development by nuking the database when migrations change
// migrator.eraseDatabaseOnSchemaChange = true
// #endif
return migrator
}

init() {
do {
dbQueue = try DatabaseQueue(path: databasePath.appendingPathComponent("payforme.sqlite").path)
try migrator.migrate(dbQueue)
try Self.makeMigrator().migrate(dbQueue)
} catch {
print("Storage couldn't be initialized \(error.localizedDescription)")
fatalError()
Expand Down Expand Up @@ -153,6 +163,6 @@ private class OldProject: Codable, Identifiable {
var bills: [Bill]

func toProject() -> StoredProject {
return StoredProject(name: name, password: password, token: name, url: url, backend: backend)
return StoredProject(name: name, password: password, token: name, url: url, backend: backend, projectId: name)
}
}
Loading
Loading