// // EbayWebServiceManager.swift // Vendoo // // Created by Okechi Onyeje on 6/3/16. // Copyright © 2016 Okechi Onyeje. All rights reserved. // import Foundation import Locksmith protocol EbayWebServiceManagerDelegate { func signInUser(string: String!) } class EbayWebServiceManager: NSObject { //API Manager class variables //----------------------------------------------// let baseURL = "https://api.sandbox.ebay.com/ws/api.dll" private var apiKey: String! private var devKey: String! private var certID: String! private var mutableData: NSMutableData = NSMutableData() private var currentElementName:NSString = "" private var catID: NSString! private var catLevel: NSString! private var currentCategory: String! private var catDetailLevel: Int! = 1 private var userEmail:String = (NSUserDefaults.standardUserDefaults().objectForKey("email") as? String)! private var signinURL: String! private var xmlResponseDictionary: Dictionary = Dictionary() var delegate: EbayWebServiceManagerDelegate? var isAuthorized: Bool = NSUserDefaults.standardUserDefaults().boolForKey("ebayAuthorized") static var settingsDictionary = Dictionary() private var subCategories = Dictionary>() private var completion: ServiceResponse! private var isGettingSubCategories: Bool = false private var isRevisingListing: Bool = false //---------------------------------------------// override init(){ super.init() if let path = NSBundle.mainBundle().pathForResource("Services", ofType: "plist"), dict = NSDictionary(contentsOfFile: path) as? [String: AnyObject] { self.apiKey = ((dict["Ebay"] as! Dictionary)["consumerKey"] as! String) self.devKey = ((dict["Ebay"] as! Dictionary)["devID"] as! String) self.certID = ((dict["Ebay"] as! Dictionary)["CertID"] as! String) self.signinURL = ((dict["Ebay"] as! Dictionary)["signin"] as! String) if(self.isAuthorized){ let dictionary = Locksmith.loadDataForUserAccount(self.userEmail, inService: "vendoo_oauth_ebay") self.xmlResponseDictionary["eBayAuthToken"] = dictionary?["ebay_oauth"] as? String } //set default posting settings for ebay if(NSUserDefaults.standardUserDefaults().boolForKey("ebayDefaultsOverriden")) { EbayWebServiceManager.settingsDictionary = (NSUserDefaults.standardUserDefaults().objectForKey("ebaySettings") as? Dictionary)! } else{ EbayWebServiceManager.settingsDictionary = ([ "listingType":"FixedPriceItem", "condition":"1500", "listingDuration":"Days_7", "ebaySite":"US", "currency":"USD", "shipping": [ "shippingType": "Flat", "freeShipping": "true", "shippingServicePriority": "1", "shippingService":"UPSGround", "shippingServiceAdditionalCost":"0.00" ], "payment":"PayPal", "return":"ReturnsNotAccepted", "postalCode":"21216" ] as Dictionary) NSUserDefaults.standardUserDefaults().setObject(EbayWebServiceManager.settingsDictionary, forKey: "ebaySettings") NSUserDefaults.standardUserDefaults().setBool(true, forKey: "ebayDefaultsOverriden") } } } func reinit() { EbayWebServiceManager.settingsDictionary = (NSUserDefaults.standardUserDefaults().objectForKey("ebaySettings") as? Dictionary)! } } //MARK: - authentication methods extension EbayWebServiceManager { private func requestMaker(soapMessage: String!, theRequest: NSMutableURLRequest!) { let msgLength = soapMessage.characters.count theRequest.addValue("text/xml", forHTTPHeaderField: "Content-Type") theRequest.addValue(String(msgLength), forHTTPHeaderField: "Content-Length") theRequest.addValue("967", forHTTPHeaderField: "X-EBAY-API-COMPATIBILITY-LEVEL") theRequest.addValue(self.devKey, forHTTPHeaderField: "X-EBAY-API-DEV-NAME") theRequest.addValue(self.certID, forHTTPHeaderField: "X-EBAY-API-CERT-NAME") theRequest.addValue(self.apiKey, forHTTPHeaderField: "X-EBAY-API-APP-NAME") theRequest.addValue("0", forHTTPHeaderField: "X-EBAY-API-SITEID") theRequest.addValue("", forHTTPHeaderField: "SOAPAction") theRequest.HTTPMethod = "POST" theRequest.HTTPBody = soapMessage.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false) // or false let connection = NSURLConnection(request: theRequest, delegate: self, startImmediately: true) connection!.start() if (connection == true) { var mutableData : Void = NSMutableData.initialize() } } func authorizeApp(){ let soapMessage = "" + "" + "Kroleo-Kroleo-Vendoo-S-ktqeobkk" + "" let url = NSURL(string: self.baseURL) let theRequest = NSMutableURLRequest(URL: url!) theRequest.addValue("GetSessionID", forHTTPHeaderField: "X-EBAY-API-CALL-NAME") self.requestMaker(soapMessage, theRequest: theRequest) } func deauthorizeApp(){ let soapMessage = "" + "" + "" + "\(self.xmlResponseDictionary["eBayAuthToken"])" + "​" let url = NSURL(string: self.baseURL) let theRequest = NSMutableURLRequest(URL: url!) theRequest.addValue("RevokeToken", forHTTPHeaderField: "X-EBAY-API-CALL-NAME") self.requestMaker(soapMessage, theRequest: theRequest) //delete token from locksmith keychain do{ try Locksmith.deleteDataForUserAccount(self.userEmail, inService: "vendoo_oauth_ebay") print("account credentials deleted for ebay") NSUserDefaults.standardUserDefaults().setBool(false, forKey: "ebayAuthorized") self.isAuthorized = false } catch{ (error) print(error) //could not save data to keychain print("account credentials could not be deleted") } } private func getPaypalEmail(onCompletion: ServiceResponse){ var soapMessage = "" + "" + "" + "\(self.xmlResponseDictionary["eBayAuthToken"] as! String)" + "" soapMessage = soapMessage + "true" + "true" + "true" + "true" + "true" + "true" + "true" + "true" + "true" + "true" + "true" + "true" + "true" + "true" + "true" + "true" + "true" + "true" + "true" + "true" + "en_US" + " string High" + "" let url = NSURL(string: self.baseURL) let theRequest = NSMutableURLRequest(URL: url!) theRequest.addValue("GetUserPreferences", forHTTPHeaderField: "X-EBAY-API-CALL-NAME") self.completion = onCompletion self.requestMaker(soapMessage, theRequest: theRequest) } func addImagesToListing(listingID: String, imageURL: String, onCompletion: ServiceResponse) { var soapMessage = "" + "" + "" + "\(self.xmlResponseDictionary["eBayAuthToken"] as! String)" + "" soapMessage = soapMessage + "en_US" + "" + "\(listingID)" + "" + "\(imageURL.stringByReplacingOccurrencesOfString("&", withString: "&"))" + "" + "" let url = NSURL(string: self.baseURL) let theRequest = NSMutableURLRequest(URL: url!) theRequest.addValue("ReviseItem", forHTTPHeaderField: "X-EBAY-API-CALL-NAME") self.completion = onCompletion self.requestMaker(soapMessage, theRequest: theRequest) } func listItem(params: [String: String], completion: ServiceResponse?){ var dict = EbayWebServiceManager.settingsDictionary var emailRetrievalGroup = dispatch_group_create() var soapMessage = "" + "" + "" + "\(self.xmlResponseDictionary["eBayAuthToken"] as! String)" + "" if((dict["payment"] as? String) == "PayPal") { dispatch_group_enter(emailRetrievalGroup) if((EbayWebServiceManager.settingsDictionary["paypal_email"]) == nil) { self.getPaypalEmail({ (any, error) -> Void in dispatch_group_leave(emailRetrievalGroup) }) }else { dispatch_group_leave(emailRetrievalGroup) } dispatch_group_notify(emailRetrievalGroup, dispatch_get_main_queue(), { soapMessage = soapMessage + "" + "\(params["title"] as String!)" + "\(params["description"] as String!)" + "" + "\(params["category_id"] as String!)" + "" + "\(params["price"] as String!)" + "\(dict["condition"] as! String!)" + "US" + "USD" + "3" + "\(dict["listingDuration"] as! String!)" + "\(dict["listingType"] as! String!)" + "\(dict["payment"] as! String!)" + "\(dict["paypal_email"] as! String!)" + "\(dict["postalCode"] as! String!)" + "\(params["quantity"] as String!)" + "" + "\(dict["return"] as! String!)" + "Vendoo requires seller to set up return policy manually." + "" + "" + "" + "\(dict["shipping"]!["shippingServicePriority"] as! String!)" + "\(dict["shipping"]!["shippingService"] as! String!)" + "0.00" + "\(dict["shipping"]!["shippingServiceAdditionalCost"] as! String!)" + "" + "" + "US" + "" let url = NSURL(string: self.baseURL) let theRequest = NSMutableURLRequest(URL: url!) theRequest.addValue("AddItem", forHTTPHeaderField: "X-EBAY-API-CALL-NAME") self.completion = completion! self.requestMaker(soapMessage, theRequest: theRequest) }) } } func fetchToken() { let soapMessage = "" + "\(self.xmlResponseDictionary["SessionID"] as! String!)" let url = NSURL(string: self.baseURL) let theRequest = NSMutableURLRequest(URL: url!) theRequest.addValue("FetchToken", forHTTPHeaderField: "X-EBAY-API-CALL-NAME") self.requestMaker(soapMessage, theRequest: theRequest) } func getSubCategories(selectedCategory: String, detailLevel: Int, catCode: String, onCompletion: ServiceResponse) { self.isGettingSubCategories = true //var dict = EbayWebServiceManager.settingsDictionary["categories"]! var soapMessage = "" + "" + "" + "\(self.xmlResponseDictionary["eBayAuthToken"] as! String)" soapMessage = soapMessage + "" + "\(catCode)" + "0" + "ReturnAll\(detailLevel)" + "" let url = NSURL(string: self.baseURL) let theRequest = NSMutableURLRequest(URL: url!) theRequest.addValue("GetCategories", forHTTPHeaderField: "X-EBAY-API-CALL-NAME") self.completion = onCompletion self.catDetailLevel = detailLevel self.requestMaker(soapMessage, theRequest: theRequest) } } extension EbayWebServiceManager: NSURLConnectionDelegate { func connection(connection: NSURLConnection!, didReceiveResponse response: NSURLResponse!) { mutableData.length = 0; print(response) } func connection(connection: NSURLConnection!, didReceiveData data: NSData!) { mutableData.appendData(data) print(data) } func connectionDidFinishLoading(connection: NSURLConnection!) { let response = NSString(data: mutableData, encoding: NSUTF8StringEncoding) print(response) var response_fixed = response!.stringByReplacingOccurrencesOfString("&", withString: "and") let data_fixed = response_fixed.dataUsingEncoding(NSUTF8StringEncoding) print(response_fixed) let xmlParser = NSXMLParser(data: data_fixed!) xmlParser.delegate = self xmlParser.parse() xmlParser.shouldResolveExternalEntities = true } func connection(connection: NSURLConnection, willSendRequestForAuthenticationChallenge challenge: NSURLAuthenticationChallenge) { challenge.sender!.performDefaultHandlingForAuthenticationChallenge!(challenge) } } extension EbayWebServiceManager: NSXMLParserDelegate { func parser(parser: NSXMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) { currentElementName = elementName } func parser(parser: NSXMLParser, foundCharacters string: String) { switch (self.currentElementName) { /* This case will be developed further to allow error handling with ebay and stateful operations */ case "Ack": if(string == "Success") { if(isRevisingListing) { self.completion(nil, nil) self.isRevisingListing = false } } break /* Used to authorize user to allow posting new listings to ebay sites and fetches all necessary information when posting to Ebay */ case "SessionID": self.xmlResponseDictionary["SessionID"] = string var str = "\(signinURL)&SessID=\(string)" self.signinURL = str print(self.signinURL) print((self.currentElementName as String) + " : " + string) self.delegate?.signInUser(self.signinURL) break case "eBayAuthToken": self.xmlResponseDictionary["eBayAuthToken"] = string print(string) //save token to locksmith keychain do{ try Locksmith.saveData(["ebay_oauth" : string], forUserAccount: self.userEmail, inService: "vendoo_oauth_ebay") print("account credentials saved") NSUserDefaults.standardUserDefaults().setBool(true, forKey: "ebayAuthorized") self.isAuthorized = true //Test authentication let soapmessage = "" + "" + "\(string)" + "" /* * boolean ItemIDType (string) string DetailLevelCodeType string string string WarningLevelCodeType */ let url = NSURL(string: self.baseURL) let theRequest = NSMutableURLRequest(URL: url!) theRequest.addValue("GetUser", forHTTPHeaderField: "X-EBAY-API-CALL-NAME") self.requestMaker(soapmessage, theRequest: theRequest) } catch{ (error) print(error) //could not save data to keychain print("account credentials could not be saved") } break case "DefaultPayPalEmailAddress": var dict = (EbayWebServiceManager.settingsDictionary) dict["paypal_email"] = string EbayWebServiceManager.settingsDictionary = dict NSUserDefaults.standardUserDefaults().setObject(EbayWebServiceManager.settingsDictionary, forKey: "ebaySettings") self.completion(nil, nil) break case "UserID" : print(string) EbayWebServiceManager.settingsDictionary["userID"] = string NSUserDefaults.standardUserDefaults().setObject(EbayWebServiceManager.settingsDictionary, forKey: "ebaySettings") print(self.xmlResponseDictionary["eBayAuthToken"]) let soapmessage = "" + "" + "\(self.xmlResponseDictionary["eBayAuthToken"] as! String)" + "0ReturnAll1" + "" let url = NSURL(string: self.baseURL) let theRequest = NSMutableURLRequest(URL: url!) theRequest.addValue("GetCategories", forHTTPHeaderField: "X-EBAY-API-CALL-NAME") self.requestMaker(soapmessage, theRequest: theRequest) break /* Used to build both the top level categories, and subcategories on request during item listing workflow */ case "CategoryID" : self.catID = string break case "CategoryLevel": self.catLevel = string break case "CategoryName" : if(!self.isGettingSubCategories) { if((EbayWebServiceManager.settingsDictionary["categories"]) == nil) { EbayWebServiceManager.settingsDictionary["categories"] = Dictionary>() } var dict: Dictionary> = (EbayWebServiceManager.settingsDictionary["categories"]!) as! Dictionary> dict[string] = ["cat_id": self.catID, "isLeaf": false, "level": self.catLevel] EbayWebServiceManager.settingsDictionary["categories"] = dict NSUserDefaults.standardUserDefaults().setObject(EbayWebServiceManager.settingsDictionary, forKey: "ebaySettings") } else { if "\(self.catDetailLevel)" == self.catLevel { if((self.subCategories[string] == nil )){ self.subCategories[string] = ["cat_id": self.catID, "isLeaf": false, "level": self.catLevel] } } } self.currentCategory = string break case "LeafCategory": if (!self.isGettingSubCategories) { var dict: Dictionary> = (EbayWebServiceManager.settingsDictionary["categories"]!) as! Dictionary> dict[self.currentCategory]!["isLeaf"] = true } else { if (self.catDetailLevel == Int((self.subCategories[self.currentCategory]!["level"] as! String))) { self.subCategories[self.currentCategory]!["isLeaf"] = true } } break case "CategoryCount": if(self.isGettingSubCategories){ self.completion(self.subCategories, nil) self.isGettingSubCategories = false self.subCategories = Dictionary>() } break /* Used during the listing creation process to save the new listing id, as well as adding pictures to the new listing */ case "ItemID": self.completion(string, nil) break case "ReviseItemResponse": self.isRevisingListing = true break default: //print(string) print("\(self.currentElementName):\(string)") } } }