Добавлена аутентификация пользователя по email/паролю

Добавлены представления аутентификации и выхода из приложения.
Добавлено представление отображения детальной информации по фильму.
Добавлено представление профиля пользователя.
Вынесены линки на регистрацию/вход/ добавление фильма в Layout
parent b32ee1e6
......@@ -8,6 +8,7 @@
<e p="Cinema.csproj" t="IncludeRecursive" />
<e p="Cinema.sln" t="IncludeFlat" />
<e p="Controllers" t="Include">
<e p="AccountController.cs" t="Include" />
<e p="FilmsController.cs" t="Include" />
</e>
<e p="Data" t="Include">
......@@ -16,12 +17,15 @@
<e p="Migrations" t="Include">
<e p="20201119082753_Initial.Designer.cs" t="Include" />
<e p="20201119082753_Initial.cs" t="Include" />
<e p="20201121110726_AddProducerFieldToFilm.Designer.cs" t="Include" />
<e p="20201121110726_AddProducerFieldToFilm.cs" t="Include" />
<e p="CinemaContextModelSnapshot.cs" t="Include" />
</e>
<e p="Models" t="Include">
<e p="ErrorViewModel.cs" t="Include" />
<e p="Film.cs" t="Include" />
<e p="FilmViewModel.cs" t="Include" />
<e p="LoginViewModel.cs" t="Include" />
<e p="RegisterViewModel.cs" t="Include" />
<e p="User.cs" t="Include" />
</e>
<e p="Program.cs" t="Include" />
......@@ -33,7 +37,13 @@
</e>
<e p="Startup.cs" t="Include" />
<e p="Views" t="Include">
<e p="Account" t="Include">
<e p="Index.cshtml" t="Include" />
<e p="Login.cshtml" t="Include" />
<e p="Register.cshtml" t="Include" />
</e>
<e p="Films" t="Include">
<e p="About.cshtml" t="Include" />
<e p="Add.cshtml" t="Include" />
<e p="Index.cshtml" t="Include" />
</e>
......@@ -64,7 +74,7 @@
<e p="favicon.ico" t="Include" />
<e p="images" t="Include">
<e p="Posters" t="Include">
<e p="bell-1096280_960_720.png" t="Include" />
<e p="Три мушкетера_Три_мушкетёра_(2013).jpg" t="Include" />
</e>
</e>
<e p="js" t="Include">
......
......@@ -14,16 +14,27 @@
</component>
<component name="ChangeListManager">
<list default="true" id="411e953d-ac1b-431b-8c52-f61006a5f2f2" name="Default Changelist" comment="&#10;Добавлен файл БД(cinema.db)&#10;Удалены лишние файлы не относящиеся к проекту (HomeController) и его представления&#10;Стартовая страница изменена на Films/Index&#10;Добавлено представление для главной страницы Films/Index&#10;В контроллере Films добавлен Экшен Index">
<change afterPath="$PROJECT_DIR$/Controllers/FilmsController.cs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/Models/FilmViewModel.cs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/Services/UploadFileService.cs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/Views/Films/Add.cshtml" afterDir="false" />
<change afterPath="$PROJECT_DIR$/Controllers/AccountController.cs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/Models/LoginViewModel.cs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/Models/RegisterViewModel.cs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/Views/Account/Index.cshtml" afterDir="false" />
<change afterPath="$PROJECT_DIR$/Views/Account/Login.cshtml" afterDir="false" />
<change afterPath="$PROJECT_DIR$/Views/Account/Register.cshtml" afterDir="false" />
<change afterPath="$PROJECT_DIR$/Views/Films/About.cshtml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/.idea.Cinema/.idea/contentModel.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/.idea.Cinema/.idea/contentModel.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/.idea.Cinema/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/.idea.Cinema/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Controllers/Films.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Cinema.csproj" beforeDir="false" afterPath="$PROJECT_DIR$/Cinema.csproj" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Controllers/FilmsController.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Controllers/FilmsController.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Data/CinemaContext.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Data/CinemaContext.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Models/ErrorViewModel.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Models/Film.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Models/Film.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Models/FilmViewModel.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Models/FilmViewModel.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Startup.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Startup.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Views/Films/Add.cshtml" beforeDir="false" afterPath="$PROJECT_DIR$/Views/Films/Add.cshtml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Views/Films/Index.cshtml" beforeDir="false" afterPath="$PROJECT_DIR$/Views/Films/Index.cshtml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Views/Shared/_Layout.cshtml" beforeDir="false" afterPath="$PROJECT_DIR$/Views/Shared/_Layout.cshtml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/cinema.db" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/wwwroot/css/site.css" beforeDir="false" afterPath="$PROJECT_DIR$/wwwroot/css/site.css" afterDir="false" />
</list>
<list id="b32251c1-d844-4e65-bf1c-9f6cfe4d536a" name="Добавлены модели: User для дополнительного описания сущности пользователя, в виде Имени и Фамилии. Film для описания сущности фильма. Определены и добавлены следующие nuget-пакеты : Identity, efCore Design, Proxies, Sqlite Настроена конфигурация используемой БД. Добавлена начальная миграция" comment="" />
<option name="SHOW_DIALOG" value="false" />
......@@ -47,16 +58,25 @@
<option name="CHANGED_PATHS">
<list>
<option value="$PROJECT_DIR$/Models/User.cs" />
<option value="$PROJECT_DIR$/Views/Shared/_Layout.cshtml" />
<option value="$PROJECT_DIR$/Views/Films/Index.cshtml" />
<option value="$PROJECT_DIR$/Services/UploadFileService.cs" />
<option value="$PROJECT_DIR$/Controllers/Films.cs" />
<option value="$PROJECT_DIR$/Models/LoginViewModel.cs" />
<option value="$PROJECT_DIR$/Models/RegisterViewModel.cs" />
<option value="$PROJECT_DIR$/Views/Account/Login.cshtml" />
<option value="$PROJECT_DIR$/Views/Account/Register.cshtml" />
<option value="$PROJECT_DIR$/Controllers/AccountController.cs" />
<option value="$PROJECT_DIR$/Migrations/20201121095402_UpdateFilmFields.cs" />
<option value="$PROJECT_DIR$/Data/CinemaContext.cs" />
<option value="$PROJECT_DIR$/Startup.cs" />
<option value="$PROJECT_DIR$/Controllers/Films.cs" />
<option value="$PROJECT_DIR$/Views/Shared/_Layout.cshtml" />
<option value="$PROJECT_DIR$/Views/Account/Index.cshtml" />
<option value="$PROJECT_DIR$/wwwroot/css/site.css" />
<option value="$PROJECT_DIR$/Views/Films/Index.cshtml" />
<option value="$PROJECT_DIR$/Models/Film.cs" />
<option value="$PROJECT_DIR$/Controllers/FilmsController.cs" />
<option value="$PROJECT_DIR$/Models/FilmViewModel.cs" />
<option value="$PROJECT_DIR$/Views/Films/Add.cshtml" />
<option value="$PROJECT_DIR$/Controllers/FilmsController.cs" />
<option value="$PROJECT_DIR$/Models/Film.cs" />
<option value="$PROJECT_DIR$/Views/Films/About.cshtml" />
</list>
</option>
</component>
......@@ -114,6 +134,7 @@
<option name="presentableId" value="Default" />
<updated>1605771522746</updated>
<workItem from="1605771536927" duration="10080000" />
<workItem from="1605950916335" duration="5649000" />
</task>
<task id="LOCAL-00001" summary="Начало проекта">
<created>1605772561160</created>
......@@ -149,7 +170,7 @@
<component name="TypeScriptGeneratedFilesManager">
<option name="version" value="3" />
</component>
<component name="UnityProjectConfiguration" hasMinimizedUI="null" />
<component name="UnityProjectConfiguration" hasMinimizedUI="false" />
<component name="UnityUnitTestConfiguration" currentTestLauncher="NUnit" />
<component name="Vcs.Log.Tabs.Properties">
<option name="TAB_STATES">
......@@ -161,6 +182,7 @@
</entry>
</map>
</option>
<option name="oldMeFiltersMigrated" value="true" />
</component>
<component name="VcsManagerConfiguration">
<option name="CLEAR_INITIAL_COMMIT_MESSAGE" value="true" />
......@@ -175,26 +197,31 @@
<screen x="0" y="0" width="1920" height="1044" />
</state>
<state x="529" y="406" width="852" height="229" key="Git.Rebase.Log.Action.NewCommitMessage.Dialog/0.0.1920.1044/1920.0.1920.1080@0.0.1920.1044" timestamp="1605775025446" />
<state width="1878" height="277" key="GridCell.Tab.0.bottom" timestamp="1605785567204">
<state width="1878" height="277" key="GridCell.Tab.0.bottom" timestamp="1605956791150">
<screen x="0" y="0" width="1920" height="1044" />
</state>
<state width="1878" height="277" key="GridCell.Tab.0.bottom/0.0.1920.1044/1920.0.1920.1080@0.0.1920.1044" timestamp="1605785567204" />
<state width="1878" height="277" key="GridCell.Tab.0.center" timestamp="1605785567204">
<state width="1878" height="277" key="GridCell.Tab.0.bottom/0.0.1920.1044@0.0.1920.1044" timestamp="1605956791150" />
<state width="1878" height="277" key="GridCell.Tab.0.center" timestamp="1605956791150">
<screen x="0" y="0" width="1920" height="1044" />
</state>
<state width="1878" height="277" key="GridCell.Tab.0.center/0.0.1920.1044/1920.0.1920.1080@0.0.1920.1044" timestamp="1605785567204" />
<state width="1878" height="277" key="GridCell.Tab.0.left" timestamp="1605785567204">
<state width="1878" height="277" key="GridCell.Tab.0.center/0.0.1920.1044@0.0.1920.1044" timestamp="1605956791150" />
<state width="1878" height="277" key="GridCell.Tab.0.left" timestamp="1605956791149">
<screen x="0" y="0" width="1920" height="1044" />
</state>
<state width="1878" height="277" key="GridCell.Tab.0.left/0.0.1920.1044/1920.0.1920.1080@0.0.1920.1044" timestamp="1605785567204" />
<state width="1878" height="277" key="GridCell.Tab.0.right" timestamp="1605785567204">
<state width="1878" height="277" key="GridCell.Tab.0.left/0.0.1920.1044@0.0.1920.1044" timestamp="1605956791149" />
<state width="1878" height="277" key="GridCell.Tab.0.right" timestamp="1605956791150">
<screen x="0" y="0" width="1920" height="1044" />
</state>
<state width="1878" height="277" key="GridCell.Tab.0.right/0.0.1920.1044/1920.0.1920.1080@0.0.1920.1044" timestamp="1605785567204" />
<state x="644" y="228" width="622" height="585" key="RiderGenerateDialog" timestamp="1605774080803">
<state width="1878" height="277" key="GridCell.Tab.0.right/0.0.1920.1044@0.0.1920.1044" timestamp="1605956791150" />
<state x="644" y="228" width="622" height="585" key="RiderGenerateDialog" timestamp="1605951142994">
<screen x="0" y="0" width="1920" height="1044" />
</state>
<state x="644" y="228" width="622" height="585" key="RiderGenerateDialog/0.0.1920.1044/1920.0.1920.1080@0.0.1920.1044" timestamp="1605774080803" />
<state x="644" y="228" key="RiderGenerateDialog/0.0.1920.1044@0.0.1920.1044" timestamp="1605951142994" />
<state x="809" y="438" width="292" height="164" key="VCS.ChangelistChooser" timestamp="1605775030802">
<screen x="0" y="0" width="1920" height="1044" />
</state>
......
......@@ -14,4 +14,8 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="3.1.10" />
</ItemGroup>
<ItemGroup>
<Folder Include="wwwroot\images\Posters" />
</ItemGroup>
</Project>
using System;
using System.Threading.Tasks;
using Cinema.Data;
using Cinema.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
namespace Cinema.Controllers
{
public class AccountController : Controller
{
private readonly UserManager<User> _userManager;
private readonly SignInManager<User> _signInManager;
public AccountController(CinemaContext db, UserManager<User> userManager, SignInManager<User> signInManager)
{
_userManager = userManager;
_signInManager = signInManager;
}
public IActionResult Register()
{
return View();
}
[Authorize]
public IActionResult Index(string id = null){
User user = id == null? _userManager.GetUserAsync(User).Result : _userManager.FindByIdAsync(id).Result;
return View(user);
}
[HttpPost]
public async Task<IActionResult> Register(RegisterViewModel model)
{
if (!ModelState.IsValid) return View(model);
User user = new User
{
Email = model.Email,
UserName = model.Email,
FirstName = model.FirstName,
SecondName = model.SecondName
};
var result = await _userManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await _signInManager.SignInAsync(user, false);
return RedirectToAction("Index", "Films");
}
foreach (var error in result.Errors)
ModelState.AddModelError(String.Empty, error.Description);
return View(model);
}
public IActionResult Login(string returnUrl = null)
{
return View(new LoginViewModel {ReturnUrl = returnUrl});
}
[HttpPost]
public async Task<IActionResult> Login(LoginViewModel model)
{
if (ModelState.IsValid)
{
User user = await _userManager.FindByEmailAsync(model.Email);
if (user != null)
{
var result = await _signInManager.PasswordSignInAsync(
user,
model.Password,
model.RememberMe,
false);
if (result.Succeeded)
{
if (!string.IsNullOrEmpty(model.ReturnUrl)&&
Url.IsLocalUrl(model.ReturnUrl))
{
return Redirect(model.ReturnUrl);
}
return RedirectToAction("Index", "Films");
}
}
ModelState.AddModelError("", "Неправильный логин или пароль");
}
return View(model);
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Logout()
{
await _signInManager.SignOutAsync();
return RedirectToAction("Login");
}
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
......@@ -15,19 +16,19 @@ namespace Cinema.Controllers
{
private CinemaContext _db;
private UploadFileService _uploader;
private UserManager<User> _userManager;
private readonly IHostEnvironment _environment;
public Films(
CinemaContext db,
UploadFileService uploader,
IHostEnvironment environment
)
IHostEnvironment environment, UserManager<User> userManager)
{
_db = db;
_uploader = uploader;
_environment = environment;
_userManager = userManager;
}
public IActionResult Index()
......@@ -35,6 +36,14 @@ namespace Cinema.Controllers
List<Film> films = _db.Films.OrderBy(f => f.UpdatedAt).ToList();
return View(films);
}
public IActionResult About(int id)
{
var film = _db.Films.FirstOrDefault(f => f.Id == id);
if (film is null)
return RedirectToAction("Index");
return View(film);
}
[HttpGet]
public IActionResult Add()
......@@ -49,13 +58,17 @@ namespace Cinema.Controllers
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
string posterPath = $"images/Posters/{film.Name}{film.File.FileName}";
_uploader.Upload(path, film.File.FileName, film.File);
string posterPath = $"images/Posters/{film.Name}_{film.File.FileName}";
_uploader.Upload(path, (film.Name + '_' + film.File.FileName), film.File);
Film post = new Film()
{
Description = film.Description,
Name = film.Name,
Poster = posterPath,
UserId = "fixture"
UserId = _userManager.GetUserId(User),
PublishYear = film.PublishYear,
CreatedAt = DateTime.Now,
Producer = film.Producer
};
var result = _db.Films.AddAsync(post);
if (!result.IsCompleted) return View(film);
......
using Cinema.Models;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
......@@ -7,12 +8,12 @@ namespace Cinema.Data
public class CinemaContext : IdentityDbContext<User>
{
public DbSet<Film> Films { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder options)
=> options
.UseLazyLoadingProxies()
.UseSqlite("Data Source=cinema.db");
public CinemaContext(DbContextOptions options) : base(options)
{
}
......
This diff is collapsed.
using Microsoft.EntityFrameworkCore.Migrations;
namespace Cinema.Migrations
{
public partial class AddProducerFieldToFilm : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "Producer",
table: "Films",
nullable: true);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "Producer",
table: "Films");
}
}
}
......@@ -34,6 +34,9 @@ namespace Cinema.Migrations
b.Property<string>("Poster")
.HasColumnType("TEXT");
b.Property<string>("Producer")
.HasColumnType("TEXT");
b.Property<int>("PublishYear")
.HasColumnType("INTEGER");
......
using System;
namespace Cinema.Models
{
public class ErrorViewModel
{
public string RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
}
}
\ No newline at end of file
......@@ -7,6 +7,9 @@ namespace Cinema.Models
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Producer { get; set; }
public string Poster { get; set; }
public int PublishYear { get; set; }
public DateTime CreatedAt { get; set; }
......
......@@ -7,21 +7,27 @@ namespace Cinema.Models
{
[Required(ErrorMessage = "Поле название обязательно для заполнения")]
[MinLength(10, ErrorMessage = "Минимальная длина описания 10 символов")]
[MinLength(3, ErrorMessage = "Минимальная длина названия 3 символа")]
[Display(Name = "Название фильма")]
public string Name { get; set; }
[Required(ErrorMessage = "Поле описание обязательно для заполнения")]
[MinLength(10, ErrorMessage = "Минимальная длина описания 10 символов")]
[Display(Name = "Описание")]
[DataType(DataType.Text)]
public string Description { get; set; }
[Required(ErrorMessage = "Поле режиссер обязательно для заполнения")]
[Display(Name = "Режиссер")]
[DataType(DataType.Text)]
public string Producer { get; set; }
[Required(ErrorMessage = "Загрузка фото обязательна")]
[DataType(DataType.Upload)]
[Display(Name = "Постер фильма")]
public IFormFile File { get; set; }
[Display(Name = "Название фильма")]
[Display(Name = "Год создания")]
public int PublishYear { get; set; }
}
}
\ No newline at end of file
using System.ComponentModel.DataAnnotations;
namespace Cinema.Models
{
public class LoginViewModel
{
[Required(ErrorMessage = "Это поле обязательно")]
[Display(Name = "Электронная почта")]
[DataType(DataType.EmailAddress)]
public string Email { get; set; }
[Required(ErrorMessage = "Это поле обязательно")]
[Display(Name = "Пароль")]
[DataType(DataType.Password)]
public string Password { get; set; }
[Display(Name = "Запомнить меня")]
public bool RememberMe { get; set; }
public string ReturnUrl { get; set; }
}
}
\ No newline at end of file
using System.ComponentModel.DataAnnotations;
namespace Cinema.Models
{
public class RegisterViewModel
{
[Required(ErrorMessage = "Это поле обязательно")]
[Display(Name = "Электронная почта")]
[DataType(DataType.EmailAddress)]
public string Email { get; set; }
[Required(ErrorMessage = "Это поле обязательно")]
[Display(Name = "Имя")]
[DataType(DataType.Text)]
public string FirstName { get; set; }
[Display(Name = "Фамилия")]
[DataType(DataType.Text)]
public string SecondName { get; set; }
[Required(ErrorMessage = "Это поле обязательно")]
[Display(Name = "Пароль")]
[DataType(DataType.Password)]
public string Password { get; set; }
[Required(ErrorMessage = "Это поле обязательно")]
[Display(Name = "Введите пароль повторно")]
[DataType(DataType.Password)]
[Compare("Password", ErrorMessage = "Пароли не совпадают")]
public string ConfirmPassword { get; set; }
}
}
\ No newline at end of file
......@@ -3,10 +3,12 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Cinema.Data;
using Cinema.Models;
using Cinema.Services;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
......@@ -28,6 +30,17 @@ namespace Cinema
services.AddDbContext<CinemaContext>();
services.ConfigureApplicationCookie(options => options.LoginPath = "/Account/Login");
services.AddTransient<UploadFileService>();
services.AddIdentity<User, IdentityRole>(
options =>
{
options.Password.RequireDigit = false;
options.Password.RequiredLength = 5;
options.Password.RequireLowercase = false;
options.Password.RequireUppercase = false;
options.Password.RequiredUniqueChars = 1;
options.Password.RequireNonAlphanumeric = false;
})
.AddEntityFrameworkStores<CinemaContext>();;
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
......@@ -46,7 +59,9 @@ namespace Cinema
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseCookiePolicy();
app.UseEndpoints(endpoints =>
{
......
@model User
@{
ViewBag.Title = "Профиль пользователя";
Layout = "_Layout";
}
<h1>Кабинет пользователя</h1>
<div class="row">
<div class="col-md-6">
<p>Имя пользователя - @Model.FirstName</p>
<p>Фамилия пользователя - @Model.SecondName</p>
<p>Фильмов загружено - @Model.Films.Count</p>
</div>
</div>
<h2>Список загруженных фильмов</h2>
<div class="d-flex align-items-stretch flex-wrap justify-content-between">
@foreach (var film in @Model.Films)
{
<div class="film-card">
<a asp-action="About" asp-controller="Films" asp-route-id="@film.Id">
<div class="film-poster">
<img src="~/@film.Poster" alt="@film.Name">
</div>
<p class="film-name">
Название - @film.Name
</p>
</a>
<p>Год выпуска - @film.PublishYear</p>
</div>
}
</div>
\ No newline at end of file
@model LoginViewModel
@{
ViewBag.Title = "Вход";
Layout = "_Layout";
}
<h2>Введите данные для входа</h2>
<div class="row justify-content-center">
<div class="col-md-6">
<form method="post" asp-controller="Account" asp-action="Login"
asp-route-returnUrl="@Model.ReturnUrl">
<div asp-validation-summary="ModelOnly"></div>
<div class="form-group">
<label asp-for="Email"></label><br/>
<input class="form-control" asp-for="Email"/>
<span asp-validation-for="Email"></span>
</div>
<div class="form-group">
<label asp-for="Password"></label><br/>
<input class="form-control" asp-for="Password"/>
<span asp-validation-for="Password"></span>
</div>
<div class="form-group">
<label asp-for="RememberMe"></label>
<input class="form-check-inline" asp-for="RememberMe"/>
</div>
<div class="form-group">
<button class="form-control" type="submit" id="submit">Войти</button>
</div>
</form>
</div>
</div>
\ No newline at end of file
@model RegisterViewModel
@{
ViewBag.Title = "Регистрация";
Layout = "_Layout";
}
<h2>Регистрация нового пользователя</h2>
<div class="row justify-content-center">
<div class="col-md-6">
<form method="post" asp-controller="Account" asp-action="Register" enctype="multipart/form-data">
<div asp-validation-summary="ModelOnly"></div>
<div class="form-group">
<label asp-for="Email"></label><br/>
<input class="form-control" asp-for="Email"/>
<span asp-validation-for="Email"></span>
</div>
<div class="form-group">
<label asp-for="FirstName"></label><br/>
<input class="form-control" asp-for="FirstName"/>
<span asp-validation-for="FirstName"></span>
</div>
<div class="form-group">
<label asp-for="SecondName"></label><br/>
<input class="form-control" asp-for="SecondName"/>
<span asp-validation-for="SecondName"></span>
</div>
<div class="form-group">
<label asp-for="Password"></label><br />
<input class="form-control" asp-for="Password" />
<span asp-validation-for="Password"></span>
</div>
<div class="form-group">
<label asp-for="ConfirmPassword"></label><br />
<input class="form-control" asp-for="ConfirmPassword" />
<span asp-validation-for="ConfirmPassword"></span>
</div>
<div>
<input class="form-control" type="submit" value="Регистрация" />
</div>
</form>
</div>
</div>
@model Film
@{
ViewBag.Title = @Model.Name;
Layout = "_Layout";
}
<h2>@Model.Name</h2>
<div class="row">
<div class="col-md-6">
<div class="film-poster">
<img src="~/@Model.Poster" alt="@Model.Name">
</div>
</div>
<div class="col-md-6">
<p>Опубликован - @Model.CreatedAt.ToShortDateString()</p>
<p>Обновлен - @Model.UpdatedAt.ToShortDateString()</p>
<p>Кем добавлен -
<a asp-action="Index" asp-controller="Account" asp-route-id="@Model.UserId">
@Model.User.Email
</a>
</p>
<hr>
<p>Год выпуска - @Model.PublishYear</p>
<p>Режиссер - @Model.Producer</p>
<h3>Описание фильма</h3>
<p>@Model.Description</p>
</div>
</div>
\ No newline at end of file
......@@ -6,18 +6,18 @@
}
<div class="row">
<div class="col align-self-center">
<div class="col-6 align-self-center">
<div class="form">
<form asp-action="Add" asp-controller="Films" method="post" enctype="multipart/form-data">
<div asp-validation-summary="ModelOnly"></div>
<div class="form-group">
<label asp-for="Name">Название фильма</label><br/>
<input class="form-control" asp-for="Name"/>
<span asp-validation-for="Description"></span>
<span asp-validation-for="Name"></span>
</div>
<div class="form-group">
<label asp-for="Description">Описание фильма</label><br/>
<input class="form-control" asp-for="Description"/>
<textarea class="form-control" asp-for="Description" name="Description" style="resize: none;" id="" rows="10"></textarea>
<span asp-validation-for="Description"></span>
</div>
<div class="form-group">
......@@ -25,10 +25,15 @@
<input class="form-control-file" asp-for="File"/>
<span asp-validation-for="File"></span>
</div>
<div class="form-group">
<label asp-for="Producer"></label><br />
<input class="form-control-file" asp-for="Producer"/>
<span asp-validation-for="Producer"></span>
</div>
<div class="form-group">
<label asp-for="PublishYear"></label><br />
<input class="form-control-file" asp-for="PublishYear"/>
<span asp-validation-for="File"></span>
<span asp-validation-for="PublishYear"></span>
</div>
<div>
<button class="form-control" type="submit" id="submit" >Добавить</button>
......
......@@ -5,13 +5,31 @@
Layout = "_Layout";
}
<h2>Все фильмы</h2>
@if (@Model.Count == 0)
{
<h3>Список фильмов Пуст</h3>
}
else
{
<p>Здесь будет список фильмов</p>
<h2>Список загруженных фильмов</h2>
<div class="d-flex align-items-stretch flex-wrap justify-content-between">
@foreach (var film in @Model)
{
<div class="film-card">
<a asp-action="About" asp-route-id="@film.Id">
<div class="film-poster">
<img src="@film.Poster" alt="@film.Name">
</div>
<p class="film-name">
Название - @film.Name
</p>
</a>
<p>Год выпуска - @film.PublishYear</p>
<a asp-action="Index" asp-controller="Account" asp-route-id="@film.UserId">
Добавлен @film.User.Email
</a>
</div>
}
</div>
}
\ No newline at end of file
......@@ -12,16 +12,32 @@
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
<div class="container">
<a class="navbar-brand" asp-area="" asp-controller="Films" asp-action="Index">Cinema</a>
@if (User.Identity.IsAuthenticated)
{
<a asp-action="Add" asp-controller="Films" class="nav-item">Новый фильм</a>
}
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse">
<ul class="navbar-nav flex-grow-1">
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Films" asp-action="Index">Home</a>
</li>
</ul>
<div class="login_group">
@if (User.Identity.IsAuthenticated)
{
<form asp-action="Logout" asp-controller="Account" method="post" asp-antiforgery="true">
<a asp-action="Index" asp-controller="Account">
<i class="fa fa-user fa-2x" style="margin-right: 10px;" aria-hidden="true"></i>
</a>
<input type="submit" value="Выход" class="brn btn-dark">
</form>
}
else
{
<a asp-action="Login" asp-controller="Account">Вход</a>
<a asp-action="Register" asp-controller="Account">Регистрация</a>
}
</div>
</div>
</div>
</nav>
......
No preview for this file type
......@@ -69,3 +69,14 @@ body {
white-space: nowrap;
line-height: 60px; /* Vertically center the text there */
}
img{
width: 100%;
height: auto;
}
.film-card{
padding: 10px;
border: 1px solid silver;
border-radius: 5px;
width: 32%;
margin-bottom: 15px;
}
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