Commit cfc19982 authored by TTrueBenji's avatar TTrueBenji

Добавить загрузку изображения телефона.

***
- Добавил поле в таблицу телефонов для хранения пути к изображению.
- Добавил возможность добавления изображения телефона. Если файл не добавлен пользователем, то устанавливается изображение по умолчанию.
***

#1
parent 60fba76d
......@@ -6,6 +6,7 @@ namespace PhoneStore.Controllers
{
public class ErrorsController : Controller
{
private const string OppsMessage = "Oops... Ошибка";
private readonly Dictionary<int, ErrorViewModel> _errorResolver;
public ErrorsController()
......@@ -15,25 +16,31 @@ namespace PhoneStore.Controllers
{
StatusCode = 404,
Message = "Ресурс не найден",
Title = "Oops... Страница не найдена"
Title = OppsMessage
});
_errorResolver.Add(400, new ErrorViewModel
{
StatusCode = 400,
Message = "Сервер не смог обработать запрос",
Title = "Oops... Ошибка"
Title = OppsMessage
});
_errorResolver.Add(500, new ErrorViewModel
{
StatusCode = 500,
Message = "Сервер не смог обработать запрос",
Title = "Oops... Ошибка"
Title = OppsMessage
});
_errorResolver.Add(777, new ErrorViewModel
{
StatusCode = 777,
Message = "Сущность не найдена",
Title = "Oops... Ошибка"
Title = OppsMessage
});
_errorResolver.Add(666, new ErrorViewModel
{
StatusCode = 666,
Message = "Такой файл уже существует. Возможно вы добавляете смартфон, который уже есть в базе данных.",
Title = OppsMessage
});
}
......
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
......@@ -9,6 +8,7 @@ using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Hosting;
using PhoneStore.Models;
using PhoneStore.Services;
using PhoneStore.Services.Abstractions;
using PhoneStore.ViewModels;
namespace PhoneStore.Controllers
......@@ -18,14 +18,18 @@ namespace PhoneStore.Controllers
private readonly MobileContext _db;
private readonly IHostEnvironment _environment;
private readonly UploadService _uploadService;
private readonly IDefaultPhoneImagePathProvider _imagePathProvider;
public PhonesController(
MobileContext db,
IHostEnvironment environment, UploadService uploadService)
IHostEnvironment environment,
UploadService uploadService,
IDefaultPhoneImagePathProvider imagePathProvider)
{
_db = db;
_environment = environment;
_uploadService = uploadService;
_imagePathProvider = imagePathProvider;
}
[HttpGet]
......@@ -56,19 +60,40 @@ namespace PhoneStore.Controllers
}
[HttpPost]
public IActionResult Create(PhoneCreateViewModel model)
public async Task<IActionResult> Create(PhoneCreateViewModel model)
{
if (ModelState.IsValid)
try
{
_db.Phones.Add(new Phone
if (ModelState.IsValid)
{
Name = model.Name,
Price = (decimal)model.Price!,
BrandId = model.BrandId
});
_db.SaveChanges();
string imagePath;
if (model.File is null)
imagePath = _imagePathProvider.GetPathToDefaultImage();
else
{
var brand = _db.Brands.FirstOrDefault(b => b.Id == model.BrandId);
string dirPath = Path.Combine(_environment.ContentRootPath, $"wwwroot\\images\\phoneImages\\{brand!.Name}");
string fileName = $"{model.File.FileName}";
await _uploadService.UploadAsync(dirPath, fileName, model.File);
imagePath = $"images\\phoneImages\\{brand!.Name}\\{fileName}";
}
_db.Phones.Add(new Phone
{
Image = imagePath,
Name = model.Name,
Price = (decimal)model.Price!,
BrandId = model.BrandId
});
await _db.SaveChangesAsync();
return RedirectToAction("Index");
return RedirectToAction("Index");
}
}
//TODO: Добавить кастомный exception
catch (FileNotFoundException e)
{
return RedirectToAction("Error", "Errors", new {statusCode = 666});
}
model.Brands = _db.Brands.ToList();
......
......@@ -33,7 +33,7 @@ namespace PhoneStore.Migrations
onDelete: ReferentialAction.Restrict);
migrationBuilder.Sql(@$"UPDATE ""Phones""
SET ""Image"" = '~/Files/Phone/Images/DefaultImage.jpg'
SET ""Image"" = 'images\phoneImages\default.jpg'
WHERE ""Image"" IS NULL;");
}
......
......@@ -18,7 +18,6 @@
<ItemGroup>
<Folder Include="Migrations" />
<Folder Include="Pages" />
</ItemGroup>
</Project>
namespace PhoneStore.Services.Abstractions
{
public interface IDefaultPhoneImagePathProvider
{
string GetPathToDefaultImage();
}
}
\ No newline at end of file
using PhoneStore.Services.Abstractions;
namespace PhoneStore.Services
{
public class DefaultPhoneImagePathProvider : IDefaultPhoneImagePathProvider
{
private readonly string _path;
public DefaultPhoneImagePathProvider(string path)
{
_path = path;
}
public string GetPathToDefaultImage() => _path;
}
}
\ No newline at end of file
......@@ -8,6 +8,11 @@ namespace PhoneStore.Services
{
public async Task UploadAsync(string dirPath, string fileName, IFormFile file)
{
if (!Directory.Exists(dirPath))
Directory.CreateDirectory(dirPath);
var absolutePath = Path.Combine(dirPath, fileName);
if (File.Exists(absolutePath))
throw new FileNotFoundException();
await using var stream = new FileStream(Path.Combine(dirPath, fileName), FileMode.Create);
await file.CopyToAsync(stream);
}
......
......@@ -29,6 +29,8 @@ namespace PhoneStore
services.AddControllersWithViews();
services.AddScoped<IBasketService, BasketService>();
services.AddTransient<UploadService>();
services.AddTransient<IDefaultPhoneImagePathProvider>(_ =>
new DefaultPhoneImagePathProvider(Configuration["PathToDefaultAvatar:Path"]));
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
......
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using PhoneStore.Models;
......@@ -17,5 +18,6 @@ namespace PhoneStore.ViewModels
public decimal? Price { get; set; }
public int BrandId { get; set; }
public List<Brand> Brands { get; set; }
public IFormFile File { get; set; }
}
}
\ No newline at end of file
......@@ -8,7 +8,7 @@
<h2>Заполните форму для добавления устройства</h2>
<div class="row">
<div class="phone_add_form col-md-6">
<form asp-action="Create" asp-controller="Phones" method="post">
<form asp-action="Create" asp-controller="Phones" method="post" enctype="multipart/form-data">
@{
await Html.RenderPartialAsync("PartialViews/PhoneFormPartialView", Model);
}
......
......@@ -6,7 +6,7 @@
}
<div class="row">
<div class="col-md-6">
<form asp-action="Edit" method="post">
<form asp-action="Edit" asp-controller="Phones" method="post" enctype="multipart/form-data">
@{
await Html.RenderPartialAsync("PartialViews/PhoneFormPartialView");
}
......
......@@ -33,7 +33,7 @@ else
@foreach (var phone in Model.Phones)
{
<tr>
<td><img class="phone_img" src="" alt="картинка паламатая"/></td>
<td><img class="phone_img" src="@phone.Image" alt="картинка паламатая"/></td>
<td>@phone.Name</td>
<td>@phone.Brand.Name</td>
<td>@phone.Price</td>
......
......@@ -22,4 +22,11 @@
}
</select>
</div>
<div class="mb-3">
<label asp-for="File" class="form-label">Добавьте изображение</label>
<input class="form-control" type="file" asp-for="File">
<div class="form-text">
<span asp-validation-for="File" class="text-danger"></span>
</div>
</div>
......@@ -9,5 +9,8 @@
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
"AllowedHosts": "*",
"PathToDefaultAvatar": {
"Path": "images\\phoneImages\\default.jpg"
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment