public async Task <IActionResult> AddToCart(AddToCartInputModel inputModel)
        {
            var currentUserId = this.userService.GetUserId(this.User.Identity.Name);
            var productId     = inputModel.ProductId;
            var quantity      = inputModel.Quantity;
            var product       = this.productService.GetProductById(productId, false);

            if (product.QuantityInStock < quantity)
            {
                this.ModelState.AddModelError("QuantityInStock", "Cannot buy more of this product than there is in stock");
            }

            if (this.ModelState.IsValid == false)
            {
                //Store needed info for get request in TempData only if the model state is invalid after doing the complex checks
                TempData[GlobalConstants.ErrorsFromPOSTRequest] = ModelStateHelper.SerialiseModelState(this.ModelState);

                //Store needed info for get request in TempData
                return(this.RedirectToAction("ProductPage", "Products", new { productId = productId }, "Reviews"));
            }

            await this.cartService.AddToCartAsync(productId, currentUserId, quantity);

            return(this.RedirectToAction(nameof(this.All)));
        }
        public async Task <IActionResult> Buy(ComplexModel <List <BuyProductInputModel>, List <ProductCartViewModel> > complexModel)
        {
            this.TempData[GlobalConstants.InputModelFromPOSTRequestType] = $"List<{nameof(BuyProductInputModel)}>";
            this.TempData[GlobalConstants.InputModelFromPOSTRequest]     = JsonSerializer.Serialize(complexModel.InputModel);

            //Inital model validation without checking the database
            if (this.ModelState.IsValid == false)
            {
                this.TempData[GlobalConstants.ErrorsFromPOSTRequest] = ModelStateHelper.SerialiseModelState(this.ModelState);

                //Set notification
                NotificationHelper.SetNotification(this.TempData, NotificationType.Error, "An error occured while processing your request");

                return(this.RedirectToAction(nameof(All)));
            }

            var currentUserId = this.userService.GetUserId(this.User.Identity.Name);

            foreach (var productInputModel in complexModel.InputModel)
            {
                if (this.cartService.ProductIsInCart(productInputModel.Id, currentUserId) == false)
                {
                    //Set notification
                    NotificationHelper.SetNotification(this.TempData, NotificationType.Error, "One or more of the products are not in the cart");

                    this.ModelState.AddModelError("", "One or more of the products are not in the cart");
                }
            }

            if (this.ModelState.IsValid == false)
            {
                //Set error model state
                this.TempData[GlobalConstants.ErrorsFromPOSTRequest] = ModelStateHelper.SerialiseModelState(this.ModelState);

                return(this.RedirectToAction(nameof(All)));
            }

            var inputModel = complexModel.InputModel;

            foreach (var item in inputModel)
            {
                await this.cartService.SetCheckoutCartAsync(currentUserId, inputModel);
            }

            return(this.RedirectToAction("Checkout", "Sales"));
        }
        public async Task <IActionResult> Create(AddCategoryInputModel inputModel)
        {
            if (this.categoryService.CategoryNameExists(inputModel.Name, true) == true)
            {
                this.ModelState.AddModelError("Name", "This category name has been already taken. Choose a different one");
            }

            if (this.ModelState.IsValid == false)
            {
                TempData[GlobalConstants.ErrorsFromPOSTRequest]     = ModelStateHelper.SerialiseModelState(this.ModelState);
                TempData[GlobalConstants.InputModelFromPOSTRequest] = JsonSerializer.Serialize(inputModel);

                return(this.RedirectToAction(nameof(Create)));
            }

            await this.categoryService.AddAsync(inputModel.Name);

            return(this.RedirectToAction(nameof(All)));
        }
        public async Task <IActionResult> Remove(string productId)
        {
            //Check if this product exists
            if (this.productService.ProductExistsById(productId) == false)
            {
                this.ModelState.AddModelError("", "This product doesn't exist");

                //Store needed info for get request in TempData only if the model state is invalid after doing the complex checks
                TempData[GlobalConstants.ErrorsFromPOSTRequest] = ModelStateHelper.SerialiseModelState(this.ModelState);

                //Set notification
                NotificationHelper.SetNotification(this.TempData, NotificationType.Error, "This product doesn't exist");

                return(this.RedirectToAction(nameof(All)));
            }

            await this.cartService.RemoveProductByIdAsync(this.userService.GetUserId(this.User.Identity.Name), productId);

            return(this.RedirectToAction(nameof(All)));
        }
        public async Task <IActionResult> Remove(string productId, string errorReturnUrl)
        {
            if (this.productService.ProductExistsById(productId) == false)
            {
                this.ModelState.AddModelError("removeProduct_productId", "This product doesn't exist");
            }

            if (this.ModelState.IsValid == false)
            {
                //Add notification
                NotificationHelper.SetNotification(TempData, NotificationType.Error, "An error occured while removing product. Product wasn't removed");

                //Store needed info for get request in TempData
                TempData[GlobalConstants.ErrorsFromPOSTRequest] = ModelStateHelper.SerialiseModelState(this.ModelState);

                return(this.Redirect(errorReturnUrl));
            }

            await this.productService.RemoveProductAsync(productId);

            NotificationHelper.SetNotification(TempData, NotificationType.Success, "Successfully remove product.");

            return(this.RedirectToAction("All", "Products", new { area = "" }));
        }
        public async Task <IActionResult> Add(AddProductInputModel inputModel)
        {
            var newProduct = this.mapper.Map <Product>(inputModel);

            //Set input model short description
            inputModel.ShortDescription = this.productService.GetShordDescription(inputModel.Description, 40);

            //Store input model for passing in get action
            TempData[GlobalConstants.InputModelFromPOSTRequest]     = JsonSerializer.Serialize(inputModel);
            TempData[GlobalConstants.InputModelFromPOSTRequestType] = nameof(AddProductInputModel);

            //Check without looking into the database
            if (this.ModelState.IsValid == false)
            {
                //Store needed info for get request in TempData only if the model state is invalid after doing the complex checks
                TempData[GlobalConstants.ErrorsFromPOSTRequest] = ModelStateHelper.SerialiseModelState(this.ModelState);

                return(this.RedirectToAction(nameof(Add), "Products"));
            }

            //Check if product with this model or name
            if (this.productService.ProductExistsByModel(inputModel.Model) == true)
            {
                this.ModelState.AddModelError("Model", "Product with this model already exists.");
            }
            if (this.productService.ProductExistsByName(inputModel.Name))
            {
                this.ModelState.AddModelError("Name", "Product with this name already exists.");
            }

            //Check if there is a main image, regardless of the imageMode
            if ((inputModel.MainImage == null && inputModel.ImagesAsFileUploads == false) || (inputModel.MainImageUpload == null && inputModel.ImagesAsFileUploads == true))
            {
                this.ModelState.AddModelError("", "Main image is required");

                //Store needed info for get request in TempData only if the model state is invalid after doing the complex checks
                TempData[GlobalConstants.ErrorsFromPOSTRequest] = ModelStateHelper.SerialiseModelState(this.ModelState);

                return(this.RedirectToAction(nameof(Add), "Products"));
            }

            //CHECK THE IMAGES LINKS
            if (inputModel.ImagesAsFileUploads == false)
            {
                //Check if all of these images are unique
                if (this.productImageService.ImagesAreRepeated(inputModel.MainImage, inputModel.AdditionalImages))
                {
                    this.ModelState.AddModelError("", "There are 2 or more non-unique images");
                }

                //Check if main image is already used
                if (this.productImageService.ProductImageExists(inputModel.MainImage) == true)
                {
                    this.ModelState.AddModelError("MainImage", "This image is already used.");
                }

                if (inputModel.AdditionalImages == null)
                {
                    inputModel.AdditionalImages = new List <string>();
                }

                //Check if any of the additional images are used
                for (int i = 0; i < inputModel.AdditionalImages.Count; i++)
                {
                    var additionalImage = inputModel.AdditionalImages[i];
                    if (this.productImageService.ProductImageExists(additionalImage) == true)
                    {
                        this.ModelState.AddModelError($"AdditionalImages[{i}]", "This image is already used.");
                    }
                }
            }
            //CHECK IMAGES UPLOADS
            else
            {
                //Check main image upload
                if (this.productImageService.ValidImageExtension(inputModel.MainImageUpload) == false)
                {
                    this.ModelState.AddModelError("MainImageUpload", "The uploaded image is invalid");
                }

                if (inputModel.AdditionalImagesUploads == null)
                {
                    inputModel.AdditionalImagesUploads = new List <IFormFile>();
                }

                //Check additional images uploads
                for (int i = 0; i < inputModel.AdditionalImagesUploads.Count; i++)
                {
                    var imageUpload = inputModel.AdditionalImagesUploads[i];
                    if (this.productImageService.ValidImageExtension(imageUpload) == false)
                    {
                        this.ModelState.AddModelError($"AdditionalImageUpload[{i}]", "The uploaded image is invalid");
                    }
                }
            }

            //Check if categories exist in the database or if there are even any categories for this product
            for (int i = 0; i < inputModel.CategoriesIds.Count; i++)
            {
                var categoryId = inputModel.CategoriesIds[i];
                if (this.categoryService.CategoryExists(categoryId) == false)
                {
                    this.ModelState.AddModelError($"CategoriesIds{i}", "This category doesn't exist");
                }
            }
            if (inputModel.CategoriesIds.Count == 0)
            {
                this.ModelState.AddModelError("", "You need to add at least one category for this product");
            }

            //Check if categories are unique
            if (inputModel.CategoriesIds.Where(x => string.IsNullOrWhiteSpace(x) == false).Distinct().Count() != inputModel.CategoriesIds.Where(x => string.IsNullOrWhiteSpace(x) == false).Count())
            {
                this.ModelState.AddModelError($"", "One category cannot be used multiple times.");
            }

            if (this.ModelState.IsValid == false)
            {
                //Store needed info for get request in TempData only if the model state is invalid after doing the complex checks
                TempData[GlobalConstants.ErrorsFromPOSTRequest] = ModelStateHelper.SerialiseModelState(this.ModelState);

                return(this.RedirectToAction(nameof(Add), "Products"));
            }

            //Add images to product
            if (inputModel.ImagesAsFileUploads == false)
            {
                newProduct.Images = new List <ProductImage>();

                //Set additional images
                newProduct.Images = inputModel.AdditionalImages
                                    .Where(x => x != null)
                                    .Select(x => new ProductImage {
                    Image = x, Product = newProduct
                }).ToList();

                //Set main image
                newProduct.Images.Add(new ProductImage {
                    Image = inputModel.MainImage, IsMain = true, Product = newProduct, ProductId = newProduct.Id
                });
            }
            else
            {
                newProduct.Images = new List <ProductImage>();

                //Upload main image
                var imageUrl = await this.productImageService.UploadImageAsync(inputModel.MainImageUpload, newProduct);

                //Set the main image
                newProduct.Images.Add(new ProductImage {
                    Image = imageUrl, IsMain = true, Product = newProduct, ProductId = newProduct.Id
                });

                //Upload the additional images and set the additional images
                foreach (var additionalImage in inputModel.AdditionalImagesUploads)
                {
                    var additionalImageUrl = await this.productImageService.UploadImageAsync(additionalImage, newProduct);

                    newProduct.Images.Add(new ProductImage {
                        Image = additionalImageUrl, IsMain = false, Product = newProduct, ProductId = newProduct.Id
                    });
                }
            }

            //Add product
            await this.productService.AddAsync(newProduct);

            //Add categories
            await this.categoryService.AddCategoriesToProductAsync(newProduct, inputModel.CategoriesIds);

            //Set notification
            NotificationHelper.SetNotification(this.TempData, NotificationType.Success, "Product was successfully added");

            return(this.RedirectToAction("ProductPage", "Products", new { area = "", productId = newProduct.Id }));
        }
        public async Task <IActionResult> Edit(EditProductInputModel inputModel)
        {
            //Set input model short description
            inputModel.ShortDescription = this.productService.GetShordDescription(inputModel.Description, 40);

            //Store input model for passing in get action
            TempData[GlobalConstants.InputModelFromPOSTRequest]     = JsonSerializer.Serialize(inputModel);
            TempData[GlobalConstants.InputModelFromPOSTRequestType] = nameof(EditProductInputModel);

            //Check without looking into the database
            if (this.ModelState.IsValid == false)
            {
                //Store needed info for get request in TempData only if the model state is invalid after doing the complex checks
                TempData[GlobalConstants.ErrorsFromPOSTRequest] = ModelStateHelper.SerialiseModelState(this.ModelState);

                return(this.RedirectToAction(nameof(Edit), "Products", new { productId = inputModel.Id }));
            }

            //Check if product with this id exists
            if (this.productService.ProductExistsById(inputModel.Id) == false)
            {
                this.ModelState.AddModelError("", "The product that you are trying to edit doesn't exist.");
            }

            var productId = inputModel.Id;

            //Check if product with this model or name exist and it is not the product that is currently being edited
            if (this.productService.ProductExistsByModel(inputModel.Model, productId) == true)
            {
                this.ModelState.AddModelError("Model", "Product with this model already exists.");
            }
            if (this.productService.ProductExistsByName(inputModel.Name, productId))
            {
                this.ModelState.AddModelError("Name", "Product with this name already exists.");
            }

            //Check if there is a main image, regardless of the imageMode
            if ((inputModel.MainImage == null && inputModel.ImagesAsFileUploads == false) || (inputModel.MainImageUploadInfo.ImageUpload == null && inputModel.MainImageUploadInfo.IsBeingModified && inputModel.ImagesAsFileUploads == true))
            {
                this.ModelState.AddModelError("", "Main image is required");

                //Store needed info for get request in TempData only if the model state is invalid after doing the complex checks
                TempData[GlobalConstants.ErrorsFromPOSTRequest] = ModelStateHelper.SerialiseModelState(this.ModelState);

                return(this.RedirectToAction(nameof(Edit), "Products", new { productId = productId }));
            }

            //CHECK THE IMAGES LINKS
            if (inputModel.ImagesAsFileUploads == false)
            {
                //Check if all of these images are unique
                if (this.productImageService.ImagesAreRepeated(inputModel.MainImage, inputModel.AdditionalImages))
                {
                    this.ModelState.AddModelError("", "There are 2 or more non-unique images");
                }

                //Check if main image is already used by OTHER products
                if (this.productImageService.ProductImageExists(inputModel.MainImage, productId) == true)
                {
                    this.ModelState.AddModelError("MainImage", "This image is already used.");
                }

                if (inputModel.AdditionalImages == null)
                {
                    inputModel.AdditionalImages = new List <string>();
                }

                //Check if any of the additional images are used by OTHER products
                for (int i = 0; i < inputModel.AdditionalImages.Count; i++)
                {
                    var additionalImage = inputModel.AdditionalImages[i];
                    if (this.productImageService.ProductImageExists(additionalImage, productId) == true)
                    {
                        this.ModelState.AddModelError($"AdditionalImages[{i}]", "This image is already used.");
                    }
                }
            }
            //CHECK IMAGES UPLOADS
            else
            {
                var mainImageUpload = inputModel.MainImageUploadInfo.ImageUpload;

                //Check main image upload extension is valid, but only if the user has actually selected a file themselves
                if (inputModel.MainImageUploadInfo.IsBeingModified && this.productImageService.ValidImageExtension(mainImageUpload) == false)
                {
                    this.ModelState.AddModelError("MainImageUploadInfo.ImageUpload", "The uploaded image is invalid");
                }

                if (inputModel.AdditionalImagesUploadsInfo == null)
                {
                    inputModel.AdditionalImagesUploadsInfo = new List <EditProductImageUploadInputModel>();
                }

                var additionalImagesUploads = inputModel.AdditionalImagesUploadsInfo
                                              .Select(x => x.ImageUpload)
                                              .Where(imageUpload => imageUpload != null)
                                              .ToList();

                //Check additional images uploads
                for (int i = 0; i < additionalImagesUploads.Count; i++)
                {
                    var imageUpload = additionalImagesUploads[i];
                    if (imageUpload != null && this.productImageService.ValidImageExtension(imageUpload) == false)
                    {
                        this.ModelState.AddModelError($"AdditionalImagesUploadsInfo[{i}].ImageUpload.", "The uploaded image is invalid");
                    }
                }
            }

            //Check if categories exist in the database or if there are even any categories for this product
            for (int i = 0; i < inputModel.CategoriesIds.Count; i++)
            {
                var categoryId = inputModel.CategoriesIds[i];
                if (this.categoryService.CategoryExists(categoryId) == false)
                {
                    this.ModelState.AddModelError($"CategoriesIds{i}", "This category doesn't exist");
                }
            }
            if (inputModel.CategoriesIds.Count == 0)
            {
                this.ModelState.AddModelError("", "You need to add at least one category for this product");
            }

            //Check if categories exist in the database
            for (int i = 0; i < inputModel.CategoriesIds.Count; i++)
            {
                var categoryId = inputModel.CategoriesIds[i];
                if (this.categoryService.CategoryExists(categoryId) == false)
                {
                    this.ModelState.AddModelError($"CategoriesIds{i}", "This category doesn't exist");
                }
            }

            //Check if categories are unique
            if (inputModel.CategoriesIds.Where(x => string.IsNullOrWhiteSpace(x) == false).Distinct().Count() != inputModel.CategoriesIds.Where(x => string.IsNullOrWhiteSpace(x) == false).Count())
            {
                this.ModelState.AddModelError($"", "One category cannot be used multiple times.");
            }


            if (this.ModelState.IsValid == false)
            {
                //Store needed info for get request in TempData only if the model state is invalid after doing the complex checks
                TempData[GlobalConstants.ErrorsFromPOSTRequest] = ModelStateHelper.SerialiseModelState(this.ModelState);

                return(this.RedirectToAction(nameof(Edit), "Products", new { productId = inputModel.Id }));
            }

            await this.productService.EditAsync(inputModel);

            var product = this.productService.GetProductById(inputModel.Id, false);

            await this.categoryService.EditCategoriesToProductAsync(product, inputModel.CategoriesIds);

            //Set notification
            NotificationHelper.SetNotification(this.TempData, NotificationType.Success, "Product was successfully edited");

            return(this.RedirectToAction("ProductPage", "Products", new { area = "", productId = inputModel.Id }));
        }
Example #8
0
        public async Task <IActionResult> Add(AddProductInputModel inputModel)
        {
            var newProduct = this.mapper.Map <Product>(inputModel);

            //Set input model short description
            inputModel.ShortDescription = this.productService.GetShordDescription(inputModel.Description, 40);

            //Store input model for passing in get action
            TempData[GlobalConstants.InputModelFromPOSTRequest]     = JsonSerializer.Serialize(inputModel);
            TempData[GlobalConstants.InputModelFromPOSTRequestType] = nameof(AddProductInputModel);

            //Check without looking into the database
            if (this.ModelState.IsValid == false)
            {
                //Store needed info for get request in TempData only if the model state is invalid after doing the complex checks
                TempData[GlobalConstants.ErrorsFromPOSTRequest] = ModelStateHelper.SerialiseModelState(this.ModelState);

                return(this.RedirectToAction(nameof(Add), "Products"));
            }

            await this.TryUpdateModelAsync(inputModel, typeof(AddProductInputModel), "");

            //Check if product with this model or name
            if (this.productService.ProductExistsByModel(inputModel.Model) == true)
            {
                this.ModelState.AddModelError("Model", "Product with this model already exists.");
            }
            if (this.productService.ProductExistsByName(inputModel.Name))
            {
                this.ModelState.AddModelError("Name", "Product with this name already exists.");
            }

            //Check if all of these images are unique
            if (this.productService.ImagesAreRepeated(inputModel.MainImage, inputModel.AdditionalImages))
            {
                this.ModelState.AddModelError("", "There are 2 or more non-unique images");
            }

            //Check if main image is already used
            if (this.productService.ProductImageExists(inputModel.MainImage) == true)
            {
                this.ModelState.AddModelError("MainImage", "This image is already used.");
            }

            //Check if any of the additional images are used
            for (int i = 0; i < inputModel.AdditionalImages.Count; i++)
            {
                var additionalImage = inputModel.AdditionalImages[i];
                if (this.productService.ProductImageExists(additionalImage) == true)
                {
                    this.ModelState.AddModelError($"AdditionalImages[{i}]", "This image is already used.");
                }
            }

            //Check if categories exist in the database or if there are even any categories for this product
            for (int i = 0; i < inputModel.CategoriesIds.Count; i++)
            {
                var categoryId = inputModel.CategoriesIds[i];
                if (this.categoryService.CategoryExists(categoryId) == false)
                {
                    this.ModelState.AddModelError($"CategoriesIds{i}", "This category doesn't exist");
                }
            }
            if (inputModel.CategoriesIds.Count == 0)
            {
                this.ModelState.AddModelError("", "You need to add at least one category for this product");
            }

            //Check if categories are unique
            if (inputModel.CategoriesIds.Where(x => string.IsNullOrWhiteSpace(x) == false).Distinct().Count() != inputModel.CategoriesIds.Where(x => string.IsNullOrWhiteSpace(x) == false).Count())
            {
                this.ModelState.AddModelError($"", "One category cannot be used multiple times.");
            }

            if (this.ModelState.IsValid == false)
            {
                //Store needed info for get request in TempData only if the model state is invalid after doing the complex checks
                TempData[GlobalConstants.ErrorsFromPOSTRequest] = ModelStateHelper.SerialiseModelState(this.ModelState);

                return(this.RedirectToAction(nameof(Add), "Products"));
            }

            //Set additional images
            newProduct.AdditionalImages = inputModel.AdditionalImages
                                          .Where(x => x != null)
                                          .Select(x => new ProductImage {
                Image = x, Product = newProduct
            }).ToList();

            //Add product
            await this.productService.AddAsync(newProduct);

            //Add categories
            await this.categoryService.AddCategoriesToProductAsync(newProduct, inputModel.CategoriesIds);/**/

            //Set notification
            NotificationHelper.SetNotification(this.TempData, NotificationType.Success, "Product was successfully added");

            return(this.RedirectToAction(nameof(ProductPage), "Products", new { productId = newProduct.Id }));
        }
Example #9
0
        public async Task <IActionResult> Edit(AddProductInputModel inputModel)
        {
            //Set input model short description
            inputModel.ShortDescription = this.productService.GetShordDescription(inputModel.Description, 40);

            //Store input model for passing in get action
            TempData[GlobalConstants.InputModelFromPOSTRequest]     = JsonSerializer.Serialize(inputModel);
            TempData[GlobalConstants.InputModelFromPOSTRequestType] = nameof(AddProductInputModel);

            //Set input model mode to edit
            inputModel.IsAdding = false;

            //Check without looking into the database
            if (this.ModelState.IsValid == false)
            {
                //Store needed info for get request in TempData only if the model state is invalid after doing the complex checks
                TempData[GlobalConstants.ErrorsFromPOSTRequest] = ModelStateHelper.SerialiseModelState(this.ModelState);

                return(this.RedirectToAction(nameof(Edit), "Products", new { productId = inputModel.Id }));
            }

            //Check if product with this id exists
            if (this.productService.ProductExistsById(inputModel.Id) == false)
            {
                this.ModelState.AddModelError("", "The product that you are trying to edit doesn't exist.");
            }

            var productId = inputModel.Id;

            //Check if product with this model or name exist and it is not the product that is currently being edited
            if (this.productService.ProductExistsByModel(inputModel.Model, productId) == true)
            {
                this.ModelState.AddModelError("Model", "Product with this model already exists.");
            }
            if (this.productService.ProductExistsByName(inputModel.Name, productId))
            {
                this.ModelState.AddModelError("Name", "Product with this name already exists.");
            }

            //Check if all of these images are unique
            if (this.productService.ImagesAreRepeated(inputModel.MainImage, inputModel.AdditionalImages))
            {
                this.ModelState.AddModelError("", "There are 2 or more non-unique images");
            }

            //Check if main image is already used
            if (this.productService.ProductImageExists(inputModel.MainImage, productId) == true)
            {
                this.ModelState.AddModelError("MainImage", "This image is already used.");
            }

            //Check if categories exist in the database or if there are even any categories for this product
            for (int i = 0; i < inputModel.CategoriesIds.Count; i++)
            {
                var categoryId = inputModel.CategoriesIds[i];
                if (this.categoryService.CategoryExists(categoryId) == false)
                {
                    this.ModelState.AddModelError($"CategoriesIds{i}", "This category doesn't exist");
                }
            }
            if (inputModel.CategoriesIds.Count == 0)
            {
                this.ModelState.AddModelError("", "You need to add at least one category for this product");
            }

            //Check if categories exist in the database
            for (int i = 0; i < inputModel.CategoriesIds.Count; i++)
            {
                var categoryId = inputModel.CategoriesIds[i];
                if (this.categoryService.CategoryExists(categoryId) == false)
                {
                    this.ModelState.AddModelError($"CategoriesIds{i}", "This category doesn't exist");
                }
            }

            //Check if categories are unique
            if (inputModel.CategoriesIds.Where(x => string.IsNullOrWhiteSpace(x) == false).Distinct().Count() != inputModel.CategoriesIds.Where(x => string.IsNullOrWhiteSpace(x) == false).Count())
            {
                this.ModelState.AddModelError($"", "One category cannot be used multiple times.");
            }


            if (this.ModelState.IsValid == false)
            {
                //Store needed info for get request in TempData only if the model state is invalid after doing the complex checks
                TempData[GlobalConstants.ErrorsFromPOSTRequest] = ModelStateHelper.SerialiseModelState(this.ModelState);

                return(this.RedirectToAction(nameof(Edit), "Products", new { productId = inputModel.Id }));
            }

            await this.productService.EditAsync(inputModel);

            var product = this.productService.GetProductById(inputModel.Id, false);

            await this.categoryService.EditCategoriesToProductAsync(product, inputModel.CategoriesIds);

            //Set notification
            NotificationHelper.SetNotification(this.TempData, NotificationType.Success, "Product was successfully edited");

            return(this.RedirectToAction(nameof(ProductPage), "Products", new { productId = inputModel.Id }));
        }
        public async Task <IActionResult> AddReview(ComplexModel <AddReviewInputModel, ProductInfoViewModel> complexModel, string pageFragment, string commentsPage, string commentsOrderingOption)
        {
            var productId = complexModel.InputModel.ProductId;

            //Sanitize pageFragment
            pageFragment = this.javaScriptEncoder.Encode(pageFragment);

            //Store input model for passing in get action
            TempData["InputModelFromPOSTRequest"]     = JsonSerializer.Serialize(complexModel.InputModel);
            TempData["InputModelFromPOSTRequestType"] = nameof(AddReviewInputModel);

            //Check if data is valid without looking into the database
            if (this.ModelState.IsValid == false)
            {
                //Store needed info for get request in TempData only if the model state is invalid after doing the complex checks
                TempData["ErrorsFromPOSTRequest"] = ModelStateHelper.SerialiseModelState(this.ModelState);

                //Store needed info for get request in TempData
                return(this.RedirectToAction("ProductPage", "Products", new { productId, commentsOrderingOption, commentsPage }, pageFragment));
            }

            var userId = this.userService.GetUserId(this.User.Identity.Name);

            var newProductRating = new ProductRating
            {
                ProductId = productId,
                UserId    = userId,
                Rating    = (int)complexModel.InputModel.Rating
            };

            var newComment = new ProductComment
            {
                CommentedOn     = DateTime.UtcNow,
                ParentCommentId = null,
                ProductId       = productId,
                Text            = complexModel.InputModel.Text,
                UserId          = userId,
            };

            //Check if user has already left a review for this product
            if (this.productService.ProductRatingExists(newProductRating) == true && this.productCommentService.CommentExists(newComment) == true)
            {
                this.ModelState.AddModelError("InputModel.Rating", "You have already given a review for this product!!!");
            }

            //Check if rating from this user for this product already exists
            else if (this.productService.ProductRatingExists(newProductRating) == true)
            {
                this.ModelState.AddModelError("InputModel.Rating", "You have already given a review with this rating for this product!!!");
            }

            //Check if comment already from this user for this product already exists(as part of his review, he can still have comments as replies to other people for the same product)
            else if (this.productCommentService.CommentExists(newComment) == true)
            {
                this.ModelState.AddModelError("InputModel.Text", "You have already given a review with a comment for this product!!!");
            }

            //Check if model state is valid after checking into the database
            if (this.ModelState.IsValid == false)
            {
                //Store needed info for get request in TempData only if the model state is invalid after doing the complex checks
                TempData["ErrorsFromPOSTRequest"] = ModelStateHelper.SerialiseModelState(this.ModelState);

                //Reload same page with the TempData
                return(this.RedirectToAction("ProductPage", "Products", new { productId, commentsPage, commentsOrderingOption }, pageFragment));
            }

            //Set the rating foreign key for new comment
            var newRating = new ProductRating
            {
                ProductCommentId = newComment.Id,
                ProductId        = productId,
                UserId           = userId,
                Rating           = (int)complexModel.InputModel.Rating
            };

            await this.productCommentService.AddAsync(newComment);

            newComment.ProductRatingId = newRating.Id;

            await this.productService.AddRatingAsync(newRating);

            return(this.RedirectToAction("ProductPage", "Products", new { productId, commentsPage = 1, commentsOrderingOption }, pageFragment));
        }
        public async Task <IActionResult> ReplyToComment(ReplyCommentInputModel inputModel, string pageFragment, string commentsPage, string commentsOrderingOption)
        {
            var productId = inputModel.ProductId;

            var commentId = inputModel.ParentCommentId;

            //Sanitize pageFragment
            pageFragment = this.javaScriptEncoder.Encode(pageFragment);

            //Sanitize commentsPage
            if (commentsPage != null)
            {
                commentsPage = this.htmlEncoder.Encode(commentsPage);
            }

            //Check if data is valid without looking into the database
            if (this.ModelState.IsValid == false)
            {
                //Store input model for passing in get action
                TempData["InputModelFromPOSTRequest"]     = JsonSerializer.Serialize(inputModel);
                TempData["InputModelFromPOSTRequestType"] = nameof(ReplyCommentInputModel);

                //Add suitable model state error for UI validation
                var newModelState = new ModelStateDictionary(this.ModelState);
                foreach (var modelStateEntry in this.ModelState.Values)
                {
                    foreach (var modelStateError in modelStateEntry.Errors)
                    {
                        newModelState.AddModelError($"ParentCommentId_{inputModel.CommentCounter}", modelStateError.ErrorMessage);
                    }
                }

                //Store needed info for get request in TempData
                TempData["ErrorsFromPOSTRequest"] = ModelStateHelper.SerialiseModelState(newModelState);

                return(this.RedirectToAction("ProductPage", "Products", new { productId, commentsPage, commentsOrderingOption }, pageFragment));
            }

            var userId = this.userService.GetUserId(this.User.Identity.Name);

            //Check if parent comment for this product exists
            if (this.productCommentService.CommentExists(commentId) == false)
            {
                this.ModelState.AddModelError($"ParentCommentId_{inputModel.CommentCounter}", "Can't reply to nonexistent comment.");
            }

            //Check if the user isn't trying to reply to himself
            if (this.productCommentService.CommentBelongsToUser(commentId, userId))
            {
                this.ModelState.AddModelError($"ParentCommentId_{inputModel.CommentCounter}", "Can't reply to yourself.");
            }

            //Check if model state is valid after checking into the database
            if (this.ModelState.IsValid == false)
            {
                //Store input model for passing in get action
                TempData["InputModelFromPOSTRequest"]     = JsonSerializer.Serialize(inputModel);
                TempData["InputModelFromPOSTRequestType"] = nameof(ReplyCommentInputModel);

                //Store needed info for get request in TempData only if the model state is invalid after doing the complex checks
                TempData["ErrorsFromPOSTRequest"] = ModelStateHelper.SerialiseModelState(this.ModelState);

                //Reload same page with the TempData
                return(this.RedirectToAction("ProductPage", "Products", new { productId, commentsPage, commentsOrderingOption }, pageFragment));
            }

            //Create new reply comment
            var replyComment = new ProductComment
            {
                ProductId       = productId,
                ParentCommentId = commentId,
                Text            = inputModel.Text,
                CommentedOn     = DateTime.UtcNow,
                UserId          = userId
            };

            await this.productCommentService.AddAsync(replyComment);

            return(this.RedirectToAction("ProductPage", "Products", new { productId, toReplyComment = replyComment.Id, commentsPage = commentsPage, commentsOrderingOption }, pageFragment));
        }
        public async Task <IActionResult> EditReview(EditReviewInputModel inputModel, string pageFragment, string commentsPage, string commentsOrderingOption)
        {
            var productId = inputModel.ProductId;

            var commentId = inputModel.CommentId;

            //Sanitize pageFragment
            pageFragment = this.javaScriptEncoder.Encode(pageFragment);

            //Sanitize commentsPage
            if (commentsPage != null)
            {
                commentsPage = this.htmlEncoder.Encode(commentsPage);
            }


            //Store input model for passing in get action
            TempData["InputModelFromPOSTRequest"]     = JsonSerializer.Serialize(inputModel);
            TempData["InputModelFromPOSTRequestType"] = nameof(EditReviewInputModel);

            //Check if data is valid without looking into the database
            if (this.ModelState.IsValid == false)
            {
                //Add suitable model state error for UI validation
                var newModelState = new ModelStateDictionary(this.ModelState);
                foreach (var modelStateEntry in this.ModelState.Values)
                {
                    foreach (var modelStateError in modelStateEntry.Errors)
                    {
                        newModelState.AddModelError($"CommentId_{inputModel.CommentCounter}", modelStateError.ErrorMessage);
                    }
                }

                //Store needed info for get request in TempData
                TempData["ErrorsFromPOSTRequest"] = ModelStateHelper.SerialiseModelState(newModelState);

                return(this.RedirectToAction("ProductPage", "Products", new { productId, commentsPage, commentsOrderingOption }, pageFragment));
            }

            var userId = this.userService.GetUserId(this.User.Identity.Name);

            var oldProductRating = new ProductRating();

            if (inputModel?.ProductRatingViewModel?.AverageRating > 0)
            {
                //Check if rating from this user for this product already exists
                if (this.productService.ProductRatingExists(userId, productId) == true)
                {
                    oldProductRating = this.productService.GetProductRating(userId, productId);
                }
                else
                {
                    this.ModelState.AddModelError($"Rating_{inputModel.CommentCounter}", "You have not given a review for this product!!!");
                }
            }
            else
            {
                oldProductRating = null;
            }


            var oldComment = new ProductComment();

            //Check if the comment exists and if it belongs to the current user and is for this product TODO
            if (this.productCommentService.CommentMatchesUserAndProduct(commentId, userId, productId) == false)
            {
                oldComment = null;
                this.ModelState.AddModelError($"CommentId_{inputModel.CommentCounter}", "You have not given a review with a comment for this product!!!");
            }
            else
            {
                oldComment = this.productCommentService.GetProductComment(commentId);
            }

            //Check if model state is valid after checking into the database
            if (this.ModelState.IsValid == false)
            {
                //Store needed info for get request in TempData only if the model state is invalid after doing the complex checks
                TempData["ErrorsFromPOSTRequest"] = ModelStateHelper.SerialiseModelState(this.ModelState);

                //Reload same page with the TempData
                return(this.RedirectToAction("ProductPage", "Products", new { productId, commentsPage, commentsOrderingOption }, pageFragment));
            }

            if (oldComment != null)
            {
                await this.productCommentService.EditCommentTextAsync(oldComment, inputModel.Text);
            }
            if (oldProductRating != null)
            {
                await this.productService.EditProductRating(oldProductRating, (double)inputModel.ProductRatingViewModel.AverageRating);
            }

            return(this.RedirectToAction("ProductPage", "Products", new { productId, toReplyComment = oldComment.Id, commentsPage, commentsOrderingOption }, pageFragment));
        }
        public async Task <IActionResult> ChangeSaleStatus(ComplexModel <ChangeSaleStatusInputModel, List <SaleStatus> > complexModel)
        {
            if (this.ModelState.IsValid == false)
            {
                //Set up temp data with model state and input model
                this.TempData[GlobalConstants.ErrorsFromPOSTRequest] = ModelStateHelper.SerialiseModelState(this.ModelState);
                this.TempData["NewSaleStatusId"] = complexModel.InputModel.NewSaleStatusId;

                return(this.RedirectToAction(nameof(ChangeSaleStatus), new { saleId = complexModel.InputModel.SaleId }));
            }

            //Check if status and sale exist
            if (this.saleService.SaleStatusExists(complexModel.InputModel.NewSaleStatusId) == false)
            {
                this.ModelState.AddModelError("InputModel.NewSaleStatusId", "This sale status doesn't exist");
            }

            if (this.ModelState.IsValid == false)
            {
                //Set up temp data with model state and input model
                this.TempData[GlobalConstants.ErrorsFromPOSTRequest] = ModelStateHelper.SerialiseModelState(this.ModelState);
                this.TempData["NewSaleStatusId"] = complexModel.InputModel.NewSaleStatusId;

                return(this.RedirectToAction(nameof(ChangeSaleStatus), new { saleId = complexModel.InputModel.SaleId }));
            }

            //Capture the payment intent and officially complete the sale and charge the customer if the paymentStatus is confirmed
            var newSaleStatus = this.saleService.GetSaleStatusById(complexModel.InputModel.NewSaleStatusId);

            if (newSaleStatus.Name == GlobalConstants.ConfirmedSaleStatus)
            {
                var paymentIntentId = this.saleService.GetPaymentIntentId(complexModel.InputModel.SaleId);
                if (paymentIntentId != null)
                {
                    var paymentIntent = await this.paymentIntentService.GetAsync(paymentIntentId);

                    if (paymentIntent.Status == "requires_capture")
                    {
                        await this.paymentIntentService.CaptureAsync(paymentIntentId);
                    }
                }
            }
            //Set free the payment intent and the funds if the paymentStatus is declined
            else if (newSaleStatus.Name == GlobalConstants.DeclinedSaleStatus)
            {
                var paymentIntentId = this.saleService.GetPaymentIntentId(complexModel.InputModel.SaleId);
                if (paymentIntentId != null)
                {
                    var paymentIntent = await this.paymentIntentService.GetAsync(paymentIntentId);

                    if (paymentIntent.Status == "requires_capture")
                    {
                        await this.paymentIntentService.CancelAsync(paymentIntentId);
                    }
                }
            }

            await this.saleService.ChangeSaleStatusAsync(complexModel.InputModel.SaleId, complexModel.InputModel.NewSaleStatusId);

            //Set up success notification
            NotificationHelper.SetNotification(this.TempData, NotificationType.Success, $"You have successfully changed sale status");

            return(this.RedirectToAction(nameof(Search)));
        }
Example #14
0
        public async Task <IActionResult> Checkout(ComplexModel <CheckoutInputModel, CheckoutViewModel> complexModel)
        {
            this.TempData[GlobalConstants.InputModelFromPOSTRequest]     = JsonSerializer.Serialize(complexModel.InputModel);
            this.TempData[GlobalConstants.InputModelFromPOSTRequestType] = nameof(CheckoutInputModel);

            //Validate model without checking the database
            if (this.ModelState.IsValid == false)
            {
                //Serialize errors from modelstate
                this.TempData[GlobalConstants.ErrorsFromPOSTRequest] = ModelStateHelper.SerialiseModelState(this.ModelState);

                //Set notification
                NotificationHelper.SetNotification(this.TempData, NotificationType.Error, "An error occured while processing your request");

                return(this.Json(new { RedirectPath = $"/Sales/Checkout" }));
            }

            //Check if the payment method exists
            if (this.paymentMethodService.PaymentMethodExistsById(complexModel.InputModel.PaymentMethodId) == false)
            {
                this.ModelState.AddModelError("", "This payment method doesn't exist");

                //Serialize errors from modelstate
                this.TempData[GlobalConstants.ErrorsFromPOSTRequest] = ModelStateHelper.SerialiseModelState(this.ModelState);

                //Set notification
                NotificationHelper.SetNotification(this.TempData, NotificationType.Error, "Selected payment method doesn't exist");

                return(this.Json(new { RedirectPath = $"/Sales/Checkout" }));
            }

            var currentUserId = this.userService.GetUserId(this.User.Identity.Name);

            var cartProducts = this.cartService.GetAllProductsForCheckoutViewModel(currentUserId);

            var inputModel = complexModel.InputModel;

            //Check if the user has any products in their cart
            if (this.cartService.GetNumberOfProductsInCart(currentUserId) == 0)
            {
                //Set notification
                NotificationHelper.SetNotification(TempData, NotificationType.Error, "You do not have any products in your cart");

                return(this.Json(new { RedirectPath = $"/Carts/All" }));
            }

            //Check if the products' quantities exceed the amount of units in stock
            foreach (var product in cartProducts)
            {
                if (product.Quantity > product.QuantityInStock)
                {
                    this.ModelState.AddModelError("", $"{product.Name}:{product.Model} has less units available than you are currently trying to buy");

                    NotificationHelper.SetNotification(this.TempData, NotificationType.Error, $"{product.Name}:{product.Model} has less units available than you are currently trying to buy");
                }
            }

            if (this.ModelState.IsValid == false)
            {
                //Serialize errors from modelstate
                this.TempData[GlobalConstants.ErrorsFromPOSTRequest] = ModelStateHelper.SerialiseModelState(this.ModelState);

                return(this.Json(new { RedirectPath = $"/Carts/All" }));
            }

            var paymentMethod = this.paymentMethodService.GetPaymentMethod(complexModel.InputModel.PaymentMethodId);

            if (paymentMethod == GlobalConstants.PaymentMethodDebitOrCreditCard)
            {
                //Set the temp data for a successful sale
                var confirmSaleToken = SetTempDataForSale(complexModel.InputModel, cartProducts);

                //Setup Stripe payment session
                var sessionId = await CreateStripeSession(cartProducts, confirmSaleToken);

                //If it is null for whatever reason, then just return an error notification and redirect
                if (sessionId == null)
                {
                    //Clear temp data with purchase info
                    this.TempData.Clear();

                    //Set notification
                    NotificationHelper.SetNotification(this.TempData, NotificationType.Error, "Something went wrong with the purchase. Purchase reverted. You have not been charged.");

                    return(this.Json(new { RedirectPath = $"/Carts/All" }));
                }

                return(this.Json(new { id = sessionId, PaymentMethod = GlobalConstants.PaymentMethodDebitOrCreditCard }));
            }
            else if (paymentMethod == GlobalConstants.PaymentMethodCashOnDelivery)
            {
                //Set the temp data for a successful sale
                var confirmSaleToken = SetTempDataForSale(complexModel.InputModel, cartProducts);

                return(this.Json(new { PaymentMethod = GlobalConstants.PaymentMethodCashOnDelivery, RedirectPath = $"/Sales/CheckoutSuccess?confirmSaleToken={confirmSaleToken}&paymentMethod={GlobalConstants.PaymentMethodCashOnDelivery}" }));
            }


            //If we have gotten this far, then the payment method was one of the other two, which are not supported at this moment
            NotificationHelper.SetNotification(this.TempData, NotificationType.Error, "These two payments are not currently supported.");
            return(this.Json(new { }));
        }