Bug in order program in which payment can be bypassed - c#

This project makes the customer first create an order and them has to pay for said order via Braintree, However the issue that I am getting is that a customer can create an order and them close the application. This will cause the order to still exist however the customer did not have to pay for their order. If any one knows of a work around for this their help would be thanked. (The orders and payments work. Its just this bug that I'm worried about)
Orders Controller
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> FirstClassCreate(FormCollection values)
{
var order = new Order();
TryUpdateModel(order);
var customer = db.Users.FirstOrDefault(x => x.Email == User.Identity.Name);
var cart = ShoppingCart.GetCart(this.HttpContext);
try
{
Sets the order attributes
order.DeliveryDate = DateTime.Now.AddDays(1);
order.DeliveryMethod = "First Class";
order.FirstName = customer.FirstName;
order.LastName = customer.LastName;
order.PostalCode = customer.PostalCode;
order.State = customer.State;
order.City = customer.City;
order.Email = customer.Email;
order.Country = customer.Country;
order.Phone = customer.PhoneNumber;
order.Address = customer.Address;
order.Username = customer.Email;
order.OrderDate = DateTime.Now;
var currentUserId = User.Identity.GetUserId();
order.Total = cart.GetFirstClass();
if (order.SaveInfo && !order.Username.Equals("guest#guest.com"))
{
var manager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
var store = new UserStore<ApplicationUser>(new ApplicationDbContext());
var ctx = store.Context;
var currentUser = manager.FindById(User.Identity.GetUserId());
//Save this back
//http://stackoverflow.com/questions/20444022/updating-user-data-asp-net-identity
//var result = await UserManager.UpdateAsync(currentUser);
await ctx.SaveChangesAsync();
await storeDB.SaveChangesAsync();
}
Saves the order to the database
//Save Order
storeDB.Orders.Add(order);
await storeDB.SaveChangesAsync();
//Process the order
cart = ShoppingCart.GetCart(this.HttpContext);
order.Total = cart.GetFirstClass();
order = cart.CreateOrder(order);
return RedirectToAction("FirstClass", "Checkouts");
}
catch
{
//Invalid - redisplay with errors
return View(order);
}
}
Checkouts controller
public ActionResult CreateFirstClass(FormCollection collection)
{
var gateway = config.GetGateway();
Decimal amount;
//Need to get the amount
try
{
amount = Convert.ToDecimal(Request["amount"]);
}
catch (FormatException e)
{
TempData["Flash"] = "Error: 81503: Amount is an invalid format.";
return RedirectToAction("New");
}
string nonceFromTheClient = collection["payment_method_nonce"];
var cart = ShoppingCart.GetCart(this.HttpContext);
//if (id == null)
//{
// return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
//}
//order = Orders.FindAsync(id);
Gets the necessary payment methods
var request = new TransactionRequest
{
Amount = cart.GetFirstClass(),
PaymentMethodNonce = nonceFromTheClient,
Options = new TransactionOptionsRequest
{
SubmitForSettlement = true
}
};
cart.EmptyCart();
Result<Transaction> result = gateway.Transaction.Sale(request);
if (result.IsSuccess())
{
Transaction transaction = result.Target;
return RedirectToAction("Show", new { id = transaction.Id });
}
else if (result.Transaction != null)
{
return RedirectToAction("Show", new { id = result.Transaction.Id });
}
else
{
string errorMessages = "";
foreach (ValidationError error in result.Errors.DeepAll())
{
errorMessages += "Error: " + (int)error.Code + " - " + error.Message + "\n";
}
TempData["Flash"] = errorMessages;
return RedirectToAction("New");
}
}
#

Related

How to check if payment was successful or not Stripe ASP.NET

public ActionResult Index()
{
StripeConfiguration.ApiKey = "secretKey";
var options = new SessionCreateOptions
{
PaymentMethodTypes = new List<string> {
"card",
},
LineItems = new List<SessionLineItemOptions> {
new SessionLineItemOptions {
Name = "Basic Plan",
Description = "Up to 1 Featured Product",
Amount = 1000,
Currency = "usd",
Quantity = 1,
},
},
SuccessUrl = "https://localhost:44390/payment/successful",
CancelUrl = "https://localhost:44390/payment/fail",
PaymentIntentData = new SessionPaymentIntentDataOptions
{
Metadata = new Dictionary<string, string>
{
{"Order_ID", "123456" },
{"Description", "Basic Plan" }
}
}
};
var service = new SessionService();
Session session = service.Create(options);
return PartialView("_PaymentIndex", session);
}
Is there any way of checking the status of the payment, because I wanna call another action if the payment is confirmed. Like the same as adding a successful url, but for an action. I'm kinda new to this so :/
Edit:
I added a webhook to https://xxxx.eu.ngrok.io/payment/UpdatePaymentStatus for this action:
[HttpPost]
public ActionResult UpdatePaymentStatus()
{
try
{
StripeConfiguration.ApiKey = "key";
Stream req = Request.InputStream;
req.Seek(0, System.IO.SeekOrigin.Begin);
string json = new StreamReader(req).ReadToEnd();
myLogger.GetInstance().Warning(User.Identity.Name, "| Check |", "Payment/UpdatePaymentStatus");
// Get all Stripe events.
var stripeEvent = EventUtility.ParseEvent(json);
string stripeJson = stripeEvent.Data.RawObject + string.Empty;
var childData = Charge.FromJson(stripeJson);
var metadata = childData.Metadata;
int orderID = -1;
string strOrderID = string.Empty;
if (metadata.TryGetValue("Order_ID", out strOrderID))
{
int.TryParse(strOrderID, out orderID);
// Find your order from database.
// For example:
// Order order = db.Order.FirstOrDefault(x=>x.ID == orderID);
}
switch (stripeEvent.Type)
{
case Events.ChargeCaptured:
case Events.ChargeFailed:
case Events.ChargePending:
case Events.ChargeRefunded:
case Events.ChargeSucceeded:
case Events.ChargeUpdated:
var charge = Charge.FromJson(stripeJson);
string amountBuyer = ((double)childData.Amount / 100.0).ToString();
if (childData.BalanceTransactionId != null)
{
long transactionAmount = 0;
long transactionFee = 0;
if (childData.BalanceTransactionId != null)
{
// Get transaction fee.
var balanceService = new BalanceTransactionService();
BalanceTransaction transaction = balanceService.Get(childData.BalanceTransactionId);
transactionAmount = transaction.Amount;
transactionFee = transaction.Fee;
}
// My status, it is defined in my system.
int status = 0; // Wait
double transactionRefund = 0;
// Set order status.
if (stripeEvent.Type == Events.ChargeFailed)
{
status = -1; // Failed
myLogger.GetInstance().Warning(User.Identity.Name, "| Purchase of basic plan failed |", "Payment/UpdatePaymentStatus");
}
if (stripeEvent.Type == Events.ChargePending)
{
status = -2; // Pending
myLogger.GetInstance().Warning(User.Identity.Name, "| Purchase of basic plan pending |", "Payment/UpdatePaymentStatus");
}
if (stripeEvent.Type == Events.ChargeRefunded)
{
status = -3; // Refunded
transactionRefund = ((double)childData.AmountRefunded / 100.0);
myLogger.GetInstance().Warning(User.Identity.Name, "| Purchase of basic plan refunded |", "Payment/UpdatePaymentStatus");
}
if (stripeEvent.Type == Events.ChargeSucceeded)
{
status = 1; // Completed
myLogger.GetInstance().Info(User.Identity.Name, "Bought Basic Plan", "Payment/UpdatePaymentStatus");
}
// Update data
// For example: database
// order.Status = status;
// db.SaveChanges();
}
break;
default:
//log.Warn("");
break;
}
return Json(new
{
Code = -1,
Message = "Update failed."
});
}
catch (Exception e)
{
//log.Error("UpdatePaymentStatus: " + e.Message);
return Json(new
{
Code = -100,
Message = "Error."
});
}
}
public ActionResult Successful()
{
return View();
}
public ActionResult Fail()
{
return View();
}
}
Still not working though. I'm not getting any logs(using nLog) and the webhook is failing(in stripe dashboard).
Your code is creating a Checkout Session via the API. This is associated with Stripe's Checkout product. Stripe controls the UI to collect all the payment method details which means you're going to redirect your customer directly to Stripe's hosted page.
Once a customer pays, they will be redirected to your payment page configured in SuccessUrl in your code. You need to write code that detects the customer hitting that URL and map it to the session they were paying.
Additionally, it's possible for a customer to close their browser too before hitting your page. For that reason, Stripe also sends the checkout.session.completed event to your webhook handler. You can write code to handle that event and look at the status of their payment and all relevant information.
Stripe covers all possible fulfillment approaches in their documentation: https://stripe.com/docs/payments/checkout/fulfill-orders

Check against an Entire list to validate user information

I'm just not getting this.
So I have a list from my API
Of Customers called a
I need to validate weather the fields correlate to any of the 100+ Logins that I'm suppose to receive from the Resposne
How I'm Going about it At the moment
foreach (var c in Users.a)
{
if (Email == c.email && Password == c.password)
{
await App.Current.MainPage.DisplayAlert("Login Success", "", "Ok");
Application.Current.Properties["Email"] = c.email;
Application.Current.Properties["Userid"] = c.id;
Users.Loggedin = true;
await Application.Current.SavePropertiesAsync();
await App.Current.MainPage.Navigation.PushAsync(new Home(c.email));
}
else
{
await App.Current.MainPage.DisplayAlert("Login Fail", "Please enter correct Email and Password", "OK");
}
}
Am I doing this wrong? Is there a better way of doing this.
The Call
RestAPI rest = new RestAPI("http://Site/wp-json/wc/v3/",
"ck_a25f******************dcd0",
"cs_8f247c22************05c");
WCObject wc = new WCObject(rest);
var x = await wc.Customer.GetAll();
Users.a = x;
I Came to the Conclusion that my best way forward with this was to Fetch => Add => Combine Until My list was empty.
RestAPI rest = new RestAPI("http://Yoursite/wp-json/wc/v3/", "Customer Key", "Customer Secret");
WCObject wc = new WCObject(rest);
int pageNum = 1;
var isNull = false;
List<Customer> oldlist;
while (!isNull)
{
var page = pageNum.ToString();
x = await wc.Customer.GetAll(new Dictionary<string, string>() {
{
"page", page
}, {
"per_page", "100"
}
});
oldlist = FetchCustomers.customers ?? new List<Customer>();
if (x.Count == 0) {
break;
}
else
{
pageNum++;
FetchCustomers.customers = oldlist.Union(x).ToList();
}
}
How i'm Validating
var list = FetchCustomers.customers.ToList();
foreach (var user in list)
{
if (user.username == Usernamelabel.Text)
{
Application.Current.Properties["CId"] = user.id;
Application.Current.Properties["CEmail"] = user.email;
Application.Current.Properties["CUsername"] = user.username;
Users.Loggedin = true;
Application.Current.SavePropertiesAsync();
App.Current.MainPage.DisplayAlert("Empty Values", "Phase 2 Done your logged in ", "OK");
}
}
User is Validated From username I'm busy with another Process to Validate the user by The Wordpress API and getting a JWT token then Sending it to this Method to validate and Fetch the Customer and then Persisting the User.
Here's that Extra Method I mentioned
var client = new WordPressClient("http://Youtsite/wp-json/");
client.AuthMethod = AuthMethod.JWT;
await client.RequestJWToken(USername, Password);
var x = client;
var isValidToken = await client.IsValidJWToken();
WpApiCredentials.token = client.GetToken();
if (isValidToken)
{
Login_Phase2();
}
else
{
await App.Current.MainPage.DisplayAlert("Empty Values", "Token not Found", "OK");
}
#endregion

Dynamic change Microsoft BOT Framework Form's Field Step: hiding and showing the confirmation

I'm new to MS BOT Framework.
I changed MS github MultiDialogsBot.sln , I added a HotelsQuery property to init Form's Field value at HotelsDialog.cs,
public class HotelsDialog : IDialog<object>
{
public HotelsQuery _HotelsQuery { get; set; }
public HotelsDialog()
{
_HotelsQuery = new HotelsQuery{
Destination = "Taiwan",
CheckIn = new DateTime(2017,10,29),
Nights = 3
};
}
public async Task StartAsync(IDialogContext context)
{
await context.PostAsync("Welcome to the Hotels finder!");
var hotelsFormDialog = FormDialog.FromForm(this.BuildHotelsForm, FormOptions.PromptInStart);
context.Call(hotelsFormDialog, this.ResumeAfterHotelsFormDialog);
}
public IForm<HotelsQuery> BuildHotelsForm()
{
OnCompletionAsyncDelegate<HotelsQuery> processHotelsSearch = async (context, state) =>
{
await context.PostAsync($"Ok. Searching for Hotels in {state.Destination} from {state.CheckIn.ToString("MM/dd")} to {state.CheckIn.AddDays(state.Nights).ToString("MM/dd")}...");
};
var destField = new FieldReflector<HotelsQuery>(nameof(HotelsQuery.Destination))
.SetActive((state) =>
{
//depend on _HotelsQuery's values
bool isActive = string.IsNullOrWhiteSpace(_HotelsQuery.Destination);
if (!isActive) state.Destination = _HotelsQuery.Destination;
return isActive;
});
var checkInField = new FieldReflector<HotelsQuery>(nameof(HotelsQuery.CheckIn))
.SetActive((state) =>
{
//depend on _HotelsQuery's values
bool isActive = _HotelsQuery.CheckIn == DateTime.MinValue;
if (!isActive) state.CheckIn = _HotelsQuery.CheckIn;
return isActive;
});
var nightsField = new FieldReflector<HotelsQuery>(nameof(HotelsQuery.Nights))
.SetActive((state) =>
{
//depend on _HotelsQuery's values
bool isActive = _HotelsQuery.Nights == 0;
if (!isActive) state.Nights = _HotelsQuery.Nights;
return isActive;
});
var form = new FormBuilder<HotelsQuery>()
.Field(destField)
.Message("Looking for hotels in {Destination}...")
.Field(checkInField)
.Message("Check in {CheckIn}...")
.Field(nightsField)
.Message("Nights : {Nights}...")
.Confirm("Is this your selection?\n {*}", state =>
{
//clean all fields for showing fields in confirmation
_HotelsQuery.Destination = string.Empty;
_HotelsQuery.CheckIn = DateTime.MinValue;
_HotelsQuery.Nights = 0;
return true;
}, new List<string>())
.Message("Thanks you ...")
.OnCompletion(processHotelsSearch)
.Build();
return form;
}
public async Task ResumeAfterHotelsFormDialog(IDialogContext context, IAwaitable<HotelsQuery> result)
{
try
{
var searchQuery = await result;
var hotels = await this.GetHotelsAsync(searchQuery);
await context.PostAsync($"I found in total {hotels.Count()} hotels for your dates:");
var resultMessage = context.MakeMessage();
resultMessage.AttachmentLayout = AttachmentLayoutTypes.Carousel;
resultMessage.Attachments = new List<Attachment>();
foreach (var hotel in hotels)
{
HeroCard heroCard = new HeroCard()
{
Title = hotel.Name,
Subtitle = $"{hotel.Rating} starts. {hotel.NumberOfReviews} reviews. From ${hotel.PriceStarting} per night.",
Images = new List<CardImage>()
{
new CardImage() { Url = hotel.Image }
},
Buttons = new List<CardAction>()
{
new CardAction()
{
Title = "More details",
Type = ActionTypes.OpenUrl,
Value = $"https://www.bing.com/search?q=hotels+in+" + HttpUtility.UrlEncode(hotel.Location)
}
}
};
resultMessage.Attachments.Add(heroCard.ToAttachment());
}
await context.PostAsync(resultMessage);
}
catch (FormCanceledException ex)
{
string reply;
if (ex.InnerException == null)
{
reply = "You have canceled the operation. Quitting from the HotelsDialog";
}
else
{
reply = $"Oops! Something went wrong :( Technical Details: {ex.InnerException.Message}";
}
await context.PostAsync(reply);
}
finally
{
context.Done<object>(null);
}
}
private async Task<IEnumerable<Hotel>> GetHotelsAsync(HotelsQuery searchQuery)
{
var hotels = new List<Hotel>();
// Filling the hotels results manually just for demo purposes
for (int i = 1; i <= 5; i++)
{
var random = new Random(i);
Hotel hotel = new Hotel()
{
Name = $"{searchQuery.Destination} Hotel {i}",
Location = searchQuery.Destination,
Rating = random.Next(1, 5),
NumberOfReviews = random.Next(0, 5000),
PriceStarting = random.Next(80, 450),
Image = $"https://placeholdit.imgix.net/~text?txtsize=35&txt=Hotel+{i}&w=500&h=260"
};
hotels.Add(hotel);
}
hotels.Sort((h1, h2) => h1.PriceStarting.CompareTo(h2.PriceStarting));
return hotels;
}
}
I have trouble after the confirmation shows. When a user answers yes, BOT will ask CheckIn's prompt.
Why does it not go to the OnCompletion event?
Thanks for your help.
You are clearing out the values in the .Confirm
Try something like this:
var form = new FormBuilder<HotelsQuery>()
.Field(destField)
.Message("Looking for hotels in {Destination}...")
.Field(checkInField)
.Message("Check in {CheckIn}...")
.Field(nightsField)
.Message("Nights : {Nights}...")
.Confirm("Is this your selection?\n {*}", state =>
{
if (_HotelsQuery.Destination == string.Empty ||
_HotelsQuery.CheckIn == DateTime.MinValue ||
_HotelsQuery.Nights == 0)
return false;
return true;
}, new List<string>())
.Message("Thanks you ...")
.OnCompletion(processHotelsSearch)
.Build();

Declare variable to return Json result (ASP.NET MVC4)

This is action from my controller
[HttpPost]
[AjaxAction]
public ActionResult Registration(RegisterUserModel registerUser)
{
var data;
if (ModelState.IsValid)
{
if (!IsUserExist(registerUser.Email))
{
var crypto = new SimpleCrypto.PBKDF2();
var encrpPass = crypto.Compute(registerUser.Password);
var newUser = _db.Users.Create();
newUser.Name = registerUser.Name;
newUser.Email = registerUser.Email;
newUser.Type = UserType.User.ToString();
newUser.Password = encrpPass;
newUser.PasswordSalt = crypto.Salt;
_db.Users.Add(newUser);
_db.SaveChanges();
data = new { status = "OK", message = "Success" };
}
else
{
data = new { status = "ERROR", message = "User already exists" };
}
}
else
{
data = new { status = "ERROR", message = "Data is incorrect" };
}
return Json(data, JsonRequestBehavior.AllowGet);
}
but I don't know how to initialize data variable in the right way, because I need to set different values in different cases. What is the right way to do that?
I usually use multiple return statements to avoid having to declare an object like
if(something){
return Json(new{status = "status 1", message = "message1"})
}
else{
return Json(new{status = "status 2", message = "message2"})
}
you can try this:
var data = new object();
Here is one of the options
[HttpPost]
[AjaxAction]
public ActionResult Registration(RegisterUserModel registerUser)
{
JsonResult data;
if (ModelState.IsValid)
{
if (!IsUserExist(registerUser.Email))
{
var crypto = new SimpleCrypto.PBKDF2();
var encrpPass = crypto.Compute(registerUser.Password);
var newUser = _db.Users.Create();
newUser.Name = registerUser.Name;
newUser.Email = registerUser.Email;
newUser.Type = UserType.User.ToString();
newUser.Password = encrpPass;
newUser.PasswordSalt = crypto.Salt;
_db.Users.Add(newUser);
_db.SaveChanges();
data = Json(new { status = "OK", message = "Success" }, JsonRequestBehavior.AllowGet);
}
else
{
data = Json(new { status = "ERROR", message = "User already exists"}, JsonRequestBehavior.AllowGet);
}
}
else
{
data = Json(new { status = "ERROR", message = "Data is incorrect" }, JsonRequestBehavior.AllowGet);
}
return data;
}
You can use the dynamic keyword.
dynamic data;

Creating objects from IDataReader

I have created the following to create User objects with an ObservableCollection of UserModule objects called UserModules.
I have approx. 100000 user records, each user could have up to 10 module records and this is taking minutes to finish.
This may mean changing from IDataReader, open to suggestion. Can someone suggest a more efficient way to do this?
public void LoadUsers()
{
clsDAL.SQLDBAccess db = new clsDAL.SQLDBAccess("USERS");
clsDAL.SQLDBAccess db_user_modules = new clsDAL.SQLDBAccess("USERS");
try
{
db.setCommandText(#"SELECT * FROM Users");
using (var reader = db.ExecuteReader())
{
while (reader.Read())
{
var user = new User();
MapUser(reader, user);
_users.Add(user);
db_user_modules.setCommandText(#"SELECT MODULE_ID, USER_MODULE_ACCESS FROM USER_MODULE_SECURITY Where USER_ID = " + user.User_ID);
using (var reader_user_modules = db_user_modules.ExecuteReader())
{
while (reader_user_modules.Read())
{
MapUserModule(reader_user_modules, user);
}
}
}
}
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
throw;
}
finally
{
db = null;
}
}
MapUser
public static void MapUser(IDataRecord record, User user)
{
try
{
user.User_ID = NullSafeGetter.GetValueOrDefault<int>(record, "USER_ID");
user.Username = NullSafeGetter.GetValueOrDefault<string>(record, "USERNAME");
user.Name = NullSafeGetter.GetValueOrDefault<string>(record, "NAME");
user.Job_Title = NullSafeGetter.GetValueOrDefault<string>(record, "JOB_TITLE");
user.Department = NullSafeGetter.GetValueOrDefault<string>(record, "DEPARTMENT");
user.Company = NullSafeGetter.GetValueOrDefault<string>(record, "COMPANY");
user.Phone_Office = NullSafeGetter.GetValueOrDefault<string>(record, "PHONE_OFFICE");
user.Phone_Mobile = NullSafeGetter.GetValueOrDefault<string>(record, "PHONE_MOBILE");
user.Email = NullSafeGetter.GetValueOrDefault<string>(record, "EMAIL");
user.Password = NullSafeGetter.GetValueOrDefault<string>(record, "PASSWORD");
user.Last_Login = NullSafeGetter.GetValueOrDefault<DateTime>(record, "LAST_LOGIN");
user.Status = NullSafeGetter.GetValueOrDefault<int>(record, "STATUS");
user.Session_Timeout = NullSafeGetter.GetValueOrDefault<int>(record, "SESSION_TIMEOUT");
}
catch (Exception ex)
{
MessageBox.Show("Mapping User error: " + ex.Message);
throw;
}
}
MapUserModule
private static void MapUserModule(IDataRecord record, User user)
{
try
{
int m_id = NullSafeGetter.GetValueOrDefault<int>(record, "MODULE_ID");
int uma = NullSafeGetter.GetValueOrDefault<int>(record, "USER_MODULE_ACCESS");
user.UserModules.Add(new Users.UserModule(user.User_ID, m_id, uma));
}
catch (Exception ex)
{
throw new Exception("Mapping UserModule error:\n" + ex.Message);
}
}
public IEnumerable<UserModule> GetUserModules()
{
using(var db = ....)
db.setCommandText("SELECT * FROM USERMODULES");
using (var reader = db.ExecuteReader())
{
while (reader.Read())
{
var userId = reader[...];
var m_id = reader[...];
var uma = reader[...];
yield return new UserModule (userid, m_id, uma)
}
}
}
public IEnumerable<User> GetUsers()
{
var userModulesLookup = GetUserModules().ToLookup(x => x.UserId);
using (var db = ...)
{
db.setCommandText("SELECT * FROM USERS");
using (var reader = db.ExecuteReader())
{
while (reader.Read())
{
var userId = reader["userId"];
...blah blah blah...
var user = return new User();
user.Modules = new ObservableCollection<UserModule>
(userModulesLookup[userId]);
...blah blah blah...
yield return user;
}
}
}
}
public void LoadUsers()
{
var users = GetUsers();
foreach(var u in users)
_users.Add(u);
}
As far as I know, there is no faster solution than using a DataReader.
I would recommend you profile the code to see what is taking up most of the time. IIRC, adding a large number of items to an observable collection one at a time is slow. Try adding them to a List<> temporarily to try and isolate the problem.

Categories