Commit cfc19982 authored by TTrueBenji's avatar TTrueBenji

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

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

#1
parent 60fba76d
...@@ -6,6 +6,7 @@ namespace PhoneStore.Controllers ...@@ -6,6 +6,7 @@ namespace PhoneStore.Controllers
{ {
public class ErrorsController : Controller public class ErrorsController : Controller
{ {
private const string OppsMessage = "Oops... Ошибка";
private readonly Dictionary<int, ErrorViewModel> _errorResolver; private readonly Dictionary<int, ErrorViewModel> _errorResolver;
public ErrorsController() public ErrorsController()
...@@ -15,25 +16,31 @@ namespace PhoneStore.Controllers ...@@ -15,25 +16,31 @@ namespace PhoneStore.Controllers
{ {
StatusCode = 404, StatusCode = 404,
Message = "Ресурс не найден", Message = "Ресурс не найден",
Title = "Oops... Страница не найдена" Title = OppsMessage
}); });
_errorResolver.Add(400, new ErrorViewModel _errorResolver.Add(400, new ErrorViewModel
{ {
StatusCode = 400, StatusCode = 400,
Message = "Сервер не смог обработать запрос", Message = "Сервер не смог обработать запрос",
Title = "Oops... Ошибка" Title = OppsMessage
}); });
_errorResolver.Add(500, new ErrorViewModel _errorResolver.Add(500, new ErrorViewModel
{ {
StatusCode = 500, StatusCode = 500,
Message = "Сервер не смог обработать запрос", Message = "Сервер не смог обработать запрос",
Title = "Oops... Ошибка" Title = OppsMessage
}); });
_errorResolver.Add(777, new ErrorViewModel _errorResolver.Add(777, new ErrorViewModel
{ {
StatusCode = 777, StatusCode = 777,
Message = "Сущность не найдена", Message = "Сущность не найдена",
Title = "Oops... Ошибка" Title = OppsMessage
});
_errorResolver.Add(666, new ErrorViewModel
{
StatusCode = 666,
Message = "Такой файл уже существует. Возможно вы добавляете смартфон, который уже есть в базе данных.",
Title = OppsMessage
}); });
} }
......
using System; using System;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
...@@ -9,6 +8,7 @@ using Microsoft.EntityFrameworkCore; ...@@ -9,6 +8,7 @@ using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using PhoneStore.Models; using PhoneStore.Models;
using PhoneStore.Services; using PhoneStore.Services;
using PhoneStore.Services.Abstractions;
using PhoneStore.ViewModels; using PhoneStore.ViewModels;
namespace PhoneStore.Controllers namespace PhoneStore.Controllers
...@@ -18,14 +18,18 @@ namespace PhoneStore.Controllers ...@@ -18,14 +18,18 @@ namespace PhoneStore.Controllers
private readonly MobileContext _db; private readonly MobileContext _db;
private readonly IHostEnvironment _environment; private readonly IHostEnvironment _environment;
private readonly UploadService _uploadService; private readonly UploadService _uploadService;
private readonly IDefaultPhoneImagePathProvider _imagePathProvider;
public PhonesController( public PhonesController(
MobileContext db, MobileContext db,
IHostEnvironment environment, UploadService uploadService) IHostEnvironment environment,
UploadService uploadService,
IDefaultPhoneImagePathProvider imagePathProvider)
{ {
_db = db; _db = db;
_environment = environment; _environment = environment;
_uploadService = uploadService; _uploadService = uploadService;
_imagePathProvider = imagePathProvider;
} }
[HttpGet] [HttpGet]
...@@ -56,19 +60,40 @@ namespace PhoneStore.Controllers ...@@ -56,19 +60,40 @@ namespace PhoneStore.Controllers
} }
[HttpPost] [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, string imagePath;
Price = (decimal)model.Price!, if (model.File is null)
BrandId = model.BrandId imagePath = _imagePathProvider.GetPathToDefaultImage();
}); else
_db.SaveChanges(); {
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(); model.Brands = _db.Brands.ToList();
......
...@@ -33,7 +33,7 @@ namespace PhoneStore.Migrations ...@@ -33,7 +33,7 @@ namespace PhoneStore.Migrations
onDelete: ReferentialAction.Restrict); onDelete: ReferentialAction.Restrict);
migrationBuilder.Sql(@$"UPDATE ""Phones"" migrationBuilder.Sql(@$"UPDATE ""Phones""
SET ""Image"" = '~/Files/Phone/Images/DefaultImage.jpg' SET ""Image"" = 'images\phoneImages\default.jpg'
WHERE ""Image"" IS NULL;"); WHERE ""Image"" IS NULL;");
} }
......
...@@ -18,7 +18,6 @@ ...@@ -18,7 +18,6 @@
<ItemGroup> <ItemGroup>
<Folder Include="Migrations" /> <Folder Include="Migrations" />
<Folder Include="Pages" />
</ItemGroup> </ItemGroup>
</Project> </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 ...@@ -8,6 +8,11 @@ namespace PhoneStore.Services
{ {
public async Task UploadAsync(string dirPath, string fileName, IFormFile file) 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 using var stream = new FileStream(Path.Combine(dirPath, fileName), FileMode.Create);
await file.CopyToAsync(stream); await file.CopyToAsync(stream);
} }
......
...@@ -29,6 +29,8 @@ namespace PhoneStore ...@@ -29,6 +29,8 @@ namespace PhoneStore
services.AddControllersWithViews(); services.AddControllersWithViews();
services.AddScoped<IBasketService, BasketService>(); services.AddScoped<IBasketService, BasketService>();
services.AddTransient<UploadService>(); 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. // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
......
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using PhoneStore.Models; using PhoneStore.Models;
...@@ -17,5 +18,6 @@ namespace PhoneStore.ViewModels ...@@ -17,5 +18,6 @@ namespace PhoneStore.ViewModels
public decimal? Price { get; set; } public decimal? Price { get; set; }
public int BrandId { get; set; } public int BrandId { get; set; }
public List<Brand> Brands { get; set; } public List<Brand> Brands { get; set; }
public IFormFile File { get; set; }
} }
} }
\ No newline at end of file
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
<h2>Заполните форму для добавления устройства</h2> <h2>Заполните форму для добавления устройства</h2>
<div class="row"> <div class="row">
<div class="phone_add_form col-md-6"> <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); await Html.RenderPartialAsync("PartialViews/PhoneFormPartialView", Model);
} }
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
} }
<div class="row"> <div class="row">
<div class="col-md-6"> <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"); await Html.RenderPartialAsync("PartialViews/PhoneFormPartialView");
} }
......
...@@ -33,7 +33,7 @@ else ...@@ -33,7 +33,7 @@ else
@foreach (var phone in Model.Phones) @foreach (var phone in Model.Phones)
{ {
<tr> <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.Name</td>
<td>@phone.Brand.Name</td> <td>@phone.Brand.Name</td>
<td>@phone.Price</td> <td>@phone.Price</td>
......
...@@ -22,4 +22,11 @@ ...@@ -22,4 +22,11 @@
} }
</select> </select>
</div> </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 @@ ...@@ -9,5 +9,8 @@
"Microsoft.Hosting.Lifetime": "Information" "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