Save data in specific user id iOS - Alamofire, Json - ios

I have a job application app that when a user registers through a registration page, it is automatically generating a unique user_id for each user. This app also supports multiple different data for each user (e.g education details, experience etc) so these data have to be connected with the user id of the corresponding user.
For example, suppose user A registers a new account with user_id ABCD. When this user adds new information to the system, the data have to be linked back to this user_id, ABCD. Likewise, if a user B registers a new account with user_id EFGH, any new data added to the system by user B, the data have to be linked back to his/her user_id, EFGH.
How could I do that in iOS using Swift?
Alamofire.request(URL_USER_COMPANY_PROFILE, method: .post, parameters: parameters).responseJSON
{
response in
// Printing response
print(response)
// Getting the json value from the server
if let result = response.result.value {
// Converting it as NSDictionary
let jsonData = result as! NSDictionary
UserDefaults.standard.value(forKey: "user_id")
}
}

I found the answer with iPhone developer # Muhammed Azharuddin, by creating a class for user defaults to store datas in user_id
extension UserDefaults{
static let isLoggedIn = "com.xyz.AlotTest1isLoggedIn"
static let userId = "com.xyz.AlotTest1userId"
}
And call this extension in parameters after #IBAction
let parameters: Parameters=[
"institute_name":univ.text!,
"degree_name":grad.text!,
"start_year":cityP.text!,
"end_year":enYear.text!,
"degree_city":proj.text!,
"degree_country":eduCountry.text!,
"user_id" : AuthService.instance.userId ?? ""
]
print(parameters)
//Sending http post request
Alamofire.request(URL_USER_EDUCATION, method: .post, parameters: parameters).responseJSON
{
response in
//printing response
print(response)
//getting the json value from the server
if let result = response.result.value {
let re = UserDefaults.standard.value(forKey: "user_id") as! Array<Parameters>
print(result)
let defaults: UserDefaults = UserDefaults.standard
//This class variable needs to be defined every class where you set or fetch values from NSUserDefaults
}

Related

Get User's friends user ID for app leaderboard scores

So, i'm creating a leaderboard where users can see global scores, regional scores and friends scores who have used the app before. all these scores are fetched and written to the fire store database in firebase along with the user's unique id when they log in with facebook.
I need to get a list of the users friends and their user ids from facebook so I can search the fire store database for their scores using the Facebook id. But I don't know how to get the id out of my result below when getting the list of friends:
func getFriendsFromFB() {
let params = ["fields": "id, first_name, last_name, name, email, picture"]
let graphRequest = FBSDKGraphRequest(graphPath: "/me/friends", parameters: params)
let connection = FBSDKGraphRequestConnection()
connection.add(graphRequest, completionHandler: { (connection, result, error) in
if error == nil {
if let userData = result as? [String:Any] {
print(userData)
}
} else {
print("Error Getting Friends \(error)");
}
})
connection.start()
}
Can someone suggest how I get the user id out of my result in the code above?
Also I do ask for the user_friends permission when asking the user to login.
You're casting the result as a Dictionary, this means the results are stored as key values. You can retrieve values by using dictionary["keyHere"]. I'm not sure how the FB graph result is structured, but you will have to do something like this:
// Don't continue if the result is not a dictionary
guard let userData = result as? [String: Any] else {
return
}
// Now, you can get values from the dictionary
// Let's say the userID is a String
if let userID = userData["id"] as? String {
print(userID)
}

Facebook graph API link parameter returning nil

I am trying to store a logged in facebook user's facebook username (eg www.facebook.com/james.dean01) in order to connect people via messenger (similar to How to open Facebook Messenger and direct to someone?). I am configuring a button which will send a user directly to someones messenger chat but to do so I need their username/facebook URL. I am attempting to use the "link" property (Facebook graph API: https://developers.facebook.com/docs/graph-api/reference/user) to obtain a link to the user's profile which could be used for this purpose, only the link property (printed) returns nil. I am not sure what I am doing wrong. The aim is that each time a user logs in the data is read and the database is updated. Below is the code.
Any help would be greatly appreciated!
import FacebookCore
class FacebookService {
static let instance = FacebookService()
let params = ["fields": "email, first_name, last_name, link, picture, name"]
func recordUserData() {
let graphRequest = GraphRequest(graphPath: "me", parameters: params)
graphRequest.start {
(urlResponse, requestResult) in
switch requestResult {
case .failed(let error):
print("error in graph request:", error)
break
case .success(let graphResponse):
if let responseDictionary = graphResponse.dictionaryValue {
print(responseDictionary)
let link = responseDictionary["link"] as? String
let email = responseDictionary["email"] as? String
let fbId = responseDictionary["id"] as? String
let name = responseDictionary["name"] as? String
let picture = responseDictionary["picture"] as? NSDictionary
let data = picture!["data"] as? NSDictionary
let url = data!["url"] as? String
print("Link: \(link)")
print(url)
}
}
}
}
}
You need to ask for the necessary permission, https://developers.facebook.com/docs/facebook-login/permissions#reference-user_link
And the use of this permission requires review by Facebook, before you can use it in your live app.
Not sure you would get this through review though, because what you would be doing is essentially what it says there is a not allowed use case:
Attempt to programmatically determine someone's Facebook username or canonical User ID.
So no guarantee Facebook will approve this; you can only try and submit it for review and see what feedback you get.

Siesta REST login

How to translate my login user URLSession code into Siesta framework code? My current attempt isn't working.
I've looked at the example in the GithubBrowser but the API I have doesn't work like that.
The issue is that the user structure is kind of split by how the endpoint in the API I'm consuming works. The endpoint is http://server.com/api/key. Yes, it really is called key and not user or login. Its called that by the authors because you post a user/pass pair and get a key back. So it takes in (via post) a json struct like:
{"name": "bob", "password": "s3krit"}
and returns as a response:
{"token":"AEWasBDasd...AAsdga"}
I have a SessionUser struct:
struct SessionUser: Codable
{
let name: String
let password: String
let token: String
}
...which encapsulates the state (the "S" in REST) for the user. The trouble is name & password get posted and token is the response.
When this state changes I do my:
service.invalidateConfiguration() // So requests get config change
service.wipeResources() // Scrub all unauthenticated data
An instance is stored in a singleton, which is picked up by the configure block so that the token from the API is put in the header for all other API requests:
configure("**") {
// This block ^ is run AGAIN when the configuration is invalidated
// even if loadManifest is not called again.
if let haveToken = SessionManager.shared.currentUser?.token
{
$0.headers["Authorization"] = haveToken
}
}
That token injection part is already working well, by the way. Yay, Siesta!
URLSession version
This is bloated compared to Siesta, and I'm now not using this but here is what it used to be:
func login(user: SessionUser, endpoint: URL)
{
DDLogInfo("Logging in: \(user.name) with \(user.password)")
let json: [String: Any] = ["name": user.name, "password": user.password]
let jsonData = try? JSONSerialization.data(withJSONObject: json)
var request = URLRequest(url: endpoint)
request.httpMethod = "POST"
request.httpBody = jsonData
_currentStatus = .Unknown
weak var welf = self
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data else {
handleLogin(error: error, message: "No data from login attempt")
return
}
let jsonData:Any
do {
jsonData = try JSONSerialization.jsonObject(with: data, options: [])
}
catch let jsonDecodeError {
handleLogin(error: jsonDecodeError, message: "Could not get JSON from login response data")
return
}
guard let jsonDecoded = jsonData as? [String: Any] else {
handleLogin(error: error, message: "Could not decode JSON as dictionary")
return
}
guard let token = jsonDecoded["token"] as? String else {
handleLogin(error: error, message: "No auth token in login response")
return
}
let newUser = SessionUser(name: user.name, password: "", token: token)
welf?.currentUser = newUser
welf?.saveCurrentSession()
welf?._currentStatus = .LoggedIn
DDLogInfo("User \(newUser.name) logged in")
loginUpdate(user: newUser, status: .LoggedIn, message: nil, error: nil)
}
task.resume()
}
Siesta Version
Here is my attempt right now:
func login(user: String, pass: String, status: #escaping (String?) -> ())
{
let json = [ "name": user, "password": pass]
let req = ManifestCloud.shared.keys.request(.post, json: json)
req.onSuccess { (tokenInfo) in
if let token = tokenInfo.jsonDict["token"] as? String
{
let newUser = SessionUser(name: user, password: pass, token: token)
self.currentUser = newUser
}
status("success")
}
req.onFailure { (error) in
status(error.userMessage)
}
req.onCompletion { (response) in
status(nil)
}
}
Its sort of working, but the log in credentials are not saved by Siesta and I've had to rig up a new notification system for login state which I'd hoped Siesta would do for me.
I want to use Siesta's caching so that the SessionUser object is cached locally and I can use it to get a new token, if required, using the cached credentials. At the moment I have a jury-rigged system using UserDefaults.
Any help appreciated!
The basic problem here is that you are requesting but not loading the resource. Siesta draws a distinction between those two things: the first is essentially a fancied-up URLSession request; the second means that Siesta hangs on to some state and notifies observers about it.
Funny thing, I just answered a different but related question about this a few minutes ago! You might find that answer a helpful starting point.
In your case, the problem is here:
let req = ManifestCloud.shared.keys.request(.post, json: json)
That .request(…) means that only your request hooks (onSuccess etc.) receive a notification when your POST request finishes, and Siesta doesn’t keep the state around for others to observe.
You would normally accomplish that by using .load(); however, that creates a GET request and you need a POST. You probably want to promote your POST to be a full-fledge load request like this:
let keysResource = ManifestCloud.shared.keys
let req = keysResource.load(using:
keysResource.request(.post, json: json))
This will take whatever that POST request returns and make it the (observable) latestData of ManifestCloud.shared.keys, which should give you the “notification system for login state” that you’re looking for.

How can I initialize an object with data from two separate Alamofire requests?

Im trying to make a GET request to Foursquare's Photos From a Venue and
Foursquare's Explore at the same time. Right now (correct me if I'm wrong) I have two methods to make the request via Alamofire and convert the response to a JSON object using SwiftyJSON.
I can successfully update the UITableViewCell's labels to reflect the data using makeRequest() below, but can't update the UIImage for the background photo of each respective cell.
My problem is A) getting a usable photo URL, and B) Initializing "pin" while providing data from two separate requests. In order to initialize pin, I need to set all of the values. Im geting 90% of the values from one request, and 10% (the photo URL that I need to get) from another request. How do I initialize "pin" with data from two separate requests?
makeImageRequest:
func makeImageRequest() {
let venueID = "43695300f964a5208c291fe3"
let firstURL = "https://api.foursquare.com/v2/venues/\(venueID)/photos"
Alamofire.request(.GET, firstURL, parameters: [
"client_id" : foursquareClientID,
"client_secret" : foursquareClientSecret,
"v" : "20140806",
"m" : "foursquare",
"limit" : "10"
])
.responseJSON { (request, response, data, error) in
println(request)
println(response)
println(error)
let jsonObj = JSON(data!)
self.pins = []
for obj in jsonObj["response"]["photos"]["items"].arrayValue {
let photoURL = obj["prefix"]["suffix"].stringValue
println("the photo url is\(photoURL)")
let pin = Pin(title: obj["venue"]["name"].stringValue, openUntil: obj["venue"]["hours"]["status"].stringValue, address: obj["venue"]["location"]["address"].stringValue, ratingSignals: obj["venue"]["ratingSignals"].stringValue, ratingImage: UIImage(named:"Score8-5")!, venueImage: UIImage(named: "FloraGrubTestImage.jpg")!)
self.pins.append(pin)
}
self.tableView.reloadData()
}
}
and makeRequest
func makeRequest(searchString: String) {
let secondURL = "https://api.foursquare.com/v2/venues/explore"
Alamofire.request(.GET, secondURL, parameters: [
"client_id" : foursquareClientID,
"client_secret" : foursquareClientSecret,
"ll" : "37.71987,-122.470089",
"query" : searchString,
"radius" : "1000",
"limit" : "10",
"v" : "20140806",
"m" : "foursquare"
])
.responseJSON { (request, response, data, error) in
println(request)
println(response)
println(error)
let jsonObj = JSON(data!)
self.pins = []
println(jsonObj)
for obj in jsonObj["response"]["groups"][0]["items"].arrayValue {
let pin = Pin(title: obj["venue"]["name"].stringValue, openUntil: obj["venue"]["hours"]["status"].stringValue, address: obj["venue"]["location"]["address"].stringValue, ratingSignals: obj["venue"]["ratingSignals"].stringValue, ratingImage: UIImage(named:"Score8-5")!, venueImage: UIImage(named: "FloraGrubTestImage.jpg")!)
self.pins.append(pin)
}
self.tableView.reloadData()
}
}
I have a separate bindData() method in my UITableViewCell class. Does this make sense? Can anyone help me?
UPDATE: An engineer I work with suggested that I make another request inside of the same method makeRequest and not bother with breaking it out into two separate methods. I also read a tutorial online that suggests a response router of some kind. Any suggestions on how I can refactor this code into one method?
UPDATE #2: I have renamed this question as I realize that the original question was not my real problem
The easiest way would be to execute these request serially. First retrieve all the pins, and then retrieve all the photos. This is essentially what the other engineer advised.
If you fire off these requests in parallel, it will require a extra work to merge the responses, since you don't know which request will return first.
Now to merge the pins you need a way to uniquely identify each pin. If they have some ID, you can use that. Otherwise you have to rely on the sort order and index. Assuming each request returns the same pins in the same order.
After the first request returns, you have an array of pins. Then in the second request callback you can retrieve the matching pin from this array and update it with the new data.

PayPal email ID of the user who has approved Future Payment

We are using PayPal future payments in our IOS app. We need to know email ID of the account that has authorized future payment. How can we fetch email ID of the user who has authorized future payment. Current API operation for approval returns only authorization token.
I'm assuming by "future payments" you're referring to Preapproved Payments..??
Setup an IPN solution and make sure to an IPNNotificationURL in your Preapproval API request. The IPN will include more details about the transaction including the payer email address.
Here is a list of the variables you can expect from a Preapproval profile getting created. You'll notice the "sender_email" parameter, which is what you'd be looking for.
Here's a sample of an actual IPN I got in the sandbox after processing a Preapproval request.
Array
(
[max_number_of_payments] => 100
[starting_date] => 2015-03-01T00:00:21.000-08:00
[pin_type] => NOT_REQUIRED
[max_amount_per_payment] => 20.00
[currency_code] => USD
[sender_email] => guy.louzon-buyer#gmail.com
[verify_sign] => AFcWxV21C7fd0v3bYYYRCpSSRl31AiHQSQchSGUInXdtl6zomfkZ7H4C
[test_ipn] => 1
[date_of_month] => 0
[current_number_of_payments] => 0
[preapproval_key] => PA-2M0807730Y425554F
[ending_date] => 2015-12-31T23:59:21.000-08:00
[approved] => true
[transaction_type] => Adaptive Payment PREAPPROVAL
[day_of_week] => NO_DAY_SPECIFIED
[status] => ACTIVE
[current_total_amount_of_all_payments] => 0.00
[current_period_attempts] => 0
[charset] => windows-1252
[payment_period] => 0
[notify_version] => UNVERSIONED
[max_total_amount_of_all_payments] => 2000.00
)
Ichathan, you'll want to utilize the Profile Sharing feature of the mSDK to get the customer attributes and pass in the Future Payment scope within that to also gain consent for those. The available scopes you can use for Profile Sharing are listed out in the PayPalOAuthScopes.h file of the iOS SDK.
This answer is correct but not detailed.
The Profile Sharing Mobile Integration allows the user to consent to future payments as well as gets email and other information in one login flow. Here's the snippet we used:
func profileController() -> PayPalProfileSharingViewController {
PayPalMobile.preconnectWithEnvironment(PayPalEnvironmentSandbox)//PayPalEnvironmentNoNetwork)
let scope: Set<String> = Set([kPayPalOAuth2ScopeEmail, kPayPalOAuth2ScopeFuturePayments])
let controller = PayPalProfileSharingViewController(scopeValues: scope, configuration: self.paypalConfiguration!, delegate: self)
return controller!
}
func payPalProfileSharingViewController(profileSharingViewController: PayPalProfileSharingViewController, userDidLogInWithAuthorization profileSharingAuthorization: [NSObject : AnyObject]) {
self.processAuthorization(profileSharingAuthorization)
}
func userDidCancelPayPalProfileSharingViewController(profileSharingViewController: PayPalProfileSharingViewController) {
self.delegate?.didFailPayPalConsent()
}
func processAuthorization(authorization: [NSObject: AnyObject]) {
if let authCode = authorization["response"]?["code"] as? String {
self.delegate?.didSucceedPayPalConsent(authCode)
}
else {
self.delegate?.didFailPayPalConsent()
}
}
Edit: The mobile controller gives you the auth token that has permissions for profile information, but you have to make another call from your server side code for that information:
https://developer.paypal.com/docs/api/#get-user-information
This is how I did it.
The profile sharing Paypal Profile Sharing gives us the Auth Token
This particular delegate function gets called
func payPalProfileSharingViewController(profileSharingViewController: PayPalProfileSharingViewController, userDidLogInWithAuthorization profileSharingAuthorization: [NSObject : AnyObject]) {
self.processAuthorization(profileSharingAuthorization)
}
After authToken we need to hit some server side APIs . We can achieve this through app side as well. I have hit server side apis from client side
First step is to make a basic Auth Request it will return us a Refresh as well as Access Token. Get Access Token
func generateAccessToken(authCode : String ,block : completionHandler){
let parameters = ["grant_type" : "authorization_code", "response_type" :"token","redirect_uri" : "urn:ietf:wg:oauth:2.0:oob","code":authCode]
let username = AppConstants().kPayPalUserName //APP_ID
let password = AppConstants().kPayPalSecret
let credentialData = "\(username):\(password)".data(using: String.Encoding.utf8)!
let base64Credentials = credentialData.base64EncodedString(options: [])
let headers = ["Authorization": "Basic \(base64Credentials)"]
let customerURL = AppConstants().kPayPalUrl
Alamofire.request(customerURL,
method: .post,
parameters: parameters,
encoding: URLEncoding.default,
headers:headers)
.validate()
.responseJSON { response in
switch response.result {
case .success(let value):
KVNProgress.dismiss(completion: {
block?(true, value as! Dictionary<String, Any>) // get the accessToken
})
// BasicFunctions.displayAlert("Success", needDismiss: false, title: "Task Created Successfully")
case .failure(let responseError):
KVNProgress.dismiss(completion: {
if (responseError != nil) {
BasicFunctions.displayAlert(SERVER_ERROR)
// let json = JSONSerialization
// block!(false,responseError as! Dictionary<String, Any>)
}else{
BasicFunctions.displayAlert(SERVER_ERROR)
}
})
}
}
}
Using the access Token we need to hit another CURL request and it will give us all the user information Get User Profile Information
Now using this request we can get complete user info. The access Token was generated from Basic Auth Token
func getUserProfileInfo(accessToken : String,block : completionHandler){
KVNProgress.show()
let parameters = ["":""]
let headers = ["Authorization": "Bearer " + accessToken]
let customerURL = "https://api.sandbox.paypal.com/v1/identity/openidconnect/userinfo/?schema=openid"
Alamofire.request(customerURL, method: .post, parameters: parameters, encoding: JSONEncoding.default, headers: headers).responseJSON { (response) in
switch response.result {
case .success(let value):
KVNProgress.dismiss(completion: {
block?(true, value as! Dictionary<String, Any>)
})
// BasicFunctions.displayAlert("Success", needDismiss: false, title: "Task Created Successfully")
case .failure(let responseError):
KVNProgress.dismiss(completion: {
if (responseError != nil) {
BasicFunctions.displayAlert(SERVER_ERROR)
// let json = JSONSerialization
// block!(false,responseError as! Dictionary<String, Any>)
}else{
BasicFunctions.displayAlert(SERVER_ERROR)
}
})
}
}
}
Note : Make sure in your app settings in Paypal You have allowed access to email or other user information
Disclaimer : This project was only for a POC so I am not sure whether we are violating the PCI compliance by hitting server side APIs from client side

Resources