Commit b080a144 authored by Yevgeniy Agrafenin's avatar Yevgeniy Agrafenin

#3 Добавил функционал добавления нового заведения, добавил форму добавления…

#3 Добавил функционал добавления нового заведения, добавил форму добавления заведения, страницу списка всех заведений и детальную страницу конкретного заведения. Удалил лишние файлы.
parent 698e45f3
...@@ -15,4 +15,9 @@ ...@@ -15,4 +15,9 @@
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="7.0.11" /> <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="7.0.11" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<_ContentIncludedByDefault Remove="Views\Home\Index.cshtml" />
<_ContentIncludedByDefault Remove="Views\Home\Privacy.cshtml" />
</ItemGroup>
</Project> </Project>
...@@ -49,7 +49,7 @@ public class AccountController : Controller ...@@ -49,7 +49,7 @@ public class AccountController : Controller
if (result.Succeeded) if (result.Succeeded)
{ {
await _signInManager.SignInAsync(user, false); await _signInManager.SignInAsync(user, false);
return RedirectToAction("Index", "Home"); return RedirectToAction("Index", "Cafe");
} }
foreach (var error in result.Errors) foreach (var error in result.Errors)
...@@ -97,7 +97,7 @@ public class AccountController : Controller ...@@ -97,7 +97,7 @@ public class AccountController : Controller
return Redirect(model.ReturnUrl); return Redirect(model.ReturnUrl);
} }
return RedirectToAction("Index", "Home"); return RedirectToAction("Index", "Cafe");
} }
ModelState.AddModelError(string.Empty, "Неправильный логин и (или) пароль"); ModelState.AddModelError(string.Empty, "Неправильный логин и (или) пароль");
} }
...@@ -109,6 +109,6 @@ public class AccountController : Controller ...@@ -109,6 +109,6 @@ public class AccountController : Controller
public async Task<IActionResult> LogOut() public async Task<IActionResult> LogOut()
{ {
await _signInManager.SignOutAsync(); await _signInManager.SignOutAsync();
return RedirectToAction("Index", "Home"); return RedirectToAction("Index", "Cafe");
} }
} }
\ No newline at end of file
using System.ComponentModel.DataAnnotations;
using CafeCritic.Context; using CafeCritic.Context;
using CafeCritic.Mappers;
using CafeCritic.Models; using CafeCritic.Models;
using CafeCritic.Services;
using CafeCritic.ViewModels;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
...@@ -17,4 +22,46 @@ public class CafeController : Controller ...@@ -17,4 +22,46 @@ public class CafeController : Controller
_userManager = userManager; _userManager = userManager;
} }
[HttpGet]
public IActionResult Index()
{
List<Cafe> models = _db.Cafes.ToList();
return View(models);
}
[HttpGet]
[Authorize]
public IActionResult AddCafe()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
[Display(Name="AddCafe")]
public async Task<IActionResult> AddCafeAsync(AddCafeViewModel model)
{
if (!ModelState.IsValid) return View(model);
var image = await FileUpload.Upload(model.Title, model.Image);
var restaurant = CafeMapper.AddCafeCafe(model, image);
await _db.Cafes.AddAsync(restaurant);
await _db.SaveChangesAsync();
return RedirectToAction("Index", "Cafe");
}
public IActionResult Details(int id)
{
var cafe = _db.Cafes.FirstOrDefault(c => c.Id == id);
if (cafe is null)
{
return NotFound();
}
return View(cafe);
}
} }
\ No newline at end of file
using System.Diagnostics;
using Microsoft.AspNetCore.Mvc;
using CafeCritic.Models;
namespace CafeCritic.Controllers;
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
}
public IActionResult Index()
{
return View();
}
public IActionResult Privacy()
{
return View();
}
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
}
\ No newline at end of file
using CafeCritic.Models;
using CafeCritic.ViewModels;
namespace CafeCritic.Mappers;
public class CafeMapper
{
public static Cafe AddCafeCafe(AddCafeViewModel vm, string image)
{
return new Cafe
{
Title = vm.Title,
Image = image,
Description = vm.Description
};
}
public static CafeViewModel CafeCafeVm(Cafe cafe)
{
return new CafeViewModel
{
Id = cafe.Id,
Title = cafe.Title,
Image = cafe.Image,
Description = cafe.Description
};
}
}
\ No newline at end of file
...@@ -17,11 +17,35 @@ namespace CafeCritic.Migrations ...@@ -17,11 +17,35 @@ namespace CafeCritic.Migrations
{ {
#pragma warning disable 612, 618 #pragma warning disable 612, 618
modelBuilder modelBuilder
.HasAnnotation("ProductVersion", "7.0.11") .HasAnnotation("ProductVersion", "7.0.14")
.HasAnnotation("Relational:MaxIdentifierLength", 63); .HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("CafeCritic.Models.Cafe", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("Description")
.HasColumnType("text");
b.Property<string>("Image")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Title")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("Cafes");
});
modelBuilder.Entity("CafeCritic.Models.User", b => modelBuilder.Entity("CafeCritic.Models.User", b =>
{ {
b.Property<string>("Id") b.Property<string>("Id")
......
...@@ -42,6 +42,6 @@ app.UseAuthorization(); ...@@ -42,6 +42,6 @@ app.UseAuthorization();
app.MapControllerRoute( app.MapControllerRoute(
name: "default", name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}"); pattern: "{controller=Cafe}/{action=Index}/{id?}");
app.Run(); app.Run();
\ No newline at end of file
namespace CafeCritic.Services;
public class FileUpload
{
public static async Task<string> Upload(string? name, IFormFile? file)
{
name = name?.Replace(' ', '_');
var basePath = Path.Combine("wwwroot", "uploads");
if (!Directory.Exists(basePath))
Directory.CreateDirectory(basePath);
var extension = Path.GetExtension(file!.FileName);
var filePath = Path.Combine(basePath, $"{name}{extension}");
await using var stream = File.Create(filePath);
await file.CopyToAsync(stream);
return Path.Combine("uploads", $"{name}{extension}");
}
}
\ No newline at end of file
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Mvc;
namespace CafeCritic.ViewModels;
public class AddCafeViewModel
{
[Required(ErrorMessage = "Поле обязательно")]
public required string Title { get; set; }
[Required(ErrorMessage = "Поле обязательно")]
[DataType(DataType.Upload)]
public required IFormFile Image { get; set; }
public string? Description { get; set; }
}
\ No newline at end of file
using CafeCritic.Models;
namespace CafeCritic.ViewModels;
public class CafeViewModel
{
public List<Cafe> Cafes { get; set; } = new();
public int Id { get; set; }
public string Title { get; set; }
public string Image { get; set; }
public string? Description { get; set; }
}
\ No newline at end of file
@model CafeCritic.ViewModels.AddCafeViewModel
@{
ViewBag.Title = "Добавление заведения";
Layout = "_Layout";
}
<div class="d-flex justify-content-center">
<div class="card card_width">
<div class="card-body d-flex justify-content-center">
<form asp-action="AddCafe" method="post" asp-antiforgery="true" enctype="multipart/form-data">
<div asp-validation-summary="ModelOnly"></div>
<div>
<span asp-validation-for="Title" class="text-danger"></span>
<input id="restaurantTitle" asp-for="Title" class="form-control my-2 text-muted" placeholder="Название заведения">
</div>
<div>
<span asp-validation-for="Image" class="text-danger"></span>
<input type="file" id="image" asp-for="Image" class="form-control my-2 text-muted" placeholder="Изображение">
</div>
<div>
<input id="description" asp-for="Description" class="form-control my-2 text-muted" placeholder="Описание">
</div>
<input type="submit" class="btn btn-info w-100 mt-3 text-white" value="Добавить заведение">
</form>
</div>
</div>
</div>
@section Scripts
{
@{
await Html.RenderPartialAsync("_ValidationScriptsPartial");
}
}
@model Cafe
@{
ViewBag.Title = "Подробнее";
Layout = "_Layout";
}
<h2>Подробнее о заведении</h2>
<img src="~/@Model.Image" alt="PhotoCafe" style="width: 18rem;">
<h2>Название: - @Model.Title</h2>
<p>Описание: - @Model.Description</p>
<a asp-controller="Cafe" asp-action="Index">Список заведений.</a>
@model List<Cafe>
@{
ViewBag.Title = "title";
Layout = "_Layout";
}
@if (Model.Count == 0)
{
<h2 class="display-4">Заведения еще не добавлены.</h2>
}
else
{
<h2 class="display-4 mb-5">Список заведений</h2>
@foreach (var m in Model)
{
<div class="card d-flex mb-3 col-3" style="width: 18rem;">
<a asp-action="Details" asp-route-id="@m.Id">
<img src="@m.Image" class="card-img-top" alt="PhotoCafe">
</a>
<div class="card-body">
<a asp-action="Details" asp-route-id="@m.Id">@m.Title</a>
</div>
</div>
}
}
@{
ViewData["Title"] = "Home Page";
}
<div class="text-center">
<h1 class="display-4">Welcome</h1>
<p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>
\ No newline at end of file
@{
ViewData["Title"] = "Privacy Policy";
}
<h1>@ViewData["Title"]</h1>
<p>Use this page to detail your site's privacy policy.</p>
\ No newline at end of file
...@@ -18,33 +18,37 @@ ...@@ -18,33 +18,37 @@
<header> <header>
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3"> <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
<div class="container-fluid"> <div class="container-fluid">
<a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">CafeCritic</a> <a class="navbar-brand" asp-area="" asp-controller="Cafe" asp-action="Index">Cafe Critic</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbarSupportedContent" <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbarSupportedContent"
aria-expanded="false" aria-label="Toggle navigation"> aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span> <span class="navbar-toggler-icon"></span>
</button> </button>
<div class="navbar-collapse collapse d-sm-inline-flex justify-content-between"> <div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
<ul class="navbar-nav flex-grow-1 justify-content-end"> <ul class="navbar-nav flex-grow-1 justify-content-end">
@if (User.Identity!.IsAuthenticated) @if (!User.Identity.IsAuthenticated)
{ {
<li class="nav-item"> <li class="nav-item">
<span class="nav-link text-dark">Привет - @user.Email</span> <a class="nav-link text-primary m-1" asp-action="Login" asp-controller="Account">Войти</a>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<form asp-action="LogOut" asp-controller="Account" method="post"> <a class="nav-link text-primary m-1" asp-action="Register" asp-controller="Account">Зарегистрироваться</a>
<button type="submit" class="btn btn-primary">Выйти</button>
</form>
</li> </li>
} }
else @if (User.Identity!.IsAuthenticated)
{ {
<li class="nav-item"> <li class="nav-item">
<a class="nav-link text-primary m-1" asp-action="Login" asp-controller="Account">Войти</a> <a class="nav-link text-dark" asp-area="" asp-controller="Cafe" asp-action="AddCafe">Добавить заведение</a>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link text-primary m-1" asp-action="Register" asp-controller="Account">Зарегистрироваться</a> <span class="nav-link text-dark">Привет - @user.Email</span>
</li>
<li class="nav-item">
<form asp-action="LogOut" asp-controller="Account" method="post">
<button type="submit" class="btn btn-primary">Выйти</button>
</form>
</li> </li>
} }
</ul> </ul>
</div> </div>
</div> </div>
......
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