public IHttpActionResult Install(string shop) { var nonce = Guid.NewGuid().ToString(); var store = _storeService.GetByHost(shop); if (store != null && !store.Options.HasFlag(StoreOptions.Disabled)) { return(BadRequest("Application already installed")); } var authUrl = ShopifyAuthorizationService.BuildAuthorizationUrl(new List <ShopifyAuthorizationScope>() { ShopifyAuthorizationScope.ReadProducts, ShopifyAuthorizationScope.ReadCustomers }, shop, SystemSettings.ApiKey, SystemSettings.RedirectUrl, nonce); if (store == null) { store = new Store() { Host = shop, Options = StoreOptions.Disabled } } ; store.Nonce = nonce; _storeService.Update(store); return(Redirect(authUrl)); }
public AuthorizeRequestValidator() { RuleFor(r => r.Code).NotEmpty(); RuleFor(r => r.ShopUrl).NotEmpty(); RuleFor(r => r.FullQueryString).NotEmpty(); RuleFor(r => r.FullQueryString).Must((qs) => { var kvps = HttpUtility.ParseQueryString(qs); return(ShopifyAuthorizationService.IsAuthenticRequest(kvps, Config.ShopifySecretKey)); }).WithMessage("Request did not pass Shopify's validation scheme."); }
public IHttpActionResult Connect(string code, string shop, string hmac, string state) { if (!ShopifyAuthorizationService.IsValidMyShopifyUrl(shop)) { return(BadRequest()); } var queryString = HttpUtility.ParseQueryString(Request.RequestUri.Query); if (!ShopifyAuthorizationService.IsAuthenticRequest(queryString, SystemSettings.ApiSecret)) { return(BadRequest()); } var store = _storeService.GetByHost(shop); if (store.Nonce != state) { return(BadRequest()); } var authService = new ShopifyAuthorizationService(new ShopifySettings() { AuthenticationType = AuthenticationType.AccessToken, HostName = shop }); var accessToken = authService.Authorize(code, SystemSettings.ApiKey, SystemSettings.ApiSecret); if (string.IsNullOrEmpty(accessToken)) { return(BadRequest()); } store.AccessToken = accessToken; store.Code = code; store.Options &= ~StoreOptions.Disabled; _storeService.Update(store); var webhookService = new ShopifyWebhookService(new ShopifySettings(shop, accessToken)); webhookService.Create(new ShopifyWebhook() { Topic = ShopifyWebhookTopic.AppUninstalled, Address = SystemSettings.UninstallUrl, Format = "json" }); return(Redirect(ShopifyAuthorizationService.BuildShopUri(shop))); }
public IHttpActionResult Uninstall(ShopifyShop shop) { var store = _storeService.GetByHost(shop.Domain); if (store == null) { return(BadRequest("Store not found.")); } store.Options |= StoreOptions.Disabled; _storeService.Update(store); return(Redirect(ShopifyAuthorizationService.BuildShopUri(shop.Domain))); }
public UnsecureShopifyRoute() : base("/api/v1/shopify") { Post["/verify_url", true] = async(parameters, ct) => { var model = this.BindAndValidate <VerifyUrlRequest>(); if (!ModelValidationResult.IsValid) { return(Response.AsJsonError("Request did not pass validation.", HttpStatusCode.NotAcceptable, ModelValidationResult.FormattedErrors)); } var isValid = await ShopifyAuthorizationService.IsValidMyShopifyUrl(model.Url); return(Response.AsJson(new { isValid = isValid })); }; }
public ShopifyRoute() : base("/api/v1/shopify") { Post["/authorize", true] = async(parameters, ct) => { var model = this.BindAndValidate <AuthorizeRequest>(); if (!ModelValidationResult.IsValid) { return(Response.AsJsonError("Request did not pass validation.", HttpStatusCode.NotAcceptable, ModelValidationResult.FormattedErrors)); } var getUser = await Database.Users.Entities.GetAsync <User>(SessionToken.UserId); if (!getUser.IsSuccess) { return(Response.AsJsonError("Could not find user in database.", HttpStatusCode.NotFound)); } // Complete the OAuth process and integrate the user var user = getUser.Content; string accessToken; try { accessToken = await ShopifyAuthorizationService.Authorize(model.Code, model.ShopUrl, Config.ShopifyApiKey, Config.ShopifySecretKey); } catch (ShopifyException e) when(e.JsonError.ContainsIgnoreCase("authorization code was not found or was already used")) { return(Response.AsJsonError("Integration failed: the authorization code was not found or was already used.", HttpStatusCode.BadRequest)); } var shop = await new ShopifyShopService(model.ShopUrl, accessToken).GetAsync(); user.ShopifyAccessToken = accessToken; user.ShopifyUrl = model.ShopUrl; user.ShopId = shop.Id; user.ShopName = shop.Name; user.Permissions = Config.ShopifyPermissions; // Create an App_Uninstalled webhook if we're not running on localhost if (!Regex.IsMatch(Request.Url.HostName, "localhost", RegexOptions.IgnoreCase)) { var service = new ShopifyWebhookService(user.ShopifyUrl, user.ShopifyAccessToken); var url = new UriBuilder(Request.Url.ToString()) { Scheme = Uri.UriSchemeHttps, // All Shopify webhooks must be https Path = "/api/v1/webhooks/app_uninstalled", Query = $"shop_id={shop.Id.Value}", }; try { await service.CreateAsync(new ShopifyWebhook() { Address = url.ToString(), Topic = "app/uninstalled", }); } catch (ShopifyException ex) when(ex.Errors.Any(e => e.Key.EqualsIgnoreCase("address") && e.Value.Any(innerError => innerError.ContainsIgnoreCase("for this topic has already been taken")))) { // Webhook already exists. } } // Update the user var update = await Database.Users.Entities.PutAsync(user); if (!update.IsSuccess) { throw new Exception($"Failed to save user's integration. {(int)update.StatusCode} {update.Reason}"); } return(Response.WithSessionToken(user)); }; Post["/activate_charge", true] = async(parameters, ct) => { long chargeId = parameters.charge_id; var getUser = await Database.Users.Entities.GetAsync <User>(this.SessionToken.UserId); if (!getUser.IsSuccess) { throw new Exception("User not found."); } // Activate the charge if its status is accepted. var user = getUser.Content; var service = new ShopifyRecurringChargeService(user.ShopifyUrl, user.ShopifyAccessToken); var charge = await service.GetAsync(chargeId); if (charge.Status != "accepted") { throw new Exception($"Charge #${charge.Id.Value} has not been accepted."); } // Update the user var update = await Database.Users.Entities.PutAsync(user); if (!update.IsSuccess) { throw new Exception($"Failed to save user's new charge. {update.StatusCode} {update.Reason}"); } return(Response.WithSessionToken(user)); }; Post["/create_authorization_url"] = (parameters) => { var model = this.Bind <CreateAuthorizationUrlRequest>(); var url = ShopifyAuthorizationService.BuildAuthorizationUrl(Config.ShopifyPermissions, model.Url, Config.ShopifyApiKey, model.RedirectUrl); return(Response.AsJson(new { url = url })); }; Get["/orders", true] = async(parameters, ct) => { int? limit = Request.Query.limit; int? page = Request.Query.page; string status = Request.Query.status ?? "any"; var service = new ShopifyOrderService(SessionToken.ShopifyUrl, SessionToken.ShopifyAccessToken); var orders = await service.ListAsync(new ShopifySharp.Filters.ShopifyOrderFilter() { Limit = limit, Page = page, Status = "any", }); return(Response.AsJson(orders)); }; Post["/orders", true] = async(parameters, ct) => { var model = this.BindAndValidate <CreateOrderRequest>(); if (!ModelValidationResult.IsValid) { return(Response.AsJsonError("Request did not pass validation.", HttpStatusCode.NotAcceptable, ModelValidationResult.FormattedErrors)); } var service = new ShopifyOrderService(SessionToken.ShopifyUrl, SessionToken.ShopifyAccessToken); var order = await service.CreateAsync(new ShopifyOrder() { CreatedAt = DateTime.UtcNow, BillingAddress = new ShopifyAddress() { Address1 = model.Street, City = model.City, Province = model.State, Zip = model.Zip, Name = model.Name, CountryCode = "US", Default = true, }, LineItems = new List <ShopifyLineItem>() { new ShopifyLineItem() { Name = model.LineItem, Title = model.LineItem, Quantity = model.Quantity, Price = 5, }, }, FinancialStatus = "authorized", Email = model.Email, }); return(Response.AsJson(order).WithStatusCode(HttpStatusCode.Created)); }; Post["/orders/{id:long}/{verb}", true] = async(parameters, ct) => { string verb = parameters.verb; long id = parameters.id; if (!verb.EqualsIgnoreCase("open") && !verb.EqualsIgnoreCase("close")) { return(Negotiate.WithStatusCode(HttpStatusCode.MethodNotAllowed)); } if (!ModelValidationResult.IsValid) { return(Response.AsJsonError("Request did not pass validation.", HttpStatusCode.NotAcceptable, ModelValidationResult.FormattedErrors)); } var service = new ShopifyOrderService(SessionToken.ShopifyUrl, SessionToken.ShopifyAccessToken); if (verb.EqualsIgnoreCase("open")) { await service.OpenAsync(id); } else { await service.CloseAsync(id); } // Refresh the order and return it to the client var order = await service.GetAsync(id); return(Response.AsJson(order)); }; Delete["/orders/{id:long}", true] = async(parameters, ct) => { long id = parameters.id; var service = new ShopifyOrderService(SessionToken.ShopifyUrl, SessionToken.ShopifyAccessToken); await service.DeleteAsync(id); return(Negotiate.WithStatusCode(200)); }; }