Stripe - check if a customer exists - ruby-on-rails

In the stripe documentation they have this:
customer = Stripe::Customer.create(email: params[:stripeEmail], card: params[:stripeToken])
charge = Stripe::Charge.create(customer: customer.id, amount: price, description: '123', currency: 'usd')
But I think it's wrong as for each payment we have to check if a customer exists first, I just tried it with a test account and it turned out there were created a number of different customers with the same email but different ids.
How do I check if a customer already exists?

There is no check on Stripe's end to ensure uniqueness of customers (email, card, name, etc,) and this is something you have to do on your end.
Usually, when you create a customer with a specific email address you need to associate the customer id you got back from the API with the email address. Then next time, you check whether this email address is already in your system and either create a new customer or re-use the customer id from the previous time.

You may check if the customer exists or not by calling GET /customers with the email as a form-urlencoded parameter. You will get 200 OK response but the returned data[] will be empty if this customer email is not there.
https://stripe.com/docs/api/customers/list

I think a simple "exists" test is essential to avoid unwanted exceptions being generated.
If your customer is new then they won't have a stripe ID, which is fine. However you might get a situation where you are using an existing customer with an existing stripe ID, but have performed some sort of dormant clean-up Stripe side. In which case its good practice to test the supplied stripeID to see if its still valid.
For example I store the stripeID with the customer profile. When I make a payment I check to see if the stripeID field in the profile exists. If it does I fire off a API request to my backend to check its existence.
Something like this (.net backend example).
[HttpGet]
public ActionResult<bool> CheckCustomer(string id)
{
var service = new CustomerService();
Customer cust;
try
{
service.Get(id);
}
catch
{
return Ok(false);
}
if (cust.Deleted ?? false)
{
return Ok(false);
}
return Ok(true);
}
I don't need the result, just it not throwing an exception is good enough. However, when you delete customers in Stripe live it keeps a copy of the ID stub and sets the delete property to true, so you need to check for that too.
The front end then can either use the stripeId for the payment or create a new stripe customer first then take the payment.

You can search for the customer by email address...
public async Task<Customer> GetCustomerByEmail(string oneEmail)
{
var service = new CustomerService();
try
{
StripeList<Customer> customerList = await service.ListAsync(new CustomerListOptions() { Email=oneEmail },null);
Debug.WriteLine(customerList.ToList().Count);
return customerList.ToList().FirstOrDefault();
}
catch
{
return null;
}
}

Related

Sending messages to specific users in Teams using Graph API

Any endpoint for sending messages to specific users in Teams via the Graph API?
(Edited because of clarity and added Custom-Requests)
You can send messages via Graph API to private users BUT there is a problem that you can't create a new chat between two users via the Graph API. This means that if you want to send a message from a user to a user, the chat must already exist. (Messages must first have been exchanged via the MSTeams client for a chat to exist)
So make sure that you have a open chat!
If so, have a look at this MSDoc (This document explains how you can list chats from a user):
https://learn.microsoft.com/en-us/graph/api/chat-list?view=graph-rest-beta&tabs=http
After you have all your chats listed, you can have a look at this MSDoc (This document explains how you can send a message to a user):
https://learn.microsoft.com/en-us/graph/api/chat-post-messages?view=graph-rest-beta&tabs=http
Pay attention to the permissions! For sending messages and listing chats there are only delegated permissions so far AND these calls are only available in BETA, so be carefull with it.
I can only provide you Java code for an example.
(For everything I do I use ScribeJava to get an Auth-Token)
For delegated permissions you need to have a "User-Auth-Token". That means you have to use a Password-Credential-Grant like this:
private void _initOAuth2Service()
{
oAuth2Service = new ServiceBuilder(clientId)
.apiSecret(clientSecret)
.defaultScope(GRAPH_SCOPE)
.build(MicrosoftAzureActiveDirectory20Api.custom(tenantId));
//PASSWORD CREDENTIALS FLOW
try
{
oAuth2Token = oAuth2Service.getAccessTokenPasswordGrant(username, password);
}
catch (IOException e) { e.printStackTrace(); }
catch (InterruptedException e) { e.printStackTrace(); }
catch (ExecutionException e) { e.printStackTrace(); }
}
username and password are the credentials from the user you want to send a message (sender).
Initial situation
This is my TeamsClient:
ScribeJava
Get all open chats
("me" in the URL is the user from above (sender).)
private Response _executeGetRequest()
{
final OAuthRequest request = new OAuthRequest(Verb.GET, "https://graph.microsoft.com/beta/me/chats");
oAuth2Service.signRequest(oAuth2Token, request);
return oAuth2Service.execute(request);
}
The response I get from this request looks like this:
{"#odata.context":"https://graph.microsoft.com/beta/$metadata#chats","value":[{"id":"{PartOfTheID}_{firstHalfOfUserID}-e52a55572b49#unq.gbl.spaces","topic":null,"createdDateTime":"2020-04-25T09:22:19.86Z","lastUpdatedDateTime":"2020-04-25T09:22:20.46Z"},{"id":"{secondUserChatID}#unq.gbl.spaces","topic":null,"createdDateTime":"2020-03-27T08:19:29.257Z","lastUpdatedDateTime":"2020-03-27T08:19:30.255Z"}]}
You can see that I have two open chats and get two entries back from the request.
Get the right conversatonID
You have to know that the id can be split in three sections. {JustAPartOfTheId}_{userId}#{EndOfTheId}. The {userId} is the id from your chatpartner (recipient).
This is a GraphExplorer response which gives me all users and all informations about them.
Now you can see that the first ID:
"id":"{PartOfTheID}_{firstHalfOfUserID}-e52a55572b49#unq.gbl.spaces"
matches the UserID after the "_".
You can split the ID at the "_" filter and find the ID you need.
Send Message to user
Now you know the right Id and can send a new request for the message like this:
final OAuthRequest request = new OAuthRequest(Verb.POST, "https://graph.microsoft.com/beta/chats/{PartOfTheID}_{firstHalfOfUserID}-e52a55572b49#unq.gbl.spaces/messages");
oAuth2Service.signRequest(oAuth2Token, request);
request.addHeader("Accept", "application/json, text/plain, */*");
request.addHeader("Content-Type", "application/json");
request.setPayload("{\"body\":{\"content\":\" " + "Hi Hi Daniel Adu-Djan" + "\"}}");
oAuth2Service.execute(request);
GraphAPI-Custom-Requests
In the Graph-SDK is no opportunity to use the beta endpoint except for Custom-Requests. (For these requests I also use ScribeJava to get an Auth-Token)
Set the BETA-Endpoint
When you want to use the BETA-Endpoint you have to use the setEndpoint() function like this:
IGraphServiceClient graphUserClient = _initGraphServiceUserClient();
//Set Beta-Endpoint
graphUserClient.setServiceRoot("https://graph.microsoft.com/beta");
Get all chats
try
{
JsonObject allChats = graphUserClient.customRequest("/me/chats").buildRequest().get();
}
catch(ClientException ex) { ex.printStacktrace(); }
Same response like above
Same situation with the userId => split and filter
Send message
IGraphServiceClient graphUserClient = _initGraphServiceUserClient();
//Set Beta-Endpoint again
graphUserClient.setServiceRoot("https://graph.microsoft.com/beta");
try
{
JsonObject allChats = graphUserClient.customRequest("/chats/{PartOfTheID}_{firstHalfOfUserID}-e52a55572b49#unq.gbl.spaces/messages").buildRequest().post({yourMessageAsJsonObject});
}
catch(ClientException ex) { ex.printStacktrace();
}
Here is a little GIF where you can see that I didn't type anything. I just started my little application and it sends messages automatically.
I hope this helps you. Feel free to comment if you don't understand something! :)
Best regards!
As of now, We do not have any endpoint to send messages to specific users via Graph API.
You may submit/vote a feature request in the UserVoice or just wait for the update from the Product Team.
You can vote for a below feature requests which are already created. All you have to do is enter your email ID and vote.
https://microsoftteams.uservoice.com/forums/555103-public/suggestions/40642198-create-new-1-1-chat-using-graph-api
https://microsoftteams.uservoice.com/forums/555103-public/suggestions/39139705-is-there-any-way-to-generate-chat-id-by-using-grap
Update:
Please find below one more user voice created for the same in Microsoft Graph user voices and vote for it.
https://microsoftgraph.uservoice.com/forums/920506-microsoft-graph-feature-requests/suggestions/37802836-add-support-for-creating-chat-messages-on-the-user

iOS - AWS Cognito - Check if user already exists

I want to allow a user to enter their email address/password in a field. Upon continuing, I want to run a check to see if that user already exists. If they do, log them in and continue with app, if they do not, move to account creation flow where they will be instructed to add name, phone number, etc.
I cannot for the life of me find documentation on how to log a user in using AWS Cognito. I should be able to pass email/pass in a call and get a response back that says User Exists/User does not exist or whatever! Am I missing something here?
Any help would be greatly appreciated. I've scoured the documentation..this is my last resort.
In the current SDK, calling getUser on your AWSCognitoIdentityUserPool just constructs the in-memory user object. To make the call over the network, you need to call the getSession method on the constructed user. Here's a Swift 3 method I wrote to check whether an email is available:
/// Check whether an email address is available.
///
/// - Parameters:
/// - email: Check whether this email is available.
/// - completion: Called on completion with parameter true if email is available, and false otherwise.
func checkEmail(_ email: String, completion: #escaping (Bool) -> Void) {
let proposedUser = CognitoIdentityUserPoolManager.shared.pool.getUser(email)
UIApplication.shared.isNetworkActivityIndicatorVisible = true
proposedUser.getSession(email, password: "deadbeef", validationData: nil).continueWith(executor: AWSExecutor.mainThread(), block: { (awsTask) in
UIApplication.shared.isNetworkActivityIndicatorVisible = false
if let error = awsTask.error as? NSError {
// Error implies login failed. Check reason for failure
let exceptionString = error.userInfo["__type"] as! String
if let exception = AWSConstants.ExceptionString(rawValue: exceptionString) {
switch exception {
case .notAuthorizedException, .resourceConflictException:
// Account with this email does exist.
completion(false)
default:
// Some other exception (e.g., UserNotFoundException). Allow user to proceed.
completion(true)
}
} else {
// Some error we did not recognize. Optimistically allow user to proceed.
completion(true)
}
} else {
// No error implies login worked (edge case where proposed email
// is linked with an account which has password 'deadbeef').
completion(false)
}
return nil
})
}
For reference, my ExceptionString enum looks like this:
public enum ExceptionString: String {
/// Thrown during sign-up when email is already taken.
case aliasExistsException = "AliasExistsException"
/// Thrown when a user is not authorized to access the requested resource.
case notAuthorizedException = "NotAuthorizedException"
/// Thrown when the requested resource (for example, a dataset or record) does not exist.
case resourceNotFoundException = "ResourceNotFoundException"
/// Thrown when a user tries to use a login which is already linked to another account.
case resourceConflictException = "ResourceConflictException"
/// Thrown for missing or bad input parameter(s).
case invalidParameterException = "InvalidParameterException"
/// Thrown during sign-up when username is taken.
case usernameExistsException = "UsernameExistsException"
/// Thrown when user has not confirmed his email address.
case userNotConfirmedException = "UserNotConfirmedException"
/// Thrown when specified user does not exist.
case userNotFoundException = "UserNotFoundException"
}
Some clarification is in order. Cognito has several parts. The part that does "Authentication" (which is what you are talking about) is called "Cognito User Pools". Not to be confused with Cognito Federated Identity Pools.
With User Pools you can create usernames and password combinations with attributes, and these can be used to authenticate and deliver a persistent, cross device, Cognito Federated identity identityId to a user (across multiple devices).
Once logged in, the Federated Identity Pool is hooked to roles which can get your "Authorized" to use AWS services (like Dynamo DB etc).
It can be tricky to get all these parts working together and AWS has an online site called "Mobile Hub" that will build code for you and download an xcode project. This process configures the Federated Identity Pool and the User Pool correctly, and connects them all up to a set of example code.
Connecting the credentials provider to the user pool to the identity pool is a bit counterintuitive, but the AWSIdentityManager in the aws-mobilehub-helper-ios on github manages all that for you. So I would recommend starting with mobile hub on the console.
Cognito is a somewhat confusing system, here is a link to a brief powerpoint that hits the highlights of how it works (for people that can't understand the AWS docs (like me)).
With that said, "how to check if a user already exists?"
The most reasonable approach is to create the user (via signup), and get a reject if the name is in use, and suggest that your user try a different username. With respect to the email being in use, you will get that reject upon confirmation (signup sends confirmation id's by email and/or via text). This can be overridden to reclaim the email address, or you can do a test beforehand to see if the email is in use by attempting to log in and looking at the failure code.
you can fetch the user as the other answer suggests, however if you have established in user pools an alias for login (like email) you will find this problematic, because this just tells you if someone has the user name, not if someone is already using the email address, and you will get a reject later at confirmation time.
ListUsers is now a nice way to check for existing usernames.
https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_ListUsers.html
You can also look for existing emails, phone numbers, and other default attributes.
Here is a simple .NET example:
Dim userRequest = New ListUsersRequest With {
.UserPoolId = "poolId",
.Filter = "username = bob#email.com"
}
Dim response = amazonCognitoIdentityProviderClient.ListUsers(userRequest)
Debug.WriteLine(response.Users.Count)

Parse Server + Stripe Connect - iOS

How do you setup Parse Server with Stripe Connect? I'm having a miserable time...
I'm trying to integrate my Parse Server (hosted on Heroku) with Stripe Connect (this is different that standard Stripe, in it allows you (the app) to transfer payments to a third party while taking a 'processing fee' while ONLY USING Parse Server + Xcode (as this is all that I'm familiar with).
For example, Lyft charges the customer's credit card, takes a percentage of the ride, and the remaining balance is transferred to the driver. How do I do this in Stripe automatically?!
Stripe's documentation did not give me an explicit example and I struggled for hours... Well, I finally got it and wanted to share it with you. Hope you all find this useful:
Assumptions:
You have an account on Stripe
You've added Stripe to your Parse Server example here. If you don't understand, message me for details.
You've added Stripe SDK to your Xcode project
You've setup Cloud Code on your Parse Server (again message if confused)
OK, so we are going to charge a credit card, pay the third party, but keep a 'fee'. First you'll go to the Stripe.com dashboard (click the top right of the screen, to view all of the options). Then click CONNECT and fill out the info.
IMPORTANT: YOU DO NOT NEED TO FILL OUT THE FIELDS "REDIRECT URI".
OK so now we need to create a CONNECTED STRIPE ACCOUNT. We do this by cloud code:
Parse.Cloud.define("createConnectedAccount", function(request, response) {
var stripe = require('stripe')('YOUR_SECRET_KEY');
stripe.accounts.create({
managed: false,
country: 'US',
email: 'example#gmail.com' //THIS IS YOUR THIRD PARTY ACCOUNT EMAIL ADDRESS
}, function(err, account) {
// asynchronously called
if (err) {
//other errror
response.error(err); // return error
} else {
//no error
response.success(account); // return charge success
}
});
});
This account is managed by the THIRD PARTY. When you run this code, it will create a Stripe account for this third party and send them an email (to the email listed). Basically, the email instructs them to Login, enter a password, and enter a bank account. When they activate the account, it will be 'connected' to your account.
Once connected, now it's time to write the "charge the card" method:
Parse.Cloud.define("charge", function(request, response) {
var stripe = require('stripe')('YOUR_SECRET_KEY');
stripe.charges.create({
amount: 100, //in CENTS
currency: "usd",
customer: request.params.customer, //customer is the id given by stripe when you create a customer. example: cus_EXAMPLE398FMFJKEP876
description: "example for people",
application_fee: 25, //again, in CENTS
}, {stripe_account: "3RD_PARTY_ACCOUNT_NUMBER"}, function(err, charge) { //the third party account number looks something like this acct_EXAMPLE352JFLE3207ME and can be found by clicking "Connected Accounts" (left side pane option after you set it up).
// asynchronously called
if (err && err.type === 'StripeCardError') {
// The card has been declined
response.error(err); // card declineded
} else if (err) {
//other errror
response.error(err); // return error
} else {
//no error
response.success(charge); // return charge success
}
});
});
Lastly, a quick picture of the "connected accounts" option on the left navigation pane:
Walah. You are done.
Hope this helps. Let me know if you have any questions.

How to get Twitter account Email address using SLRequest or ACAccount?

I am developing an iOS app where i use Social.framework and Accounts.farmework to get Twitter account information.I am getting all the necessary info but not the Email address of the account.
After googling i am confuse is it really available?
Need help.
To request a user’s email, call the TwitterAuthClient#requestEmail method, passing in a valid TwitterSession and Callback.
TwitterAuthClient authClient = new TwitterAuthClient();
authClient.requestEmail(session, new Callback() {
#Override
public void success(Result result) {
// Do something with the result, which provides
// the email address
}
#Override
public void failure(TwitterException exception) {
// Do something on failure
}
});
Click 'Allow' when asked to 'Share your Email Address'.
If the user grants access and the email address is available, the success method is called with the email address in the result.
If the user denies access, the failure method will be called instead.
Note that even if the user grants access to her email address, it is not guaranteed you will get an email address. For example, if someone signed up for Twitter with a phone number instead of an email address, the email field may be empty. When this happens, the failure method will be called because there is no email address available.
Yes, you can get user the information. Check out this!

Cloud code - "Execution timed out" during saveAll call in afterSave

Situation
I have a messaging Android app providing following feature(s)
to send message direct message to one selected recipient
to create public announcement that all users using the app receive (except author)
each user sees on his phone a list of messages he got
each message is either unread, read, or deleted
I use Parse.com as back-end
Current implementation
On Android client
When there is a new message, a new messageRequest of the MessageRequest class is created
If the message should be direct, the messageRequest has type 0, otherwise type 1
If the message is direct, there is recipient stored in the messageRequest object
The messageRequest object is stored to parse.com
On parse.com back-end
In the afterSave of the MessageRequest it is checked if the message is direct or public and based on that
in case of direct message - one new message object of the Message class is created and saved
in case of public announcement - for each user except author, a new message object is created and added to a list of messages, then the list is saved
In both cases, the data like content, type, etc. are copied from messageRequest object into the newly created message object(s).
The reason for creating separate message for each user is that each user can have it in another status (unread, read, deleted).
The status column representing the unread, read, deleted status is set (by unread) for the message object.
Problem
When I call the ParseObject.saveAll method in the afterSave of MessageRequest, I get the Execution timed out - Request timed out error
I think the cause is that there are some limits on time in which the request must complete
in cloud code. In my case, I'm creating ca 100 Messages for 1 MessageRequest
This doesn't seem so much to me, but maybe I'm wrong.
Source code
var generateAnnouncement = function(messageRequest, recipients) {
var messageList = [];
for (var i = 0; i < recipients.length; i++) {
var msg = new Message();
msg.set("type", 1);
msg.set("author", messageRequest.get("author"));
msg.set("content", messageRequest.get("content"));
msg.set("recipient", recipients[i]);
msg.set("status", 0)
messageList.push(msg);
}
Parse.Object.saveAll(messageList).then(function(list) {
}, function(error) {
console.error(error.message);
});
}
Parse.Cloud.afterSave("MessageRequest", function(request) {
var mr = request.object;
var type = mr.get("type");
if (type == 0) {
generateDirectMessage(mr);
} else {
var query = new Parse.Query(Parse.User);
query.notEqualTo("objectId", mr.get("author").id);
query.find().then(function(allUsersExceptAuthor) {
generateAnnouncement(mr, allUsersExceptAuthor);
}, function(error) {
console.error(error.message);
});
}
});
How would you suggest to solve this?
Additional thoughts
My only other idea how to solve this is to have only one Message object, and two columns called e.g. viewedBy and deletedFor which would contain lists of users that already viewed the message or have delete the message for them.
In this case, I'm not very sure about the performance of the queries
Also, I know, many of you think Why isn't he using table for splitting the M:N relation between the MessageRequest(which could be actually called Message in that case) and User?
My answer is that I had this solution, but it was harder to work with it in the Android code, more pointers, more includes in queries, etc.
Moreover, I would have to create the same amount of objects representing status for each user in the on parse.com back-end anyway, so I think the problem with Execution time out would be the same in the end
Update - mockup representing user's "Inbox"
In the "inbox" user sees both direct messages and public announcements. They are sorted by chronological order.
Update #2 - using arrays to identify who viewed and who marked as deleted
I have just one Message object, via type I identify if it is direct or public
Two array columns were added
viewedBy - containing users that already viewed the message
deletedFor - containing users that marked the message as deleted for them
Then my query for all messages not deleted by currently logged in user looks like this
//direct messages for me
ParseQuery<Message> queryDirect = ParseQuery.getQuery(Message.class);
queryDirect.whereEqualTo("type", 0);
queryDirect.whereEqualTo("recipient", ParseUser.getCurrentUser());
//public announcements
ParseQuery<Message> queryAnnouncements = ParseQuery.getQuery(Message.class);
queryAnnouncements.whereEqualTo("type", 1);
//I want both direct and public
List<ParseQuery<Message>> queries = new ArrayList<ParseQuery<Message>>();
queries.add(queryDirect);
queries.add(queryAnnouncements);
ParseQuery<Message> queryMessages = ParseQuery.or(queries);
//... but only those which I haven't deleted for myself
queryMessages.whereNotEqualTo("deletedFor", ParseUser.getCurrentUser());
//puting them in correct order
queryMessages.addDescendingOrder("createdAt");
//and attaching the author ParseUser object (to get e.g. his name or URL to photo)
queryMessages.include("author");
queryMessages.findInBackground(new FindCallback<Message>() {/*DO SOMETHING HERE*/});
I would suggest changing your schema to better support public messages.
You should have a single copy of the public message, as there's no changing the message itself.
You should then store just the status for each user if it is anything other than "unread". This would be another table.
When a MessageRequest comes in with type 1, create a new PublicMessage, don't create any status rows as everyone will use the default status of "unread". This makes your afterSave handler work cleanly as it is always creating just one new object, either a Message or a PublicMessage.
As each user reads the message or deletes it, create new PublicMessageStatus row for that user with the correct status.
When showing public messages to a user, you will do two queries:
Query for PublicMessage, probably with some date range
Query for PublicMessageStatus with a filter on user matching the current user and matchesQuery('publicMessage', publicMessageQuery) constraint using a clone of the first query
Client side you'll then need to combine the two to hide/remove those with status "deleted" and mark those with status "read" accordingly.
Update based on feedback
You could choose instead to use a single Message class for public/private messages, and a MessageStatus class to handle status.
Public vs Private would be based on the Message.recipient being empty or not.
To get all messages for the current user:
// JavaScript sample since you haven't specified a language
// assumes Underscore library available
var Message = Parse.Object.extend('Message');
var MessageStatus = Parse.Object.extend('MessageStatus');
var publicMessageQuery = new Parse.Query(Message);
publicMessageQuery.doesNotExist('recipient');
publicMessageQuery.notEqualTo('author', currentUser);
var privateMessageQuery = new Parse.Query(Message);
privateMessageQuery.equalTo('recipient', currentUser);
var messagesQuery = new Parse.Query.or(publicMessageQuery, privateMessageQuery);
messagesQuery.descending('createdAt');
// set any other filters to apply to both queries
var messages = [];
messageQuery.find().then(function(results) {
messages = _(results).map(function (message) {
return { message: message, status: 'unread', messageId: message.objectId };
});
var statusQuery = new Parse.Query(MessageStatus);
statusQuery.containedIn('message', results);
statusQuery.equalTo('user', currentUser);
// process status in order so last applies
statusQuery.ascending('createdAt');
return
}).then(function(results) {
_(results).each(function (messageStatus) {
var messageId = messageStatus.get('message').objectId;
_(messages).findWhere({ messageId: messageId }).status = messageStatus.get('status');
});
});
// optionally filter messages that are deleted
messages = _(messages).filter(function(message) { return message.status !== 'deleted'; });
// feed messages array to UI...

Resources