Fix not posting status special characters or dropping part of it (Post in JSON now)
This commit is contained in:
parent
9e569df417
commit
d05d9fbfff
|
@ -66,18 +66,29 @@ public class Client: ObservableObject, Equatable {
|
|||
return components.url!
|
||||
}
|
||||
|
||||
private func makeURLRequest(url: URL, httpMethod: String) -> URLRequest {
|
||||
private func makeURLRequest(url: URL, endpoint: Endpoint, httpMethod: String) -> URLRequest {
|
||||
var request = URLRequest(url: url)
|
||||
request.httpMethod = httpMethod
|
||||
if let oauthToken {
|
||||
request.setValue("Bearer \(oauthToken.accessToken)", forHTTPHeaderField: "Authorization")
|
||||
}
|
||||
if let json = endpoint.jsonValue {
|
||||
let encoder = JSONEncoder()
|
||||
encoder.keyEncodingStrategy = .convertToSnakeCase
|
||||
do {
|
||||
let jsonData = try encoder.encode(json)
|
||||
request.httpBody = jsonData
|
||||
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
|
||||
} catch {
|
||||
print("Client Error encoding JSON: \(error.localizedDescription)")
|
||||
}
|
||||
}
|
||||
return request
|
||||
}
|
||||
|
||||
private func makeGet(endpoint: Endpoint) -> URLRequest {
|
||||
let url = makeURL(endpoint: endpoint)
|
||||
return makeURLRequest(url: url, httpMethod: "GET")
|
||||
return makeURLRequest(url: url, endpoint: endpoint, httpMethod: "GET")
|
||||
}
|
||||
|
||||
public func get<Entity: Decodable>(endpoint: Endpoint, forceVersion: Version? = nil) async throws -> Entity {
|
||||
|
@ -101,14 +112,14 @@ public class Client: ObservableObject, Equatable {
|
|||
|
||||
public func post(endpoint: Endpoint) async throws -> HTTPURLResponse? {
|
||||
let url = makeURL(endpoint: endpoint)
|
||||
let request = makeURLRequest(url: url, httpMethod: "POST")
|
||||
let request = makeURLRequest(url: url, endpoint: endpoint, httpMethod: "POST")
|
||||
let (_, httpResponse) = try await urlSession.data(for: request)
|
||||
return httpResponse as? HTTPURLResponse
|
||||
}
|
||||
|
||||
public func patch(endpoint: Endpoint) async throws -> HTTPURLResponse? {
|
||||
let url = makeURL(endpoint: endpoint)
|
||||
let request = makeURLRequest(url: url, httpMethod: "PATCH")
|
||||
let request = makeURLRequest(url: url, endpoint: endpoint, httpMethod: "PATCH")
|
||||
let (_, httpResponse) = try await urlSession.data(for: request)
|
||||
return httpResponse as? HTTPURLResponse
|
||||
}
|
||||
|
@ -119,7 +130,7 @@ public class Client: ObservableObject, Equatable {
|
|||
|
||||
public func delete(endpoint: Endpoint) async throws -> HTTPURLResponse? {
|
||||
let url = makeURL(endpoint: endpoint)
|
||||
let request = makeURLRequest(url: url, httpMethod: "DELETE")
|
||||
let request = makeURLRequest(url: url, endpoint: endpoint, httpMethod: "DELETE")
|
||||
let (_, httpResponse) = try await urlSession.data(for: request)
|
||||
return httpResponse as? HTTPURLResponse
|
||||
}
|
||||
|
@ -128,7 +139,7 @@ public class Client: ObservableObject, Equatable {
|
|||
method: String,
|
||||
forceVersion: Version? = nil) async throws -> Entity {
|
||||
let url = makeURL(endpoint: endpoint, forceVersion: forceVersion)
|
||||
let request = makeURLRequest(url: url, httpMethod: method)
|
||||
let request = makeURLRequest(url: url, endpoint: endpoint, httpMethod: method)
|
||||
let (data, httpResponse) = try await urlSession.data(for: request)
|
||||
logResponseOnError(httpResponse: httpResponse, data: data)
|
||||
return try decoder.decode(Entity.self, from: data)
|
||||
|
@ -157,7 +168,7 @@ public class Client: ObservableObject, Equatable {
|
|||
|
||||
public func makeWebSocketTask(endpoint: Endpoint) -> URLSessionWebSocketTask {
|
||||
let url = makeURL(scheme: "wss", endpoint: endpoint)
|
||||
let request = makeURLRequest(url: url, httpMethod: "GET")
|
||||
let request = makeURLRequest(url: url, endpoint: endpoint, httpMethod: "GET")
|
||||
return urlSession.webSocketTask(with: request)
|
||||
}
|
||||
|
||||
|
@ -168,7 +179,7 @@ public class Client: ObservableObject, Equatable {
|
|||
filename: String,
|
||||
data: Data) async throws -> Entity {
|
||||
let url = makeURL(endpoint: endpoint, forceVersion: version)
|
||||
var request = makeURLRequest(url: url, httpMethod: method)
|
||||
var request = makeURLRequest(url: url, endpoint: endpoint, httpMethod: method)
|
||||
let boundary = UUID().uuidString
|
||||
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
|
||||
let httpBody = NSMutableData()
|
||||
|
|
|
@ -3,6 +3,13 @@ import Foundation
|
|||
public protocol Endpoint {
|
||||
func path() -> String
|
||||
func queryItems() -> [URLQueryItem]?
|
||||
var jsonValue: Encodable? { get }
|
||||
}
|
||||
|
||||
extension Endpoint {
|
||||
public var jsonValue: Encodable? {
|
||||
nil
|
||||
}
|
||||
}
|
||||
|
||||
extension Endpoint {
|
||||
|
|
|
@ -2,19 +2,8 @@ import Foundation
|
|||
import Models
|
||||
|
||||
public enum Statuses: Endpoint {
|
||||
case postStatus(status: String,
|
||||
inReplyTo: String?,
|
||||
mediaIds: [String]?,
|
||||
spoilerText: String?,
|
||||
visibility: Visibility,
|
||||
pollOptions: [String],
|
||||
pollVotingFrequency: Bool?,
|
||||
pollDuration: Int?)
|
||||
case editStatus(id: String,
|
||||
status: String,
|
||||
mediaIds: [String]?,
|
||||
spoilerText: String?,
|
||||
visibility: Visibility)
|
||||
case postStatus(json: StatusData)
|
||||
case editStatus(id: String, json: StatusData)
|
||||
case status(id: String)
|
||||
case context(id: String)
|
||||
case favourite(id: String)
|
||||
|
@ -34,7 +23,7 @@ public enum Statuses: Endpoint {
|
|||
return "statuses"
|
||||
case .status(let id):
|
||||
return "statuses/\(id)"
|
||||
case .editStatus(let id, _, _, _, _):
|
||||
case .editStatus(let id, _):
|
||||
return "statuses/\(id)"
|
||||
case .context(let id):
|
||||
return "statuses/\(id)/context"
|
||||
|
@ -63,41 +52,6 @@ public enum Statuses: Endpoint {
|
|||
|
||||
public func queryItems() -> [URLQueryItem]? {
|
||||
switch self {
|
||||
case let .postStatus(status, inReplyTo, mediaIds, spoilerText, visibility, pollOptions, pollVotingFrequency, pollDuration):
|
||||
var params: [URLQueryItem] = [.init(name: "status", value: status),
|
||||
.init(name: "visibility", value: visibility.rawValue)]
|
||||
if let inReplyTo {
|
||||
params.append(.init(name: "in_reply_to_id", value: inReplyTo))
|
||||
}
|
||||
if let mediaIds {
|
||||
for mediaId in mediaIds {
|
||||
params.append(.init(name: "media_ids[]", value: mediaId))
|
||||
}
|
||||
}
|
||||
if let spoilerText {
|
||||
params.append(.init(name: "spoiler_text", value: spoilerText))
|
||||
}
|
||||
if !pollOptions.isEmpty, let pollVotingFrequency, let pollDuration {
|
||||
for option in pollOptions {
|
||||
params.append(.init(name: "poll[options][]", value: option))
|
||||
}
|
||||
|
||||
params.append(.init(name: "poll[multiple]", value: pollVotingFrequency ? "true" : "false"))
|
||||
params.append(.init(name: "poll[expires_in]", value: "\(pollDuration)"))
|
||||
}
|
||||
return params
|
||||
case let .editStatus(_, status, mediaIds, spoilerText, visibility):
|
||||
var params: [URLQueryItem] = [.init(name: "status", value: status),
|
||||
.init(name: "visibility", value: visibility.rawValue)]
|
||||
if let mediaIds {
|
||||
for mediaId in mediaIds {
|
||||
params.append(.init(name: "media_ids[]", value: mediaId))
|
||||
}
|
||||
}
|
||||
if let spoilerText {
|
||||
params.append(.init(name: "spoiler_text", value: spoilerText))
|
||||
}
|
||||
return params
|
||||
case let .rebloggedBy(_, maxId):
|
||||
return makePaginationParam(sinceId: nil, maxId: maxId, mindId: nil)
|
||||
case let .favouritedBy(_, maxId):
|
||||
|
@ -106,4 +60,50 @@ public enum Statuses: Endpoint {
|
|||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
public var jsonValue: Encodable? {
|
||||
switch self {
|
||||
case let .postStatus(json):
|
||||
return json
|
||||
case let .editStatus(_, json):
|
||||
return json
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public struct StatusData: Encodable {
|
||||
public let status: String
|
||||
public let visibility: Visibility
|
||||
public let inReplyToId: String?
|
||||
public let spoilerText: String?
|
||||
public let mediaIds: [String]?
|
||||
public let poll: PollData?
|
||||
|
||||
public struct PollData: Encodable {
|
||||
public let options: [String]
|
||||
public let multiple: Bool
|
||||
public let expires_in: Int
|
||||
|
||||
public init(options: [String], multiple: Bool, expires_in: Int) {
|
||||
self.options = options
|
||||
self.multiple = multiple
|
||||
self.expires_in = expires_in
|
||||
}
|
||||
}
|
||||
|
||||
public init(status: String,
|
||||
visibility: Visibility,
|
||||
inReplyToId: String? = nil,
|
||||
spoilerText: String? = nil,
|
||||
mediaIds: [String]? = nil,
|
||||
poll: PollData? = nil) {
|
||||
self.status = status
|
||||
self.visibility = visibility
|
||||
self.inReplyToId = inReplyToId
|
||||
self.spoilerText = spoilerText
|
||||
self.mediaIds = mediaIds
|
||||
self.poll = poll
|
||||
}
|
||||
}
|
||||
|
|
|
@ -95,8 +95,9 @@ public class StatusEditorViewModel: ObservableObject {
|
|||
selectedRange = .init(location: text.utf16.count, length: 0)
|
||||
}
|
||||
|
||||
private func getPollOptionsForAPI() -> [String] {
|
||||
pollOptions.filter { !$0.trimmingCharacters(in: .whitespaces).isEmpty }
|
||||
private func getPollOptionsForAPI() -> [String]? {
|
||||
let options = pollOptions.filter { !$0.trimmingCharacters(in: .whitespaces).isEmpty }
|
||||
return options.isEmpty ? nil : options
|
||||
}
|
||||
|
||||
func postStatus() async -> Status? {
|
||||
|
@ -104,22 +105,23 @@ public class StatusEditorViewModel: ObservableObject {
|
|||
do {
|
||||
isPosting = true
|
||||
let postStatus: Status?
|
||||
var pollData: StatusData.PollData?
|
||||
if let pollOptions = getPollOptionsForAPI() {
|
||||
pollData = .init(options: pollOptions,
|
||||
multiple: pollVotingFrequency.canVoteMultipleTimes,
|
||||
expires_in: pollDuration.rawValue)
|
||||
}
|
||||
let data = StatusData(status: statusText.string,
|
||||
visibility: visibility,
|
||||
inReplyToId: mode.replyToStatus?.id,
|
||||
spoilerText: spoilerOn ? spoilerText : nil,
|
||||
mediaIds: mediasImages.compactMap{ $0.mediaAttachement?.id },
|
||||
poll: pollData)
|
||||
switch mode {
|
||||
case .new, .replyTo, .quote, .mention:
|
||||
postStatus = try await client.post(endpoint: Statuses.postStatus(status: statusText.string,
|
||||
inReplyTo: mode.replyToStatus?.id,
|
||||
mediaIds: mediasImages.compactMap{ $0.mediaAttachement?.id },
|
||||
spoilerText: spoilerOn ? spoilerText : nil,
|
||||
visibility: visibility,
|
||||
pollOptions: getPollOptionsForAPI(),
|
||||
pollVotingFrequency: pollVotingFrequency.canVoteMultipleTimes,
|
||||
pollDuration: pollDuration.rawValue))
|
||||
postStatus = try await client.post(endpoint: Statuses.postStatus(json: data))
|
||||
case let .edit(status):
|
||||
postStatus = try await client.put(endpoint: Statuses.editStatus(id: status.id,
|
||||
status: statusText.string,
|
||||
mediaIds: mediasImages.compactMap{ $0.mediaAttachement?.id },
|
||||
spoilerText: spoilerOn ? spoilerText : nil,
|
||||
visibility: visibility))
|
||||
postStatus = try await client.put(endpoint: Statuses.editStatus(id: status.id, json: data))
|
||||
}
|
||||
generator.notificationOccurred(.success)
|
||||
isPosting = false
|
||||
|
|
Loading…
Reference in New Issue