Ejemplo n.º 1
0
        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));
        }
Ejemplo n.º 2
0
        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.");
        }
Ejemplo n.º 3
0
        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)));
        }
Ejemplo n.º 4
0
        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)));
        }
Ejemplo n.º 5
0
        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
                }));
            };
        }
Ejemplo n.º 6
0
        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));
            };
        }