Initial Commit

This commit is contained in:
Laura Hausmann 2023-04-08 12:48:27 +02:00
commit 0dd08b93ad
Signed by: zotan
GPG Key ID: D044E84C5BE01605
45 changed files with 15075 additions and 0 deletions

186
.gitignore vendored Normal file
View File

@ -0,0 +1,186 @@
/packages/
/_ReSharper.Caches/
# Created by https://www.toptal.com/developers/gitignore/api/rider,dotnetcore,jetbrains+all
# Edit at https://www.toptal.com/developers/gitignore?templates=rider,dotnetcore,jetbrains+all
### DotnetCore ###
# .NET Core build folders
bin/
obj/
# Common node modules locations
/node_modules
/wwwroot/node_modules
### JetBrains+all ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
# Generated files
.idea/**/contentModel.xml
# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
# Gradle
.idea/**/gradle.xml
.idea/**/libraries
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/jarRepositories.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr
# CMake
cmake-build-*/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
### JetBrains+all Patch ###
# Ignores the whole .idea folder and all .iml files
# See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360
.idea/
# Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023
*.iml
modules.xml
.idea/misc.xml
*.ipr
# Sonarlint plugin
.idea/sonarlint
### Rider ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff
# Generated files
# Sensitive or high-churn files
# Gradle
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/jarRepositories.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr
# CMake
# Mongo Explorer plugin
# File-based project format
# IntelliJ
# mpeltonen/sbt-idea plugin
# JIRA plugin
# Cursive Clojure plugin
# Crashlytics plugin (for Android Studio and IntelliJ)
# Editor-based Rest Client
# Android studio 3.1+ serialized cache file
# End of https://www.toptal.com/developers/gitignore/api/rider,dotnetcore,jetbrains+all
# Created by https://www.toptal.com/developers/gitignore/api/macos
# Edit at https://www.toptal.com/developers/gitignore?templates=macos
### macOS ###
# General
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
# End of https://www.toptal.com/developers/gitignore/api/macos
database.db

View File

@ -0,0 +1,79 @@
{
"$schema": "http://json.schemastore.org/template",
"author": "zotan",
"classifications": [
"Web",
"MVC",
"Razor Pages"
],
"identity": "zotan.ASPTemplate",
"name": "ASP.NET Core (zotan)",
"shortName": "razor-zotan",
"sourceName": "ASPTemplate",
"defaultName": "RazorApplication",
"preferNameDirectory": true,
"primaryOutputs": [
{
"path": "ASPTemplate.csproj"
}
],
"tags": {
"language": "C#",
"type": "project"
},
"sources": [
{
"copyOnly": [
"wwwroot/**"
],
"modifiers": [
{
"exclude": [
".idea/**",
".git/**"
]
}
]
}
],
"symbols": {
"auth": {
"type": "parameter",
"datatype": "choice",
"choices": [
{
"choice": "None",
"description": "No authentication"
},
{
"choice": "SSO",
"description": "Remote-User auth"
},
{
"choice": "SSO_partial",
"description": "Remote-User auth (partial)"
}
],
"defaultValue": "None",
"description": "The type of authentication to use"
},
"kestrelPort": {
"type": "generated",
"generator": "port",
"parameters": {
"low": 8000,
"high": 8999
},
"replaces": "7039"
},
"kestrelAltPort": {
"type": "generated",
"generator": "port",
"parameters": {
"low": 9000,
"high": 9999
},
"replaces": "7040"
}
}
}

30
ASPTemplate.csproj Normal file
View File

@ -0,0 +1,30 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="7.0.4" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.4">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.4" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
<PackageReference Include="Swashbuckle.AspNetCore.Filters" Version="7.0.6" />
</ItemGroup>
<ItemGroup>
<Content Include=".template.config\template.json" />
</ItemGroup>
<Target Name="SetSourceRevisionId" BeforeTargets="InitializeSourceControlInformation">
<Exec Command="git describe --long --always --dirty --exclude=* --abbrev=8 2&gt;/dev/null || echo unknown" ConsoleToMSBuild="True" IgnoreExitCode="False">
<Output PropertyName="SourceRevisionId" TaskParameter="ConsoleOutput" />
</Exec>
</Target>
</Project>

View File

@ -0,0 +1,19 @@
using System.Reflection;
using ASPTemplate.Backend.Database.Tables;
using Microsoft.EntityFrameworkCore;
namespace ASPTemplate.Backend.Database;
public class DatabaseContext : DbContext {
public DatabaseContext() { }
public DatabaseContext(DbContextOptions<DatabaseContext> options) : base(options) { }
public virtual DbSet<Config> Config { get; set; } = null!;
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder.UseSqlite("Data Source=database.db");
protected override void OnModelCreating(ModelBuilder modelBuilder) {
modelBuilder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly());
}
}

View File

@ -0,0 +1,18 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace ASPTemplate.Backend.Database.Tables;
public class Config {
public string Key { get; set; } = null!;
public string Value { get; set; } = null!;
public class Configuration : IEntityTypeConfiguration<Config> {
public void Configure(EntityTypeBuilder<Config> builder) {
builder.ToTable("Config");
builder.HasKey(p => p.Key);
builder.Property(b => b.Key).HasColumnName("Key").IsRequired();
builder.Property(b => b.Value).HasColumnName("Value").IsRequired();
}
}
}

40
Backend/Startup.cs Normal file
View File

@ -0,0 +1,40 @@
using System.Reflection;
using ASPTemplate.Backend.Database;
using Microsoft.EntityFrameworkCore;
using Swashbuckle.AspNetCore.Filters;
new DatabaseContext().Database.Migrate();
var builder = WebApplication.CreateBuilder(args);
if (Environment.GetCommandLineArgs().Contains("--razor-runtime-comp")) {
builder.Services.AddRazorPages().AddRazorRuntimeCompilation();
builder.Services.AddControllers().AddRazorRuntimeCompilation();
}
else {
builder.Services.AddRazorPages();
builder.Services.AddControllers();
}
builder.Services.AddSwaggerGen(options => {
var xmlFilename = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFilename));
options.ExampleFilters();
});
builder.Services.AddSwaggerExamplesFromAssemblies(Assembly.GetEntryAssembly());
var app = builder.Build();
if (!app.Environment.IsDevelopment())
app.UseExceptionHandler("/Error");
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapRazorPages();
app.Run();

View File

@ -0,0 +1,16 @@
using System.Reflection;
namespace ASPTemplate.Backend.Utils;
public static class ApplicationInformation {
public const bool WideContainers = false;
public const string Project = "ASPTemplate";
public const string Repository = "https://git.ztn.sh/zotan/ASPTemplate";
public static readonly string Version =
((AssemblyInformationalVersionAttribute)Assembly.GetEntryAssembly()!.GetCustomAttributes(typeof(AssemblyInformationalVersionAttribute), false)[0])
.InformationalVersion[6..];
public static readonly string LinkVersion = Version.Length >= 8 ? Version[..8] : Version;
public static readonly bool HasVersion = Version != "unknown";
}

24
Backend/Utils/AuthUtil.cs Normal file
View File

@ -0,0 +1,24 @@
namespace ASPTemplate.Backend.Utils;
public static class AuthUtil {
public const string OverrideAuthCli = "--disable-auth";
private const string InternalUserPrefix = "_";
private const string GuestUser = $"{InternalUserPrefix}guest";
private const string FallbackUser = $"{InternalUserPrefix}debug";
private static readonly string[] FallbackGroups = { "admin" };
public static readonly bool OverrideAuth = Environment.GetCommandLineArgs().Contains(OverrideAuthCli);
public static string GetRemoteUser(this HttpContext ctx) =>
OverrideAuth ? FallbackUser : ctx.Request.Headers.TryGetValue("Remote-User", out var header) ? header.ToString() : GuestUser;
public static bool IsAuthenticated(this HttpContext ctx) => OverrideAuth || ctx.Request.Headers.ContainsKey("Remote-User");
public static IEnumerable<string> GetRemoteGroups(this HttpContext ctx) {
if (OverrideAuth)
return FallbackGroups;
return ctx.Request.Headers.TryGetValue("Remote-Groups", out var header) ? header.ToString().Split(",") : Array.Empty<string>();
}
}

View File

@ -0,0 +1,40 @@
// <auto-generated />
using ASPTemplate.Backend.Database;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace ASPTemplate.Migrations
{
[DbContext(typeof(DatabaseContext))]
[Migration("20230407214043_3DA5B7D1-3C1E-496D-9A32-07EAFD2C09D7")]
partial class _3DA5B7D13C1E496D9A3207EAFD2C09D7
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "7.0.4");
modelBuilder.Entity("ASPTemplate.Backend.Database.Tables.Config", b =>
{
b.Property<string>("Key")
.HasColumnType("TEXT")
.HasColumnName("Key");
b.Property<string>("Value")
.IsRequired()
.HasColumnType("TEXT")
.HasColumnName("Value");
b.HasKey("Key");
b.ToTable("Config", (string)null);
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,33 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace ASPTemplate.Migrations
{
/// <inheritdoc />
public partial class _3DA5B7D13C1E496D9A3207EAFD2C09D7 : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Config",
columns: table => new
{
Key = table.Column<string>(type: "TEXT", nullable: false),
Value = table.Column<string>(type: "TEXT", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Config", x => x.Key);
});
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Config");
}
}
}

View File

@ -0,0 +1,37 @@
// <auto-generated />
using ASPTemplate.Backend.Database;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace ASPTemplate.Migrations
{
[DbContext(typeof(DatabaseContext))]
partial class DatabaseContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "7.0.4");
modelBuilder.Entity("ASPTemplate.Backend.Database.Tables.Config", b =>
{
b.Property<string>("Key")
.HasColumnType("TEXT")
.HasColumnName("Key");
b.Property<string>("Value")
.IsRequired()
.HasColumnType("TEXT")
.HasColumnName("Value");
b.HasKey("Key");
b.ToTable("Config", (string)null);
});
#pragma warning restore 612, 618
}
}
}

25
Pages/Error.cshtml Normal file
View File

@ -0,0 +1,25 @@
@page
@model ErrorModel
@{
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 the <strong>Development</strong> environment displays 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>

20
Pages/Error.cshtml.cs Normal file
View File

@ -0,0 +1,20 @@
using System.Diagnostics;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace ASPTemplate.Pages;
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true), IgnoreAntiforgeryToken]
public class ErrorModel : PageModel {
private readonly ILogger<ErrorModel> _logger;
public ErrorModel(ILogger<ErrorModel> logger) => _logger = logger;
public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public void OnGet() {
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
}
}

17
Pages/Index.cshtml Normal file
View File

@ -0,0 +1,17 @@
@page
@using ASPTemplate.Backend.Utils
@model IndexModel
@{
ViewData["Title"] = "Home";
}
<div class="text-center">
<h1 class="display-4">
Welcome
</h1>
<p>
This is the default landing page of <a href="@ApplicationInformation.Repository">@ApplicationInformation.Project</a>, a work in progress ASP.NET Core project by <a href="https://zotan.pw">~zotan</a>.
<br/>
Expect to see something more useful here once project development continues.
</p>
</div>

11
Pages/Index.cshtml.cs Normal file
View File

@ -0,0 +1,11 @@
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace ASPTemplate.Pages;
public class IndexModel : PageModel {
private readonly ILogger<IndexModel> _logger;
public IndexModel(ILogger<IndexModel> logger) => _logger = logger;
public void OnGet() { }
}

View File

@ -0,0 +1,88 @@
@using ASPTemplate.Backend.Utils
@using Microsoft.AspNetCore.Mvc.TagHelpers
@using System.Web
<!DOCTYPE html>
<html lang="en" data-bs-theme="dark">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
@await RenderSectionAsync("Meta", false)
<title>@ViewData["Title"] - @ApplicationInformation.Project</title>
<link rel="stylesheet" href="~/lib/bootstrap/bootstrap.min.css"/>
<link rel="stylesheet" href="~/css/site.css" asp-append-version="true"/>
@await RenderSectionAsync("Stylesheets", false)
</head>
<body class="d-flex flex-column min-vh-100">
<header>
<nav class="navbar navbar-expand-sm navbar-toggleable-sm border-bottom box-shadow mb-3">
@* ReSharper disable once HeuristicUnreachableCode *@
<div class="@(ApplicationInformation.WideContainers ? "container-fluid" : "container")">
<a class="navbar-brand align-middle" asp-area="" asp-page="/Index">
<img src="/favicon.svg" alt="Logo">
</a>
<a class="navbar-brand align-middle" asp-area="" asp-page="/Index">@ApplicationInformation.Project</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbarSupportedContent"
aria-expanded="false" aria-label="Toggle navigation">
<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" asp-area="" asp-page="/Index">Home</a>
</li>
</ul>
<ul class="navbar-nav">
<li class="nav-item">
@if (!Context.IsAuthenticated()) {
<a class="nav-link" href="/auth?rd=@HttpUtility.UrlEncode(Context.Request.Path.ToString())">
<span class="fw-semibold">Log in</span>
</a>
}
else if (AuthUtil.OverrideAuth) {
<span>
<b>&#x26A0; Auth system overriden &#x26A0;</b>
</span>
}
else {
<span>Authenticated as <b>@Context.GetRemoteUser()</b></span>
}
</li>
</ul>
</div>
</div>
</nav>
</header>
@* ReSharper disable once HeuristicUnreachableCode *@
<div class="@(ApplicationInformation.WideContainers ? "container-custom" : "container") ">
<main role="main" class="pb-3">
@if (AuthUtil.OverrideAuth) {
<div class="alert alert-warning" role="alert">
You are connected as the fallback user '@Context.GetRemoteUser()' because this program was started with the '@AuthUtil.OverrideAuthCli' command line argument. If this is a production deployment, please make sure your configuration is correct.
</div>
}
@RenderBody()
</main>
</div>
<footer class="footer bg-body-tertiary mt-auto py-3">
<div class="container text-muted text-center">
@if (ApplicationInformation.HasVersion) {
<div>
Served by @Environment.MachineName running <a class="footerlink" href="@ApplicationInformation.Repository/commit/@ApplicationInformation.LinkVersion" target="_blank">@ApplicationInformation.Project @ApplicationInformation.Version</a> on .NET @Environment.Version
</div>
}
else {
<div>
Served by @Environment.MachineName running <a href="@ApplicationInformation.Repository">@ApplicationInformation.Project</a> (git revision unknown) on .NET @Environment.Version
</div>
}
</div>
</footer>
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="~/lib/bootstrap/bootstrap.bundle.min.js"></script>
<script src="~/js/site.js" asp-append-version="true"></script>
@await RenderSectionAsync("Scripts", false)
</body>
</html>

View File

@ -0,0 +1,49 @@
/* 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;
}
a {
color: #0077cc;
}
.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;
}
.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;
}
.footer {
position: absolute;
bottom: 0;
width: 100%;
white-space: nowrap;
line-height: 60px;
}

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>

View File

@ -0,0 +1,3 @@
@using ASPTemplate
@namespace ASPTemplate.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

3
Pages/_ViewStart.cshtml Normal file
View File

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

View File

@ -0,0 +1,24 @@
{
"profiles": {
"AuthOverride": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": false,
"applicationUrl": "https://localhost:7039",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"commandLineArgs": "--disable-auth --razor-runtime-comp"
},
"Guest": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": false,
"applicationUrl": "https://localhost:7040",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"commandLineArgs": "--razor-runtime-comp"
}
}
}

View File

@ -0,0 +1,9 @@
{
"DetailedErrors": true,
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}

9
appsettings.json Normal file
View File

@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}

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

@ -0,0 +1,47 @@
html {
position: relative;
min-height: 100%;
}
.footer {
bottom: 0;
width: 100%;
white-space: normal;
padding: 1em;
}
.form-group {
margin-bottom: 10px;
}
.container-custom, .container-fluid {
margin-left: 1.5%;
margin-right: 1.5%;
}
:root {
--bs-link-hover-color: #b06d09;
--bs-link-hover-color-rgb: 176, 109, 9;
--bs-link-color: #e38d0b;
--bs-link-color-rgb: 227, 141, 11;
--bs-border-color: #343a40;
}
a {
text-decoration-color: rgba(var(--bs-link-color-rgb), 0.3);
text-underline-offset: 2px;
}
nav.navbar {
line-height: 20px;
}
.navbar-brand {
line-height: 20px;
}
.navbar-brand img {
height: 35px;
margin-right: 5px;
}

BIN
wwwroot/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

34
wwwroot/favicon.svg Normal file
View File

@ -0,0 +1,34 @@
<svg xmlns="http://www.w3.org/2000/svg" height="596pt" version="1.1" viewBox="1 -19 596.717 596" width="596pt">
<g id="surface1">
<path d="M 39.800781 10.316406 L 477.597656 10.316406 C 494.085938 10.316406 507.449219 23.679688 507.449219 40.167969 L 507.449219 438.167969 C 507.449219 454.65625 494.085938 468.019531 477.597656 468.019531 L 39.800781 468.019531 C 23.3125 468.019531 9.949219 454.65625 9.949219 438.167969 L 9.949219 40.167969 C 9.949219 23.679688 23.3125 10.316406 39.800781 10.316406 Z M 39.800781 10.316406 " style=" stroke:none;fill-rule:nonzero;fill:rgb(26.27451%,59.607843%,81.960784%);fill-opacity:1;" />
<path d="M 39.800781 40.167969 L 59.699219 40.167969 L 59.699219 60.066406 L 39.800781 60.066406 Z M 39.800781 40.167969 " style=" stroke:none;fill-rule:nonzero;fill:rgb(24.313725%,54.901961%,78.039216%);fill-opacity:1;" />
<path d="M 79.597656 40.167969 L 99.5 40.167969 L 99.5 60.066406 L 79.597656 60.066406 Z M 79.597656 40.167969 " style=" stroke:none;fill-rule:nonzero;fill:rgb(24.313725%,54.901961%,78.039216%);fill-opacity:1;" />
<path d="M 119.402344 40.167969 L 139.300781 40.167969 L 139.300781 60.066406 L 119.402344 60.066406 Z M 119.402344 40.167969 " style=" stroke:none;fill-rule:nonzero;fill:rgb(24.313725%,54.901961%,78.039216%);fill-opacity:1;" />
<path d="M 119.402344 89.917969 L 557.199219 89.917969 C 573.6875 89.917969 587.050781 103.28125 587.050781 119.765625 L 587.050781 517.765625 C 587.050781 534.253906 573.6875 547.617188 557.199219 547.617188 L 119.402344 547.617188 C 102.914062 547.617188 89.550781 534.253906 89.550781 517.765625 L 89.550781 119.765625 C 89.550781 103.28125 102.914062 89.917969 119.402344 89.917969 Z M 119.402344 89.917969 " style=" stroke:none;fill-rule:nonzero;fill:rgb(52.941176%,80.784314%,85.098039%);fill-opacity:1;" />
<path d="M 557.199219 89.917969 L 537.296875 89.917969 L 93.988281 533.230469 C 99.351562 542.144531 108.992188 547.605469 119.398438 547.617188 L 557.199219 547.617188 C 573.6875 547.617188 587.050781 534.253906 587.050781 517.765625 L 587.050781 119.765625 C 587.050781 103.28125 573.6875 89.917969 557.199219 89.917969 Z M 557.199219 89.917969 " style=" stroke:none;fill-rule:nonzero;fill:rgb(44.313725%,76.862745%,81.960784%);fill-opacity:1;" />
<path d="M 119.402344 119.765625 L 139.300781 119.765625 L 139.300781 139.667969 L 119.402344 139.667969 Z M 119.402344 119.765625 " style=" stroke:none;fill-rule:nonzero;fill:rgb(36.862745%,70.196078%,81.960784%);fill-opacity:1;" />
<path d="M 159.199219 119.765625 L 179.101562 119.765625 L 179.101562 139.667969 L 159.199219 139.667969 Z M 159.199219 119.765625 " style=" stroke:none;fill-rule:nonzero;fill:rgb(36.862745%,70.196078%,81.960784%);fill-opacity:1;" />
<path d="M 199 119.765625 L 218.902344 119.765625 L 218.902344 139.667969 L 199 139.667969 Z M 199 119.765625 " style=" stroke:none;fill-rule:nonzero;fill:rgb(36.862745%,70.196078%,81.960784%);fill-opacity:1;" />
<path d="M 119.402344 159.566406 L 557.199219 159.566406 L 557.199219 179.46875 L 119.402344 179.46875 Z M 119.402344 159.566406 " style=" stroke:none;fill-rule:nonzero;fill:rgb(36.862745%,70.196078%,81.960784%);fill-opacity:1;" />
<path d="M 119.402344 209.316406 L 199 209.316406 L 199 229.21875 L 119.402344 229.21875 Z M 119.402344 209.316406 " style=" stroke:none;fill-rule:nonzero;fill:rgb(36.862745%,70.196078%,81.960784%);fill-opacity:1;" />
<path d="M 119.402344 249.117188 L 179.101562 249.117188 L 179.101562 269.019531 L 119.402344 269.019531 Z M 119.402344 249.117188 " style=" stroke:none;fill-rule:nonzero;fill:rgb(36.862745%,70.196078%,81.960784%);fill-opacity:1;" />
<path d="M 487.550781 388.417969 L 487.550781 328.71875 L 453.789062 328.71875 C 451.011719 317.929688 446.734375 307.601562 441.074219 298.011719 L 464.953125 274.132812 L 422.734375 231.914062 L 398.855469 255.792969 C 389.265625 250.132812 378.9375 245.855469 368.148438 243.078125 L 368.148438 209.316406 L 308.449219 209.316406 L 308.449219 243.078125 C 297.664062 245.855469 287.335938 250.132812 277.746094 255.792969 L 253.863281 231.914062 L 211.644531 274.132812 L 235.527344 298.011719 C 229.863281 307.59375 225.585938 317.929688 222.808594 328.71875 L 189.050781 328.71875 L 189.050781 388.417969 L 222.808594 388.417969 C 225.585938 399.203125 229.863281 409.53125 235.527344 419.121094 L 211.644531 443.003906 L 253.863281 485.222656 L 277.746094 461.339844 C 287.335938 467.003906 297.664062 471.28125 308.449219 474.058594 L 308.449219 507.816406 L 368.148438 507.816406 L 368.148438 474.058594 C 378.9375 471.28125 389.265625 467.003906 398.855469 461.339844 L 422.734375 485.222656 L 464.953125 443.003906 L 441.074219 419.121094 C 446.734375 409.53125 451.011719 399.203125 453.789062 388.417969 Z M 338.300781 418.265625 C 305.324219 418.265625 278.597656 391.542969 278.597656 358.566406 C 278.597656 325.59375 305.324219 298.867188 338.300781 298.867188 C 371.273438 298.867188 398 325.59375 398 358.566406 C 398 391.542969 371.273438 418.265625 338.300781 418.265625 Z M 338.300781 418.265625 " style=" stroke:none;fill-rule:nonzero;fill:rgb(89.019608%,29.411765%,52.941176%);fill-opacity:1;" />
<path d="M 497.5 497.867188 L 557.199219 497.867188 L 557.199219 517.765625 L 497.5 517.765625 Z M 497.5 497.867188 " style=" stroke:none;fill-rule:nonzero;fill:rgb(36.862745%,70.196078%,81.960784%);fill-opacity:1;" />
<path d="M 441.074219 298.011719 L 464.953125 274.132812 L 445.351562 254.519531 C 428.050781 279.582031 408.875 303.304688 388 325.484375 C 406.21875 352.964844 398.695312 390.007812 371.214844 408.226562 C 349.113281 422.875 319.992188 421.191406 299.734375 404.089844 C 275.238281 422.394531 249.664062 439.230469 223.167969 454.496094 L 253.882812 485.210938 L 277.765625 461.332031 C 287.347656 466.992188 297.675781 471.28125 308.449219 474.058594 L 308.449219 507.816406 L 368.148438 507.816406 L 368.148438 474.058594 C 378.9375 471.28125 389.265625 467.003906 398.855469 461.339844 L 422.734375 485.222656 L 464.953125 443.003906 L 441.074219 419.121094 C 446.734375 409.53125 451.011719 399.203125 453.789062 388.417969 L 487.550781 388.417969 L 487.550781 328.71875 L 453.789062 328.71875 C 451.011719 317.933594 446.734375 307.601562 441.074219 298.011719 Z M 441.074219 298.011719 " style=" stroke:none;fill-rule:nonzero;fill:rgb(85.098039%,28.235294%,50.588235%);fill-opacity:1;" />
<path d="M 89.550781 119.765625 L 89.550781 468.015625 L 59.699219 468.015625 L 59.699219 149.617188 C 59.699219 133.128906 73.0625 119.765625 89.550781 119.765625 Z M 89.550781 119.765625 " style=" stroke:none;fill-rule:nonzero;fill:rgb(24.313725%,54.901961%,78.039216%);fill-opacity:1;" />
<path d="M 39.800781 477.96875 L 59.699219 477.96875 L 59.699219 458.066406 L 39.800781 458.066406 C 28.804688 458.066406 19.898438 449.160156 19.898438 438.167969 L 19.898438 40.167969 C 19.898438 29.171875 28.804688 20.265625 39.800781 20.265625 L 477.597656 20.265625 C 488.59375 20.265625 497.5 29.171875 497.5 40.167969 L 497.5 60.066406 L 517.402344 60.066406 L 517.402344 40.167969 C 517.402344 18.1875 499.578125 0.367188 477.601562 0.367188 L 39.800781 0.367188 C 17.820312 0.367188 0 18.1875 0 40.167969 L 0 438.167969 C 0 460.148438 17.820312 477.96875 39.800781 477.96875 Z M 39.800781 477.96875 " style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" />
<path d="M 39.800781 40.167969 L 59.699219 40.167969 L 59.699219 60.066406 L 39.800781 60.066406 Z M 39.800781 40.167969 " style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" />
<path d="M 79.597656 40.167969 L 99.5 40.167969 L 99.5 60.066406 L 79.597656 60.066406 Z M 79.597656 40.167969 " style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" />
<path d="M 119.402344 40.167969 L 139.300781 40.167969 L 139.300781 60.066406 L 119.402344 60.066406 Z M 119.402344 40.167969 " style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" />
<path d="M 79.597656 517.765625 C 79.597656 539.746094 97.421875 557.566406 119.398438 557.566406 L 557.199219 557.566406 C 579.179688 557.566406 597 539.746094 597 517.765625 L 597 119.765625 C 597 97.789062 579.179688 79.96875 557.199219 79.96875 L 119.402344 79.96875 C 97.421875 79.96875 79.601562 97.789062 79.601562 119.765625 L 79.601562 517.765625 Z M 99.5 119.765625 C 99.5 108.773438 108.40625 99.867188 119.402344 99.867188 L 557.199219 99.867188 C 568.195312 99.867188 577.101562 108.773438 577.101562 119.765625 L 577.101562 517.765625 C 577.101562 528.761719 568.195312 537.667969 557.199219 537.667969 L 119.402344 537.667969 C 108.40625 537.667969 99.5 528.761719 99.5 517.765625 Z M 99.5 119.765625 " style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" />
<path d="M 119.402344 119.765625 L 139.300781 119.765625 L 139.300781 139.667969 L 119.402344 139.667969 Z M 119.402344 119.765625 " style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" />
<path d="M 159.199219 119.765625 L 179.101562 119.765625 L 179.101562 139.667969 L 159.199219 139.667969 Z M 159.199219 119.765625 " style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" />
<path d="M 199 119.765625 L 218.902344 119.765625 L 218.902344 139.667969 L 199 139.667969 Z M 199 119.765625 " style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" />
<path d="M 119.402344 159.566406 L 557.199219 159.566406 L 557.199219 179.46875 L 119.402344 179.46875 Z M 119.402344 159.566406 " style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" />
<path d="M 119.402344 209.316406 L 199 209.316406 L 199 229.21875 L 119.402344 229.21875 Z M 119.402344 209.316406 " style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" />
<path d="M 119.402344 249.117188 L 179.101562 249.117188 L 179.101562 269.019531 L 119.402344 269.019531 Z M 119.402344 249.117188 " style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" />
<path d="M 338.300781 288.917969 C 299.832031 288.917969 268.648438 320.101562 268.648438 358.566406 C 268.648438 397.035156 299.832031 428.21875 338.300781 428.21875 C 376.765625 428.21875 407.949219 397.035156 407.949219 358.566406 C 407.910156 320.121094 376.746094 288.957031 338.300781 288.917969 Z M 338.300781 408.316406 C 310.828125 408.316406 288.550781 386.039062 288.550781 358.566406 C 288.550781 331.097656 310.828125 308.820312 338.300781 308.820312 C 365.773438 308.820312 388.050781 331.097656 388.050781 358.566406 C 388.019531 386.027344 365.761719 408.289062 338.300781 408.316406 Z M 338.300781 408.316406 " style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" />
<path d="M 497.5 328.71875 C 497.5 323.222656 493.042969 318.765625 487.550781 318.765625 L 461.253906 318.765625 C 459.152344 312.230469 456.515625 305.871094 453.382812 299.761719 L 471.980469 281.175781 C 475.859375 277.292969 475.859375 270.988281 471.980469 267.105469 L 429.761719 224.886719 C 425.878906 221.007812 419.570312 221.007812 415.691406 224.886719 L 397.105469 243.476562 C 390.984375 240.351562 384.636719 237.722656 378.097656 235.613281 L 378.097656 209.316406 C 378.097656 203.824219 373.640625 199.367188 368.148438 199.367188 L 308.449219 199.367188 C 302.957031 199.367188 298.5 203.824219 298.5 209.316406 L 298.5 235.613281 C 291.964844 237.722656 285.613281 240.351562 279.496094 243.476562 L 260.910156 224.886719 C 257.027344 221.007812 250.71875 221.007812 246.839844 224.886719 L 204.621094 267.105469 C 200.738281 270.988281 200.738281 277.292969 204.621094 281.175781 L 223.207031 299.761719 C 222.371094 301.394531 221.574219 303.027344 220.820312 304.675781 C 218.71875 309.265625 216.890625 313.972656 215.347656 318.765625 L 189.050781 318.765625 C 183.558594 318.765625 179.097656 323.226562 179.097656 328.71875 L 179.097656 388.417969 C 179.097656 393.910156 183.558594 398.367188 189.050781 398.367188 L 215.347656 398.367188 C 217.445312 404.902344 220.082031 411.261719 223.21875 417.371094 L 204.621094 435.957031 C 200.738281 439.839844 200.738281 446.148438 204.621094 450.027344 L 246.839844 492.246094 C 250.71875 496.128906 257.027344 496.128906 260.910156 492.246094 L 279.496094 473.660156 C 285.613281 476.785156 291.960938 479.410156 298.5 481.519531 L 298.5 507.816406 C 298.5 513.308594 302.957031 517.765625 308.449219 517.765625 L 368.148438 517.765625 C 373.640625 517.765625 378.097656 513.308594 378.097656 507.816406 L 378.097656 481.519531 C 384.636719 479.410156 390.984375 476.78125 397.105469 473.660156 L 415.691406 492.246094 C 419.570312 496.125 425.878906 496.125 429.761719 492.246094 L 471.980469 450.027344 C 475.859375 446.144531 475.859375 439.839844 471.980469 435.957031 L 453.382812 417.371094 C 456.515625 411.261719 459.152344 404.902344 461.253906 398.367188 L 487.550781 398.367188 C 493.042969 398.367188 497.5 393.910156 497.5 388.417969 Z M 477.597656 378.46875 L 453.78125 378.46875 C 449.242188 378.46875 445.28125 381.542969 444.148438 385.929688 C 441.601562 395.8125 437.691406 405.28125 432.507812 414.066406 C 430.199219 417.980469 430.835938 422.945312 434.039062 426.15625 L 450.863281 442.992188 L 422.726562 471.140625 L 405.890625 454.304688 C 402.679688 451.09375 397.703125 450.464844 393.792969 452.773438 C 385.007812 457.957031 375.542969 461.878906 365.664062 464.414062 C 361.277344 465.550781 358.203125 469.507812 358.203125 474.046875 L 358.203125 497.867188 L 318.402344 497.867188 L 318.402344 474.046875 C 318.402344 469.507812 315.328125 465.550781 310.941406 464.414062 C 301.058594 461.878906 291.597656 457.957031 282.8125 452.773438 C 278.902344 450.464844 273.925781 451.09375 270.710938 454.304688 L 253.878906 471.140625 L 225.738281 442.992188 L 242.566406 426.15625 C 245.769531 422.945312 246.40625 417.980469 244.097656 414.066406 C 238.914062 405.28125 235.003906 395.808594 232.457031 385.929688 C 231.320312 381.542969 227.363281 378.46875 222.824219 378.46875 L 199.003906 378.46875 L 199.003906 338.667969 L 222.824219 338.667969 C 227.363281 338.667969 231.320312 335.59375 232.457031 331.207031 C 234.066406 324.945312 236.226562 318.835938 238.921875 312.964844 C 240.472656 309.5625 242.207031 306.242188 244.097656 303.015625 C 246.394531 299.105469 245.769531 294.140625 242.566406 290.9375 L 225.738281 274.101562 L 253.878906 245.953125 L 270.710938 262.789062 C 273.925781 266.003906 278.902344 266.628906 282.8125 264.320312 C 291.597656 259.136719 301.058594 255.21875 310.941406 252.679688 C 315.328125 251.546875 318.402344 247.585938 318.402344 243.046875 L 318.402344 219.269531 L 358.203125 219.269531 L 358.203125 243.089844 C 358.203125 247.625 361.277344 251.585938 365.664062 252.71875 C 375.546875 255.257812 385.007812 259.175781 393.792969 264.363281 C 397.703125 266.667969 402.679688 266.042969 405.890625 262.828125 L 422.726562 245.992188 L 450.863281 274.140625 L 434.039062 290.976562 C 430.835938 294.191406 430.199219 299.15625 432.507812 303.066406 C 437.691406 311.851562 441.601562 321.324219 444.148438 331.203125 C 445.285156 335.59375 449.242188 338.667969 453.78125 338.667969 L 477.601562 338.667969 L 477.601562 378.46875 Z M 477.597656 378.46875 " style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" />
<path d="M 497.5 497.867188 L 557.199219 497.867188 L 557.199219 517.765625 L 497.5 517.765625 Z M 497.5 497.867188 " style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 15 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.

View File

@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2011-2021 Twitter, Inc.
Copyright (c) 2011-2021 The Bootstrap Authors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,4 @@
/*! DataTables Bootstrap 5 integration
* 2020 SpryMedia Ltd - datatables.net/license
*/
!function(t){"function"==typeof define&&define.amd?define(["jquery","datatables.net"],function(e){return t(e,window,document)}):"object"==typeof exports?module.exports=function(e,a){return e=e||window,(a=a||("undefined"!=typeof window?require("jquery"):require("jquery")(e))).fn.dataTable||require("datatables.net")(e,a),t(a,0,e.document)}:t(jQuery,window,document)}(function(x,e,r,s){"use strict";var o=x.fn.dataTable;return x.extend(!0,o.defaults,{dom:"<'row'<'col-sm-12 col-md-6'l><'col-sm-12 col-md-6'f>><'row dt-row'<'col-sm-12'tr>><'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",renderer:"bootstrap"}),x.extend(o.ext.classes,{sWrapper:"dataTables_wrapper dt-bootstrap5",sFilterInput:"form-control form-control-sm",sLengthSelect:"form-select form-select-sm",sProcessing:"dataTables_processing card",sPageButton:"paginate_button page-item"}),o.ext.renderer.pageButton.bootstrap=function(i,e,d,a,l,c){function u(e,a){for(var t,n,r=function(e){e.preventDefault(),x(e.currentTarget).hasClass("disabled")||b.page()==e.data.action||b.page(e.data.action).draw("page")},s=0,o=a.length;s<o;s++)if(n=a[s],Array.isArray(n))u(e,n);else{switch(f=p="",n){case"ellipsis":p="&#x2026;",f="disabled";break;case"first":p=m.sFirst,f=n+(0<l?"":" disabled");break;case"previous":p=m.sPrevious,f=n+(0<l?"":" disabled");break;case"next":p=m.sNext,f=n+(l<c-1?"":" disabled");break;case"last":p=m.sLast,f=n+(l<c-1?"":" disabled");break;default:p=n+1,f=l===n?"active":""}p&&(t=x("<li>",{class:g.sPageButton+" "+f,id:0===d&&"string"==typeof n?i.sTableId+"_"+n:null}).append(x("<a>",{href:"#","aria-controls":i.sTableId,"aria-label":w[n],"data-dt-idx":n,tabindex:i.iTabIndex,class:"page-link"}).html(p)).appendTo(e),i.oApi._fnBindAction(t,{action:n},r))}}var p,f,t,b=new o.Api(i),g=i.oClasses,m=i.oLanguage.oPaginate,w=i.oLanguage.oAria.paginate||{},e=x(e);try{t=e.find(r.activeElement).data("dt-idx")}catch(e){}var n=e.children("ul.pagination");n.length?n.empty():n=e.html("<ul/>").children("ul").addClass("pagination"),u(n,a),t!==s&&e.find("[data-dt-idx="+t+"]").trigger("focus")},o});

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,23 @@
The MIT License (MIT)
Copyright (c) .NET Foundation and Contributors
All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,435 @@
/**
* @license
* Unobtrusive validation support library for jQuery and jQuery Validate
* Copyright (c) .NET Foundation. All rights reserved.
* Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
* @version v4.0.0
*/
/*jslint white: true, browser: true, onevar: true, undef: true, nomen: true, eqeqeq: true, plusplus: true, bitwise: true, regexp: true, newcap: true, immed: true, strict: false */
/*global document: false, jQuery: false */
(function (factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define("jquery.validate.unobtrusive", ['jquery-validation'], factory);
} else if (typeof module === 'object' && module.exports) {
// CommonJS-like environments that support module.exports
module.exports = factory(require('jquery-validation'));
} else {
// Browser global
jQuery.validator.unobtrusive = factory(jQuery);
}
}(function ($) {
var $jQval = $.validator,
adapters,
data_validation = "unobtrusiveValidation";
function setValidationValues(options, ruleName, value) {
options.rules[ruleName] = value;
if (options.message) {
options.messages[ruleName] = options.message;
}
}
function splitAndTrim(value) {
return value.replace(/^\s+|\s+$/g, "").split(/\s*,\s*/g);
}
function escapeAttributeValue(value) {
// As mentioned on http://api.jquery.com/category/selectors/
return value.replace(/([!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~])/g, "\\$1");
}
function getModelPrefix(fieldName) {
return fieldName.substr(0, fieldName.lastIndexOf(".") + 1);
}
function appendModelPrefix(value, prefix) {
if (value.indexOf("*.") === 0) {
value = value.replace("*.", prefix);
}
return value;
}
function onError(error, inputElement) { // 'this' is the form element
var container = $(this).find("[data-valmsg-for='" + escapeAttributeValue(inputElement[0].name) + "']"),
replaceAttrValue = container.attr("data-valmsg-replace"),
replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) !== false : null;
container.removeClass("field-validation-valid").addClass("field-validation-error");
error.data("unobtrusiveContainer", container);
if (replace) {
container.empty();
error.removeClass("input-validation-error").appendTo(container);
}
else {
error.hide();
}
}
function onErrors(event, validator) { // 'this' is the form element
var container = $(this).find("[data-valmsg-summary=true]"),
list = container.find("ul");
if (list && list.length && validator.errorList.length) {
list.empty();
container.addClass("validation-summary-errors").removeClass("validation-summary-valid");
$.each(validator.errorList, function () {
$("<li />").html(this.message).appendTo(list);
});
}
}
function onSuccess(error) { // 'this' is the form element
var container = error.data("unobtrusiveContainer");
if (container) {
var replaceAttrValue = container.attr("data-valmsg-replace"),
replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) : null;
container.addClass("field-validation-valid").removeClass("field-validation-error");
error.removeData("unobtrusiveContainer");
if (replace) {
container.empty();
}
}
}
function onReset(event) { // 'this' is the form element
var $form = $(this),
key = '__jquery_unobtrusive_validation_form_reset';
if ($form.data(key)) {
return;
}
// Set a flag that indicates we're currently resetting the form.
$form.data(key, true);
try {
$form.data("validator").resetForm();
} finally {
$form.removeData(key);
}
$form.find(".validation-summary-errors")
.addClass("validation-summary-valid")
.removeClass("validation-summary-errors");
$form.find(".field-validation-error")
.addClass("field-validation-valid")
.removeClass("field-validation-error")
.removeData("unobtrusiveContainer")
.find(">*") // If we were using valmsg-replace, get the underlying error
.removeData("unobtrusiveContainer");
}
function validationInfo(form) {
var $form = $(form),
result = $form.data(data_validation),
onResetProxy = $.proxy(onReset, form),
defaultOptions = $jQval.unobtrusive.options || {},
execInContext = function (name, args) {
var func = defaultOptions[name];
func && $.isFunction(func) && func.apply(form, args);
};
if (!result) {
result = {
options: { // options structure passed to jQuery Validate's validate() method
errorClass: defaultOptions.errorClass || "input-validation-error",
errorElement: defaultOptions.errorElement || "span",
errorPlacement: function () {
onError.apply(form, arguments);
execInContext("errorPlacement", arguments);
},
invalidHandler: function () {
onErrors.apply(form, arguments);
execInContext("invalidHandler", arguments);
},
messages: {},
rules: {},
success: function () {
onSuccess.apply(form, arguments);
execInContext("success", arguments);
}
},
attachValidation: function () {
$form
.off("reset." + data_validation, onResetProxy)
.on("reset." + data_validation, onResetProxy)
.validate(this.options);
},
validate: function () { // a validation function that is called by unobtrusive Ajax
$form.validate();
return $form.valid();
}
};
$form.data(data_validation, result);
}
return result;
}
$jQval.unobtrusive = {
adapters: [],
parseElement: function (element, skipAttach) {
/// <summary>
/// Parses a single HTML element for unobtrusive validation attributes.
/// </summary>
/// <param name="element" domElement="true">The HTML element to be parsed.</param>
/// <param name="skipAttach" type="Boolean">[Optional] true to skip attaching the
/// validation to the form. If parsing just this single element, you should specify true.
/// If parsing several elements, you should specify false, and manually attach the validation
/// to the form when you are finished. The default is false.</param>
var $element = $(element),
form = $element.parents("form")[0],
valInfo, rules, messages;
if (!form) { // Cannot do client-side validation without a form
return;
}
valInfo = validationInfo(form);
valInfo.options.rules[element.name] = rules = {};
valInfo.options.messages[element.name] = messages = {};
$.each(this.adapters, function () {
var prefix = "data-val-" + this.name,
message = $element.attr(prefix),
paramValues = {};
if (message !== undefined) { // Compare against undefined, because an empty message is legal (and falsy)
prefix += "-";
$.each(this.params, function () {
paramValues[this] = $element.attr(prefix + this);
});
this.adapt({
element: element,
form: form,
message: message,
params: paramValues,
rules: rules,
messages: messages
});
}
});
$.extend(rules, { "__dummy__": true });
if (!skipAttach) {
valInfo.attachValidation();
}
},
parse: function (selector) {
/// <summary>
/// Parses all the HTML elements in the specified selector. It looks for input elements decorated
/// with the [data-val=true] attribute value and enables validation according to the data-val-*
/// attribute values.
/// </summary>
/// <param name="selector" type="String">Any valid jQuery selector.</param>
// $forms includes all forms in selector's DOM hierarchy (parent, children and self) that have at least one
// element with data-val=true
var $selector = $(selector),
$forms = $selector.parents()
.addBack()
.filter("form")
.add($selector.find("form"))
.has("[data-val=true]");
$selector.find("[data-val=true]").each(function () {
$jQval.unobtrusive.parseElement(this, true);
});
$forms.each(function () {
var info = validationInfo(this);
if (info) {
info.attachValidation();
}
});
}
};
adapters = $jQval.unobtrusive.adapters;
adapters.add = function (adapterName, params, fn) {
/// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation.</summary>
/// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
/// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
/// <param name="params" type="Array" optional="true">[Optional] An array of parameter names (strings) that will
/// be extracted from the data-val-nnnn-mmmm HTML attributes (where nnnn is the adapter name, and
/// mmmm is the parameter name).</param>
/// <param name="fn" type="Function">The function to call, which adapts the values from the HTML
/// attributes into jQuery Validate rules and/or messages.</param>
/// <returns type="jQuery.validator.unobtrusive.adapters" />
if (!fn) { // Called with no params, just a function
fn = params;
params = [];
}
this.push({ name: adapterName, params: params, adapt: fn });
return this;
};
adapters.addBool = function (adapterName, ruleName) {
/// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
/// the jQuery Validate validation rule has no parameter values.</summary>
/// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
/// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
/// <param name="ruleName" type="String" optional="true">[Optional] The name of the jQuery Validate rule. If not provided, the value
/// of adapterName will be used instead.</param>
/// <returns type="jQuery.validator.unobtrusive.adapters" />
return this.add(adapterName, function (options) {
setValidationValues(options, ruleName || adapterName, true);
});
};
adapters.addMinMax = function (adapterName, minRuleName, maxRuleName, minMaxRuleName, minAttribute, maxAttribute) {
/// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
/// the jQuery Validate validation has three potential rules (one for min-only, one for max-only, and
/// one for min-and-max). The HTML parameters are expected to be named -min and -max.</summary>
/// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
/// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
/// <param name="minRuleName" type="String">The name of the jQuery Validate rule to be used when you only
/// have a minimum value.</param>
/// <param name="maxRuleName" type="String">The name of the jQuery Validate rule to be used when you only
/// have a maximum value.</param>
/// <param name="minMaxRuleName" type="String">The name of the jQuery Validate rule to be used when you
/// have both a minimum and maximum value.</param>
/// <param name="minAttribute" type="String" optional="true">[Optional] The name of the HTML attribute that
/// contains the minimum value. The default is "min".</param>
/// <param name="maxAttribute" type="String" optional="true">[Optional] The name of the HTML attribute that
/// contains the maximum value. The default is "max".</param>
/// <returns type="jQuery.validator.unobtrusive.adapters" />
return this.add(adapterName, [minAttribute || "min", maxAttribute || "max"], function (options) {
var min = options.params.min,
max = options.params.max;
if (min && max) {
setValidationValues(options, minMaxRuleName, [min, max]);
}
else if (min) {
setValidationValues(options, minRuleName, min);
}
else if (max) {
setValidationValues(options, maxRuleName, max);
}
});
};
adapters.addSingleVal = function (adapterName, attribute, ruleName) {
/// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
/// the jQuery Validate validation rule has a single value.</summary>
/// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
/// in the data-val-nnnn HTML attribute(where nnnn is the adapter name).</param>
/// <param name="attribute" type="String">[Optional] The name of the HTML attribute that contains the value.
/// The default is "val".</param>
/// <param name="ruleName" type="String" optional="true">[Optional] The name of the jQuery Validate rule. If not provided, the value
/// of adapterName will be used instead.</param>
/// <returns type="jQuery.validator.unobtrusive.adapters" />
return this.add(adapterName, [attribute || "val"], function (options) {
setValidationValues(options, ruleName || adapterName, options.params[attribute]);
});
};
$jQval.addMethod("__dummy__", function (value, element, params) {
return true;
});
$jQval.addMethod("regex", function (value, element, params) {
var match;
if (this.optional(element)) {
return true;
}
match = new RegExp(params).exec(value);
return (match && (match.index === 0) && (match[0].length === value.length));
});
$jQval.addMethod("nonalphamin", function (value, element, nonalphamin) {
var match;
if (nonalphamin) {
match = value.match(/\W/g);
match = match && match.length >= nonalphamin;
}
return match;
});
if ($jQval.methods.extension) {
adapters.addSingleVal("accept", "mimtype");
adapters.addSingleVal("extension", "extension");
} else {
// for backward compatibility, when the 'extension' validation method does not exist, such as with versions
// of JQuery Validation plugin prior to 1.10, we should use the 'accept' method for
// validating the extension, and ignore mime-type validations as they are not supported.
adapters.addSingleVal("extension", "extension", "accept");
}
adapters.addSingleVal("regex", "pattern");
adapters.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url");
adapters.addMinMax("length", "minlength", "maxlength", "rangelength").addMinMax("range", "min", "max", "range");
adapters.addMinMax("minlength", "minlength").addMinMax("maxlength", "minlength", "maxlength");
adapters.add("equalto", ["other"], function (options) {
var prefix = getModelPrefix(options.element.name),
other = options.params.other,
fullOtherName = appendModelPrefix(other, prefix),
element = $(options.form).find(":input").filter("[name='" + escapeAttributeValue(fullOtherName) + "']")[0];
setValidationValues(options, "equalTo", element);
});
adapters.add("required", function (options) {
// jQuery Validate equates "required" with "mandatory" for checkbox elements
if (options.element.tagName.toUpperCase() !== "INPUT" || options.element.type.toUpperCase() !== "CHECKBOX") {
setValidationValues(options, "required", true);
}
});
adapters.add("remote", ["url", "type", "additionalfields"], function (options) {
var value = {
url: options.params.url,
type: options.params.type || "GET",
data: {}
},
prefix = getModelPrefix(options.element.name);
$.each(splitAndTrim(options.params.additionalfields || options.element.name), function (i, fieldName) {
var paramName = appendModelPrefix(fieldName, prefix);
value.data[paramName] = function () {
var field = $(options.form).find(":input").filter("[name='" + escapeAttributeValue(paramName) + "']");
// For checkboxes and radio buttons, only pick up values from checked fields.
if (field.is(":checkbox")) {
return field.filter(":checked").val() || field.filter(":hidden").val() || '';
}
else if (field.is(":radio")) {
return field.filter(":checked").val() || '';
}
return field.val();
};
});
setValidationValues(options, "remote", value);
});
adapters.add("password", ["min", "nonalphamin", "regex"], function (options) {
if (options.params.min) {
setValidationValues(options, "minlength", options.params.min);
}
if (options.params.nonalphamin) {
setValidationValues(options, "nonalphamin", options.params.nonalphamin);
}
if (options.params.regex) {
setValidationValues(options, "regex", options.params.regex);
}
});
adapters.add("fileextensions", ["extensions"], function (options) {
setValidationValues(options, "extension", options.params.extensions);
});
$(function () {
$jQval.unobtrusive.parse(document);
});
return $jQval.unobtrusive;
}));

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,22 @@
The MIT License (MIT)
=====================
Copyright Jörn Zaefferer
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,21 @@
Copyright OpenJS Foundation and other contributors, https://openjsf.org/
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

10881
wwwroot/lib/jquery/dist/jquery.js vendored Normal file

File diff suppressed because it is too large Load Diff

2
wwwroot/lib/jquery/dist/jquery.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long