hallo
This commit is contained in:
138
Desktop/hallo/LEA/Controllers/AccountController.cs
Normal file
138
Desktop/hallo/LEA/Controllers/AccountController.cs
Normal file
@@ -0,0 +1,138 @@
|
||||
using System.Security.Claims;
|
||||
using LEA.Models;
|
||||
using LEA.ViewModels;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace LEA.Controllers;
|
||||
|
||||
public class AccountController : Controller
|
||||
{
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
private readonly SignInManager<ApplicationUser> _signInManager;
|
||||
private readonly ILogger<AccountController> _logger;
|
||||
|
||||
public AccountController(
|
||||
UserManager<ApplicationUser> userManager,
|
||||
SignInManager<ApplicationUser> signInManager,
|
||||
ILogger<AccountController> logger)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_signInManager = signInManager;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[AllowAnonymous]
|
||||
public IActionResult Register()
|
||||
{
|
||||
return View(new RegisterViewModel());
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[AllowAnonymous]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> Register(RegisterViewModel model)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View(model);
|
||||
}
|
||||
|
||||
var existingUser = await _userManager.FindByEmailAsync(model.Email);
|
||||
if (existingUser != null)
|
||||
{
|
||||
ModelState.AddModelError(nameof(model.Email), "Diese E-Mail-Adresse wird bereits verwendet.");
|
||||
return View(model);
|
||||
}
|
||||
|
||||
var user = new ApplicationUser
|
||||
{
|
||||
FullName = model.FullName.Trim(),
|
||||
Email = model.Email.Trim(),
|
||||
UserName = model.Email.Trim(),
|
||||
CreatedAt = DateTime.UtcNow
|
||||
};
|
||||
|
||||
var result = await _userManager.CreateAsync(user, model.Password);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
await _userManager.AddClaimAsync(user, new Claim("FullName", user.FullName));
|
||||
await _signInManager.SignInAsync(user, isPersistent: true);
|
||||
_logger.LogInformation("Neuer Benutzer {Email} wurde erstellt und angemeldet.", user.Email);
|
||||
TempData["Success"] = "Registrierung erfolgreich. Willkommen zurück!";
|
||||
return RedirectToAction("Index", "Applications");
|
||||
}
|
||||
|
||||
foreach (var error in result.Errors)
|
||||
{
|
||||
ModelState.AddModelError(string.Empty, TranslateIdentityError(error));
|
||||
}
|
||||
|
||||
return View(model);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[AllowAnonymous]
|
||||
public IActionResult Login(string? returnUrl = null)
|
||||
{
|
||||
return View(new LoginViewModel { ReturnUrl = returnUrl });
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[AllowAnonymous]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> Login(LoginViewModel model)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View(model);
|
||||
}
|
||||
|
||||
var user = await _userManager.FindByEmailAsync(model.Email);
|
||||
if (user == null)
|
||||
{
|
||||
ModelState.AddModelError(string.Empty, "Ungültige Anmeldedaten.");
|
||||
return View(model);
|
||||
}
|
||||
|
||||
var result = await _signInManager.PasswordSignInAsync(user, model.Password, model.RememberMe, lockoutOnFailure: false);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
_logger.LogInformation("Benutzer {Email} hat sich angemeldet.", user.Email);
|
||||
if (!string.IsNullOrWhiteSpace(model.ReturnUrl) && Url.IsLocalUrl(model.ReturnUrl))
|
||||
{
|
||||
return Redirect(model.ReturnUrl);
|
||||
}
|
||||
|
||||
TempData["Success"] = "Erfolgreich angemeldet.";
|
||||
return RedirectToAction("Index", "Applications");
|
||||
}
|
||||
|
||||
ModelState.AddModelError(string.Empty, "Ungültige Anmeldedaten.");
|
||||
return View(model);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Authorize]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> Logout()
|
||||
{
|
||||
await _signInManager.SignOutAsync();
|
||||
TempData["Success"] = "Sie wurden abgemeldet.";
|
||||
return RedirectToAction("Index", "Home");
|
||||
}
|
||||
|
||||
private static string TranslateIdentityError(IdentityError error) => error.Code switch
|
||||
{
|
||||
"PasswordTooShort" => "Das Passwort ist zu kurz.",
|
||||
"PasswordRequiresNonAlphanumeric" => "Das Passwort muss mindestens ein Sonderzeichen enthalten.",
|
||||
"PasswordRequiresDigit" => "Das Passwort muss mindestens eine Zahl enthalten.",
|
||||
"PasswordRequiresUpper" => "Das Passwort muss mindestens einen Großbuchstaben enthalten.",
|
||||
"PasswordRequiresLower" => "Das Passwort muss mindestens einen Kleinbuchstaben enthalten.",
|
||||
"DuplicateEmail" or "DuplicateUserName" => "Diese E-Mail-Adresse wird bereits verwendet.",
|
||||
"InvalidEmail" => "Bitte eine gültige E-Mail-Adresse eingeben.",
|
||||
_ => error.Description
|
||||
};
|
||||
}
|
289
Desktop/hallo/LEA/Controllers/ApplicationsController.cs
Normal file
289
Desktop/hallo/LEA/Controllers/ApplicationsController.cs
Normal file
@@ -0,0 +1,289 @@
|
||||
using LEA.Data;
|
||||
using LEA.Extensions;
|
||||
using LEA.Models;
|
||||
using LEA.ViewModels;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace LEA.Controllers;
|
||||
|
||||
[Authorize]
|
||||
public class ApplicationsController : Controller
|
||||
{
|
||||
private readonly AppDbContext _context;
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
|
||||
public ApplicationsController(AppDbContext context, UserManager<ApplicationUser> userManager)
|
||||
{
|
||||
_context = context;
|
||||
_userManager = userManager;
|
||||
}
|
||||
|
||||
public async Task<IActionResult> Index(string? searchTerm, ApplicationStatus? status)
|
||||
{
|
||||
var userId = GetCurrentUserId();
|
||||
var query = _context.Applications
|
||||
.Include(a => a.Contact)
|
||||
.Where(a => a.UserId == userId);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(searchTerm))
|
||||
{
|
||||
var term = $"%{searchTerm.Trim()}%";
|
||||
query = query.Where(a =>
|
||||
EF.Functions.Like(a.Company, term) ||
|
||||
EF.Functions.Like(a.Role, term) ||
|
||||
EF.Functions.Like(a.Source ?? string.Empty, term) ||
|
||||
EF.Functions.Like(a.Notes ?? string.Empty, term) ||
|
||||
(a.Contact != null && (
|
||||
EF.Functions.Like(a.Contact.FullName ?? string.Empty, term) ||
|
||||
EF.Functions.Like(a.Contact.Email ?? string.Empty, term))));
|
||||
}
|
||||
|
||||
if (status.HasValue)
|
||||
{
|
||||
query = query.Where(a => a.Status == status.Value);
|
||||
}
|
||||
|
||||
var applications = await query
|
||||
.OrderByDescending(a => a.UpdatedAt)
|
||||
.ThenByDescending(a => a.AppliedOn)
|
||||
.ToListAsync();
|
||||
|
||||
var statsQuery = _context.Applications.Where(a => a.UserId == userId);
|
||||
var statusCounts = await statsQuery
|
||||
.GroupBy(a => a.Status)
|
||||
.Select(g => new { g.Key, Count = g.Count() })
|
||||
.ToListAsync();
|
||||
|
||||
var statusDictionary = Enum.GetValues<ApplicationStatus>()
|
||||
.ToDictionary(s => s, s => statusCounts.FirstOrDefault(sc => sc.Key == s)?.Count ?? 0);
|
||||
|
||||
var model = new ApplicationListViewModel
|
||||
{
|
||||
Applications = applications,
|
||||
SearchTerm = searchTerm,
|
||||
StatusFilter = status,
|
||||
StatusOptions = GetStatusSelectList(status, includeAllOption: true),
|
||||
StatusCounts = statusDictionary,
|
||||
TotalApplications = await statsQuery.CountAsync()
|
||||
};
|
||||
|
||||
return View(model);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public IActionResult Create()
|
||||
{
|
||||
var model = new ApplicationFormViewModel
|
||||
{
|
||||
AppliedOn = DateTime.Today,
|
||||
Status = ApplicationStatus.Applied,
|
||||
StatusOptions = GetStatusSelectList(ApplicationStatus.Applied),
|
||||
Heading = "Bewerbung hinzufügen",
|
||||
SubmitText = "Speichern"
|
||||
};
|
||||
|
||||
return View(model);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> Create(ApplicationFormViewModel model)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
model.StatusOptions = GetStatusSelectList(model.Status);
|
||||
model.Heading = "Bewerbung hinzufügen";
|
||||
model.SubmitText = "Speichern";
|
||||
return View(model);
|
||||
}
|
||||
|
||||
var application = new Application
|
||||
{
|
||||
Role = model.Role.Trim(),
|
||||
Company = model.Company.Trim(),
|
||||
Source = string.IsNullOrWhiteSpace(model.Source) ? null : model.Source.Trim(),
|
||||
Status = model.Status,
|
||||
AppliedOn = model.AppliedOn,
|
||||
Notes = string.IsNullOrWhiteSpace(model.Notes) ? null : model.Notes.Trim(),
|
||||
UserId = GetCurrentUserId(),
|
||||
UpdatedAt = DateTime.UtcNow
|
||||
};
|
||||
|
||||
if (HasContactInformation(model))
|
||||
{
|
||||
application.Contact = new Contact
|
||||
{
|
||||
FullName = string.IsNullOrWhiteSpace(model.ContactName) ? null : model.ContactName.Trim(),
|
||||
Email = string.IsNullOrWhiteSpace(model.ContactEmail) ? null : model.ContactEmail.Trim(),
|
||||
Phone = string.IsNullOrWhiteSpace(model.ContactPhone) ? null : model.ContactPhone.Trim()
|
||||
};
|
||||
}
|
||||
|
||||
_context.Applications.Add(application);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
TempData["Success"] = "Die Bewerbung wurde gespeichert.";
|
||||
return RedirectToAction(nameof(Index));
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> Edit(int id)
|
||||
{
|
||||
var application = await FindApplicationForCurrentUserAsync(id);
|
||||
if (application == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
var model = new ApplicationFormViewModel
|
||||
{
|
||||
Id = application.Id,
|
||||
Role = application.Role,
|
||||
Company = application.Company,
|
||||
Source = application.Source,
|
||||
Status = application.Status,
|
||||
AppliedOn = application.AppliedOn,
|
||||
Notes = application.Notes,
|
||||
ContactName = application.Contact?.FullName,
|
||||
ContactEmail = application.Contact?.Email,
|
||||
ContactPhone = application.Contact?.Phone,
|
||||
StatusOptions = GetStatusSelectList(application.Status),
|
||||
Heading = "Bewerbung bearbeiten",
|
||||
SubmitText = "Änderungen speichern"
|
||||
};
|
||||
|
||||
return View(model);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> Edit(int id, ApplicationFormViewModel model)
|
||||
{
|
||||
if (id != model.Id)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
model.StatusOptions = GetStatusSelectList(model.Status);
|
||||
model.Heading = "Bewerbung bearbeiten";
|
||||
model.SubmitText = "Änderungen speichern";
|
||||
return View(model);
|
||||
}
|
||||
|
||||
var application = await FindApplicationForCurrentUserAsync(id);
|
||||
if (application == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
application.Role = model.Role.Trim();
|
||||
application.Company = model.Company.Trim();
|
||||
application.Source = string.IsNullOrWhiteSpace(model.Source) ? null : model.Source.Trim();
|
||||
application.Status = model.Status;
|
||||
application.AppliedOn = model.AppliedOn;
|
||||
application.Notes = string.IsNullOrWhiteSpace(model.Notes) ? null : model.Notes.Trim();
|
||||
application.UpdatedAt = DateTime.UtcNow;
|
||||
|
||||
if (HasContactInformation(model))
|
||||
{
|
||||
if (application.Contact == null)
|
||||
{
|
||||
application.Contact = new Contact();
|
||||
}
|
||||
|
||||
application.Contact.FullName = string.IsNullOrWhiteSpace(model.ContactName) ? null : model.ContactName.Trim();
|
||||
application.Contact.Email = string.IsNullOrWhiteSpace(model.ContactEmail) ? null : model.ContactEmail.Trim();
|
||||
application.Contact.Phone = string.IsNullOrWhiteSpace(model.ContactPhone) ? null : model.ContactPhone.Trim();
|
||||
}
|
||||
else if (application.Contact != null)
|
||||
{
|
||||
_context.Contacts.Remove(application.Contact);
|
||||
}
|
||||
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
TempData["Success"] = "Die Bewerbung wurde aktualisiert.";
|
||||
return RedirectToAction(nameof(Index));
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> Details(int id)
|
||||
{
|
||||
var application = await FindApplicationForCurrentUserAsync(id);
|
||||
if (application == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
return View(application);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> Delete(int id)
|
||||
{
|
||||
var application = await FindApplicationForCurrentUserAsync(id);
|
||||
if (application == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
_context.Applications.Remove(application);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
TempData["Success"] = "Die Bewerbung wurde gelöscht.";
|
||||
return RedirectToAction(nameof(Index));
|
||||
}
|
||||
|
||||
private async Task<Application?> FindApplicationForCurrentUserAsync(int id)
|
||||
{
|
||||
var userId = GetCurrentUserId();
|
||||
return await _context.Applications
|
||||
.Include(a => a.Contact)
|
||||
.Where(a => a.UserId == userId)
|
||||
.FirstOrDefaultAsync(a => a.Id == id);
|
||||
}
|
||||
|
||||
private IEnumerable<SelectListItem> GetStatusSelectList(ApplicationStatus? selectedStatus, bool includeAllOption = false)
|
||||
{
|
||||
var options = Enum.GetValues<ApplicationStatus>()
|
||||
.Select(status => new SelectListItem
|
||||
{
|
||||
Text = status.GetDisplayName(),
|
||||
Value = status.ToString(),
|
||||
Selected = selectedStatus.HasValue && selectedStatus.Value == status
|
||||
})
|
||||
.ToList();
|
||||
|
||||
if (includeAllOption)
|
||||
{
|
||||
options.Insert(0, new SelectListItem
|
||||
{
|
||||
Text = "Alle Status",
|
||||
Value = string.Empty,
|
||||
Selected = !selectedStatus.HasValue
|
||||
});
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
private bool HasContactInformation(ApplicationFormViewModel model)
|
||||
{
|
||||
return !string.IsNullOrWhiteSpace(model.ContactName)
|
||||
|| !string.IsNullOrWhiteSpace(model.ContactEmail)
|
||||
|| !string.IsNullOrWhiteSpace(model.ContactPhone);
|
||||
}
|
||||
|
||||
private string GetCurrentUserId()
|
||||
{
|
||||
return _userManager.GetUserId(User)
|
||||
?? throw new InvalidOperationException("Benutzer ist nicht angemeldet.");
|
||||
}
|
||||
}
|
97
Desktop/hallo/LEA/Controllers/HomeController.cs
Normal file
97
Desktop/hallo/LEA/Controllers/HomeController.cs
Normal file
@@ -0,0 +1,97 @@
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using LEA.Data;
|
||||
using LEA.Models;
|
||||
using LEA.ViewModels;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace LEA.Controllers;
|
||||
|
||||
public class HomeController : Controller
|
||||
{
|
||||
private readonly ILogger<HomeController> _logger;
|
||||
private readonly AppDbContext _context;
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
|
||||
public HomeController(
|
||||
ILogger<HomeController> logger,
|
||||
AppDbContext context,
|
||||
UserManager<ApplicationUser> userManager)
|
||||
{
|
||||
_logger = logger;
|
||||
_context = context;
|
||||
_userManager = userManager;
|
||||
}
|
||||
|
||||
public async Task<IActionResult> Index()
|
||||
{
|
||||
var viewModel = new DashboardViewModel();
|
||||
|
||||
if (User.Identity?.IsAuthenticated ?? false)
|
||||
{
|
||||
var userId = _userManager.GetUserId(User);
|
||||
var user = await _userManager.GetUserAsync(User);
|
||||
|
||||
var applications = await _context.Applications
|
||||
.Include(a => a.Contact)
|
||||
.Where(a => a.UserId == userId)
|
||||
.OrderByDescending(a => a.UpdatedAt)
|
||||
.ThenByDescending(a => a.AppliedOn)
|
||||
.Take(5)
|
||||
.ToListAsync();
|
||||
|
||||
var statusCounts = await _context.Applications
|
||||
.Where(a => a.UserId == userId)
|
||||
.GroupBy(a => a.Status)
|
||||
.Select(group => new { group.Key, Count = group.Count() })
|
||||
.ToListAsync();
|
||||
|
||||
var startOfCurrentMonth = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1);
|
||||
var startDate = startOfCurrentMonth.AddMonths(-5);
|
||||
|
||||
var monthlyResults = await _context.Applications
|
||||
.Where(a => a.UserId == userId && a.AppliedOn >= startDate)
|
||||
.GroupBy(a => new { a.AppliedOn.Year, a.AppliedOn.Month })
|
||||
.Select(group => new { group.Key.Year, group.Key.Month, Count = group.Count() })
|
||||
.ToListAsync();
|
||||
|
||||
var germanCulture = CultureInfo.GetCultureInfo("de-DE");
|
||||
var monthlyStatistics = new List<MonthlyApplicationStat>();
|
||||
|
||||
for (var offset = 0; offset < 6; offset++)
|
||||
{
|
||||
var currentMonth = startDate.AddMonths(offset);
|
||||
var match = monthlyResults.FirstOrDefault(result =>
|
||||
result.Year == currentMonth.Year && result.Month == currentMonth.Month);
|
||||
|
||||
var label = currentMonth.ToString("MMM yyyy", germanCulture);
|
||||
monthlyStatistics.Add(new MonthlyApplicationStat(label, match?.Count ?? 0));
|
||||
}
|
||||
|
||||
viewModel.IsAuthenticated = true;
|
||||
viewModel.FullName = user?.FullName;
|
||||
viewModel.RecentApplications = applications;
|
||||
viewModel.TotalApplications = statusCounts.Sum(sc => sc.Count);
|
||||
viewModel.AppliedCount = statusCounts.FirstOrDefault(sc => sc.Key == ApplicationStatus.Applied)?.Count ?? 0;
|
||||
viewModel.InterviewCount = statusCounts.FirstOrDefault(sc => sc.Key == ApplicationStatus.Interview)?.Count ?? 0;
|
||||
viewModel.OfferCount = statusCounts.FirstOrDefault(sc => sc.Key == ApplicationStatus.Offer)?.Count ?? 0;
|
||||
viewModel.RejectedCount = statusCounts.FirstOrDefault(sc => sc.Key == ApplicationStatus.Rejected)?.Count ?? 0;
|
||||
viewModel.MonthlyApplications = monthlyStatistics;
|
||||
}
|
||||
|
||||
return View(viewModel);
|
||||
}
|
||||
|
||||
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 });
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user