Startpunkten

This commit is contained in:
2026-03-05 15:43:26 +01:00
commit dd99fb7b01
95 changed files with 3262 additions and 0 deletions

12
.config/dotnet-tools.json Normal file
View File

@@ -0,0 +1,12 @@
{
"version": 1,
"isRoot": true,
"tools": {
"dotnet-ef": {
"version": "5.0.10",
"commands": [
"dotnet-ef"
]
}
}
}

62
.gitignore vendored Normal file
View File

@@ -0,0 +1,62 @@
## Build results
bin/
obj/
out/
.idea/
## Visual Studio cache/options
.vs/
*.user
*.suo
*.userosscache
*.sln.docstates
## ASP.NET Core
appsettings.Development.json
appsettings.Local.json
appsettings.*.json
## Sensitive data
*.pfx
*.snk
secrets.json
## NuGet
*.nupkg
*.snupkg
packages/
.nuget/packages/
## Logs
*.log
logs/
## IIS
_IISExpress/
*.vspscc
## Rider / JetBrains
.idea/
*.DotSettings.user
## Resharper
_ReSharper*/
*.[Rr]e[Ss]harper
## Node / Frontend
node_modules/
npm-debug.log
yarn-error.log
dist/
wwwroot/lib/
## Coverage & analysis
coverage/
*.coverage
*.coveragexml
## Temporary files
*.tmp
*.temp
~$*

View File

@@ -0,0 +1,161 @@
using Microsoft.AspNetCore.Mvc;
using PersonSport.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication; //För autentisering med Claims
using Microsoft.AspNetCore.Authentication.Cookies; //För autentisering med Claims
using System.Security.Claims;
using System.Text;
using System.Security.Cryptography;
using Microsoft.AspNetCore.Authorization;
namespace PersonSport.Controllers {
[Authorize]
public class LoginController : Controller {
[AllowAnonymous]
public IActionResult Index() {
return View();
}
public IActionResult ShowAdmins() {
List<Admin> administratorer = new();
using (var db = new IdrottContext()) {
administratorer = db.Administratorer.ToList();
ViewBag.antal = db.Administratorer.Count();
}
return View(administratorer);
}
[HttpGet]
public IActionResult CreateAdmin() {
return View();
}
[HttpPost]
public IActionResult CreateAdmin(Admin nyAdmin) {
try {
nyAdmin.Password = Sha256_hash(nyAdmin.Password);
if (ModelState.IsValid) {
using (var db = new IdrottContext()) {
// Kolla om namnet är upptaget
var antal = db.Administratorer.Where(s => s.Username == nyAdmin.Username).Count();
if (antal == 0) {
db.Add(nyAdmin);
db.SaveChanges();
}
else {
TempData["Meddelande"] = "Administratören finns redan. Välj ett annat namn.";
}
}
return RedirectToAction(nameof(ShowAdmins));
}
}
catch (Exception) {
throw;
}
return NotFound();
}
public IActionResult DeleteAdmin(int id) {
var admin = new Admin() { AdminId = id };
using (var db = new IdrottContext()) {
int antalAdmins = db.Administratorer.Count();
if (antalAdmins <= 1) {
TempData["TooFewAdmins"] = "Det måste finnas minst 1 Administratör kvar.";
}
else {
db.Attach(admin);
db.Remove(admin);
db.SaveChanges();
}
}
return RedirectToAction(nameof(ShowAdmins));
}
[HttpGet]
public IActionResult EditAdmin(int id) {
Admin ny = new();
if (ModelState.IsValid) {
using var db = new IdrottContext(); var admin = db.Administratorer.Where(p => p.AdminId == id).FirstOrDefault();
ny.AdminId = admin.AdminId;
ny.Username = admin.Username;
db.SaveChanges();
}
return View(ny);
}
[HttpPost]
public IActionResult EditAdmin(Admin updated) {
if (ModelState.IsValid) {
using (var db = new IdrottContext()) {
var up = db.Administratorer.Where(p => p.AdminId == updated.AdminId).FirstOrDefault();
up.AdminId = updated.AdminId;
up.Username = updated.Username;
up.Password = Sha256_hash(updated.Password);
db.SaveChanges();
}
return RedirectToAction(nameof(ShowAdmins));
}
return NotFound();
}
[AllowAnonymous]
[HttpPost]
public async Task<IActionResult> CheckLogin(Admin attKolla, string returnUrl = null) {
using var db = new IdrottContext(); // Kolla uppgifterna mot DB
// Lösenordet krypteras med SHA-256
var loginAttempt = db.Administratorer.Where(p => p.Username == attKolla.Username && p.Password == Sha256_hash(attKolla.Password)).FirstOrDefault();
if (loginAttempt == null) {
// Om de inte stämmer; skicka tillbaka till Login-sidan
TempData["msg"] = "Inloggningen inte godkänd.";
TempData["hint"] = "Tips: Testa 'admin' och 'password'";
return RedirectToAction(nameof(Index));
}
else {
var identity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme);
identity.AddClaim(new Claim(ClaimTypes.Name, attKolla.Username));
await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(identity));
if (returnUrl != null)
return Redirect(returnUrl);
else
return RedirectToAction("Index", "Start");
}
}
public async Task<IActionResult> Logout() {
await HttpContext.SignOutAsync(
CookieAuthenticationDefaults.AuthenticationScheme);
return RedirectToAction("Index", "Start");
}
[AllowAnonymous]
public static String Sha256_hash(string value) {
StringBuilder sb = new();
using (var hash = SHA256.Create()) {
Encoding enc = Encoding.UTF8;
Byte[] result = hash.ComputeHash(enc.GetBytes(value));
foreach (Byte b in result)
sb.Append(b.ToString("x2"));
}
return sb.ToString();
}
}
}

View File

@@ -0,0 +1,229 @@
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using PersonSport.Models;
using Microsoft.AspNetCore.Http;
using System.IO;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Authorization;
namespace PersonSport.Controllers {
[Authorize]
public class PersonController : Controller {
private const int FileNameLength = 8;
private readonly IWebHostEnvironment Environment;
public PersonController(IWebHostEnvironment _environment) {
Environment = _environment;
}
public IActionResult Index(string sortOrder) {
List<Person> personer = new();
using (var db = new IdrottContext()) {
personer = sortOrder switch {
"PersonId" => db.Personer.OrderBy(p => p.PersonId).ToList(),
"PersonNamn" => db.Personer.OrderBy(p => p.PersonNamn).ToList(),
"Epost" => db.Personer.OrderBy(p => p.Epost).ToList(),
"Alder" => db.Personer.OrderBy(p => p.Alder).ToList(),
"StartDatum" => db.Personer.OrderBy(p => p.StartDatum).ToList(),
_ => db.Personer.OrderBy(p => p.PersonId).ToList(),
};
}
return View(personer);
}
/* *********************************************************
* Function: Search()
* -----------------------------------------
* Sammanfattning: Söker i databasen efter en viss post genom
* att söka efter namn eller e-postadress.
* Skapar en lista av personer och sparar undan söksträngen.
* Populerar listan genom ett lambda-uttryck som motsvarade söksträngen.
* Denna lista av personer skickas slutligen till Vyn.
* ****************************************************** */
[HttpPost]
public IActionResult Search(IFormCollection fc) {
string search = fc["search"];
List<Person> personer = new();
using (var db = new IdrottContext()) {
personer = db.Personer.Where(p => p.PersonNamn.ToLower().Contains(search.ToLower()) || p.Epost.ToLower().Contains(search.ToLower())).ToList();
}
return View(personer);
}
[AllowAnonymous]
[HttpGet]
public IActionResult Create() {
return View();
}
[AllowAnonymous]
[HttpPost]
public IActionResult Create(IFormCollection fc) {
Person person = new();
try {
person.PersonNamn = fc["PersonNamn"];
person.Epost = fc["Epost"];
person.Visningsbild = fc["Visningsbild"];
person.Alder = int.Parse(fc["Alder"]);
if (person.Visningsbild != "") {
person.Visningsbild = Request.Form.Files[0].FileName;
IFormFileCollection files = Request.Form.Files;
long size = files.Sum(f => f.Length);
string BaseURL = this.Environment.WebRootPath + @"\images\userphoto\";
foreach (var formFile in files) {
string localFileName = DateTime.UtcNow.Ticks.ToString()[FileNameLength..] + ".jpg";
var filePath = BaseURL + localFileName;
person.Visningsbild = localFileName;
// Kontrollerar så att den valda filen är en bildfil
if (formFile.ContentType == "image/jpeg" || formFile.ContentType == "image/jpg" || formFile.ContentType == "image/png" || formFile.ContentType == "image/gif") {
if (formFile.Length > 0) {
using var stream = new FileStream(filePath, FileMode.Create); formFile.CopyTo(stream);
}
else
ViewBag.e = "Där där bilden är 0 bytes. Måste vara lite tråkig eller?";
}
else
ViewBag.e = "Det där var ingen bildfil";
}
}
else
person.Visningsbild = "noimage.jpg";
if (ModelState.IsValid) {
person.StartDatum = DateTime.Now;
using (var db = new IdrottContext()) {
db.Add(person);
db.SaveChanges();
}
TempData["MeddelandeSuccess"] = "Medlemmen är tillagd i systemet.";
return RedirectToAction("Index", "Start");
}
}
catch (Exception) {
throw;
}
TempData["MeddelandeFail"] = "Kunde inte lägga till personen.";
return NotFound();
}
public IActionResult Delete(int id) {
try {
var person = new Person() { PersonId = id };
using (var db = new IdrottContext()) {
db.Attach(person);
db.Remove(person);
db.SaveChanges();
}
TempData["MeddelandeSuccess"] = "Medlemmen är borttagen ur systemet.";
return RedirectToAction(nameof(Index));
}
catch (Exception) {
TempData["MeddelandeFail"] = "Kunde inte ta bort personen.";
throw;
}
}
[HttpGet]
public IActionResult Edit(int id) {
Person p = new();
try {
using (var db = new IdrottContext()) {
var person = db.Personer.Where(p => p.PersonId == id).FirstOrDefault();
p.PersonId = person.PersonId;
p.PersonNamn = person.PersonNamn;
p.Epost = person.Epost;
p.Alder = person.Alder;
p.Visningsbild = person.Visningsbild;
db.SaveChanges();
}
return View(p);
}
catch (Exception) {
throw;
}
}
[HttpPost]
public IActionResult Edit(IFormCollection fc) {
Person person = new();
bool bytaBild = false;
try {
person.PersonId = int.Parse(fc["PersonId"]);
person.PersonNamn = fc["PersonNamn"];
person.Epost = fc["Epost"];
person.Visningsbild = fc["Visningsbild"];
person.Alder = int.Parse(fc["Alder"]);
if (person.Visningsbild == "")
bytaBild = false;
else
bytaBild = true;
if (bytaBild) {
person.Visningsbild = Request.Form.Files[0].FileName;
IFormFileCollection files = Request.Form.Files;
long size = files.Sum(f => f.Length);
string BaseURL = this.Environment.WebRootPath + @"\images\userphoto\";
foreach (var formFile in files) {
string localFileName = DateTime.UtcNow.Ticks.ToString()[FileNameLength..] + ".jpg";
var filePath = BaseURL + localFileName;
person.Visningsbild = localFileName;
// Kontrollerar så att den valda filen är en bildfil
if (formFile.ContentType == "image/jpeg" || formFile.ContentType == "image/jpg" || formFile.ContentType == "image/png" || formFile.ContentType == "image/gif") {
if (formFile.Length > 0) {
using var stream = new FileStream(filePath, FileMode.Create);
formFile.CopyTo(stream);
}
else
ViewBag.e = "Där där bilden är 0 bytes. Måste vara lite tråkig eller?";
}
else
ViewBag.e = "Det där var ingen bildfil";
}
}
else
person.Visningsbild = "noimage.jpg";
if (ModelState.IsValid) {
using (var db = new IdrottContext()) {
var up = db.Personer.Where(p => p.PersonId == person.PersonId).FirstOrDefault();
up.PersonId = person.PersonId;
up.PersonNamn = person.PersonNamn;
up.Epost = person.Epost;
up.Alder = person.Alder;
if (bytaBild)
up.Visningsbild = person.Visningsbild;
db.SaveChanges();
}
TempData["MeddelandeSuccess"] = "Medlemmen är editerat med de nya uppgifterna.";
return RedirectToAction(nameof(Index));
}
}
catch (Exception) {
throw;
}
TempData["MeddelandeFail"] = "Kunde inte editera personen.";
return NotFound();
}
}
}

View File

@@ -0,0 +1,119 @@
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using PersonSport.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Authorization;
namespace PersonSport.Controllers {
[Authorize]
public class PersonSportController : Controller {
public IActionResult Index(int? sportens_id = 1) {
var db = new IdrottContext();
ViewBag.AllaSporter = db.Sporter.ToList();
ViewBag.sportens_id = sportens_id;
ViewBag.SportNamn = db.Sporter
.Where(a => a.SportId == sportens_id)
.Select(a => a.SportNamn).Single();
ViewBag.PersonerIValdSport = (from pers in db.Personer
where pers.PersonSporter.Any(c => c.SportId == sportens_id)
select pers).ToList();
return View();
}
[HttpGet]
public IActionResult Enroll() {
List<Person> personer = new();
List<Sport> sporter = new();
using (var db = new IdrottContext()) {
personer = db.Personer.ToList();
}
using (var db = new IdrottContext()) {
sporter = db.Sporter.ToList();
}
ViewBag.personer = personer;
ViewBag.sporter = sporter;
return View();
}
[HttpPost]
public IActionResult Enroll(IFormCollection fc) {
try {
int valtNamn = int.Parse(fc["Namn"]);
int valdSport = int.Parse(fc["Sport"]);
using (var db = new IdrottContext()) {
PersonSport.Models.PersonSport ps = new() { PersonId = valtNamn, SportId = valdSport };
db.Add(ps);
db.SaveChanges();
}
TempData["MeddelandeSuccess"] = "Medlemmen är tillagd i sporten.";
return RedirectToAction(nameof(Index));
}
catch (Exception) {
TempData["MeddelandeFail"] = "Kunde inte lägga till medlemmen i sporten.";
return View("/Start/Error");
throw;
}
}
public IActionResult Deroll() {
List<Person> personer = new();
using (var db = new IdrottContext()) {
personer = db.Personer.ToList();
}
return View(personer);
}
[HttpPost]
public IActionResult DerollSport(IFormCollection fc) {
try {
int valdPersonId = int.Parse(fc["PersonId"]);
using (var db = new IdrottContext()) {
ViewBag.SportForValdPerson = (from sport in db.Sporter
where sport.PersonSporter.Any(c => c.PersonId == valdPersonId)
select sport).ToList();
}
ViewBag.PersonId = valdPersonId;
return View();
}
catch (FormatException) {
return RedirectToAction(nameof(Index));
throw;
}
}
[HttpPost]
public IActionResult DerollDone(IFormCollection fc) {
try {
int valtPersonId = int.Parse(fc["PersonId"]);
int valtSportId = int.Parse(fc["SportId"]);
using (var db = new IdrottContext()) {
PersonSport.Models.PersonSport ps = new() { PersonId = valtPersonId, SportId = valtSportId };
db.Remove(ps);
db.SaveChanges();
}
TempData["MeddelandeSuccess"] = "Medlemmen är borttagen från sporten.";
return RedirectToAction(nameof(Index));
}
catch (FormatException) {
TempData["MeddelandeFail"] = "Kunde inte ta bort medlemmen från sporten";
return RedirectToAction(nameof(Index));
}
}
}
}

View File

@@ -0,0 +1,236 @@
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using PersonSport.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Hosting;
using System.IO;
using Microsoft.AspNetCore.Authorization;
namespace PersonSport.Controllers {
[Authorize]
public class SportController : Controller {
private const int FileNameLength = 8;
private readonly IWebHostEnvironment Environment;
public SportController(IWebHostEnvironment _environment) {
Environment = _environment;
}
public IActionResult Index() {
List<Sport> sporter = new();
using (var db = new IdrottContext()) {
sporter = db.Sporter.ToList();
}
return View(sporter);
}
[AllowAnonymous]
public IActionResult Utbud() {
List<Sport> sporter = new();
using (var db = new IdrottContext()) {
sporter = db.Sporter.ToList();
}
return View(sporter);
}
[HttpGet]
public IActionResult Create() {
return View();
}
[HttpPost]
public IActionResult Create(IFormCollection fc) {
Sport sport = new();
try {
sport.SportNamn = fc["SportNamn"];
sport.Ingress = fc["Ingress"];
sport.DetaljText = fc["DetaljText"];
sport.Traningstider = fc["Traningstider"];
sport.Bakgrundsbild = fc["Bakgrundsbild"];
if (sport.Bakgrundsbild != "") {
sport.Bakgrundsbild = Request.Form.Files[0].FileName;
IFormFileCollection files = Request.Form.Files;
long size = files.Sum(f => f.Length);
string BaseURL = this.Environment.WebRootPath + @"\images\sport\";
foreach (var formFile in files) {
string localFileName = DateTime.UtcNow.Ticks.ToString()[FileNameLength..] + ".jpg";
var filePath = BaseURL + localFileName;
sport.Bakgrundsbild = localFileName;
// Kontrollerar så att den valda filen är en bildfil
if (formFile.ContentType == "image/jpeg" || formFile.ContentType == "image/jpg" || formFile.ContentType == "image/png" || formFile.ContentType == "image/gif") {
if (formFile.Length > 0) {
using var stream = new FileStream(filePath, FileMode.Create); formFile.CopyTo(stream);
}
else
ViewBag.e = "Där där bilden är 0 bytes. Måste vara lite tråkig eller?";
}
else
ViewBag.e = "Det där var ingen bildfil";
}
}
else
sport.Bakgrundsbild = "noimage.jpg";
if (ModelState.IsValid) {
using (var db = new IdrottContext()) {
db.Add(sport);
db.SaveChanges();
}
TempData["MeddelandeSuccess"] = "Sporten är tillagd i systemet.";
return RedirectToAction(nameof(Index));
}
}
catch (Exception) {
throw;
}
TempData["MeddelandeFail"] = "Kunde inte lägga till sporten.";
return NotFound();
}
public IActionResult Delete(int id) {
try {
var sport = new Sport() { SportId = id };
using (var db = new IdrottContext()) {
db.Attach(sport);
db.Remove(sport);
db.SaveChanges();
}
TempData["MeddelandeSuccess"] = "Sporten är borttagen ur systemet.";
return RedirectToAction(nameof(Index));
}
catch (Exception) {
TempData["MeddelandeFail"] = "Kunde inte ta bort sporten.";
throw;
}
}
[HttpGet]
public IActionResult Edit(int id) {
Sport p = new();
try {
using (var db = new IdrottContext()) {
var sport = db.Sporter.Where(p => p.SportId == id).FirstOrDefault();
p.SportId = sport.SportId;
p.SportNamn = sport.SportNamn;
p.Ingress = sport.Ingress;
p.DetaljText = sport.DetaljText;
p.Traningstider = sport.Traningstider;
p.Bakgrundsbild = sport.Bakgrundsbild;
db.SaveChanges();
}
return View(p);
}
catch (Exception) {
throw;
}
}
[HttpPost]
public IActionResult Edit(IFormCollection fc) {
Sport sport = new();
bool bytaBild = false;
try {
sport.SportId = int.Parse(fc["SportId"]);
sport.SportNamn = fc["SportNamn"];
sport.Ingress = fc["Ingress"];
sport.DetaljText = fc["DetaljText"];
sport.Traningstider = fc["Traningstider"];
sport.Bakgrundsbild = fc["Bakgrundsbild"];
if (sport.Bakgrundsbild == "")
bytaBild = false;
else
bytaBild = true;
if (bytaBild) {
sport.Bakgrundsbild = Request.Form.Files[0].FileName;
IFormFileCollection files = Request.Form.Files;
long size = files.Sum(f => f.Length);
string BaseURL = this.Environment.WebRootPath + @"\images\sport\";
foreach (var formFile in files) {
string localFileName = DateTime.UtcNow.Ticks.ToString()[FileNameLength..] + ".jpg";
var filePath = BaseURL + localFileName;
sport.Bakgrundsbild = localFileName;
// Kontrollerar så att den valda filen är en bildfil
if (formFile.ContentType == "image/jpeg" || formFile.ContentType == "image/jpg" || formFile.ContentType == "image/png" || formFile.ContentType == "image/gif") {
if (formFile.Length > 0) {
using var stream = new FileStream(filePath, FileMode.Create); formFile.CopyTo(stream);
}
else
ViewBag.e = "Där där bilden är 0 bytes. Måste vara lite tråkig eller?";
}
else
ViewBag.e = "Det där var ingen bildfil";
}
}
else
sport.Bakgrundsbild = "nosport.jpg";
if (ModelState.IsValid) {
using (var db = new IdrottContext()) {
var up = db.Sporter.Where(p => p.SportId == sport.SportId).FirstOrDefault();
up.SportId = sport.SportId;
up.SportNamn = sport.SportNamn;
up.Ingress = sport.Ingress;
up.DetaljText = sport.DetaljText;
up.Traningstider = sport.Traningstider;
if (bytaBild)
up.Bakgrundsbild = sport.Bakgrundsbild;
db.SaveChanges();
}
TempData["MeddelandeSuccess"] = "Sporten är uppdaterad med de nya uppgifterna.";
return RedirectToAction(nameof(Index));
}
}
catch (Exception) {
throw;
}
TempData["MeddelandeFail"] = "Kunde inte editera sporten.";
return NotFound();
}
[AllowAnonymous]
[HttpGet]
public IActionResult Details(int id) {
Sport s = new();
try {
using (var db = new IdrottContext()) {
var valdSport = db.Sporter.Where(p => p.SportId == id).FirstOrDefault();
s.SportId = valdSport.SportId;
s.SportNamn = valdSport.SportNamn;
s.Ingress = valdSport.Ingress;
s.DetaljText = valdSport.DetaljText;
s.Traningstider = valdSport.Traningstider;
s.Bakgrundsbild = valdSport.Bakgrundsbild;
}
ViewBag.metaAbstract = s.Ingress;
ViewBag.metaImage = "https://sportpalatset.se/images/sport/" + s.Bakgrundsbild;
return View(s);
}
catch (Exception) {
throw;
}
}
}
}

View File

@@ -0,0 +1,79 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Text;
using System.Net;
using System.Net.Mail;
using PersonSport.Models;
namespace PersonSport.Controllers {
public class StartController : Controller {
public IActionResult Index() {
return View();
}
public IActionResult Priser() {
return View();
}
public IActionResult Kurser() {
return View();
}
public IActionResult Receptionen() {
return View();
}
public IActionResult Oppettider() {
return View();
}
[HttpPost]
public IActionResult SendMail(IFormCollection fc) {
MailViewModel mvm = new();
if (ModelState.IsValid) {
string formFrom = fc["Epost"];
string formSubject = fc["Subject"];
string formMessage = fc["Message"];
string to = "christian.ohlsson@gmail.com"; // Mottagarens e-postadress
string from = "imcoh@hv.se"; // Avsändarens e-postadress
string mailIntro = "<h3>Detta är ett meddelande från formuläret på SportPalatset</h3>"
+ "Avsändare: <b>" + formFrom + "</b><br />"
+ "Meddelandet lyder:<br /><br />";
string mailEnd = "<br /><br /><br /><br />"
+ "-------------------------------------------------------------"
+ "<p>Tänk på miljön och skriv inte ut detta mail</p>"
+ "<img src='https://crille.org/sportpalatsetlogo.png' alt='Logo'>";
MailMessage message = new(from, to);
message.Subject = formSubject;
message.Body = mailIntro + formMessage + mailEnd;
message.BodyEncoding = Encoding.UTF8;
message.IsBodyHtml = true;
SmtpClient client = new("smtp.live.com", 587); // Outlook smtp
NetworkCredential basicCredential1 = new("imcoh@hv.se", "s3jsVYQc3Bs2N4MN");
client.EnableSsl = true;
client.UseDefaultCredentials = false;
client.Credentials = basicCredential1;
try {
TempData["MeddelandeSuccess"] = "Ditt meddelande har skickats till SportPalatset.";
client.Send(message);
}
catch (Exception) {
throw;
}
return RedirectToAction(nameof(Index));
}
else {
TempData["MeddelandeFail"] = "Mailet har inte skickats";
return NotFound();
}
}
}
}

BIN
Data/PersonSport.db Normal file

Binary file not shown.

1
Data/PersonSport.sqbpro Normal file
View File

@@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><sqlb_project><db path="C:\Users\ChristianOhlsson(HV)\OneDrive - Högskolan Väst\skola\Databasteknik och webbaserade system [Umeå HT21]\Projektarbete\PersonSport\Data\PersonSport.db" readonly="0" foreign_keys="1" case_sensitive_like="0" temp_store="0" wal_autocheckpoint="1000" synchronous="2"/><attached/><window><main_tabs open="structure browser pragmas query" current="1"/></window><tab_structure><column_width id="0" width="300"/><column_width id="1" width="0"/><column_width id="2" width="100"/><column_width id="3" width="2708"/><column_width id="4" width="0"/><expanded_item id="0" parent="1"/><expanded_item id="1" parent="1"/><expanded_item id="2" parent="1"/><expanded_item id="3" parent="1"/></tab_structure><tab_browse><current_table name="4,15:mainAdministratorer"/><default_encoding codec=""/><browse_table_settings><table schema="main" name="Administratorer" show_row_id="0" encoding="" plot_x_axis="" unlock_view_pk="_rowid_"><sort/><column_widths><column index="1" value="61"/><column index="2" value="72"/><column index="3" value="300"/></column_widths><filter_values/><conditional_formats/><row_id_formats/><display_formats/><hidden_columns/><plot_y_axes/><global_filter/></table></browse_table_settings></tab_browse><tab_sql><sql name="SQL 1"></sql><current_tab id="0"/></tab_sql></sqlb_project>

View File

@@ -0,0 +1,156 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using PersonSport.Models;
namespace PersonSport.Migrations
{
[DbContext(typeof(IdrottContext))]
[Migration("20211013071744_Initial")]
partial class Initial
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "5.0.10");
modelBuilder.Entity("PersonSport.Models.Admin", b =>
{
b.Property<int>("AdminId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("Password")
.IsRequired()
.HasMaxLength(80)
.HasColumnType("TEXT");
b.Property<string>("Username")
.IsRequired()
.HasMaxLength(40)
.HasColumnType("TEXT");
b.HasKey("AdminId");
b.ToTable("Administratorer");
});
modelBuilder.Entity("PersonSport.Models.Person", b =>
{
b.Property<int>("PersonId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("Alder")
.HasColumnType("INTEGER");
b.Property<string>("Epost")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("TEXT");
b.Property<string>("PersonNamn")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("TEXT");
b.Property<DateTime>("StartDatum")
.HasColumnType("TEXT");
b.Property<string>("Visningsbild")
.HasMaxLength(80)
.HasColumnType("TEXT");
b.HasKey("PersonId");
b.ToTable("Personer");
});
modelBuilder.Entity("PersonSport.Models.PersonSport", b =>
{
b.Property<int>("PersonId")
.HasColumnType("INTEGER");
b.Property<int>("SportId")
.HasColumnType("INTEGER");
b.Property<DateTime>("StartDatum")
.HasColumnType("TEXT");
b.HasKey("PersonId", "SportId");
b.HasIndex("SportId");
b.ToTable("PersonSport");
});
modelBuilder.Entity("PersonSport.Models.Sport", b =>
{
b.Property<int>("SportId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("Bakgrundsbild")
.IsRequired()
.HasMaxLength(60)
.HasColumnType("TEXT");
b.Property<string>("DetaljText")
.HasMaxLength(2000)
.HasColumnType("TEXT");
b.Property<string>("Ingress")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("TEXT");
b.Property<string>("SportNamn")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("TEXT");
b.Property<string>("Traningstider")
.HasMaxLength(200)
.HasColumnType("TEXT");
b.HasKey("SportId");
b.ToTable("Sporter");
});
modelBuilder.Entity("PersonSport.Models.PersonSport", b =>
{
b.HasOne("PersonSport.Models.Person", "Person")
.WithMany("PersonSporter")
.HasForeignKey("PersonId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.HasOne("PersonSport.Models.Sport", "Sport")
.WithMany("PersonSporter")
.HasForeignKey("SportId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.Navigation("Person");
b.Navigation("Sport");
});
modelBuilder.Entity("PersonSport.Models.Person", b =>
{
b.Navigation("PersonSporter");
});
modelBuilder.Entity("PersonSport.Models.Sport", b =>
{
b.Navigation("PersonSporter");
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -0,0 +1,104 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
namespace PersonSport.Migrations
{
public partial class Initial : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Administratorer",
columns: table => new
{
AdminId = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
Username = table.Column<string>(type: "TEXT", maxLength: 40, nullable: false),
Password = table.Column<string>(type: "TEXT", maxLength: 80, nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Administratorer", x => x.AdminId);
});
migrationBuilder.CreateTable(
name: "Personer",
columns: table => new
{
PersonId = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
PersonNamn = table.Column<string>(type: "TEXT", maxLength: 50, nullable: false),
Epost = table.Column<string>(type: "TEXT", maxLength: 50, nullable: false),
Alder = table.Column<int>(type: "INTEGER", nullable: false),
StartDatum = table.Column<DateTime>(type: "TEXT", nullable: false),
Visningsbild = table.Column<string>(type: "TEXT", maxLength: 80, nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Personer", x => x.PersonId);
});
migrationBuilder.CreateTable(
name: "Sporter",
columns: table => new
{
SportId = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
SportNamn = table.Column<string>(type: "TEXT", maxLength: 50, nullable: false),
Bakgrundsbild = table.Column<string>(type: "TEXT", maxLength: 60, nullable: false),
Ingress = table.Column<string>(type: "TEXT", maxLength: 200, nullable: false),
DetaljText = table.Column<string>(type: "TEXT", maxLength: 2000, nullable: true),
Traningstider = table.Column<string>(type: "TEXT", maxLength: 200, nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Sporter", x => x.SportId);
});
migrationBuilder.CreateTable(
name: "PersonSport",
columns: table => new
{
PersonId = table.Column<int>(type: "INTEGER", nullable: false),
SportId = table.Column<int>(type: "INTEGER", nullable: false),
StartDatum = table.Column<DateTime>(type: "TEXT", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_PersonSport", x => new { x.PersonId, x.SportId });
table.ForeignKey(
name: "FK_PersonSport_Personer_PersonId",
column: x => x.PersonId,
principalTable: "Personer",
principalColumn: "PersonId",
onDelete: ReferentialAction.Restrict);
table.ForeignKey(
name: "FK_PersonSport_Sporter_SportId",
column: x => x.SportId,
principalTable: "Sporter",
principalColumn: "SportId",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateIndex(
name: "IX_PersonSport_SportId",
table: "PersonSport",
column: "SportId");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Administratorer");
migrationBuilder.DropTable(
name: "PersonSport");
migrationBuilder.DropTable(
name: "Personer");
migrationBuilder.DropTable(
name: "Sporter");
}
}
}

View File

@@ -0,0 +1,154 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using PersonSport.Models;
namespace PersonSport.Migrations
{
[DbContext(typeof(IdrottContext))]
partial class IdrottContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "5.0.10");
modelBuilder.Entity("PersonSport.Models.Admin", b =>
{
b.Property<int>("AdminId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("Password")
.IsRequired()
.HasMaxLength(80)
.HasColumnType("TEXT");
b.Property<string>("Username")
.IsRequired()
.HasMaxLength(40)
.HasColumnType("TEXT");
b.HasKey("AdminId");
b.ToTable("Administratorer");
});
modelBuilder.Entity("PersonSport.Models.Person", b =>
{
b.Property<int>("PersonId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("Alder")
.HasColumnType("INTEGER");
b.Property<string>("Epost")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("TEXT");
b.Property<string>("PersonNamn")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("TEXT");
b.Property<DateTime>("StartDatum")
.HasColumnType("TEXT");
b.Property<string>("Visningsbild")
.HasMaxLength(80)
.HasColumnType("TEXT");
b.HasKey("PersonId");
b.ToTable("Personer");
});
modelBuilder.Entity("PersonSport.Models.PersonSport", b =>
{
b.Property<int>("PersonId")
.HasColumnType("INTEGER");
b.Property<int>("SportId")
.HasColumnType("INTEGER");
b.Property<DateTime>("StartDatum")
.HasColumnType("TEXT");
b.HasKey("PersonId", "SportId");
b.HasIndex("SportId");
b.ToTable("PersonSport");
});
modelBuilder.Entity("PersonSport.Models.Sport", b =>
{
b.Property<int>("SportId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("Bakgrundsbild")
.IsRequired()
.HasMaxLength(60)
.HasColumnType("TEXT");
b.Property<string>("DetaljText")
.HasMaxLength(2000)
.HasColumnType("TEXT");
b.Property<string>("Ingress")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("TEXT");
b.Property<string>("SportNamn")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("TEXT");
b.Property<string>("Traningstider")
.HasMaxLength(200)
.HasColumnType("TEXT");
b.HasKey("SportId");
b.ToTable("Sporter");
});
modelBuilder.Entity("PersonSport.Models.PersonSport", b =>
{
b.HasOne("PersonSport.Models.Person", "Person")
.WithMany("PersonSporter")
.HasForeignKey("PersonId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.HasOne("PersonSport.Models.Sport", "Sport")
.WithMany("PersonSporter")
.HasForeignKey("SportId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.Navigation("Person");
b.Navigation("Sport");
});
modelBuilder.Entity("PersonSport.Models.Person", b =>
{
b.Navigation("PersonSporter");
});
modelBuilder.Entity("PersonSport.Models.Sport", b =>
{
b.Navigation("PersonSporter");
});
#pragma warning restore 612, 618
}
}
}

18
Models/Admin.cs Normal file
View File

@@ -0,0 +1,18 @@
using System.ComponentModel.DataAnnotations;
namespace PersonSport.Models {
public class Admin {
[Required]
public int AdminId { get; set; }
[Required(ErrorMessage = "Du måste ange ett användarnamn")]
[StringLength(40, MinimumLength = 2, ErrorMessage = "Användarnamnet måste vara mellan 2 och 40 tecken")]
public string Username { get; set; }
[Required(ErrorMessage = "Du måste ange ett lösenord")]
[DataType(DataType.Password)]
[StringLength(80, MinimumLength=6, ErrorMessage="Lösenordet måste vara minst 6 tecken.")]
public string Password { get; set; }
}
}

7
Models/ErrorViewModel.cs Normal file
View File

@@ -0,0 +1,7 @@
namespace PersonSport.Models {
public class ErrorViewModel {
public string RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
}
}

35
Models/IdrottContext.cs Normal file
View File

@@ -0,0 +1,35 @@
using Microsoft.EntityFrameworkCore;
using System.Linq;
namespace PersonSport.Models {
public class IdrottContext : DbContext {
public DbSet<Person> Personer { get; set; }
public DbSet<Sport> Sporter { get; set; }
public DbSet<Admin> Administratorer { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder options)
// Azure
// => options.UseSqlite("FileName=C:/Users/ChristianOhlsson(HV)/OneDrive - Högskolan Väst/skola/Databasteknik och webbaserade system [Umeå HT21]/Projektarbete/PersonSport/Data/PersonSport.db");
// Lokalt
=> options.UseSqlite("DataSource=./Data/PersonSport.db");
protected override void OnModelCreating(ModelBuilder modelBuilder) {
modelBuilder.Entity<PersonSport>()
.HasKey(c => new { c.PersonId, c.SportId });
modelBuilder.Entity<Person>()
.HasMany(c => c.PersonSporter);
modelBuilder.Entity<Sport>()
.HasMany(c => c.PersonSporter);
// Tar bort "ON DELETE CASCADE" så att inte sporten försvinner om sista personen
// som utövar den gör det.
base.OnModelCreating(modelBuilder);
foreach (var relationship in modelBuilder.Model.GetEntityTypes().SelectMany(e => e.GetForeignKeys())) {
relationship.DeleteBehavior = DeleteBehavior.Restrict;
}
}
}
}

21
Models/MailViewModel.cs Normal file
View File

@@ -0,0 +1,21 @@
using System.ComponentModel.DataAnnotations;
namespace PersonSport.Models {
public class MailViewModel {
[Required(ErrorMessage = "Du måste ange din e-postadress så vi kan kontakta dig")]
[StringLength(50, MinimumLength = 6, ErrorMessage = "Din epost-adress måste vara minst 6 tecken och max 50 tecken")]
[Display(Name = "Din E-postadress")]
[RegularExpression(@"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$", ErrorMessage = "Felaktig e-postadress")]
public string Epost { get; set; }
[Required(ErrorMessage = "Du måste ange ditt ärende")]
[StringLength(50, MinimumLength = 3, ErrorMessage = "Ditt ärende måste vara minst 3 tecken och max 50 tecken")]
[Display(Name = "Ärende")]
public string Subject { get; set; }
[Required(ErrorMessage = "Du måste skriva vad det gäller")]
[StringLength(500, MinimumLength = 5, ErrorMessage="Ditt meddelande måste vara minst 5 tecken och max 500 tecken")]
[Display(Name = "Meddelande")]
public string Message { get; set; }
}
}

36
Models/Person.cs Normal file
View File

@@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace PersonSport.Models {
public class Person {
[Required]
public int PersonId { get; set; }
[Required(ErrorMessage ="Du måste ange ditt namn")]
[StringLength(50, MinimumLength = 3, ErrorMessage = "Namnet måste vara mellan 3 och 50 tecken")]
[Display(Name = "Ditt namn")]
public string PersonNamn { get; set; }
[Required(ErrorMessage="Du måste ange din e-postadress")]
[StringLength(50, MinimumLength = 6)]
[Display(Name = "Din E-postadress")]
[RegularExpression(@"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$", ErrorMessage = "Felaktig e-postadress")]
public string Epost { get; set; }
[Required(ErrorMessage="Du måste ange hur många år du är")]
[Range(8, 99, ErrorMessage = "Din ålder måste vara mellan 8 och 99 år")]
[Display(Name = "Ålder")]
public int Alder { get; set; }
[Display(Name = "Registrerad")]
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:yyyy-MM-d}")]
[DataType(DataType.DateTime)]
public DateTime StartDatum { get; set; }
[StringLength(80, MinimumLength = 3, ErrorMessage = "Bildens namn måste vara mellan 3 och 80 tecken")]
public string Visningsbild { get; set; }
public virtual ICollection<PersonSport> PersonSporter { get; set; }
}
}

20
Models/PersonSport.cs Normal file
View File

@@ -0,0 +1,20 @@
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace PersonSport.Models {
public class PersonSport {
[Key, Column(Order = 1)]
public int PersonId { get; set; }
[Key, Column(Order = 2)]
public int SportId { get; set; }
[DataType(DataType.Date)]
public DateTime StartDatum { get; set; }
public virtual Person Person { get; set; }
public virtual Sport Sport { get; set; }
}
}

34
Models/Sport.cs Normal file
View File

@@ -0,0 +1,34 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace PersonSport.Models {
public class Sport {
[Required]
public int SportId { get; set; }
[Required(ErrorMessage="Du måste ange sportens namn")]
[StringLength(50, MinimumLength = 3, ErrorMessage = "Namnet måste vara mellan 3 och 50 tecken")]
[Display(Name = "Namn på sporten")]
public string SportNamn { get; set; }
[Required(ErrorMessage = "Du måste välja en bild för webbsidan")]
[StringLength(60, MinimumLength = 3, ErrorMessage = "Bildens namn måste vara mellan 3 och 60 tecken")]
[Display(Name = "Stor bakgrundsbild")]
public string Bakgrundsbild { get; set; }
[Required(ErrorMessage = "Du måste skriva en ingresstext")]
[StringLength(200, MinimumLength = 10, ErrorMessage = "Din ingress-text måste vara mellan 10 och 200 tecken")]
[Display(Name = "Ingresstext")]
public string Ingress { get; set; }
[StringLength(2000)]
[Display(Name = "Detaljerad text")]
public string DetaljText { get; set; }
[StringLength(200)]
[Display(Name = "Träningstider")]
public string Traningstider { get; set; }
public virtual ICollection<PersonSport> PersonSporter { get; set; }
}
}

23
PersonSport.csproj Normal file
View File

@@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="EntityFramework" Version="6.4.4" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.11" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="5.0.11" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.11" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="5.0.11">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="5.0.2" />
</ItemGroup>
<ItemGroup>
<Folder Include="Data\" />
</ItemGroup>
</Project>

25
PersonSport.sln Normal file
View File

@@ -0,0 +1,25 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31702.278
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PersonSport", "PersonSport.csproj", "{ECAC1C40-BD93-408C-8820-FAC230779619}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{ECAC1C40-BD93-408C-8820-FAC230779619}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{ECAC1C40-BD93-408C-8820-FAC230779619}.Debug|Any CPU.Build.0 = Debug|Any CPU
{ECAC1C40-BD93-408C-8820-FAC230779619}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ECAC1C40-BD93-408C-8820-FAC230779619}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {557145B7-E0D6-41AA-A112-BC4FA6D775CE}
EndGlobalSection
EndGlobal

16
Program.cs Normal file
View File

@@ -0,0 +1,16 @@
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
namespace PersonSport {
public class Program {
public static void Main(string[] args) {
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder => {
webBuilder.UseStartup<Startup>();
});
}
}

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
This file is used by the publish/package process of your Web project. You can customize the behavior of this process
by editing this MSBuild file. In order to learn more about this please visit https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<WebPublishMethod>MSDeploy</WebPublishMethod>
<ResourceId>/subscriptions/04503b37-5476-437e-91f0-db13b29af319/resourceGroups/PersonSport20211012092753ResourceGroup/providers/Microsoft.Web/sites/sportpalatset</ResourceId>
<ResourceGroup>PersonSport20211012092753ResourceGroup</ResourceGroup>
<PublishProvider>AzureWebSite</PublishProvider>
<LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
<LastUsedPlatform>Any CPU</LastUsedPlatform>
<SiteUrlToLaunchAfterPublish>https://sportpalatset.azurewebsites.net</SiteUrlToLaunchAfterPublish>
<LaunchSiteAfterPublish>True</LaunchSiteAfterPublish>
<ExcludeApp_Data>False</ExcludeApp_Data>
<ProjectGuid>ecac1c40-bd93-408c-8820-fac230779619</ProjectGuid>
<MSDeployServiceURL>sportpalatset.scm.azurewebsites.net:443</MSDeployServiceURL>
<DeployIisAppPath>sportpalatset</DeployIisAppPath>
<RemoteSitePhysicalPath />
<SkipExtraFilesOnServer>True</SkipExtraFilesOnServer>
<MSDeployPublishMethod>WMSVC</MSDeployPublishMethod>
<EnableMSDeployBackup>True</EnableMSDeployBackup>
<EnableMsDeployAppOffline>True</EnableMsDeployAppOffline>
<UserName>$sportpalatset</UserName>
<_SavePWD>True</_SavePWD>
<_DestinationType>AzureWebSite</_DestinationType>
<InstallAspNetCoreSiteExtension>False</InstallAspNetCoreSiteExtension>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,28 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:46988",
"sslPort": 44370
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"PersonSport": {
"commandName": "Project",
"dotnetRunMessages": "true",
"launchBrowser": true,
"applicationUrl": "https://localhost:5001;http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

View File

@@ -0,0 +1,10 @@
{
"dependencies": {
"mssql1": {
"type": "mssql",
"connectionId": "",
"suggestion": "true",
"ignored": "true"
}
}
}

0
README.md Normal file
View File

54
Startup.cs Normal file
View File

@@ -0,0 +1,54 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.AspNetCore.Authentication.Cookies; // För inloggning med Claims
namespace PersonSport {
public class Startup {
public Startup(IConfiguration configuration) {
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services) {
services.AddControllersWithViews();
// Lägg till stöd för loginfunktionen. OBS LoginPath!
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options => { options.LoginPath = "/Login/Index/"; });
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
if (env.IsDevelopment()) {
app.UseDeveloperExceptionPage();
}
else {
app.UseExceptionHandler("/Start/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
// Gör att sidan använder sig av autentisering med Claims
app.UseAuthentication();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
// Sidan ska även använda sig av Authorization
app.UseAuthorization();
app.UseEndpoints(endpoints => {
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Start}/{action=Index}/{id?}");
});
}
}
}

6
TODO.txt Normal file
View File

@@ -0,0 +1,6 @@
https://sportpalatset.azurewebsites.net/
- Pluggen WebDeveloper till FF för att kolla alla sidors syntax
- URL-rewrite på Details så att det blir /karate och inte /1
- Kolla validator på allt

View File

@@ -0,0 +1,27 @@
@model Admin
@{
ViewData["Title"] = "Lägg till administratör";
}
<h2 class="text-center mt-3 mb-4">@ViewData["Title"]</h2>
<div class="container">
<form action="/Login/CreateAdmin" method="post">
<div class="form-group">
<label asp-for="@Model.Username" class="control-label"></label>
<input type="text" class="form-control" asp-for="Username" tabindex="1" placeholder="Username">
<span asp-validation-for="Username" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="@Model.Password" class="control-label"></label>
<input type="password" class="form-control" asp-for="Password" tabindex="2" placeholder="Password">
<span asp-validation-for="Password" class="text-danger"></span>
</div>
<button type="submit" class="btn btn-primary">Skapa admin</button>
</form>
<p>@ViewBag.error</p>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

View File

@@ -0,0 +1,30 @@
@model Admin
@{
ViewData["Title"] = "Editera administratör";
}
<h2 class="text-center mt-3 mb-4">@ViewData["Title"]</h2>
<div class="container">
<form action="/Login/EditAdmin" method="post">
<input type="hidden" asp-for="AdminId" value="@Model.AdminId" />
<div class="form-group">
<label asp-for="Username" class="control-label"></label>
<input type="text" class="form-control" asp-for="Username" tabindex="1">
<span asp-validation-for="Username" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="@Model.Password" class="control-label"></label>
<input type="password" class="form-control" asp-for="Password" tabindex="2">
<span asp-validation-for="Password" class="text-danger"></span>
</div>
<button type="submit" class="btn btn-primary mb-5">Editera admin</button>
</form>
<p>@ViewBag.error</p>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

29
Views/Login/Index.cshtml Normal file
View File

@@ -0,0 +1,29 @@
@model Admin
@{
ViewData["Title"] = "Logga in";
}
<h2 class="text-center mt-3 mb-4">@ViewData["Title"]</h2>
<div class="container mb-5">
<div class="myLoginForm card p-4">
<form action="~/Login/CheckLogin" method="post">
<div class="form-group">
<label asp-for="@Model.Username" class="control-label"></label>
<input type="text" class="form-control" asp-for="Username" tabindex="1" placeholder="Username">
<span asp-validation-for="Username" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="@Model.Password" class="control-label"></label>
<input type="password" class="form-control" asp-for="Password" tabindex="2" placeholder="Password">
<span asp-validation-for="Password" class="text-danger"></span>
</div>
<button type="submit" class="btn btn-primary">Logga in</button>
</form>
<p class="text-danger mt-3">@TempData["msg"]</p>
<p class="text-primary mt-3" ">@TempData["hint"]</p>
</div>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

View File

@@ -0,0 +1,55 @@
@model List<Admin>
@{
ViewData["Title"] = "Här finns alla administratörer";
}
<h2 class="text-center mt-3 mb-4">@ViewData["Title"]</h2>
<p class="lead text-center">Det är bra om alla i receptionen är registrerade som administratör.</p>
@if (TempData.ContainsKey("Meddelande")) {
<div class="alert alert-danger alert-dismissible">
<button type="button" class="close" data-dismiss="alert">&times;</button>
<strong>Skapades inte!</strong> @TempData["Meddelande"]
</div>
}
else @if (TempData.ContainsKey("TooFewAdmins")) {
<div class="alert alert-danger alert-dismissible">
<button type="button" class="close" data-dismiss="alert">&times;</button>
<strong>Togs inte bort!</strong> @TempData["TooFewAdmins"]
</div>
}
<a asp-action="CreateAdmin" asp-controller="Login" class="btn btn-success mb-3">Skapa ny administratör</a>
<div class="container mb-5">
@if (Model.Count() >= 1) {
<table class="table">
<thead>
<tr>
<th>Administratör</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var admin in Model) {
<tr>
<td>@admin.Username</td>
<td>
<a asp-action="DeleteAdmin" asp-controller="Login" asp-route-Id="@admin.AdminId">Ta bort</a> |
<a asp-action="EditAdmin" asp-controller="Login" asp-route-Id="@admin.AdminId">Editera</a>
</td>
</tr>
}
</tbody>
</table>
}
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

View File

@@ -0,0 +1,38 @@
@model Person
@{
ViewData["Title"] = "Lägg till ny medlem";
}
<h2 class="text-center mt-3 mb-4">@ViewData["Title"]</h2>
<div class="container mb-5">
<form action="Create" method="post" enctype="multipart/form-data">
<div class="form-group">
<label asp-for="@Model.PersonNamn" class="control-label"></label>
<input type="text" class="form-control" asp-for="PersonNamn" tabindex="1" placeholder="Ditt namn">
<span asp-validation-for="PersonNamn" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="@Model.Epost" class="control-label"></label>
<input type="text" class="form-control" asp-for="Epost" tabindex="2" placeholder="ditt.namn@adress.com">
<span asp-validation-for="Epost" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="@Model.Alder" class="control-label"></label>
<input type="number" class="form-control" asp-for="Alder" tabindex="3" placeholder="Ange din ålder">
<span asp-validation-for="Alder" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="@Model.Visningsbild" class="control-label"></label>
<input type="file" class="form-control" asp-for="Visningsbild" tabindex="4">
<span asp-validation-for="Visningsbild" class="text-danger"></span>
</div>
<button type="submit" class="btn btn-primary mt-3">@ViewData["Title"]</button>
</form>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

36
Views/Person/Edit.cshtml Normal file
View File

@@ -0,0 +1,36 @@
@model Person
@{
ViewData["Title"] = "Editera en person";
}
<h2 class="text-center mt-3 mb-4">@ViewData["Title"]</h2>
<div class="container">
<form action="Edit" method="post" enctype="multipart/form-data">
<input type="hidden" asp-for="PersonId" value="@Model.PersonId" />
<div class="form-group">
<label>Namn</label>
<input type="text" class="form-control" asp-for="PersonNamn" tabindex="1">
<span asp-validation-for="PersonNamn" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Epost" class="control-label"></label>
<input type="text" class="form-control" asp-for="Epost" tabindex="2" placeholder="ditt.namn@adress.com">
<span asp-validation-for="Epost" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Alder" class="control-label"></label>
<input type="number" class="form-control" asp-for="Alder" tabindex="3" placeholder="Ange din ålder">
<span asp-validation-for="Alder" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="@Model.Visningsbild" class="control-label"></label>
<input type="file" class="form-control" asp-for="Visningsbild" tabindex="4">
<span asp-validation-for="Visningsbild" class="text-danger"></span>
</div>
<button type="submit" class="btn btn-primary">Spara ändringar</button>
</form>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

77
Views/Person/Index.cshtml Normal file
View File

@@ -0,0 +1,77 @@
@model List<Person>
@{
ViewData["Title"] = "Mina medlemmar";
}
@if (TempData.ContainsKey("MeddelandeSuccess")) {
<div class="alert alert-success alert-dismissible">
<button type="button" class="close" data-dismiss="alert">&times;</button>
<strong>Allt klart!</strong> @TempData["MeddelandeSuccess"]
</div>
}
else if (TempData.ContainsKey("MeddelandeFail")) {
<div class="alert alert-danger alert-dismissible">
<button type="button" class="close" data-dismiss="alert">&times;</button>
<strong>Något gick fel.</strong> @TempData["MeddelandeFail"]
</div>
}
<h2 class="text-center mt-3 mb-4">@ViewData["Title"]</h2>
<div class="container">
<div class="row">
<div class="col-md-8">
<a href="/Person/Create" class="btn btn-success mb-5">Skapa ny medlem</a>
</div>
<div class="col-md-4">
<form asp-action="Search" method="post">
<div class="form-group">
<label class="control-label">
<input name="search" id="search" class="form-control" tabindex="1" placeholder="Namn eller E-post" />
</label>
<input type="submit" value="Sök" class="btn btn-primary" />
</div>
</form>
</div>
</div>
</div>
<div class="container mb-5">
@if (Model.Count() >= 0) {
<table class="table">
<thead>
<tr>
<th>@Html.ActionLink("Id", "Index", null, new { sortOrder = "PersonId" })</th>
<th>@Html.ActionLink("Namn", "Index", null, new { sortOrder = "PersonNamn" })</th>
<th>@Html.ActionLink("E-post", "Index", null, new { sortOrder = "Epost" })</th>
<th>@Html.ActionLink("Ålder", "Index", null, new { sortOrder = "Alder" })</th>
<th>@Html.ActionLink("Registrerad", "Index", null, new { sortOrder = "StartDatum" })</th>
<th>Visningsbild</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var person in Model) {
<tr>
<td>@person.PersonId</td>
<td>@person.PersonNamn</td>
<td>@person.Epost</td>
<td>@person.Alder</td>
<td>@person.StartDatum</td>
<td><img src="~/images/userphoto/@person.Visningsbild" alt="@person.PersonNamn" class="visningsbild" /></td>
<td>
<a asp-action="Delete" asp-controller="Person" asp-route-Id="@person.PersonId">Ta bort</a> |
<a asp-action="Edit" asp-controller="Person" asp-route-Id="@person.PersonId">Editera</a>
</td>
</tr>
}
</tbody>
</table>
}
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

View File

@@ -0,0 +1,65 @@
@model List<Person>
@{
ViewData["Title"] = "Sökresultat";
}
<h2 class="text-center mt-3 mb-4">@ViewData["Title"]</h2>
<div class="container">
<div class="row">
<div class="col-md-8">
<a href="/Person/Create" class="btn btn-success mb-5">Skapa ny medlem</a>
</div>
<div class="col-md-4">
<form asp-action="Search" method="post">
<div class="form-group">
<label class="control-label">
<input name="search" id="search" class="form-control" tabindex="1" placeholder="Namn eller E-post" />
</label>
<input type="submit" value="Sök" class="btn btn-primary" />
</div>
</form>
</div>
</div>
</div>
<div class="container mb-5">
@if (Model.Count() >= 0) {
<table class="table">
<thead>
<tr>
<th>Id</th>
<th>Namn</th>
<th>Epost</th>
<th>Alder</th>
<th>Registrerad</th>
<th>Visningsbild</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var person in Model) {
<tr>
<td>@person.PersonId</td>
<td>@person.PersonNamn</td>
<td>@person.Epost</td>
<td>@person.Alder</td>
<td>@person.StartDatum</td>
<td><img src="~/images/userphoto/@person.Visningsbild" alt="@person.PersonNamn" class="visningsbild" /></td>
<td>
<a asp-action="Delete" asp-controller="Person" asp-route-Id="@person.PersonId">Ta bort</a> |
<a asp-action="Edit" asp-controller="Person" asp-route-Id="@person.PersonId">Editera</a>
</td>
</tr>
}
</tbody>
</table>
}
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

View File

@@ -0,0 +1,28 @@
@model List<Person>
@{
ViewData["Title"] = "Steg 1: Välj person";
}
<div class="container mb-5">
<h2 class="text-center mt-3 mb-4">@ViewData["Title"]</h2>
<form asp-action="DerollSport" method="post">
<div class="row">
<div class="col">
<div class="input-group mb-3">
<select name="PersonId" class="custom-select" tabindex="1">
<option selected>Välj medlem</option>
@foreach (var person in Model) {
<option value="@person.PersonId">@person.PersonNamn</option>
}
</select>
</div>
</div>
</div>
<button type="submit" class="btn btn-primary mt-3">Vidare till nästa steg</button>
</form>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

View File

@@ -0,0 +1,30 @@
@model List<Person>
@{
ViewData["Title"] = "...och vilken sport ska denne sluta med?";
}
<div class="container mb-5">
<h2 class="text-center mt-3 mb-4">@ViewData["Title"]</h2>
<form asp-action="DerollDone" method="post">
<input type="hidden" name="PersonId" value="@ViewBag.PersonId" />
<div class="col">
<div class="input-group mb-3">
<select name="SportId" class="custom-select" tabindex="1">
<option selected>Välj sport</option>
@foreach (var sport in ViewBag.SportForValdPerson) {
<option value="@sport.SportId">@sport.SportNamn</option>
}
</select>
</div>
</div>
<button type="submit" class="btn btn-primary mt-3">Avregistrera från aktivitet</button>
</form>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

View File

@@ -0,0 +1,40 @@
@model IEnumerable<Person>
@{
ViewData["Title"] = "Registrera medlem i aktivitet";
}
<h2 class="text-center mt-3 mb-4">@ViewData["Title"]</h2>
<div class="container mb-5">
<h4 class="mt-4 mb-4">Vem ska börja träna vad?</h4>
<form asp-action="Enroll" method="post">
<div class="row">
<div class="col">
<div class="input-group mb-3">
<select name="Namn" class="custom-select" tabindex="1">
<option selected>Välj medlem</option>
@foreach (var namn in ViewBag.personer) {
<option value="@namn.PersonId">@namn.PersonNamn</option>
}
</select>
</div>
</div>
<div class="col">
<div class="input-group mb-3">
<select name="Sport" class="custom-select" tabindex="2">
<option selected>Välj sport</option>
@foreach (var sport in ViewBag.sporter) {
<option value="@sport.SportId">@sport.SportNamn</option>
}
</select>
</div>
</div>
</div>
<button type="submit" class="btn btn-primary mt-3">@ViewData["Title"]</button>
</form>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

View File

@@ -0,0 +1,57 @@
@{
ViewData["Title"] = "Klicka på en sport för att se vilka som utövar den";
}
<h2 class="text-center mt-3 mb-4">@ViewData["Title"]</h2>
@if (TempData.ContainsKey("MeddelandeSuccess")) {
<div class="alert alert-success alert-dismissible">
<button type="button" class="close" data-dismiss="alert">&times;</button>
<strong>Allt klart!</strong> @TempData["MeddelandeSuccess"]
</div>
}
else if (TempData.ContainsKey("MeddelandeFail")) {
<div class="alert alert-danger alert-dismissible">
<button type="button" class="close" data-dismiss="alert">&times;</button>
<strong>Något gick fel.</strong> @TempData["MeddelandeFail"]
</div>
}
<div class="container mb-5">
<div class="text-center mb-3">
@foreach (var sp in ViewBag.AllaSporter) {
<span class="btn btn-light text-black-50">
@Html.ActionLink((string)sp.SportNamn, "Index", new { sportens_id = sp.SportId })
</span>
}
</div>
<h2 class="text-center">@ViewBag.SportNamn</h2>
@if (ViewBag.PersonerIValdSport != null && ViewBag.PersonerIValdSport.Count >= 1) {
<table class="table table-hover">
<thead>
<tr class="d-flex">
<th class="col-2">Person-Id</th>
<th class="col-6">Personens namn</th>
<th class="col-4">Startade</th>
</tr>
</thead>
<tbody>
@foreach (var item in ViewBag.PersonerIValdSport) {
<tr class="d-flex">
<td class="col-2">@item.PersonId</td>
<td class="col-6">@item.PersonNamn</td>
<td class="col-4">@item.StartDatum</td>
</tr>
}
</tbody>
</table>
}
else {
<p class="lead text-center mt-5 mb-5">Det finns ingen som utövar det där...</p>
}
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

25
Views/Shared/Error.cshtml Normal file
View File

@@ -0,0 +1,25 @@
@model ErrorViewModel
@{
ViewData["Title"] = "Error";
}
<h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2>
@if (Model.ShowRequestId)
{
<p>
<strong>Request ID:</strong> <code>@Model.RequestId</code>
</p>
}
<h3>Development Mode</h3>
<p>
Swapping to <strong>Development</strong> environment will display more detailed information about the error that occurred.
</p>
<p>
<strong>The Development environment shouldn't be enabled for deployed applications.</strong>
It can result in displaying sensitive information from exceptions to end users.
For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
and restarting the app.
</p>

View File

@@ -0,0 +1,28 @@
<div class="row myFooter pt-5 pb-5">
<div class="col-sm">
<h5>&copy; 2021 - SportPalatset</h5>
<p class="m-0">Storgatan 1</p>
<p class="m-0">432 10 Staden</p>
<p class="m-0">Tel. 0123-10 20 30</p>
<p class="m-0">Fax. 0123-30 40 50</p>
<p class="m-0"><a href="mailto:info@sportpalatset.se">info@sportpalatset.se</a></p>
</div>
<div class="col-sm">
<h5>Länkar</h5>
<a href="/Person/Create" class="mb-1">Bli medlem</a><br />
<a href="/Sport/Utbud" class="mb-1">Utbudet</a><br />
<a href="/Start/Priser" class="mb-1">Priser</a><br />
<a href="/Start/Kurser" class="mb-1">Kurser</a><br />
<a href="/Start/Receptionen" class="mb-1">Receptionen</a><br />
<a href="/Start/Oppettider" class="mb-1">Öppettider</a><br />
</div>
<div class="col-sm social">
<h5>Sociala medier</h5>
<p class="m-1 mb-4">Hitta oss i våra kanaler! Vi lägger ut nya bilder hela tiden.</p>
<i class="fab fa-facebook-square"></i>
<i class="fab fa-twitter-square"></i>
<i class="fab fa-instagram-square"></i>
<i class="fab fa-tiktok"></i>
</div>
</div>

View File

@@ -0,0 +1,67 @@
<!DOCTYPE html>
<!-- Observera att detta är en skoluppgift och inte något -->
<!-- som används på riktigt. -->
<!-- Sidan är skapad för en kurs på Umeå Universitet av -->
<!-- Christian Ohlsson 2021-10-10 -->
<!-- -------------------------------------------------------- -->
<html lang="en">
<head>
<meta charset="utf-8" />
<!-- Lite meta-element för visning på vanliga webben -->
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="keywords" content="sport, palatset, sportpalatset, staden, yoga, karate, bandy" />
<meta name="description" content="Här kan du träna på många olika sporter och delta i kurser." />
@if (ViewBag.metaAbstract != null) {
<meta name="abstract" content="@ViewBag.metaAbstract" />
}
@if (ViewBag.metaImage != null) {
<meta name="image" content="@ViewBag.metaImage" />
}
<meta name="referrer" content="no-referrer">
<!-- Lite meta-element enligt Social Graph -->
<meta property="og:type" content="website" />
<meta property="og:title" content="SportPalatset - Din träningsanläggning i Staden" />
<meta property="og:description" content="Här kan du träna på många olika sporter och delta i kurser." />
<meta property="og:url" content="https://sportpalatset.se/" />
<meta property="og:site_name" content="SportPalatset" />
<meta property="og:image" content="https://sportpalatset.se/images/Logo.png" />
<!-- Lite meta-element för Twitterläsare -->
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:creator" content="SportPalatset" />
<meta name="twitter:image" content="https://sportpalatset.se/images/Logo.png" />
<meta name="twitter:site" content="SportPalatset" />
<title>@ViewData["Title"] - PersonSport</title>
<link rel='stylesheet' href='https://fonts.googleapis.com/css2?family=Raleway:wght@300&family=Oswald&display=swap'>
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/css/all.css" />
<link rel="stylesheet" href="~/css/site.css" />
<link rel="stylesheet" href="~/css/crille.css" />
</head>
<body>
<header>
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-0">
<partial name="_Menu" />
</nav>
</header>
<div class="container">
<main role="main" class="pb-3">
@RenderBody()
</main>
</div>
<footer class="border-top">
<div class="container-fluid bg-dark">
<div class="container">
<partial name="_Footer" />
</div>
</div>
</footer>
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
<script src="~/js/site.js" asp-append-version="true"></script>
@await RenderSectionAsync("Scripts", required: false)
</body>
</html>

54
Views/Shared/_Menu.cshtml Normal file
View File

@@ -0,0 +1,54 @@
<div class="container">
<a class="navbar-brand" asp-area="" asp-controller="Start" asp-action="Index">
<img src="/images/Logo.png" height="80" alt="Logo" class="minLogotyp mr-1">
</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 justify-content-between">
<ul class="navbar-nav flex-grow-1">
<li class="nav-item">
<a class="nav-link text-dark btn btn-light mr-2" asp-area="" asp-controller="Sport" asp-action="Utbud">Utbud</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark btn btn-light mr-2" asp-area="" asp-controller="Start" asp-action="Priser">Priser</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark btn btn-light mr-2" asp-area="" asp-controller="Start" asp-action="Kurser">Kurser</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark btn btn-light mr-2" asp-area="" asp-controller="Start" asp-action="Receptionen">Receptionen</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark btn btn-light mr-2" asp-area="" asp-controller="Start" asp-action="Oppettider">Öppettider</a>
</li>
</ul>
@if (Context.User.Identity.IsAuthenticated) {
<div class="dropdown show">
<a class="btn bg-info dropdown-toggle" href="#" role="button" id="dropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Hantera
</a>
<div class="dropdown-menu" aria-labelledby="dropdownMenuLink">
<a class="dropdown-item" asp-area="" asp-controller="Person" asp-action="Index">Medlemmar</a>
<a class="dropdown-item" asp-area="" asp-controller="Sport" asp-action="Index">Sporter</a>
<a class="dropdown-item" asp-area="" asp-controller="PersonSport" asp-action="Enroll">Registrera träning</a>
<a class="dropdown-item" asp-area="" asp-controller="PersonSport" asp-action="Deroll">Sluta träning</a>
<a class="dropdown-item" asp-area="" asp-controller="PersonSport" asp-action="Index">Vem utövar vad</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" asp-area="" asp-controller="Login" asp-action="ShowAdmins">Administratörer</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" asp-area="" asp-controller="Login" asp-action="Logout">Logga ut</a>
</div>
</div>
}
else {
<ul class="navbar-nav mr-0">
<li class="nav-item">
<a class="nav-link text-dark btn btn-light" asp-area="" asp-controller="Login" asp-action="Index">Login</a>
</li>
</ul>
}
</div>
</div>

View File

@@ -0,0 +1,2 @@
<script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>

44
Views/Sport/Create.cshtml Normal file
View File

@@ -0,0 +1,44 @@
@model Sport
@{
ViewData["Title"] = "Lägg till sport";
}
<div class="container mb-5">
<h2 class="text-center mt-3 mb-4">@ViewData["Title"]</h2>
<form action="Create" method="post" enctype="multipart/form-data">
<div class="form-group">
<label asp-for="@Model.SportNamn" class="control-label"></label>
<input type="text" class="form-control" asp-for="SportNamn" tabindex="1" placeholder="Sportens namn">
<span asp-validation-for="SportNamn" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="@Model.Ingress" class="control-label"></label>
<input type="text" class="form-control" asp-for="Ingress" tabindex="2" placeholder="Ingresstext">
<span asp-validation-for="Ingress" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="@Model.DetaljText" class="control-label"></label>
<textarea class="form-control" asp-for="DetaljText" tabindex="3" placeholder="Detaljerad text"></textarea>
<span asp-validation-for="DetaljText" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="@Model.Traningstider" class="control-label"></label>
<input type="text" class="form-control" asp-for="Traningstider" tabindex="4" placeholder="Träningstider">
<span asp-validation-for="Traningstider" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="@Model.Bakgrundsbild" class="control-label"></label>
<input type="file" class="form-control" asp-for="Bakgrundsbild" tabindex="5">
<span asp-validation-for="Bakgrundsbild" class="text-danger"></span>
</div>
<button type="submit" class="btn btn-primary">Lägg till</button>
</form>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

View File

@@ -0,0 +1,27 @@
@model Sport
@{
ViewData["Title"] = "Mina Sporter";
}
<div class="container mt-2 mb-5">
<img src="~/images/sport/@Model.Bakgrundsbild" alt="@Model.SportNamn" class="img-fluid maxad mb-5" />
<h2>@Model.SportNamn</h2>
<p class="lead font-weight-bold">@Model.Ingress</p>
<p>@Model.DetaljText</p>
<h2>Träningstider</h2>
<p>@Model.Traningstider</p>
@if (Context.User.Identity.IsAuthenticated) {
<a href="/Sport" class="btn btn-success mt-3">Tillbaka till sporterna</a>
}
else {
<a href="/Sport/Utbud" class="btn btn-success mt-3">Tillbaka till utbudet</a>
}
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

40
Views/Sport/Edit.cshtml Normal file
View File

@@ -0,0 +1,40 @@
@model Sport
@{
ViewData["Title"] = "Editera en Sport";
}
<h2 class="text-center mt-3 mb-4">@ViewData["Title"]</h2>
<form action="Edit" method="post" enctype="multipart/form-data">
<input type="hidden" asp-for="SportId" value="@Model.SportId" />
<div class="form-group">
<label>SportNamn</label>
<input type="text" class="form-control" asp-for="SportNamn" tabindex="1">
<span asp-validation-for="SportNamn" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Ingress" class="control-label"></label>
<input type="text" class="form-control" asp-for="Ingress" value="@Model.Ingress">
<span asp-validation-for="Ingress" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="DetaljText" class="control-label"></label>
<textarea class="form-control" asp-for="DetaljText" tabindex="2">@Model.DetaljText</textarea>
<span asp-validation-for="DetaljText" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Traningstider" class="control-label"></label>
<input type="text" class="form-control" asp-for="Traningstider" tabindex="3">
<span asp-validation-for="Traningstider" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="@Model.Bakgrundsbild" class="control-label"></label>
<input type="file" class="form-control" asp-for="Bakgrundsbild" tabindex="4">
<span asp-validation-for="Bakgrundsbild" class="text-danger"></span>
</div>
<button type="submit" class="btn btn-primary">Spara ändringar</button>
</form>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

58
Views/Sport/Index.cshtml Normal file
View File

@@ -0,0 +1,58 @@
@model List<Sport>
@{
ViewData["Title"] = "Detta finns på SportPalatset";
}
<h2 class="text-center mt-3 mb-4">@ViewData["Title"]</h2>
<a href="/Sport/Create" class="btn btn-success mb-5">Skapa ny Sport</a>
@if (TempData.ContainsKey("MeddelandeSuccess")) {
<div class="alert alert-success alert-dismissible">
<button type="button" class="close" data-dismiss="alert">&times;</button>
<strong>Allt klart!</strong> @TempData["MeddelandeSuccess"]
</div>
}
else if (TempData.ContainsKey("MeddelandeFail")) {
<div class="alert alert-danger alert-dismissible">
<button type="button" class="close" data-dismiss="alert">&times;</button>
<strong>Något gick fel.</strong> @TempData["MeddelandeFail"]
</div>
}
<div class="container">
@if (Model.Count() >= 1) {
<table class="table">
<thead>
<tr>
<th>Id</th>
<th>SportNamn</th>
<th>Traningstider</th>
<th>Bild</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var sport in Model) {
<tr>
<td>@sport.SportId</td>
<td>@sport.SportNamn</td>
<td>@sport.Traningstider</td>
<td><img src="~/images/sport/@sport.Bakgrundsbild" alt="@sport.SportNamn" class="visningsbild" /></td>
<td>
<a asp-action="Delete" asp-controller="Sport" asp-route-Id="@sport.SportId">Ta bort</a> |
<a asp-action="Edit" asp-controller="Sport" asp-route-Id="@sport.SportId">Editera</a> |
<a asp-action="Details" asp-controller="Sport" asp-route-Id="@sport.SportId">Detaljer</a>
</td>
</tr>
}
</tbody>
</table>
}
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

28
Views/Sport/Utbud.cshtml Normal file
View File

@@ -0,0 +1,28 @@
@model List<Sport>
@{
ViewData["Title"] = "Detta finns på SportPalatset";
}
<h2 class="text-center mt-3 mb-4">@ViewData["Title"]</h2>
<p class="lead text-center font-weight-bold mt-1 mb-4">Hos oss hittar du allt för din träning. Det spelar ingen roll om du är elitsatsande eller motionär.</p>
<div class="container">
@foreach (var sport in Model) {
<a href="/Sport/Details/@sport.SportId">
<div class="col-sm mt-3">
<div class="card bg-dark text-white">
<img class="card-img" src="~/images/sport/@sport.Bakgrundsbild" alt="@sport.SportNamn">
<div class="card-img-overlay myCard">
<h3 class="card-title">@sport.SportNamn</h3>
<p class="card-text mt-5">@sport.Ingress</p>
</div>
</div>
</div>
</a>
}
</div>
<p class="lead mt-5 mb-5 text-center font-weight-bold">Kom du ända hit utan att hitta något? Scrolla tillbaka så hittar du något kul för dig!</p>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

53
Views/Start/Index.cshtml Normal file
View File

@@ -0,0 +1,53 @@
@{
ViewData["Title"] = "Välkommen till SportPalatset";
}
@if (TempData.ContainsKey("MeddelandeSuccess")) {
<div class="alert alert-success alert-dismissible">
<button type="button" class="close" data-dismiss="alert">&times;</button>
<strong>Allt klart!</strong> @TempData["MeddelandeSuccess"]
</div>
}
else if (TempData.ContainsKey("MeddelandeFail")) {
<div class="alert alert-danger alert-dismissible">
<button type="button" class="close" data-dismiss="alert">&times;</button>
<strong>Något gick fel.</strong> @TempData["MeddelandeFail"]
</div>
}
<div class="container mb-5">
<h2 class="text-center mt-3 mb-4">@ViewData["Title"]</h2>
<p class="lead text-center">
Vi har många olika sporthallar som ger dig precis den träning som du letar efter.
Kom in till oss och låt ditt nya liv börja!
</p>
<img src="~/images/arenan.jpg" alt="Arenan" class="maxad" />
<a href="/Person/Create" class="registrera mb-5">Registrera gratis medlemskap</a>
<h4 class="mt-4">Vad är SportPalatset?</h4>
<p class="lead font-weight-bold">
Kul att du frågar! Jag ska berätta!
</p>
<p>
SportPalatset är en kommunal träningsanläggning här i Staden. Vi erbjuder träning
och friskvård till kommunens alla invånare; unga i kropp eller sinne!
Vår kunniga personal hjälper dig gärna på vägen för att du skall nå precis
så långt som du vill. Hos oss finns inga måsten, bara kul träning!
</p>
<h4 class="mt-5">Vad kan jag träna hos er?</h4>
<p>
Vi har flera olika sporter och kurser som du kan vara med på. Registrera dig för ett
gratis medlemsskap här ovanför så får du tillgång till vårt månadsbrev som kommer ut varje månad.
Där får du tips om allt som händer hos oss och ibland med lite djupdykning på olika
träningsformer. Vi kallar det för "Månadens fokusträning".
</p>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

80
Views/Start/Kurser.cshtml Normal file
View File

@@ -0,0 +1,80 @@
@{
ViewData["Title"] = "Häng med på våra kurser";
}
<div class="container mb-5">
<h2 class="text-center mt-3 mb-4">@ViewData["Title"]</h2>
<p class="lead text-center font-weight-bold">Inte sugen på att börja träna något nytt, men vill gärna testa på? Vi har kursen för dig!</p>
<img src="~/images/kurser.jpg" alt="Arenan" class="maxad" />
<p class="lead text-center mt-5 mb-3">
Våra kurser är fasta paket där du under några enstaka gånger i mindre grupper tränar för att lära dig mer.
Efter en avslutad kurs kommer du att kunna stå på dina egna ben!
</p>
<div class="row">
<div class="col-sm mt-3">
<div class="card bg-dark text-white">
<img class="card-img" src="/images/kampsport.jpg">
<div class="card-img-overlay myKursCard">
<h3 class="card-title text-uppercase">Kampsport</h3>
</div>
</div>
</div>
<div class="col-sm mt-3">
<div class="card bg-dark text-white">
<img class="card-img" src="/images/crossfit.jpg">
<div class="card-img-overlay myKursCard">
<h3 class="card-title text-uppercase">Crossfit</h3>
</div>
</div>
</div>
<div class="col-sm mt-3">
<div class="card bg-dark text-white">
<img class="card-img" src="/images/kids.jpg">
<div class="card-img-overlay myKursCard">
<h3 class="card-title text-uppercase">Funky Kidz</h3>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-sm mt-3">
<div class="card bg-dark text-white">
<img class="card-img" src="/images/vardagsstark.jpg">
<div class="card-img-overlay myKursCard">
<h3 class="card-title text-uppercase">Vardagsstark</h3>
</div>
</div>
</div>
<div class="col-sm mt-3">
<div class="card bg-dark text-white">
<img class="card-img" src="/images/yoga.jpg">
<div class="card-img-overlay myKursCard">
<h3 class="card-title text-uppercase">Yoga</h3>
</div>
</div>
</div>
<div class="col-sm mt-3">
<div class="card bg-dark text-white">
<img class="card-img" src="/images/vikt.jpg">
<div class="card-img-overlay myKursCard">
<h3 class="card-title text-uppercase">Viktminskning</h3>
</div>
</div>
</div>
</div>
<p class="lead text-center mt-5 mb-3 font-weight-bold">
Blev du sugen på att testa på något? Hör av dig till receptionen för starttiden för kursen du gillade.
</p>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

View File

@@ -0,0 +1,141 @@
@{
ViewData["Title"] = "Öppettider";
}
<div class="container">
<h2 class="text-center mt-3 mb-4">@ViewData["Title"]</h2>
<p class="lead text-center font-weight-bold">Om du har ett gymkort är det alltid öppet för dig. Andra öppettider kan du se nedan.</p>
<img src="~/images/oppettider.jpg" alt="Öppettider" class="maxad" />
<h2 class="mt-5">Information om Coronaviruset</h2>
<p class="lead">
Vi följer Folkhälsomyndighetens rekommendationer och arbetar för att du ska kunna fortsätta att träna och
bada i en frisk miljö. Det gör vi bland annat genom att öka städfrekvensen, anpassa våra aktiviteter samt informera
dig som besöker oss om hur du kan hjälpa till att minska risken för smittspridning.
</p>
<p class="m-0"><i class="fas fa-check-square"></i>Följ skyltad hänvisning.</p>
<p class="m-0"><i class="fas fa-check-square"></i>Håll avstånd till andra personer</p>
<p class="m-0"><i class="fas fa-check-square"></i>Var extra noga med handhygien.</p>
<p class="m-0"><i class="fas fa-check-square"></i>Torka av gymutrustning efter användning.</p>
<h3 class="mt-5">Öppettider för SportPalatset</h3>
<p class="lead">
Läs nedan för de olika sektionernas öppettider.
Observera att på <span class="text-danger">röda dagar</span> gäller speciella öppettider.
För dig med gymkort är det dock alltid öppet som vanligt.
</p>
<h3>Kampsporthallen</h3>
<table class="table table-hover">
<thead>
<tr>
<th>Veckodag</th>
<th>Öppettider</th>
</tr>
</thead>
<tbody>
<tr>
<td>Måndag</td>
<td>07.00 - 22.00</td>
</tr>
<tr>
<td>Tisdag</td>
<td>09.00 - 21.00</td>
</tr>
<tr>
<td>Onsdag</td>
<td>07.00 - 22.00</td>
</tr>
<tr>
<td>Torsdag</td>
<td>09.00 - 21.00</td>
</tr>
<tr>
<td>Fredag</td>
<td>07.00 - 22.00</td>
</tr>
<tr>
<td>Lördag</td>
<td>10.00 - 20.00</td>
</tr>
<tr>
<td>Söndag</td>
<td>10.00 - 20.00</td>
</tr>
</tbody>
</table>
<h3>Yogasalen</h3>
<table class="table table-hover">
<thead>
<tr>
<th>Veckodag</th>
<th>Öppettider</th>
</tr>
</thead>
<tbody>
<tr>
<td>Måndag till Fredag</td>
<td>16.00 - 22.00</td>
</tr>
<tr>
<td>Lördag till Söndag</td>
<td>06.00 - 19.00</td>
</tr>
</tbody>
</table>
<h3>Stora hallen</h3>
<p>Stora hallen har endast öppet för bokade tider. Hör av dig till receptionen om du vill boka Stora hallen.</p>
<table class="table table-hover">
<thead>
<tr>
<th>Veckodag</th>
<th>Öppettider</th>
</tr>
</thead>
<tbody>
<tr>
<td>Måndag</td>
<td>09.00 - 20.00</td>
</tr>
<tr>
<td>Tisdag</td>
<td>09.00 - 20.00</td>
</tr>
<tr>
<td>Onsdag</td>
<td>09.00 - 20.00</td>
</tr>
<tr>
<td>Torsdag</td>
<td>09.00 - 20.00</td>
</tr>
<tr>
<td>Fredag</td>
<td>09.00 - 23.00</td>
</tr>
<tr>
<td>Lördag</td>
<td>07.00 - 23.00</td>
</tr>
<tr>
<td>Söndag</td>
<td>07.00 - 20.00</td>
</tr>
</tbody>
</table>
<p class="lead text-center mt-5 mb-5 font-weight-bold">
För andra sporthallars öppettider: Kontakta receptionen.
</p>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

159
Views/Start/Priser.cshtml Normal file
View File

@@ -0,0 +1,159 @@
@{
ViewData["Title"] = "Priser för kort och träningar";
}
<div class="container">
<h2 class="text-center mt-3 mb-4">@ViewData["Title"]</h2>
<p class="lead text-center font-weight-bold">Vi vet att det bara är på SportPalatset som du hittar en träning för just dig och din plånbok.</p>
<img src="~/images/priser.jpg" alt="Arenan" class="maxad" />
<p class="lead text-center mt-3">Vi har mycket bra priser som kommer att få dig att vilja komma lite oftare.</p>
<p class="lead text-center">
Vi ger dig de senaste och bästa träningsmöjligheterna, utbudet är näst intill obegränsat.
Om du har funderingar eller vill boka tid för rådgivning kan du kontakta oss alla dagar i veckan 0123-10 20 30.
</p>
<h3 class="mt-5">Träningskort för gym</h3>
<table class="table table-hover">
<thead>
<tr>
<th>Korttyp</th>
<th>Månadskostnad</th>
<th>Årskort</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<b>Maxade kortet</b><br />
Gruppträning, styrketräning, konditionsträning. Wellness Online. Träna på alla klubbar. Kundkonto med 1000 kr i kredit (Gäller endast autogiro).
</td>
<td>449kr/mån</td>
<td>5199kr</td>
</tr>
<tr>
<td>
<b>Guldkortet</b><br />
Styrketräning, konditionsträning. Träna på alla klubbar inom en region. Kundkonto med 1000 kr i kredit. (Gäller endast autogiro).
</td>
<td>399kr/mån</td>
<td>4699kr</td>
</tr>
<tr>
<td>
<b>Silverkortet</b><br />
Styrketräning, konditionsträning. Träna på vald Family Fitness-klubb. Gästträna för 20 kr på annan valfri SportPalatset-klubb. Kundkonto med 1000 kr i kredit. (Gäller endast autogiro).
</td>
<td>349kr/mån</td>
<td>4199kr</td>
</tr>
<tr>
<td>
<b>Dagskortet</b><br />
Tillgång till all träning vi erbjuder under en dag på valfri SportPalatset-klubb.
</td>
<td></td>
<td>119kr</td>
</tr>
</tbody>
</table>
<h3 class="mt-5">Kampsportskort</h3>
<table class="table table-hover">
<thead>
<tr>
<th>Medlemskap</th>
<th>Årskostnad</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<b>Fighting Guld</b><br />
Kortet ger dig tillträde på alla träningar i alla kampsporter på SportPalatset. Medlemsskapet är personligt.
</td>
<td>800kr/år</td>
</tr>
<tr>
<td>
<b>Fighting Student</b><br />
Kortet ger dig tillträde på alla träningar i alla kampsporter på SportPalatset. Medlemsskapet är personligt. Priset gäller vid uppvisande av giltigt Mecenat-kort.
</td>
<td>550kr/år</td>
</tr>
<tr>
<td>
<b>Fighting Pensionär</b><br />
Kortet ger dig tillträde på alla träningar i alla kampsporter på SportPalatset. Medlemsskapet är personligt och kräver att du visar legitimation och har fyllt 65år.
</td>
<td>550kr/år</td>
</tr>
</tbody>
</table>
<h3 class="mt-5">Seniorkort Zumba</h3>
<table class="table table-hover">
<thead>
<tr>
<th>Medlemsskap</th>
<th>Pris</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<b>Zumba för old-timers</b><br />
Träna exotisk dans med Zumba-inslag för dig över 65. Alla pass anpassas vi att alla kan vara med oavsett vilken nivå du startar från.
</td>
<td>1499kr/år</td>
</tr>
</tbody>
</table>
<h3 class="mt-5">Innebandykortet</h3>
<table class="table table-hover">
<thead>
<tr>
<th>Medlemsskap</th>
<th>Pris</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<b>Kullerbyttan</b><br />
Kortet som ger dig mellan 2år och 7år tillgång till alla träningar i vår innebandyhall. Naturligtvis finns tränare på plats.
</td>
<td>699kr/år</td>
</tr>
<tr>
<td>
<b>Ungdomsmedlemskap</b><br />
Kortet som ger dig mellan 8år och 14år tillgång till alla träningar i vår innebandyhall. Mobilladdare och WiFi finns, så detta blir som hemma för dig.
</td>
<td>1099kr/år</td>
</tr>
<tr>
<td>
<b>Going for Pro</b><br />
Detta är innebandy-kortet för dig som vill satsa lite extra på din innebandy. I detta kort har vi inga mobilladdare och håller WiFi avstängt för att ge dig en så koncentrerad form av innebandyträning som möjligt.
</td>
<td>1499kr/år</td>
</tr>
</tbody>
</table>
<p class=" text-center lead mt-5 mb-5 font-weight-bold">För andra priser kontakta din tränare eller receptionen</p>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

View File

@@ -0,0 +1,53 @@
@model MailViewModel
@{
ViewData["Title"] = "Receptionen";
}
<div class="container mb-5">
<h2 class="text-center mt-3 mb-4">@ViewData["Title"]</h2>
<p class="lead text-center font-weight-bold">Vad kan vi hjälpa till med? Receptionen på SportPalatset är bemannad alla dagar 6.30-23.00</p>
<div class="row">
<div class="col">
<img src="~/images/map.jpg" alt="Hitta hit" />
</div>
<div class="col">
<h4 class="text-dark">Du hittar oss här</h4>
<p class="m-1">Storgatan 1</p>
<p class="m-1">432 10 Staden</p>
<p class="m-1">Tel. 0123-10 20 30</p>
<p class="m-1">Fax. 0123-30 40 50</p>
<p class="m-1">info@sportpalatset.se</p>
<form action="SendMail" method="post">
<fieldset class="form-group mt-4">
<legend class="mt-3 font-weight-bold">Maila till oss</legend>
<div class="form-group">
<label asp-for="@Model.Epost" class="control-label"></label>
<input type="text" class="form-control" asp-for="Epost" tabindex="1" placeholder="Din e-postadress">
<span asp-validation-for="Epost" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="@Model.Subject" class="control-label"></label>
<input type="text" class="form-control" asp-for="Subject" tabindex="2" placeholder="Ärende">
<span asp-validation-for="Subject" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="@Model.Message" class="control-label"></label>
<textarea name="Message" class="form-control" asp-for="Message" tabindex="3" placeholder="Meddelande"></textarea>
<span asp-validation-for="Message" class="text-danger"></span>
</div>
<button type="submit" class="btn btn-primary">Skicka mail</button>
</fieldset>
</form>
</div>
</div>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

View File

@@ -0,0 +1,3 @@
@using PersonSport
@using PersonSport.Models
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

3
Views/_ViewStart.cshtml Normal file
View File

@@ -0,0 +1,3 @@
@{
Layout = "_Layout";
}

10
appsettings.json Normal file
View File

@@ -0,0 +1,10 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}

BIN
wwwroot/LogoOrginal.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

124
wwwroot/css/crille.css Normal file
View File

@@ -0,0 +1,124 @@
@import url('https://fonts.googleapis.com/css2?family=Open+Sans:wght@300&family=Oswald&display=swap');
:root {
--LogoMainColor: #f6be00;
--LogoSecondColor: #4f3e07;
}
body {
font-family: "Open Sans", sans-serif;
margin-bottom: 0;
line-height: 1.8;
}
h1, h2, h3, h4, h5, h6 {
font-family: Oswald, sans-serif;
color: var(--LogoMainColor) !important;
}
h1 {
font-size: 3.1rem
}
h2 {
font-size: 2.7rem
}
h3 {
font-size: 2.3rem
}
h4 {
font-size: 2rem
}
p {
font-size: 120%;
}
.visningsbild {
width: 70px !important;
height: 70px !important;
border-radius: 50%;
}
.maxad {
width: 100%;
}
.minLogotyp {
transition: transform .2s
}
.minLogotyp:hover {
transform: scale(1.1);
}
.myLoginForm {
width: 20rem;
margin: 0 auto;
}
.registrera {
background-color: var(--LogoMainColor);
color: var(--LogoSecondColor);
display: block;
width: 100%;
text-align: center;
padding: 2rem 0;
font-size: 2rem;
font-weight: bold;
transition: 0.3s;
}
.registrera:hover {
background-color: var(--LogoSecondColor);
color: var(--LogoMainColor);
}
.myCard .card-title {
font-size: 9rem;
text-shadow: 4px 4px 2px #111, -4px -4px 2px #111, -4px 4px 2px #111, 4px -4px 2px #111;
}
.myCard .card-text {
font-size: 2.2rem;
text-shadow: 3px 3px 3px #111, -3px -3px 3px #111, -3px 3px 3px #111, 3px -3px 3px #111;
}
.myFooter {
color: var(--LogoMainColor);
font-size: 90%;
}
.myFooter a,
.myFooter a:visited {
color: var(--LogoMainColor);
text-decoration: underline;
font-size: 120%;
}
.myFooter a:hover {
background-color: var(--LogoSecondColor);
}
.social i {
font-size: 3rem;
padding: 0 10px;
}
.myKursCard {
text-align: center;
margin-top: 40%;
text-shadow: 2px 2px 2px #111, -2px -2px 2px #111, -2px 2px 2px #111, 2px -2px 2px #111;
}
.fa-check-square {
color: var(--LogoSecondColor);
margin-right: 5px;
}
.alert {
left: 15%;
width: 70%;
}

71
wwwroot/css/site.css Normal file
View File

@@ -0,0 +1,71 @@
/* Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification
for details on configuring this project to bundle and minify static web assets. */
a.navbar-brand {
white-space: normal;
text-align: center;
word-break: break-all;
}
/* Provide sufficient contrast against white background */
a {
color: #0366d6;
}
.btn-primary {
color: #fff;
background-color: #1b6ec2;
border-color: #1861ac;
}
.nav-pills .nav-link.active, .nav-pills .show > .nav-link {
color: #fff;
background-color: #1b6ec2;
border-color: #1861ac;
}
/* Sticky footer styles
-------------------------------------------------- */
html {
font-size: 14px;
}
@media (min-width: 768px) {
html {
font-size: 16px;
}
}
.border-top {
border-top: 1px solid #e5e5e5;
}
.border-bottom {
border-bottom: 1px solid #e5e5e5;
}
.box-shadow {
box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05);
}
button.accept-policy {
font-size: 1rem;
line-height: inherit;
}
/* Sticky footer styles
-------------------------------------------------- */
html {
position: relative;
min-height: 100%;
}
body {
/* Margin bottom by footer height */
margin-bottom: 60px;
}
.footer {
position: absolute;
bottom: 0;
width: 100%;
white-space: nowrap;
line-height: 60px; /* Vertically center the text there */
}

BIN
wwwroot/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

BIN
wwwroot/images/Logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
wwwroot/images/arenan.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

BIN
wwwroot/images/crossfit.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

BIN
wwwroot/images/kids.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

BIN
wwwroot/images/kurser.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

BIN
wwwroot/images/map.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

BIN
wwwroot/images/priser.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 238 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 325 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

BIN
wwwroot/images/vikt.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

BIN
wwwroot/images/yoga.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

4
wwwroot/js/site.js Normal file
View File

@@ -0,0 +1,4 @@
// Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification
// for details on configuring this project to bundle and minify static web assets.
// Write your JavaScript code.