Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BIT-162: Add sync API #22

Merged
merged 11 commits into from
Sep 15, 2023
Merged

BIT-162: Add sync API #22

merged 11 commits into from
Sep 15, 2023

Conversation

matt-livefront
Copy link
Collaborator

🎟️ Tracking

BIT-162

🚧 Type of change

  • 🚀 New feature development

📔 Objective

Adds the sync API request and response for syncing the user's vault.

📋 Code changes

  • SyncAPIService.swift: Implements the getSync() method for making a sync request.

⏰ Reminders before review

  • Contributor guidelines followed
  • All formatters and local linters executed and passed
  • Written new unit and / or integration tests where applicable
  • Used internationalization (i18n) for all UI strings
  • CI builds passed
  • Communicated to DevOps any deployment requirements
  • Updated any necessary documentation or informed the documentation team

🦮 Reviewer guidelines

  • 👍 (:+1:) or similar for great changes
  • 📝 (:memo:) or ℹ️ (:information_source:) for notes or general info
  • ❓ (:question:) for questions
  • 🤔 (:thinking:) or 💭 (:thought_balloon:) for more open inquiry that's not quite a confirmed issue and could potentially benefit from discussion
  • 🎨 (:art:) for suggestions / improvements
  • ❌ (:x:) or ⚠️ (:warning:) for more significant problems or concerns needing attention
  • 🌱 (:seedling:) or ♻️ (:recycle:) for future improvements or indications of technical debt
  • ⛏ (:pick:) for minor or nitpick changes

@bitwarden-bot
Copy link

bitwarden-bot commented Sep 7, 2023

Logo
Checkmarx One – Scan Summary & Detailsef298d29-7ec0-48b1-ae86-d13c53446b9b

No New Or Fixed Issues Found

@github-actions
Copy link
Contributor

github-actions bot commented Sep 8, 2023

1 Warning
⚠️ Total coverage less than 80%

Code coverage

Total coverage: 46.01%

Powered by Slather

Generated by 🚫 Danger

Comment on lines 15 to 16
///
let sizeName: String?
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@fedemkr I wasn't sure what this field was used for based on the name. Is this a formatted string of the size (e.g. "5 MB") or something else?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, exactly. You can find the usage here.
And here the Server side code that converts the size into human readable string SizeName.

Copy link
Member

@fedemkr fedemkr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome work!
🤔 A question, I see that you've added the let object: String? to some models, we don't currently use that on the app, is it going to be useful for decoding or something or could we remove it?
🤔 Also I've marked several type properties as never being nil: I was wondering that maybe you marked it with ? because perhaps is something needed for swift that I don't know, is it?

Comment on lines 45 to 73
XCTAssertThrowsError(
try subject.decode(Date.self, from: Data(#""2023-08-23""#.utf8))
) { error in
XCTAssertTrue(error is DecodingError)
guard case let .dataCorrupted(context) = error as? DecodingError else {
return XCTFail("Expected error to be DecodingError.dataCorrupted")
}
XCTAssertEqual(context.debugDescription, "Unable to decode date with value '2023-08-23'")
}

XCTAssertThrowsError(
try subject.decode(Date.self, from: Data(#""🔒""#.utf8))
) { error in
XCTAssertTrue(error is DecodingError)
guard case let .dataCorrupted(context) = error as? DecodingError else {
return XCTFail("Expected error to be DecodingError.dataCorrupted")
}
XCTAssertEqual(context.debugDescription, "Unable to decode date with value '🔒'")
}

XCTAssertThrowsError(
try subject.decode(Date.self, from: Data(#""date""#.utf8))
) { error in
XCTAssertTrue(error is DecodingError)
guard case let .dataCorrupted(context) = error as? DecodingError else {
return XCTFail("Expected error to be DecodingError.dataCorrupted")
}
XCTAssertEqual(context.debugDescription, "Unable to decode date with value 'date'")
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎨 Instead of repeating each time with different values what do you think on having something like:

Suggested change
XCTAssertThrowsError(
try subject.decode(Date.self, from: Data(#""2023-08-23""#.utf8))
) { error in
XCTAssertTrue(error is DecodingError)
guard case let .dataCorrupted(context) = error as? DecodingError else {
return XCTFail("Expected error to be DecodingError.dataCorrupted")
}
XCTAssertEqual(context.debugDescription, "Unable to decode date with value '2023-08-23'")
}
XCTAssertThrowsError(
try subject.decode(Date.self, from: Data(#""🔒""#.utf8))
) { error in
XCTAssertTrue(error is DecodingError)
guard case let .dataCorrupted(context) = error as? DecodingError else {
return XCTFail("Expected error to be DecodingError.dataCorrupted")
}
XCTAssertEqual(context.debugDescription, "Unable to decode date with value '🔒'")
}
XCTAssertThrowsError(
try subject.decode(Date.self, from: Data(#""date""#.utf8))
) { error in
XCTAssertTrue(error is DecodingError)
guard case let .dataCorrupted(context) = error as? DecodingError else {
return XCTFail("Expected error to be DecodingError.dataCorrupted")
}
XCTAssertEqual(context.debugDescription, "Unable to decode date with value 'date'")
}
func expectFail(dateFrom value: String) {
XCTAssertThrowsError(
try subject.decode(Date.self, from: Data(value))
) { error in
XCTAssertTrue(error is DecodingError)
guard case let .dataCorrupted(context) = error as? DecodingError else {
return XCTFail("Expected error to be DecodingError.dataCorrupted")
}
XCTAssertEqual(context.debugDescription, "Unable to decode date with value \(value)")
}
}
expectFail(dateFrom: #""2023-08-23""#.utf8)
expectFail(dateFrom: #""🔒""#.utf8)
expectFail(dateFrom: #""date""#.utf8)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good suggestion! I'll update this.

Comment on lines 15 to 16
///
let sizeName: String?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, exactly. You can find the usage here.
And here the Server side code that converts the size into human readable string SizeName.

Comment on lines 12 to 13
/// The size of the file.
let size: Int?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔 Just in case, bear in mind that currently the size is a string because of some problems when converting the number and server side is allowing expecting an string.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I'll convert it to a string.

Comment on lines 26 to 27
/// Whether the user's email address should be hidden from recipients.
let hideEmail: Bool
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⛏️ This can be nil, although it's transformed into false when that happens in the process of creating the SendData mobile object. I don't know if you plan to do that directly when decoding.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good to know, I'll probably make it optional for now, but may either change that in the future or default it to false when transforming it into an app model.

let text: SendTextModel?

/// The type of data in the send.
let type: SendType?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⛏️ type is never nil

Comment on lines 18 to 19
/// The attachment's size.
let size: Int
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔 Same as with SendFileModel

Comment on lines 62 to 64
/// Whether the user needs to be re-prompted for their master password prior to autofilling the
/// cipher's password.
let reprompt: CipherRepromptType?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⛏️ reprompt is never nil

Comment on lines 72 to 73
/// The type of the cipher.
let type: CipherType?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⛏️ type is never nil

Comment on lines 20 to 21
/// The policy type.
let type: PolicyType?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⛏️ type is never nil

Comment on lines +5 to +6
struct PolicyResponseModel: Codable, Equatable {
// MARK: Properties
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔 I think the property Data is missing unless it's meant to be added in a later stage. (server code)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! Do you have an example of what this data looks like? It wasn't clear from the Swagger document I have and it's not populated for my account. It looks like it's Dictionary<string, object> on the server, but what is object?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It could be anything, currently we have int, bool and string values stored in there, like minimum timeout time in minutes. Here you have some keys of that and the methods to get the specified value type from the data object.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I think I may hold off on implementing this for now until we get into policy stuff. There isn't a standard way of decoding JSON like this in Swift, so it'd be helpful to have more context prior to implementing this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, no problem. Could a TODO be added in the code just to note that it's missing and will be addressed later?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, added!

Comment on lines 9 to 12
let ciphers: [CipherDetailsResponseModel]?

/// The user's list of collections.
let collections: [CollectionDetailsResponseModel]?
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@fedemkr These arrays in SyncResponseModel and other models are marked as nullable: true in the Swagger document. But from looking at the response I get back from the API, an empty array is returned. Do I need to make these optional?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From what I can see they don't need to be optional. ciphers is not being considered null and collections is defaulted to empty list so it's safe to remove the ? (server code)

@matt-livefront
Copy link
Collaborator Author

Thanks for the feedback, @fedemkr!

🤔 A question, I see that you've added the let object: String? to some models, we don't currently use that on the app, is it going to be useful for decoding or something or could we remove it?

Nope, I can remove these if they aren't needed.

🤔 Also I've marked several type properties as never being nil: I was wondering that maybe you marked it with ? because perhaps is something needed for swift that I don't know, is it?

I thought those were marked as nullable in the Swagger document that I have, but it looks like they aren't. If we know things can't be optional/nullable from the API, it's definitely easier on our side to make them be non-optional. I've updated all the properties that you commented on above.

fedemkr
fedemkr previously approved these changes Sep 12, 2023
Comment on lines +5 to +6
struct PolicyResponseModel: Codable, Equatable {
// MARK: Properties
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, no problem. Could a TODO be added in the code just to note that it's missing and will be addressed later?

fedemkr
fedemkr previously approved these changes Sep 14, 2023
@matt-livefront matt-livefront merged commit 6e07b78 into main Sep 15, 2023
@matt-livefront matt-livefront deleted the matt/BIT-162-sync-api branch September 15, 2023 20:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants