merge
This commit is contained in:
+5
-2
@@ -1,4 +1,4 @@
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||
@@ -388,4 +388,7 @@ FodyWeavers.xsd
|
||||
# JetBrains Rider
|
||||
.idea/
|
||||
*.sln.iml
|
||||
© 2021 GitHub, Inc.
|
||||
© 2021 GitHub, Inc.
|
||||
|
||||
|
||||
*.config
|
||||
|
||||
@@ -155,7 +155,7 @@
|
||||
</site>
|
||||
<site name="MeterProcessState" id="2">
|
||||
<application path="/" applicationPool="Clr4IntegratedAppPool">
|
||||
<virtualDirectory path="/" physicalPath="C:\Users\drabesch_ro\Repo\lab\la_operations\laa_production\Common\Service\MeterProcessState" />
|
||||
<virtualDirectory path="/" physicalPath="C:\Users\SZLATEV\Source\Repos\laa_production\Common\Service\MeterProcessState" />
|
||||
</application>
|
||||
<bindings>
|
||||
<binding protocol="http" bindingInformation="*:56011:localhost" />
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
5ed75d99ee45ff67821090f1b3dbb001dd9e4fe3
|
||||
2060865c94a192d7a90bef853b7068b66f669cb3
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
0d85a5b3a7561b41163c20e5dc7713bcd0d65555
|
||||
590ff54dbee38af4239a7555d24927a48da34616
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" />
|
||||
<PackageReference Include="nunit" Version="3.10.1" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.10.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.8.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\LaaProductionWeb.API\LaaProductionWeb.API.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.AspNetCore.Mvc.Abstractions">
|
||||
<HintPath>..\..\..\..\..\..\..\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.aspnetcore.mvc.abstractions\2.1.1\lib\netstandard2.0\Microsoft.AspNetCore.Mvc.Abstractions.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,171 @@
|
||||
namespace LaaProductionWeb.Tests.Models
|
||||
{
|
||||
using LaaProductionWeb.API.Models;
|
||||
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
public class ModelResultTests
|
||||
{
|
||||
[Test]
|
||||
public void ModelResult_ShouldBeImplicitlyCreated_FromModelStateDictionary()
|
||||
{
|
||||
// Act
|
||||
ModelResult<string> modelResult = default(ModelStateDictionary);
|
||||
|
||||
// Assert
|
||||
Assert.IsNotNull(modelResult);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ModelResult_ShouldInitializeModelErrors_WhenCreatedFrom_ModelStateDictionary()
|
||||
{
|
||||
// Act
|
||||
ModelResult<string> modelResult = default(ModelStateDictionary);
|
||||
|
||||
// Assert
|
||||
Assert.IsNotNull(modelResult.ModelErrors);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ModelResult_ShouldNotSucceeded_WhenCreatedFrom_ModelStateDictionary()
|
||||
{
|
||||
// Act
|
||||
ModelResult<string> modelResult = default(ModelStateDictionary);
|
||||
|
||||
// Assert
|
||||
Assert.IsFalse(modelResult.Succeeded);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ModelResult_ShouldBeImplicitlyCreated_FromOtherObjects()
|
||||
{
|
||||
// Act
|
||||
ModelResult<dynamic> modelResult = default(object);
|
||||
|
||||
// Assert
|
||||
Assert.IsNotNull(modelResult);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ModelResult_ShouldSucceeded_WhenCreated_FromOtherObjects()
|
||||
{
|
||||
// Act
|
||||
ModelResult<dynamic> modelResult = default(object);
|
||||
|
||||
// Assert
|
||||
Assert.IsTrue(modelResult.Succeeded);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ModelResult_ShouldHaveSameValue_WhenCreated_FromOtherObjects()
|
||||
{
|
||||
// Arrange
|
||||
var value = nameof(ModelResult<dynamic>);
|
||||
ModelResult<string> modelResult = value;
|
||||
|
||||
// Act
|
||||
var fieldValue = typeof(ModelResult<string>)
|
||||
.GetFields(BindingFlags.NonPublic | BindingFlags.Instance)
|
||||
.FirstOrDefault(x => x.Name == nameof(value))
|
||||
?.GetValue(modelResult);
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(value, fieldValue);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ModelResult_AddModelError_ShuldNotAddError_WhenKeyIsNull()
|
||||
{
|
||||
// Arrange
|
||||
ModelResult<dynamic> modelResult = default(ModelStateDictionary);
|
||||
var modelErrors = modelResult.ModelErrors;
|
||||
|
||||
// Act
|
||||
var errorsCountBefore = modelErrors.Count;
|
||||
modelResult.AddModelError(null, null);
|
||||
var errorsCountAfter = modelErrors.Count;
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(errorsCountBefore, errorsCountAfter);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ModelResult_AddModelError_ShuldAddErrors_WhenKeyIsNotNull()
|
||||
{
|
||||
// Arrange
|
||||
ModelResult<dynamic> modelResult = default(ModelStateDictionary);
|
||||
var modelErrors = modelResult.ModelErrors;
|
||||
|
||||
// Act
|
||||
var errorsCountBefore = modelErrors.Count;
|
||||
modelResult.AddModelError(string.Empty, null);
|
||||
var errorsCountAfter = modelErrors.Count;
|
||||
|
||||
// Assert
|
||||
Assert.Greater(errorsCountAfter, errorsCountBefore);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ModelResult_AddModelError_ShuldOverrideError_WhenKeyExists()
|
||||
{
|
||||
// Arrange
|
||||
ModelResult<dynamic> modelResult = default(ModelStateDictionary);
|
||||
var modelErrors = modelResult.ModelErrors;
|
||||
|
||||
// Act
|
||||
modelResult.AddModelError(string.Empty, "1");
|
||||
var valueBefore = modelErrors[string.Empty];
|
||||
|
||||
modelResult.AddModelError(string.Empty, "2");
|
||||
var valueAfter = modelErrors[string.Empty];
|
||||
|
||||
// Assert
|
||||
Assert.AreNotEqual(valueBefore, valueAfter);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ModelResult_ReturnsNotFoundResult_WhenModelResult_IsNull()
|
||||
{
|
||||
// Arrange
|
||||
ModelResult<dynamic> modelResult = null;
|
||||
|
||||
// Act
|
||||
ActionResult actionResult = modelResult;
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(actionResult.GetType(), typeof(NotFoundResult));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ModelResult_ReturnsBadRequestObjectResult_WhenCreatedFrom_ModelStateDictionary()
|
||||
{
|
||||
// Arrange
|
||||
ModelResult<dynamic> modelResult = default(ModelStateDictionary);
|
||||
|
||||
// Act
|
||||
ActionResult actionResult = modelResult;
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(actionResult.GetType(), typeof(BadRequestObjectResult));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ModelResult_ReturnsOkObjectResult_WhenCreatedWhitValue()
|
||||
{
|
||||
// Arrange
|
||||
ModelResult<dynamic> modelResult = default(string);
|
||||
|
||||
// Act
|
||||
ActionResult actionResult = modelResult;
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(actionResult.GetType(), typeof(OkObjectResult));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
namespace LaaProductionWeb.Tests.Models
|
||||
{
|
||||
using LaaProductionWeb.API.Areas.Serach.Models;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
public class WildcardInputModelTests
|
||||
{
|
||||
private readonly WildcardInputModel model;
|
||||
private readonly PropertyInfo tokenPropertyInfo;
|
||||
|
||||
public WildcardInputModelTests()
|
||||
{
|
||||
this.model = new WildcardInputModel();
|
||||
this.tokenPropertyInfo = typeof(WildcardInputModel)
|
||||
.GetProperty(nameof(WildcardInputModel.Token), BindingFlags.Instance | BindingFlags.Public);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ModelValidation_ShouldNotValidate_WhenTokenIsNull()
|
||||
{
|
||||
// Arrange
|
||||
var errorMessage = this.ValidateModelWhitValue(default(string));
|
||||
|
||||
// Act
|
||||
var attributeMessage = this.GetAttributeMessage<RequiredAttribute>();
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(errorMessage, attributeMessage);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ModelValidation_ShouldNotValidate_WhenTokenIsUnder_1CharLength()
|
||||
{
|
||||
// Arrange
|
||||
var errorMessage = this.ValidateModelWhitValue(string.Empty);
|
||||
|
||||
// Act
|
||||
var attributeMessage = this.GetAttributeMessage<StringLengthAttribute>();
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(errorMessage, attributeMessage);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ModelValidation_ShouldNotValidate_WhenTokenIsOver_50CharsLength()
|
||||
{
|
||||
// Arrange
|
||||
var errorMessage = this.ValidateModelWhitValue(new string('0', 51));
|
||||
|
||||
// Act
|
||||
var attributeMessage = this.GetAttributeMessage<StringLengthAttribute>();
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(errorMessage, attributeMessage);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase("^")]
|
||||
[TestCase("°")]
|
||||
[TestCase("\"")]
|
||||
[TestCase("§")]
|
||||
[TestCase("$")]
|
||||
[TestCase("%")]
|
||||
[TestCase("&")]
|
||||
[TestCase("/")]
|
||||
[TestCase("(")]
|
||||
[TestCase(")")]
|
||||
[TestCase("=")]
|
||||
[TestCase("?")]
|
||||
[TestCase("`")]
|
||||
[TestCase("´")]
|
||||
[TestCase("'")]
|
||||
[TestCase("#")]
|
||||
[TestCase("*")]
|
||||
[TestCase("+")]
|
||||
[TestCase("|")]
|
||||
[TestCase("\t")]
|
||||
[TestCase("\n")]
|
||||
[TestCase("<")]
|
||||
[TestCase(">")]
|
||||
[TestCase(".")]
|
||||
[TestCase(";")]
|
||||
[TestCase(":")]
|
||||
[TestCase("_")]
|
||||
[TestCase("ä")]
|
||||
[TestCase("ö")]
|
||||
[TestCase("ü")]
|
||||
[TestCase("Ä")]
|
||||
[TestCase("Ö")]
|
||||
[TestCase("Ü")]
|
||||
[TestCase("ß")]
|
||||
public void ModelValidation_ShouldNotValidate_WhenTokenContains_NonWordCharachters(string token)
|
||||
{
|
||||
// Arrange
|
||||
var errorMessage = this.ValidateModelWhitValue(token);
|
||||
|
||||
// Act
|
||||
var attributeMessage = this.GetAttributeMessage<RegularExpressionAttribute>();
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(errorMessage, attributeMessage);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase("0123245 5575689-ARWQGVVJALR fasdkfawe irfoelvm")]
|
||||
public void ModelValidation_ShouldValidate_WhenTokenIsValidNr(string token)
|
||||
{
|
||||
// Arrange
|
||||
var nullMessage = default(string);
|
||||
|
||||
// Act
|
||||
var errorMessage = this.ValidateModelWhitValue(token);
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(errorMessage, nullMessage);
|
||||
}
|
||||
|
||||
private string ValidateModelWhitValue(string value)
|
||||
{
|
||||
var validationResults = new List<ValidationResult>();
|
||||
var validationContext = new ValidationContext(this.model);
|
||||
|
||||
if (Validator.TryValidateObject(this.model, validationContext, validationResults))
|
||||
{
|
||||
return validationResults
|
||||
.Where(x => x.MemberNames.Contains(nameof(WildcardInputModel.Token)))
|
||||
.FirstOrDefault(x => !string.IsNullOrWhiteSpace(x.ErrorMessage))
|
||||
?.ErrorMessage ?? default(string);
|
||||
}
|
||||
|
||||
return default(string);
|
||||
}
|
||||
|
||||
private string GetAttributeMessage<T>() where T : ValidationAttribute
|
||||
=> this.tokenPropertyInfo
|
||||
.GetCustomAttribute<RequiredAttribute>()
|
||||
.ErrorMessage;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace LaaProductionWeb.API.Areas
|
||||
{
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
[ApiController]
|
||||
[Route("[area]/[controller]")]
|
||||
public class AreaController : ControllerBase
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
namespace LaaProductionWeb.API.Areas.Serach.Controllers
|
||||
{
|
||||
using LaaProductionWeb.API.Areas.Serach.Models;
|
||||
using LaaProductionWeb.API.Areas.Serach.Models.Interfaces;
|
||||
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
public class WildcardController : SearchController
|
||||
{
|
||||
private readonly IWildcardModel wildcardModel;
|
||||
|
||||
public WildcardController(IWildcardModel wildcardModel)
|
||||
=> this.wildcardModel = wildcardModel;
|
||||
|
||||
[HttpOptions]
|
||||
public ActionResult Options()
|
||||
=> this.wildcardModel.Options();
|
||||
|
||||
[HttpGet]
|
||||
public ActionResult Get([FromQuery] WildcardInputModel model)
|
||||
=> this.wildcardModel.Find(this.ModelState, model);
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
namespace LaaProductionWeb.API.Areas.Serach.Models.Interfaces
|
||||
{
|
||||
using LaaProductionWeb.API.Models;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
public interface IWildcardModel
|
||||
{
|
||||
ModelResult<IEnumerable<WildcardResult>> Find(ModelStateDictionary validationState, WildcardInputModel model);
|
||||
|
||||
ModelResult<IEnumerable<string>> Options();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
namespace LaaProductionWeb.API.Areas.Serach.Models
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
|
||||
public class WildcardInputModel
|
||||
{
|
||||
private IEnumerable<string> fields = Array.Empty<string>();
|
||||
|
||||
[Required(ErrorMessageResourceType = typeof(ErrorMessages), ErrorMessageResourceName = nameof(ErrorMessages.Required))]
|
||||
[StringLength(50, ErrorMessageResourceType = typeof(ErrorMessages), ErrorMessageResourceName = nameof(ErrorMessages.StringLength), MinimumLength = 1)]
|
||||
[RegularExpression("^[0-9 a-z-A-Z]+$", ErrorMessageResourceType = typeof(ErrorMessages), ErrorMessageResourceName = nameof(ErrorMessages.RegularExpression))]
|
||||
public string Token { get; set; }
|
||||
|
||||
public string Fields
|
||||
{
|
||||
get => string.Join(",", this.fields);
|
||||
set => this.fields = $"{value}".Split(',', StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
|
||||
internal IEnumerable<string> GetRequiredFields(IEnumerable<string> allFields)
|
||||
{
|
||||
if (this.fields.Any())
|
||||
{
|
||||
return allFields.Where(x => this.fields.Contains(x, StringComparer.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
return allFields;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
namespace LaaProductionWeb.API.Areas.Serach.Models
|
||||
{
|
||||
using LaaProductionWeb.Data.Interfaces;
|
||||
using LaaProductionWeb.API.Areas.Serach.Models.Interfaces;
|
||||
using LaaProductionWeb.API.Models;
|
||||
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
public class WildcardModel : IWildcardModel
|
||||
{
|
||||
public static readonly IEnumerable<string> fields = new[]
|
||||
{
|
||||
"Client",
|
||||
"OrderNo",
|
||||
"PosNo",
|
||||
"SerialNo",
|
||||
"ClientSerialNo",
|
||||
"KurzBez",
|
||||
"Typ",
|
||||
"Nennweite",
|
||||
"Baulaenge",
|
||||
"Quantity",
|
||||
"FabricNo",
|
||||
"IdentNr",
|
||||
"PcbId",
|
||||
"ERAddress",
|
||||
"GMAddress",
|
||||
};
|
||||
|
||||
private readonly ISqlClient sqlClient;
|
||||
|
||||
public WildcardModel(ISqlClient sqlClient)
|
||||
=> this.sqlClient = sqlClient;
|
||||
|
||||
public ModelResult<IEnumerable<WildcardResult>> Find(ModelStateDictionary validationState, WildcardInputModel model)
|
||||
{
|
||||
if (validationState.IsValid)
|
||||
{
|
||||
var requiredFields = model.GetRequiredFields(fields);
|
||||
|
||||
return sqlClient.ExecuteReader($@"
|
||||
DECLARE @serienNr TABLE([Nr] VARCHAR(50));
|
||||
-----------------------------------------------------------------------------
|
||||
-- 1. LOOK FOR SERIAL NUMBER ------------------------------------------------
|
||||
-----------------------------------------------------------------------------
|
||||
INSERT INTO @serienNr
|
||||
SELECT [APS].[SerienNr]
|
||||
FROM [AuftragPositionSerienNr] AS [APS]
|
||||
WHERE [APS].[SerienNr] LIKE @{nameof(model.Token)}
|
||||
OR [APS].[KundeneigeneSerienNr] LIKE @{nameof(model.Token)};
|
||||
-----------------------------------------------------------------------------
|
||||
-- 2. LOOK FOR PCB NUMBER ---------------------------------------------------
|
||||
-----------------------------------------------------------------------------
|
||||
INSERT INTO @serienNr
|
||||
SELECT [PCBS].[MapPcbIdToSerialNumber_SerialNumber]
|
||||
FROM [MapPcbIdToSerialNumber] AS [PCBS]
|
||||
WHERE [PCBS].[MapPcbIdToSerialNumber_PcbId] LIKE @{nameof(model.Token)};
|
||||
-----------------------------------------------------------------------------
|
||||
-- 3. LOOK FOR FUNK ADDRESS E-REGISTER --------------------------------------
|
||||
-----------------------------------------------------------------------------
|
||||
INSERT INTO @serienNr
|
||||
SELECT [ER].[Seriennummer]
|
||||
FROM [eRegister] AS [ER]
|
||||
WHERE [ER].[Adresse] LIKE @{nameof(model.Token)};
|
||||
-----------------------------------------------------------------------------
|
||||
-- 4. LOOK FOR FUNK ADDRESS GENESIS -----------------------------------------
|
||||
-----------------------------------------------------------------------------
|
||||
INSERT INTO @serienNr
|
||||
SELECT [GM].[Seriennummer]
|
||||
FROM [Genesis_Meter] AS [GM]
|
||||
WHERE [GM].[Adresse] LIKE @{nameof(model.Token)};
|
||||
-----------------------------------------------------------------------------
|
||||
-- 5. TAKE ORDERS INFO ------------------------------------------------------
|
||||
-----------------------------------------------------------------------------
|
||||
SELECT DISTINCT
|
||||
-- KundenNr CustomerNr
|
||||
[KN].[Name] AS [Client] -- Customer
|
||||
-- FertigungNr - ProductionOrderNo
|
||||
, [APS].[AuftragNr] AS [OrderNo] -- CustomerOrderNo
|
||||
, [APS].[PositionNr] AS [PosNo]
|
||||
, [APS].[SerienNr] AS [SerialNo]
|
||||
, [APS].[KundeneigeneSerienNr] AS [ClientSerialNo] -- CustomerSerialNo
|
||||
, [IDN].[KurzBez] AS [KurzBez]
|
||||
, [IDN].[Typ] AS [Typ]
|
||||
, [IDN].[Nennweite] AS [Nennweite]
|
||||
, [IDN].[Baulaenge] AS [Baulaenge]
|
||||
, [AP].[Menge] AS [Quantity]
|
||||
, [APS].[FabNr] AS [FabricNo]
|
||||
, [IDN].[IdentNr] AS [IdentNr]
|
||||
, [PCBS].[MapPcbIdToSerialNumber_PcbId] AS [PcbId]
|
||||
, [ER].[Adresse] AS [ERAddress] -- ErRadioAddress
|
||||
, [GM].[Adresse] AS [GMAddress] -- GmRadioAddress
|
||||
FROM [AuftragPositionSerienNr] AS [APS]
|
||||
LEFT JOIN [AuftragPosition_Gesamt] AS [AP]
|
||||
ON [AP].[AuftragNr] = [APS].[AuftragNr]
|
||||
AND [AP].[PositionNr] = [APS].[PositionNr]
|
||||
LEFT JOIN [Auftrag_Gesamt] AS [AG]
|
||||
ON [AG].[AuftragNr] = [APS].[AuftragNr]
|
||||
LEFT JOIN [Kunde] AS [KN]
|
||||
ON [KN].[KundenNr] = [AG].[KundenNr]
|
||||
LEFT JOIN [Identnr] AS [IDN]
|
||||
ON [IDN].[IdentNr] = [AP].[Identnr]
|
||||
LEFT JOIN [MapPcbIdToSerialNumber] AS [PCBS]
|
||||
ON [PCBS].[MapPcbIdToSerialNumber_SerialNumber] = [APS].[SerienNr]
|
||||
LEFT JOIN [eRegister] AS [ER]
|
||||
ON [ER].[Seriennummer] = [APS].[SerienNr]
|
||||
LEFT JOIN [Genesis_Meter] AS [GM]
|
||||
ON [GM].[Seriennummer] = [APS].[SerienNr]
|
||||
WHERE [APS].[SerienNr] IN (SELECT [Nr] FROM @serienNr)",
|
||||
parameters => parameters.Add(nameof(model.Token), model.Token),
|
||||
reader => this.ToWildcardResult(reader, requiredFields))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
return validationState;
|
||||
}
|
||||
|
||||
public ModelResult<IEnumerable<string>> Options()
|
||||
=> fields.ToList();
|
||||
|
||||
internal WildcardResult ToWildcardResult(ISqlReader reader, IEnumerable<string> fields)
|
||||
{
|
||||
var wildcardResult = new WildcardResult();
|
||||
|
||||
foreach (var field in fields)
|
||||
{
|
||||
wildcardResult[field] = reader.GetValue(field);
|
||||
}
|
||||
|
||||
return wildcardResult;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace LaaProductionWeb.API.Areas.Serach.Models
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class WildcardResult : Dictionary<string, object>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace LaaProductionWeb.API.Areas.Serach
|
||||
{
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
[Area("Search")]
|
||||
public class SearchController : AreaController
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
namespace LaaProductionWeb.API.Areas.Shipment.Controllers.Scanned
|
||||
{
|
||||
using LaaProductionWeb.API.Areas.Shipment.Models.Interfaces;
|
||||
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
public class ScannedController : ShipmentController
|
||||
{
|
||||
private readonly IScanModel scanModel;
|
||||
|
||||
public ScannedController(IScanModel scanModel)
|
||||
{
|
||||
this.scanModel = scanModel;
|
||||
}
|
||||
|
||||
[HttpGet("Serial/{serialNo}")]
|
||||
public IActionResult Get([FromRoute] string serialNo)
|
||||
=> this.Ok(serialNo);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace LaaProductionWeb.API.Areas.Shipment.Models.Interfaces
|
||||
{
|
||||
public interface IScanModel
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace LaaProductionWeb.API.Areas.Shipment.Models
|
||||
{
|
||||
using LaaProductionWeb.API.Areas.Shipment.Models.Interfaces;
|
||||
using LaaProductionWeb.Data.Interfaces;
|
||||
|
||||
public class ScanModel : IScanModel
|
||||
{
|
||||
private readonly ISqlClient sqlClient;
|
||||
|
||||
public ScanModel(ISqlClient sqlClient)
|
||||
=> this.sqlClient = sqlClient;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace LaaProductionWeb.API.Areas.Shipment
|
||||
{
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
[Area("Shipment")]
|
||||
public class ShipmentController : AreaController
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace LaaProductionWeb.API {
|
||||
using System;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
public class ErrorMessages {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal ErrorMessages() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
public static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("LaaProductionWeb.API.ErrorMessages", typeof(ErrorMessages).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
public static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Field {0} is not well formatted..
|
||||
/// </summary>
|
||||
public static string RegularExpression {
|
||||
get {
|
||||
return ResourceManager.GetString("RegularExpression", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Field {0} is required..
|
||||
/// </summary>
|
||||
public static string Required {
|
||||
get {
|
||||
return ResourceManager.GetString("Required", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Field {0} requires at liest {2} and up to {1} charachters..
|
||||
/// </summary>
|
||||
public static string StringLength {
|
||||
get {
|
||||
return ResourceManager.GetString("StringLength", resourceCulture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="RegularExpression" xml:space="preserve">
|
||||
<value>Field {0} is not well formatted.</value>
|
||||
</data>
|
||||
<data name="Required" xml:space="preserve">
|
||||
<value>Field {0} is required.</value>
|
||||
</data>
|
||||
<data name="StringLength" xml:space="preserve">
|
||||
<value>Field {0} requires at liest {2} and up to {1} charachters.</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -0,0 +1,38 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
<UserSecretsId>1fb61288-8dc8-4657-b44c-193c6aad5f65</UserSecretsId>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.App" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.1.2" PrivateAssets="All" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="2.1.9" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\LaaProductionWeb.Data\LaaProductionWeb.Data.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="ErrorMessages.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>ErrorMessages.resx</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Update="ErrorMessages.resx">
|
||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>ErrorMessages.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Areas\Shipment\Data\" />
|
||||
<Folder Include="Areas\Shipment\Views\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,21 @@
|
||||
namespace LaaProductionWeb.API.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// C# class representation of the appsettings.json file.
|
||||
/// </summary>
|
||||
public class ApplicationSettings
|
||||
{
|
||||
/// <summary>
|
||||
/// Default defined ConnectionStrings section for the appsettings.json
|
||||
/// </summary>
|
||||
public ConnectionStrings ConnectionStrings { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default defined ConnectionStrings section for the appsettings.json
|
||||
/// </summary>
|
||||
public class ConnectionStrings
|
||||
{
|
||||
public string DefaultConnection { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
namespace LaaProductionWeb.API.Models
|
||||
{
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
public class ModelResult<T>
|
||||
{
|
||||
private readonly T value;
|
||||
private readonly Dictionary<string, string> errors;
|
||||
|
||||
private ModelResult(bool succeeded)
|
||||
{
|
||||
this.Succeeded = succeeded;
|
||||
this.errors = new Dictionary<string, string>();
|
||||
}
|
||||
|
||||
private ModelResult(T value)
|
||||
{
|
||||
this.Succeeded = true;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public bool Succeeded { get; }
|
||||
|
||||
public IReadOnlyDictionary<string, string> ModelErrors
|
||||
=> this.errors;
|
||||
|
||||
public void AddModelError(string key, string value)
|
||||
{
|
||||
if (key != null)
|
||||
{
|
||||
this.errors[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public static implicit operator ModelResult<T>(T value)
|
||||
=> new ModelResult<T>(value);
|
||||
|
||||
public static implicit operator ModelResult<T>(ModelStateDictionary modelState)
|
||||
{
|
||||
var validationResults = new ModelResult<T>(false);
|
||||
|
||||
if (modelState != null)
|
||||
{
|
||||
foreach (var entry in modelState)
|
||||
{
|
||||
var errorKey = entry.Key;
|
||||
var errorValue = entry.Value;
|
||||
|
||||
if (errorValue.ValidationState == ModelValidationState.Invalid && errorValue.Errors.Any())
|
||||
{
|
||||
validationResults.AddModelError(errorKey, errorValue.Errors.First().ErrorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return validationResults;
|
||||
}
|
||||
|
||||
public static implicit operator ActionResult(ModelResult<T> modelState)
|
||||
{
|
||||
if (modelState is null)
|
||||
{
|
||||
return new NotFoundResult();
|
||||
}
|
||||
else if (modelState.Succeeded)
|
||||
{
|
||||
return new OkObjectResult(modelState.value);
|
||||
}
|
||||
|
||||
return new BadRequestObjectResult(modelState.errors);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
namespace LaaProductionWeb.API
|
||||
{
|
||||
using Microsoft.AspNetCore;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
|
||||
/// <summary>
|
||||
/// Application startup class contining the <seealso cref="Program.Main(string[])"/> method.
|
||||
/// </summary>
|
||||
public class Program
|
||||
{
|
||||
/// <summary>
|
||||
/// Default start point for the application.
|
||||
/// </summary>
|
||||
/// <param name="args"><see cref="string[]"/> arguments provided from server on application start.</param>
|
||||
public static void Main(string[] args)
|
||||
=> CreateWebHostBuilder(args)
|
||||
.Build()
|
||||
.Run();
|
||||
|
||||
/// <summary>
|
||||
/// !Important do not refactor. This method is used from other frameworks, like EntityFramework.
|
||||
/// </summary>
|
||||
/// <param name="args"><see cref="string[]"/> arguments provided from for creating the <seealso cref="WebHost"/>.</param>
|
||||
/// <returns>Created and configured <see cref="IWebHostBuilder"/>.</returns>
|
||||
public static IWebHostBuilder CreateWebHostBuilder(string[] args)
|
||||
=> WebHost
|
||||
.CreateDefaultBuilder(args)
|
||||
.UseStartup<Startup>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"$schema": "http://json.schemastore.org/launchsettings.json",
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:59262",
|
||||
"sslPort": 44346
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "api/values",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"LaaProductionWeb.API": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "api/values",
|
||||
"applicationUrl": "https://localhost:5001;http://localhost:5000",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
namespace LaaProductionWeb.API
|
||||
{
|
||||
using LaaProductionWeb.Data;
|
||||
using LaaProductionWeb.Data.Interfaces;
|
||||
using LaaProductionWeb.API.Areas.Serach.Models;
|
||||
using LaaProductionWeb.API.Areas.Serach.Models.Interfaces;
|
||||
using LaaProductionWeb.API.Models;
|
||||
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
public class Startup
|
||||
{
|
||||
private readonly IConfiguration configuration;
|
||||
|
||||
public Startup(IConfiguration configuration)
|
||||
=> this.configuration = configuration;
|
||||
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
var connectionString = this.configuration
|
||||
.GetConnectionString(nameof(ConnectionStrings.DefaultConnection));
|
||||
services.AddTransient<ISqlClient, SqlClient>(_ => new SqlClient(connectionString));
|
||||
services.AddTransient<IWildcardModel, WildcardModel>();
|
||||
services.Configure<ApiBehaviorOptions>(options =>
|
||||
{
|
||||
options.SuppressModelStateInvalidFilter = true;
|
||||
});
|
||||
services
|
||||
.AddMvc()
|
||||
.SetCompatibilityVersion(CompatibilityVersion.Latest);
|
||||
}
|
||||
|
||||
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
|
||||
{
|
||||
app.UseHsts();
|
||||
app.UseDeveloperExceptionPage();
|
||||
app.UseHttpsRedirection();
|
||||
app.UseStaticFiles();
|
||||
app.UseCookiePolicy();
|
||||
|
||||
app.UseMvc(routes =>
|
||||
{
|
||||
routes.MapRoute(name: "default", template: "{controller=Home}/{action=Index}/{id?}");
|
||||
routes.MapRoute(name: "areas", template: "{area:exists}/{controller=Home}/{action=Index}/{id?}");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"ConnectionStrings": {
|
||||
"DefaultConnection": "Data Source=SLASQL01.emea.sensus.net;Initial Catalog=Auftrag;Password=ServiceParingfile;Persist Security Info=True;User ID=ServiceParingfile;"
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
|
||||
using System.Threading.Tasks;
|
||||
|
||||
public interface ISqlClient
|
||||
{
|
||||
int ExecuteNonQuery(string query, Action<SqlParameters> parameters, SqlInfoMessageEventHandler errorCallback = null);
|
||||
|
||||
@@ -7,5 +7,7 @@
|
||||
string GetString(int index = -1);
|
||||
|
||||
T GetValue<T>(int index = -1);
|
||||
|
||||
object GetValue(string field);
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@
|
||||
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<Deterministic>true</Deterministic>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
@@ -48,6 +49,7 @@
|
||||
<Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Web" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
@@ -56,8 +58,6 @@
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Repositories\Interfaces\IRepository[T].cs" />
|
||||
<Compile Include="Repositories\Repository[T].cs" />
|
||||
<Compile Include="SqlClient.cs" />
|
||||
<Compile Include="SqlClientExtensions.cs" />
|
||||
<Compile Include="Interfaces\ISqlClient.cs" />
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
namespace LaaProductionWeb.Data.Repositories.Interfaces
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
|
||||
public interface IRepository<T>
|
||||
{
|
||||
int Create(string query, object parameters);
|
||||
|
||||
int Delete(string query, object parameters);
|
||||
|
||||
IEnumerable<T> First(string query, object parameters);
|
||||
|
||||
T Read(string query, object parameters);
|
||||
|
||||
int Update(string query, object parameters);
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
namespace LaaProductionWeb.Data.Repositories
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
|
||||
using LaaProductionWeb.Data.Interfaces;
|
||||
using LaaProductionWeb.Data.Repositories.Interfaces;
|
||||
|
||||
public abstract class Repository<T> : IRepository<T>
|
||||
{
|
||||
private readonly ISqlClient sqlClient;
|
||||
|
||||
protected Repository(ISqlClient sqlClient)
|
||||
=> this.sqlClient = sqlClient;
|
||||
|
||||
public int Create(string query, object parameters)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public int Delete(string query, object parameters)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public IEnumerable<T> First(string query, object parameters)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public T Read(string query, object parameters)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public int Update(string query, object parameters)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Data.SqlClient;
|
||||
|
||||
|
||||
public class SqlClient : ISqlClient
|
||||
{
|
||||
private readonly string connectionString;
|
||||
|
||||
@@ -3,9 +3,13 @@
|
||||
using LaaProductionWeb.Data.Interfaces;
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
|
||||
using System;
|
||||
using System.Data.SqlClient;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
|
||||
public static class SqlClientExtensions
|
||||
{
|
||||
@@ -29,11 +33,31 @@
|
||||
sqlConnection.Open();
|
||||
}
|
||||
|
||||
internal static async Task OpenWithErrorHandlingAsync(this SqlConnection sqlConnection, SqlInfoMessageEventHandler messageHandler = null)
|
||||
{
|
||||
sqlConnection.FireInfoMessageEventOnUserErrors = true;
|
||||
sqlConnection.InfoMessage += SqlConnectionInfoMessage;
|
||||
|
||||
if (messageHandler != null)
|
||||
{
|
||||
sqlConnection.InfoMessage += messageHandler;
|
||||
}
|
||||
|
||||
await sqlConnection.OpenAsync();
|
||||
}
|
||||
|
||||
internal static void SqlConnectionInfoMessage(object sender, SqlInfoMessageEventArgs e)
|
||||
{
|
||||
Debug.WriteLine(e);
|
||||
|
||||
Log($"[{DateTime.Now: hh:mm:ss}] Error: {e.Source} - {e.Message}{Environment.NewLine}{string.Join(Environment.NewLine, e.Errors)}");
|
||||
|
||||
// TODO: Handle errors
|
||||
}
|
||||
|
||||
internal static void Log(string message)
|
||||
{
|
||||
// File.AppendAllText($"{Environment.CurrentDirectory}/App_Data/{DateTime.Now:yyyy_MM_dd}.log", $"{Environment.NewLine}{message}{Environment.NewLine}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,16 +3,32 @@
|
||||
using LaaProductionWeb.Data.Interfaces;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
public class SqlReader : ISqlReader, IDisposable
|
||||
{
|
||||
private readonly SqlDataReader sqlDataReader;
|
||||
private readonly IDictionary<string, int> columns;
|
||||
|
||||
private int column;
|
||||
|
||||
private SqlReader(SqlDataReader sqlDataReader)
|
||||
=> this.sqlDataReader = sqlDataReader;
|
||||
private SqlReader(SqlDataReader sqlDataReader)
|
||||
{
|
||||
this.sqlDataReader = sqlDataReader;
|
||||
this.columns = new Dictionary<string, int>();
|
||||
|
||||
var columnsCount = this.sqlDataReader.FieldCount;
|
||||
var columns = new string[columnsCount];
|
||||
|
||||
for (int i = 0; i < columnsCount; i++)
|
||||
{
|
||||
var columnName = this.sqlDataReader.GetName(i);
|
||||
this.columns[columnName] = i;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
@@ -38,17 +54,7 @@
|
||||
}
|
||||
|
||||
internal string[] GetColumns()
|
||||
{
|
||||
var columnsCount = this.sqlDataReader.FieldCount;
|
||||
var columns = new string[columnsCount];
|
||||
|
||||
for (int i = 0; i < columnsCount; i++)
|
||||
{
|
||||
columns[i] = this.sqlDataReader.GetName(i);
|
||||
}
|
||||
|
||||
return columns;
|
||||
}
|
||||
=> this.columns.Keys.ToArray();
|
||||
|
||||
public string GetString(int index = -1)
|
||||
{
|
||||
@@ -90,6 +96,26 @@
|
||||
return this.sqlDataReader.Read();
|
||||
}
|
||||
|
||||
internal Task<bool> ReadAsync()
|
||||
{
|
||||
this.column = 0;
|
||||
|
||||
return this.sqlDataReader.ReadAsync();
|
||||
}
|
||||
|
||||
public object GetValue(string field)
|
||||
{
|
||||
if (this.columns.TryGetValue($"{field}", out int index))
|
||||
{
|
||||
if (!this.sqlDataReader.IsDBNull(index))
|
||||
{
|
||||
return this.sqlDataReader.GetValue(index);
|
||||
}
|
||||
}
|
||||
|
||||
return default(object);
|
||||
}
|
||||
|
||||
public static implicit operator SqlReader(SqlDataReader sqlDataReader)
|
||||
=> new SqlReader(sqlDataReader);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
|
||||
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
|
||||
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0"/>
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
||||
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2"/></startup></configuration>
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
using LaaProductionWeb.Services.Interfaces;
|
||||
using LaaProductionWeb.Services.Models;
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class AccountService : IAccountService
|
||||
{
|
||||
private readonly ISqlClient sqlClient;
|
||||
@@ -11,22 +13,39 @@
|
||||
public AccountService(ISqlClient sqlClient)
|
||||
=> this.sqlClient = sqlClient;
|
||||
|
||||
public Employee FindEmployee(string firstName, string lastName)
|
||||
public Employee FindEmployee(int userId)
|
||||
{
|
||||
var employeIdentity = this.sqlClient.FirstOrDefault($@"
|
||||
SELECT TOP 1
|
||||
[MitarbeiterNr]
|
||||
, [Vorname] + ' ' + [Name]
|
||||
FROM [Mitarbeiter]
|
||||
WHERE [MitarbeiterNr] = @{nameof(userId)}",
|
||||
parameters => parameters.Add(nameof(userId), userId),
|
||||
reader => new KeyValuePair<int, string>(
|
||||
key: reader.GetValue<short>(),
|
||||
value: reader.GetString()));
|
||||
|
||||
var permissions = this.sqlClient.ExecuteReader($@"
|
||||
SELECT [MitarbeiterRechte].[Recht]
|
||||
FROM [Mitarbeiter]
|
||||
JOIN [MitarbeiterRechte]
|
||||
ON [MitarbeiterRechte].[MitarbeiterNr] = [Mitarbeiter].[MitarbeiterNr]
|
||||
WHERE [Vorname] LIKE @{nameof(firstName)}
|
||||
AND [Name] LIKE @{nameof(lastName)}
|
||||
FROM [MitarbeiterRechte]
|
||||
WHERE [MitarbeiterNr] = @{nameof(employeIdentity.Key)}
|
||||
AND [MitarbeiterRechte].[Recht] LIKE 'WEB_%'",
|
||||
parameters => parameters
|
||||
.Add(nameof(firstName), firstName)
|
||||
.Add(nameof(lastName), lastName),
|
||||
parameters => parameters.Add(nameof(employeIdentity.Key), employeIdentity.Key),
|
||||
reader => reader.GetString());
|
||||
|
||||
return new Employee(permissions);
|
||||
return new Employee(employeIdentity.Value, permissions);
|
||||
}
|
||||
|
||||
public int Login(string username, string password)
|
||||
=> this.sqlClient.FirstOrDefault($@"
|
||||
SELECT TOP 1 [MitarbeiterNr]
|
||||
FROM [Mitarbeiter]
|
||||
WHERE [Benutzername] LIKE @{nameof(username)}
|
||||
AND [Kennwort] LIKE @{nameof(password)}",
|
||||
parameters => parameters
|
||||
.Add(nameof(username), username)
|
||||
.Add(nameof(password), password),
|
||||
reader => reader.GetValue<short>());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
namespace LaaProductionWeb.Services
|
||||
{
|
||||
using LaaProductionWeb.Services.Interfaces;
|
||||
using LaaProductionWeb.Services.Models;
|
||||
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
public class HttpService : IHttpService
|
||||
{
|
||||
private readonly HttpClient httpClient;
|
||||
|
||||
public HttpService(string url)
|
||||
=> this.httpClient = new HttpClient
|
||||
{
|
||||
BaseAddress = new Uri(url, UriKind.Absolute)
|
||||
};
|
||||
|
||||
public async Task<HttpResponseModel> GetAsync(string path)
|
||||
{
|
||||
var httpResponseModel = new HttpResponseModel();
|
||||
|
||||
try
|
||||
{
|
||||
using (var httpRequestMessage = new HttpRequestMessage())
|
||||
{
|
||||
httpRequestMessage.Method = HttpMethod.Get;
|
||||
httpRequestMessage.RequestUri = new Uri(path, UriKind.Relative);
|
||||
|
||||
using (var httpResponseMessage = await this.httpClient.SendAsync(httpRequestMessage))
|
||||
{
|
||||
httpResponseModel.Succeeded = httpResponseMessage.IsSuccessStatusCode;
|
||||
|
||||
if (httpResponseMessage.Content != null)
|
||||
{
|
||||
httpResponseModel.Content = await httpResponseMessage.Content?.ReadAsStringAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
httpResponseModel.Error = e.Message;
|
||||
}
|
||||
|
||||
return httpResponseModel;
|
||||
}
|
||||
|
||||
public async Task<HttpResponseModel> OptionsAsync(string path)
|
||||
{
|
||||
var httpResponseModel = new HttpResponseModel();
|
||||
|
||||
try
|
||||
{
|
||||
using (var httpRequestMessage = new HttpRequestMessage())
|
||||
{
|
||||
httpRequestMessage.Method = HttpMethod.Options;
|
||||
httpRequestMessage.RequestUri = new Uri(path, UriKind.Relative);
|
||||
|
||||
using (var httpResponseMessage = await this.httpClient.SendAsync(httpRequestMessage))
|
||||
{
|
||||
httpResponseModel.Succeeded = httpResponseMessage.IsSuccessStatusCode;
|
||||
|
||||
if (httpResponseMessage.Content != null)
|
||||
{
|
||||
httpResponseModel.Content = await httpResponseMessage.Content?.ReadAsStringAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
httpResponseModel.Error = e.Message;
|
||||
}
|
||||
|
||||
return httpResponseModel;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
public interface IAccountService : ITransient
|
||||
{
|
||||
Employee FindEmployee(string firstName, string lastName);
|
||||
Employee FindEmployee(int userId);
|
||||
|
||||
int Login(string username, string password);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace LaaProductionWeb.Services.Interfaces
|
||||
{
|
||||
using LaaProductionWeb.Services.Models;
|
||||
|
||||
using System.Threading.Tasks;
|
||||
|
||||
public interface IHttpService
|
||||
{
|
||||
Task<HttpResponseModel> GetAsync(string path);
|
||||
|
||||
Task<HttpResponseModel> OptionsAsync(string path);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
namespace LaaProductionWeb.Services.Interfaces
|
||||
{
|
||||
using LaaProductionWeb.Services.Models;
|
||||
using LaaProductionWeb.Services.Models.Reports;
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
namespace LaaProductionWeb.Services.Interfaces
|
||||
{
|
||||
using LaaProductionWeb.Services.Models;
|
||||
using LaaProductionWeb.Services.Models.Reports;
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
@@ -11,5 +11,9 @@
|
||||
IEnumerable<HeliumPressurePoint> LoadHeliumPressureResults(int testId);
|
||||
|
||||
byte[] LoadHeliumPressureReportAsCSV(HeliumReportModel model);
|
||||
|
||||
KottmannReportModel LoadKottmannPressureReport(KottmannReportModel model = null);
|
||||
|
||||
byte[] LoadKottmannPressureReportAsCSV(KottmannReportModel model);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace LaaProductionWeb.Services.Interfaces
|
||||
{
|
||||
public interface ISingleton
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -40,6 +40,10 @@
|
||||
<Reference Include="Microsoft.Extensions.DependencyInjection.Abstractions, Version=7.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.7.0.0\lib\net462\Microsoft.Extensions.DependencyInjection.Abstractions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json, Version=11.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\..\..\..\Program Files\dotnet\sdk\NuGetFallbackFolder\newtonsoft.json\11.0.2\lib\netstandard2.0\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.ComponentModel.DataAnnotations" />
|
||||
<Reference Include="System.Core" />
|
||||
@@ -59,20 +63,28 @@
|
||||
<ItemGroup>
|
||||
<Compile Include="AccountService.cs" />
|
||||
<Compile Include="ApprovalsService.cs" />
|
||||
<Compile Include="HttpService.cs" />
|
||||
<Compile Include="Interfaces\IAccountService.cs" />
|
||||
<Compile Include="Interfaces\IApprovalsService.cs" />
|
||||
<Compile Include="Interfaces\IHttpService.cs" />
|
||||
<Compile Include="Interfaces\IOrdersService.cs" />
|
||||
<Compile Include="Interfaces\IProtocolService.cs" />
|
||||
<Compile Include="Interfaces\IReportService.cs" />
|
||||
<Compile Include="Interfaces\IShipmentsService.cs" />
|
||||
<Compile Include="Interfaces\ISingleton.cs" />
|
||||
<Compile Include="Interfaces\ITransient.cs" />
|
||||
<Compile Include="Models\Employee.cs" />
|
||||
<Compile Include="Models\HeliumPressurePoint.cs" />
|
||||
<Compile Include="Models\HeliumReportFilter.cs" />
|
||||
<Compile Include="Models\HeliumReportFilterProperty.cs" />
|
||||
<Compile Include="Models\HeliumReportItem.cs" />
|
||||
<Compile Include="Models\HeliumReportModel.cs" />
|
||||
<Compile Include="Models\HeliumReportModelExtensions.cs" />
|
||||
<Compile Include="Models\HttpResponseModel.cs" />
|
||||
<Compile Include="Models\Reports\HeliumPressurePoint.cs" />
|
||||
<Compile Include="Models\Reports\HeliumReportFilter.cs" />
|
||||
<Compile Include="Models\Reports\KottmannReportFilter.cs" />
|
||||
<Compile Include="Models\Reports\KottmannReportItem.cs" />
|
||||
<Compile Include="Models\Reports\PropertyType.cs" />
|
||||
<Compile Include="Models\Reports\ReportFilterProperty.cs" />
|
||||
<Compile Include="Models\Reports\HeliumReportItem.cs" />
|
||||
<Compile Include="Models\Reports\HeliumReportModel.cs" />
|
||||
<Compile Include="Models\Reports\ReportModelExtensions.cs" />
|
||||
<Compile Include="Models\Reports\KottmannReportModel.cs" />
|
||||
<Compile Include="Models\OrderIdentity.cs" />
|
||||
<Compile Include="Models\PalletPosition.cs" />
|
||||
<Compile Include="Models\ProductionApproval.cs" />
|
||||
@@ -85,10 +97,13 @@
|
||||
<Compile Include="Models\OrderScanModel.cs" />
|
||||
<Compile Include="Models\OrdersFoundModel.cs" />
|
||||
<Compile Include="Models\PalletsBatchModel.cs" />
|
||||
<Compile Include="Models\Reports\ReportFilter.cs" />
|
||||
<Compile Include="Models\Result.cs" />
|
||||
<Compile Include="Models\Search\SearchWildcardModel.cs" />
|
||||
<Compile Include="Models\SerialNr.cs" />
|
||||
<Compile Include="Models\ShipmentModel.cs" />
|
||||
<Compile Include="Models\TestStatus.cs" />
|
||||
<Compile Include="Models\Reports\SqlExpression.cs" />
|
||||
<Compile Include="Models\Reports\TestStatus.cs" />
|
||||
<Compile Include="OrdersService.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="ProtocolService.cs" />
|
||||
|
||||
@@ -5,8 +5,16 @@
|
||||
|
||||
public class Employee
|
||||
{
|
||||
public Employee(IEnumerable<string> permissions)
|
||||
=> this.Permissions = permissions;
|
||||
public Employee(string name, IEnumerable<string> permissions)
|
||||
{
|
||||
this.Name = name;
|
||||
this.IsValid = !string.IsNullOrWhiteSpace(name);
|
||||
this.Permissions = permissions ?? Array.Empty<string>();
|
||||
}
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public bool IsValid { get; }
|
||||
|
||||
public IEnumerable<string> Permissions { get; }
|
||||
= Array.Empty<string>();
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
namespace LaaProductionWeb.Services.Models
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
|
||||
public class HeliumReportModel
|
||||
{
|
||||
public HeliumReportFilter Filter { get; set; }
|
||||
= new HeliumReportFilter();
|
||||
|
||||
public IEnumerable<HeliumReportItem> Items { get; set; }
|
||||
= Array.Empty<HeliumReportItem>();
|
||||
|
||||
public static implicit operator HeliumReportModel(HeliumReportFilter filter)
|
||||
=> new HeliumReportModel { Filter = filter };
|
||||
|
||||
public string Display(Expression<Func<HeliumReportItem, object>> expression)
|
||||
{
|
||||
var memberInfo = default(MemberInfo);
|
||||
|
||||
if (expression.Body is MemberExpression memberExpression)
|
||||
{
|
||||
memberInfo = memberExpression.Member;
|
||||
}
|
||||
else if (expression.Body is UnaryExpression unaryExpression && unaryExpression.Operand is MemberExpression operandExpression)
|
||||
{
|
||||
memberInfo = operandExpression.Member;
|
||||
}
|
||||
|
||||
return memberInfo
|
||||
?.GetCustomAttribute<DisplayAttribute>()
|
||||
?.Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
namespace LaaProductionWeb.Services.Models
|
||||
{
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
|
||||
public enum PropertyType
|
||||
{
|
||||
Text,
|
||||
Date,
|
||||
Bool
|
||||
}
|
||||
|
||||
public static class HeliumReportModelExtensions
|
||||
{
|
||||
|
||||
public static HeliumReportFilterProperty Text(this HeliumReportItem model, Expression<Func<HeliumReportItem, object>> expression, int index, int orderBy = 0)
|
||||
=> model.Property(expression, index, PropertyType.Text, orderBy);
|
||||
|
||||
public static HeliumReportFilterProperty DateTime(this HeliumReportItem model, Expression<Func<HeliumReportItem, object>> expression, int index, int orderBy = 0)
|
||||
=> model.Property(expression, index, PropertyType.Date, orderBy);
|
||||
|
||||
public static HeliumReportFilterProperty Boolean(this HeliumReportItem model, Expression<Func<HeliumReportItem, object>> expression, int index, int orderBy = 0)
|
||||
=> model.Property(expression, index, PropertyType.Bool, orderBy);
|
||||
|
||||
public static HeliumReportFilterProperty Property(
|
||||
this HeliumReportItem model
|
||||
, Expression<Func<HeliumReportItem, object>> expression
|
||||
, int index
|
||||
, PropertyType propertyType
|
||||
, int orderBy)
|
||||
{
|
||||
var memberInfo = default(MemberInfo);
|
||||
|
||||
if (expression.Body is MemberExpression memberExpression)
|
||||
{
|
||||
memberInfo = memberExpression.Member;
|
||||
}
|
||||
else if (expression.Body is UnaryExpression unaryExpression && unaryExpression.Operand is MemberExpression operandExpression)
|
||||
{
|
||||
memberInfo = operandExpression.Member;
|
||||
}
|
||||
|
||||
return new HeliumReportFilterProperty
|
||||
{
|
||||
Column = memberInfo?.GetCustomAttribute<ColumnAttribute>()?.Name,
|
||||
Property = memberInfo?.Name,
|
||||
OrderBy = orderBy,
|
||||
Index = index,
|
||||
Type = propertyType
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
namespace LaaProductionWeb.Services.Models
|
||||
{
|
||||
using Newtonsoft.Json;
|
||||
|
||||
public class HttpResponseModel
|
||||
{
|
||||
public bool Succeeded { get; internal set; }
|
||||
|
||||
public string Content { get; internal set; }
|
||||
|
||||
public string Error { get; internal set; }
|
||||
|
||||
public T Deserialize<T>() where T : new ()
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(this.Content))
|
||||
{
|
||||
return JsonConvert.DeserializeObject<T>(this.Content);
|
||||
}
|
||||
|
||||
return new T();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,4 @@
|
||||
using System.Web;
|
||||
|
||||
namespace LaaProductionWeb.Services.Models
|
||||
namespace LaaProductionWeb.Services.Models
|
||||
{
|
||||
public class OrderClientModel
|
||||
{
|
||||
|
||||
@@ -19,10 +19,10 @@
|
||||
= new Dictionary<int, bool> { { 1, false } };
|
||||
|
||||
public string PrintUrl
|
||||
=> $"/Shipments/Print?ordernr={this.OrderNr}&positionnr={this.PositionNr}&palletnr={this.PalletNr}";
|
||||
=> $"~/Shipments/Print?ordernr={this.OrderNr}&positionnr={this.PositionNr}&palletnr={this.PalletNr}";
|
||||
|
||||
public string DownloadUrl
|
||||
=> $"/Shipments/Download?ordernr={this.OrderNr}&positionnr={this.PositionNr}&palletnr={this.PalletNr}";
|
||||
=> $"~/Shipments/Download?ordernr={this.OrderNr}&positionnr={this.PositionNr}&palletnr={this.PalletNr}";
|
||||
|
||||
public void UpdatePalletsCount(int palletsCount)
|
||||
{
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
namespace LaaProductionWeb.Services.Models
|
||||
namespace LaaProductionWeb.Services.Models.Reports
|
||||
{
|
||||
public class HeliumPressurePoint
|
||||
{
|
||||
@@ -0,0 +1,30 @@
|
||||
namespace LaaProductionWeb.Services.Models.Reports
|
||||
{
|
||||
public partial class HeliumReportFilter : ReportFilter
|
||||
{
|
||||
public HeliumReportFilter()
|
||||
{
|
||||
var model = default(HeliumReportItem);
|
||||
|
||||
this.Add(model.Text(x => x.FertigungNr, this.Count));
|
||||
this.Add(model.Text(x => x.AuftragNr, this.Count));
|
||||
this.Add(model.Text(x => x.PositionNr, this.Count));
|
||||
this.Add(model.Text(x => x.SerialNr, this.Count));
|
||||
this.Add(model.Text(x => x.IdentNr, this.Count));
|
||||
this.Add(model.Text(x => x.HeId, this.Count));
|
||||
this.Add(model.Text(x => x.HeTestId, this.Count));
|
||||
this.Add(model.Text(x => x.PcbId, this.Count));
|
||||
this.Add(model.Text(x => x.Nennweite, this.Count));
|
||||
this.Add(model.Text(x => x.Baulaenge, this.Count));
|
||||
this.Add(model.Text(x => x.Typ, this.Count));
|
||||
this.Add(model.Text(x => x.Druck, this.Count));
|
||||
this.Add(model.Text(x => x.Temperatur, this.Count));
|
||||
this.Add(model.Text(x => x.HeLakeRate, this.Count));
|
||||
this.Add(model.Text(x => x.HeTestPressure, this.Count));
|
||||
this.Add(model.Boolean(x => x.IsValid, this.Count));
|
||||
this.Add(model.Text(x => x.Text, this.Count));
|
||||
this.Add(model.DateTime(x => x.TestDate, this.Count, -1));
|
||||
this.Add(model.Text(x => x.Tester, this.Count));
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
namespace LaaProductionWeb.Services.Models
|
||||
namespace LaaProductionWeb.Services.Models.Reports
|
||||
{
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
@@ -0,0 +1,21 @@
|
||||
namespace LaaProductionWeb.Services.Models.Reports
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
public class HeliumReportModel
|
||||
{
|
||||
public HeliumReportFilter Filter { get; set; }
|
||||
= new HeliumReportFilter();
|
||||
|
||||
public IEnumerable<HeliumReportItem> Items { get; set; }
|
||||
= Array.Empty<HeliumReportItem>();
|
||||
|
||||
public static implicit operator HeliumReportModel(HeliumReportFilter filter)
|
||||
=> new HeliumReportModel { Filter = filter };
|
||||
|
||||
public string Display(Expression<Func<HeliumReportItem, object>> expression)
|
||||
=> ReportModelExtensions.Display(expression);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
namespace LaaProductionWeb.Services.Models.Reports
|
||||
{
|
||||
public class KottmannReportFilter : ReportFilter
|
||||
{
|
||||
public KottmannReportFilter()
|
||||
{
|
||||
var model = default(KottmannReportItem);
|
||||
|
||||
this.Add(model.Text(x => x.FertigungsNr, this.Count));
|
||||
this.Add(model.Text(x => x.SerialNr, this.Count));
|
||||
this.Add(model.Text(x => x.PcbId, this.Count));
|
||||
this.Add(model.Text(x => x.Nennweite, this.Count));
|
||||
this.Add(model.Text(x => x.Baulaenge, this.Count));
|
||||
this.Add(model.Text(x => x.Typ, this.Count));
|
||||
this.Add(model.Text(x => x.StartDruck, this.Count));
|
||||
this.Add(model.Text(x => x.EndDruck, this.Count));
|
||||
this.Add(model.Text(x => x.DruckZeit, this.Count));
|
||||
this.Add(model.Boolean(x => x.Dicht, this.Count, -1));
|
||||
this.Add(model.DateTime(x => x.Datum, this.Count, -1));
|
||||
this.Add(model.DateTime(x => x.Bemerkung, this.Count, -1));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
namespace LaaProductionWeb.Services.Models.Reports
|
||||
{
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
public class KottmannReportItem
|
||||
{
|
||||
[Display(Name = "Fertigung Nr.")]
|
||||
[Column("[DP].[FertigungsauftragNr]")]
|
||||
public int? FertigungsNr { get; set; }
|
||||
|
||||
[Display(Name = "Serial Nr.")]
|
||||
[Column("[PCB2SN].[MapPcbIdToSerialNumber_SerialNumber]")]
|
||||
public int SerialNr { get; set; }
|
||||
|
||||
[Display(Name = "Pcb Id")]
|
||||
[Column("[PT].[CordonelPressureTest_PcbId]")]
|
||||
public int PcbId { get; set; }
|
||||
|
||||
[Display(Name = "Nennweite")]
|
||||
[Column("[ID].[Nennweite]")]
|
||||
public int? Nennweite { get; set; }
|
||||
|
||||
[Display(Name = "Baulaenge")]
|
||||
[Column("[ID].[Baulaenge]")]
|
||||
public int? Baulaenge { get; set; }
|
||||
|
||||
[Display(Name = "Typ")]
|
||||
[Column("[ID].[Typ]")]
|
||||
public string Typ { get; set; }
|
||||
|
||||
[Display(Name = "Start Druck")]
|
||||
[Column("[DP].[StartDruck]")]
|
||||
public double StartDruck { get; set; }
|
||||
|
||||
[Display(Name = "End Druck")]
|
||||
[Column("[DP].[EndDruck]")]
|
||||
public double EndDruck { get; set; }
|
||||
|
||||
[Display(Name = "Zeit")]
|
||||
[Column("[DP].[Pruefzeit]")]
|
||||
public int DruckZeit { get; set; }
|
||||
|
||||
[Display(Name = "Dicht")]
|
||||
[Column("[DP].[Dicht]")]
|
||||
public bool Dicht { get; set; }
|
||||
|
||||
[Display(Name = "Datum")]
|
||||
[Column("[DP].[Datum]")]
|
||||
public DateTime Datum { get; set; }
|
||||
|
||||
[Display(Name = "Bemerkung")]
|
||||
[Column("[DP].[Bemerkung]")]
|
||||
public string Bemerkung { get; internal set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
namespace LaaProductionWeb.Services.Models.Reports
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
public class KottmannReportModel
|
||||
{
|
||||
public KottmannReportFilter Filter { get; set; }
|
||||
= new KottmannReportFilter();
|
||||
|
||||
public IEnumerable<KottmannReportItem> Items { get; set; }
|
||||
= Array.Empty<KottmannReportItem>();
|
||||
|
||||
public static implicit operator KottmannReportModel(KottmannReportFilter filter)
|
||||
=> new KottmannReportModel { Filter = filter };
|
||||
|
||||
public string Display(Expression<Func<KottmannReportItem, object>> expression)
|
||||
=> ReportModelExtensions.Display(expression);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace LaaProductionWeb.Services.Models.Reports
|
||||
{
|
||||
public enum PropertyType
|
||||
{
|
||||
Text,
|
||||
Date,
|
||||
Bool
|
||||
}
|
||||
}
|
||||
+4
-66
@@ -1,37 +1,12 @@
|
||||
namespace LaaProductionWeb.Services.Models
|
||||
namespace LaaProductionWeb.Services.Models.Reports
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
|
||||
public class HeliumReportFilter : List<HeliumReportFilterProperty>
|
||||
public class ReportFilter : List<ReportFilterProperty>
|
||||
{
|
||||
public HeliumReportFilter()
|
||||
{
|
||||
var model = default(HeliumReportItem);
|
||||
|
||||
this.Add(model.Text(x => x.FertigungNr, this.Count));
|
||||
this.Add(model.Text(x => x.AuftragNr, this.Count));
|
||||
this.Add(model.Text(x => x.PositionNr, this.Count));
|
||||
this.Add(model.Text(x => x.SerialNr, this.Count));
|
||||
this.Add(model.Text(x => x.IdentNr, this.Count));
|
||||
this.Add(model.Text(x => x.HeId, this.Count));
|
||||
this.Add(model.Text(x => x.HeTestId, this.Count));
|
||||
this.Add(model.Text(x => x.PcbId, this.Count));
|
||||
this.Add(model.Text(x => x.Nennweite, this.Count));
|
||||
this.Add(model.Text(x => x.Baulaenge, this.Count));
|
||||
this.Add(model.Text(x => x.Typ, this.Count));
|
||||
this.Add(model.Text(x => x.Druck, this.Count));
|
||||
this.Add(model.Text(x => x.Temperatur, this.Count));
|
||||
this.Add(model.Text(x => x.HeLakeRate, this.Count));
|
||||
this.Add(model.Text(x => x.HeTestPressure, this.Count));
|
||||
this.Add(model.Boolean(x => x.IsValid, this.Count));
|
||||
this.Add(model.Text(x => x.Text, this.Count));
|
||||
this.Add(model.DateTime(x => x.TestDate, this.Count, -1));
|
||||
this.Add(model.Text(x => x.Tester, this.Count));
|
||||
}
|
||||
|
||||
internal SqlExpression OrderBy()
|
||||
{
|
||||
var sqlExpression = new SqlExpression();
|
||||
@@ -69,8 +44,8 @@
|
||||
var dateTokens = property
|
||||
.Like
|
||||
.Split(new[] { '-' })
|
||||
.Select(x => DateTimeOffset.TryParse($"{x}".Trim(), new CultureInfo("de"), DateTimeStyles.None, out DateTimeOffset date)
|
||||
? (DateTimeOffset?)date
|
||||
.Select(x => DateTimeOffset.TryParse($"{x}".Trim(), new CultureInfo("de"), DateTimeStyles.None, out DateTimeOffset date)
|
||||
? (DateTimeOffset?)date
|
||||
: null)
|
||||
.ToArray();
|
||||
|
||||
@@ -121,42 +96,5 @@
|
||||
|
||||
return sqlExpression.BuildWhere(" AND ");
|
||||
}
|
||||
|
||||
public class SqlExpression
|
||||
{
|
||||
private readonly ICollection<string> expressions
|
||||
= new List<string>();
|
||||
|
||||
public string Query { get; set; }
|
||||
|
||||
public IDictionary<string, object> Parameters { get; set; }
|
||||
= new Dictionary<string, object>();
|
||||
|
||||
internal void Add(string expression)
|
||||
=> this.expressions.Add(expression);
|
||||
|
||||
internal void Add(string expression, string propertyName, object propertyValue)
|
||||
{
|
||||
this.Parameters[propertyName] = propertyValue;
|
||||
|
||||
this.expressions.Add(expression);
|
||||
}
|
||||
|
||||
internal SqlExpression BuildOrderBy(string delimiter)
|
||||
{
|
||||
this.Query = string.Join(delimiter, this.expressions);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
internal SqlExpression BuildWhere(string delimiter)
|
||||
{
|
||||
this.Query = this.expressions.Any()
|
||||
? string.Join(delimiter, this.expressions)
|
||||
: "1 = 1";
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
namespace LaaProductionWeb.Services.Models
|
||||
namespace LaaProductionWeb.Services.Models.Reports
|
||||
{
|
||||
public class HeliumReportFilterProperty
|
||||
public class ReportFilterProperty
|
||||
{
|
||||
public int Index { get; set; }
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
namespace LaaProductionWeb.Services.Models.Reports
|
||||
{
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
|
||||
public static class ReportModelExtensions
|
||||
{
|
||||
public static ReportFilterProperty Text<T>(this T model, Expression<Func<T, object>> expression, int index, int orderBy = 0)
|
||||
=> model.Property(expression, index, PropertyType.Text, orderBy);
|
||||
|
||||
public static ReportFilterProperty DateTime<T>(this T model, Expression<Func<T, object>> expression, int index, int orderBy = 0)
|
||||
=> model.Property(expression, index, PropertyType.Date, orderBy);
|
||||
|
||||
public static ReportFilterProperty Boolean<T>(this T model, Expression<Func<T, object>> expression, int index, int orderBy = 0)
|
||||
=> model.Property(expression, index, PropertyType.Bool, orderBy);
|
||||
|
||||
public static ReportFilterProperty Property<T>(this T model, Expression<Func<T, object>> expression, int index, PropertyType propertyType, int orderBy)
|
||||
{
|
||||
var memberInfo = default(MemberInfo);
|
||||
|
||||
if (expression.Body is MemberExpression memberExpression)
|
||||
{
|
||||
memberInfo = memberExpression.Member;
|
||||
}
|
||||
else if (expression.Body is UnaryExpression unaryExpression && unaryExpression.Operand is MemberExpression operandExpression)
|
||||
{
|
||||
memberInfo = operandExpression.Member;
|
||||
}
|
||||
|
||||
return new ReportFilterProperty
|
||||
{
|
||||
Column = memberInfo?.GetCustomAttribute<ColumnAttribute>()?.Name,
|
||||
Property = memberInfo?.Name,
|
||||
OrderBy = orderBy,
|
||||
Index = index,
|
||||
Type = propertyType
|
||||
};
|
||||
}
|
||||
|
||||
public static string Display<T>(Expression<Func<T, object>> expression)
|
||||
{
|
||||
var memberInfo = default(MemberInfo);
|
||||
|
||||
if (expression.Body is MemberExpression memberExpression)
|
||||
{
|
||||
memberInfo = memberExpression.Member;
|
||||
}
|
||||
else if (expression.Body is UnaryExpression unaryExpression && unaryExpression.Operand is MemberExpression operandExpression)
|
||||
{
|
||||
memberInfo = operandExpression.Member;
|
||||
}
|
||||
|
||||
return memberInfo
|
||||
?.GetCustomAttribute<DisplayAttribute>()
|
||||
?.Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
namespace LaaProductionWeb.Services.Models.Reports
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class SqlExpression
|
||||
{
|
||||
private readonly ICollection<string> expressions
|
||||
= new List<string>();
|
||||
|
||||
public string Query { get; set; }
|
||||
|
||||
public IDictionary<string, object> Parameters { get; set; }
|
||||
= new Dictionary<string, object>();
|
||||
|
||||
internal void Add(string expression)
|
||||
=> this.expressions.Add(expression);
|
||||
|
||||
internal void Add(string expression, string propertyName, object propertyValue)
|
||||
{
|
||||
this.Parameters[propertyName] = propertyValue;
|
||||
|
||||
this.expressions.Add(expression);
|
||||
}
|
||||
|
||||
internal SqlExpression BuildOrderBy(string delimiter)
|
||||
{
|
||||
this.Query = string.Join(delimiter, this.expressions);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
internal SqlExpression BuildWhere(string delimiter)
|
||||
{
|
||||
this.Query = this.expressions.Count > 0
|
||||
? string.Join(delimiter, this.expressions)
|
||||
: "1 = 1";
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
namespace LaaProductionWeb.Services.Models
|
||||
namespace LaaProductionWeb.Services.Models.Reports
|
||||
{
|
||||
public class TestStatus
|
||||
{
|
||||
@@ -0,0 +1,16 @@
|
||||
namespace LaaProductionWeb.Services.Models.Search
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
public class SearchWildcardModel
|
||||
{
|
||||
[Display(Name = "Search text")]
|
||||
public string Token { get; set; }
|
||||
|
||||
[Display(Name = "Select fields")]
|
||||
public IDictionary<string, bool> Fields { get; set; }
|
||||
|
||||
public IEnumerable<IDictionary<string, object>> Results { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
using LaaProductionWeb.Data.Interfaces;
|
||||
using LaaProductionWeb.Services.Interfaces;
|
||||
using LaaProductionWeb.Services.Models;
|
||||
using LaaProductionWeb.Services.Models.Reports;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
{
|
||||
using LaaProductionWeb.Data.Interfaces;
|
||||
using LaaProductionWeb.Services.Interfaces;
|
||||
using LaaProductionWeb.Services.Models;
|
||||
using LaaProductionWeb.Services.Models.Reports;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
public class ReportService : IReportService
|
||||
public partial class ReportService : IReportService
|
||||
{
|
||||
private readonly ISqlClient sqlClient;
|
||||
|
||||
@@ -27,32 +27,33 @@
|
||||
var orderBy = model.Filter.OrderBy();
|
||||
|
||||
model.Items = this.sqlClient.ExecuteReader($@"
|
||||
SELECT [PT].[CordonelPressureTest_FertigungsAuftragsNr] AS [FertigungNr] -- 0 Filter
|
||||
, [POS].[AuftragNr] AS [AuftragNr] -- 1 Filter
|
||||
, [POS].[PositionNr] AS [PositionNr] -- 2 Filter
|
||||
, [PCB2SN].[MapPcbIdToSerialNumber_SerialNumber] AS [SerialNr] -- 3
|
||||
, [ID].[IdentNr] AS [IdentNr] -- 4 Filter
|
||||
, [PT_HE].[CordonelPressureTestHe_Id] AS [HeId] -- 5
|
||||
, [PT_HE].[CordonelPressureTestHe_TestID] AS [HeTestId] -- 6
|
||||
, [PT].[CordonelPressureTest_PcbId] AS [PcbId] -- 7 Filter
|
||||
, [ID].[Nennweite] AS [Nennweite] -- 8 Filter
|
||||
, [ID].[Baulaenge] AS [Baulaenge] -- 9 Filter
|
||||
, [ID].[Typ] AS [Typ] -- 10 Filter
|
||||
, [ID].[Druck] AS [Druck] -- 11 Filter
|
||||
, [ID].[Temperatur] AS [Temperatur] -- 12 Filter
|
||||
, [PT_HE].[CordonelPressureTestHe_LeakRate] AS [HeLakeRate] -- 13
|
||||
, [PT_HE].[CordonelPressureTestHe_TestPressure] AS [HeTestPressure] -- 14
|
||||
, [PT].[CordonelPressureTest_Valid] AS [IsValid] -- 15 Filter
|
||||
, [PT].[CordonelPressureTest_Date] AS [TestDate] -- 16 Filter
|
||||
, [PT].[CordonelPressureTest_Text] AS [Text] -- 17 Filter
|
||||
, [PT_HE].[CordonelPressureTestHe_TesterName] AS [Tester] -- 18
|
||||
SELECT DISTINCT
|
||||
[PT].[CordonelPressureTest_FertigungsAuftragsNr] AS [FertigungNr] -- 0
|
||||
, [POS].[AuftragNr] AS [AuftragNr] -- 1
|
||||
, [POS].[PositionNr] AS [PositionNr] -- 2
|
||||
, [PCB2SN].[MapPcbIdToSerialNumber_SerialNumber] AS [SerialNr] -- 3
|
||||
, [ID].[IdentNr] AS [IdentNr] -- 4
|
||||
, [PT_HE].[CordonelPressureTestHe_Id] AS [HeId] -- 5
|
||||
, [PT_HE].[CordonelPressureTestHe_TestID] AS [HeTestId] -- 6
|
||||
, [PT].[CordonelPressureTest_PcbId] AS [PcbId] -- 7
|
||||
, [ID].[Nennweite] AS [Nennweite] -- 8
|
||||
, [ID].[Baulaenge] AS [Baulaenge] -- 9
|
||||
, [ID].[Typ] AS [Typ] -- 10
|
||||
, [ID].[Druck] AS [Druck] -- 11
|
||||
, [ID].[Temperatur] AS [Temperatur] -- 12
|
||||
, [PT_HE].[CordonelPressureTestHe_LeakRate] AS [HeLakeRate] -- 13
|
||||
, [PT_HE].[CordonelPressureTestHe_TestPressure] AS [HeTestPressure] -- 14
|
||||
, [PT].[CordonelPressureTest_Valid] AS [IsValid] -- 15
|
||||
, [PT].[CordonelPressureTest_Date] AS [TestDate] -- 16
|
||||
, [PT].[CordonelPressureTest_Text] AS [Text] -- 17
|
||||
, [PT_HE].[CordonelPressureTestHe_TesterName] AS [Tester] -- 18
|
||||
FROM [Cordonel_PressureTest] AS [PT]
|
||||
JOIN [Cordonel_PressureTest_He] AS [PT_HE] ON [PT_HE].[CordonelPressureTestHe_TestID] = [PT].[CordonelPressureTest_Id]
|
||||
LEFT JOIN [Druckpruefung] AS [DP] ON [DP].[FabNr] = [PT].[CordonelPressureTest_PcbId]
|
||||
JOIN [MapPcbIdToSerialNumber] AS [PCB2SN] ON [PCB2SN].[MapPcbIdToSerialNumber_PcbId] = [PT].[CordonelPressureTest_PcbId]
|
||||
JOIN [AuftragPosition_Gesamt] AS [POS] ON [POS].[FertigungsauftragNr] = [PT].[CordonelPressureTest_FertigungsAuftragsNr]
|
||||
JOIN [Identnr] AS [ID] ON [ID].[IdentNr] = [POS].[Identnr]
|
||||
WHERE [CordonelPressureTest_IsDeleted] = 0
|
||||
JOIN [Identnr] AS [ID] ON [ID].[IdentNr] = [POS].[Identnr]
|
||||
WHERE [CordonelPressureTest_IsDeleted] = 0
|
||||
AND {where.Query}
|
||||
ORDER BY {orderBy.Query}",
|
||||
parameters =>
|
||||
@@ -105,35 +106,33 @@
|
||||
var csvItems = new List<object[]>();
|
||||
var headers = Array.Empty<string>();
|
||||
var items = this.sqlClient.ExecuteReader($@"
|
||||
SELECT [PT].[CordonelPressureTest_FertigungsAuftragsNr] AS [FertigungNr] -- 0 Filter
|
||||
, [POS].[AuftragNr] AS [AuftragNr] -- 1 Filter
|
||||
, [POS].[PositionNr] AS [PositionNr] -- 2 Filter
|
||||
, [PCB2SN].[MapPcbIdToSerialNumber_SerialNumber] AS [SerialNr] -- 3
|
||||
, [ID].[IdentNr] AS [IdentNr] -- 4 Filter
|
||||
, [PT_HE].[CordonelPressureTestHe_Id] AS [HeId] -- 5
|
||||
, [PT_HE].[CordonelPressureTestHe_TestID] AS [HeTestId] -- 6
|
||||
, [PT].[CordonelPressureTest_PcbId] AS [PcbId] -- 7 Filter
|
||||
, [ID].[Nennweite] AS [Nennweite] -- 8 Filter
|
||||
, [ID].[Baulaenge] AS [Baulaenge] -- 9 Filter
|
||||
, [ID].[Typ] AS [Typ] -- 10 Filter
|
||||
, [ID].[Druck] AS [Druck] -- 11 Filter
|
||||
, [ID].[Temperatur] AS [Temperatur] -- 12 Filter
|
||||
, [PT_HE].[CordonelPressureTestHe_LeakRate] AS [HeLakeRate] -- 13
|
||||
, [PT_HE].[CordonelPressureTestHe_TestPressure] AS [HeTestPressure] -- 14
|
||||
, [PT].[CordonelPressureTest_Valid] AS [IsValid] -- 15 Filter
|
||||
, [PT].[CordonelPressureTest_Date] AS [TestDate] -- 16 Filter
|
||||
, [PT].[CordonelPressureTest_Text] AS [Text] -- 17 Filter
|
||||
, [PT_HE].[CordonelPressureTestHe_TesterName] AS [Tester] -- 18
|
||||
, [CPT].[CordonelPressureTest_TestPointNr] AS [PointNr] -- 19
|
||||
, CAST([CPT].[CordonelPressureTest_TestPointResult] AS NUMERIC(9, 8)) AS [PointResult] -- 20
|
||||
FROM [Cordonel_PressureTest] AS [PT]
|
||||
JOIN [Cordonel_PressureTest_He] AS [PT_HE] ON [PT_HE].[CordonelPressureTestHe_TestID] = [PT].[CordonelPressureTest_Id]
|
||||
LEFT JOIN [Druckpruefung] AS [DP] ON [DP].[FabNr] = [PT].[CordonelPressureTest_PcbId]
|
||||
JOIN [MapPcbIdToSerialNumber] AS [PCB2SN] ON [PCB2SN].[MapPcbIdToSerialNumber_PcbId] = [PT].[CordonelPressureTest_PcbId]
|
||||
JOIN [AuftragPosition_Gesamt] AS [POS] ON [POS].[FertigungsauftragNr] = [PT].[CordonelPressureTest_FertigungsAuftragsNr]
|
||||
JOIN [Identnr] AS [ID] ON [ID].[IdentNr] = [POS].[Identnr]
|
||||
LEFT JOIN [Cordonel_PressureTest_TestPoints] AS [CPT] ON [CPT].[CordonelPressureTest_Id] = [PT].[CordonelPressureTest_Id]
|
||||
WHERE [CordonelPressureTest_IsDeleted] = 0
|
||||
SELECT DISTINCT
|
||||
[PT].[CordonelPressureTest_FertigungsAuftragsNr] AS [FertigungNr] -- 0 Filter
|
||||
, [POS].[AuftragNr] AS [AuftragNr] -- 1 Filter
|
||||
, [POS].[PositionNr] AS [PositionNr] -- 2 Filter
|
||||
, [PCB2SN].[MapPcbIdToSerialNumber_SerialNumber] AS [SerialNr] -- 3
|
||||
, [ID].[IdentNr] AS [IdentNr] -- 4 Filter
|
||||
, [PT_HE].[CordonelPressureTestHe_Id] AS [HeId] -- 5
|
||||
, [PT_HE].[CordonelPressureTestHe_TestID] AS [HeTestId] -- 6
|
||||
, [PT].[CordonelPressureTest_PcbId] AS [PcbId] -- 7 Filter
|
||||
, [ID].[Nennweite] AS [Nennweite] -- 8 Filter
|
||||
, [ID].[Baulaenge] AS [Baulaenge] -- 9 Filter
|
||||
, [ID].[Typ] AS [Typ] -- 10 Filter
|
||||
, [ID].[Druck] AS [Druck] -- 11 Filter
|
||||
, [ID].[Temperatur] AS [Temperatur] -- 12 Filter
|
||||
, [PT_HE].[CordonelPressureTestHe_LeakRate] AS [HeLakeRate] -- 13
|
||||
, [PT_HE].[CordonelPressureTestHe_TestPressure] AS [HeTestPressure] -- 14
|
||||
, [PT].[CordonelPressureTest_Valid] AS [IsValid] -- 15 Filter
|
||||
, [PT].[CordonelPressureTest_Date] AS [TestDate] -- 16 Filter
|
||||
, [PT].[CordonelPressureTest_Text] AS [Text] -- 17 Filter
|
||||
, [PT_HE].[CordonelPressureTestHe_TesterName] AS [Tester] -- 18
|
||||
FROM [Cordonel_PressureTest] AS [PT]
|
||||
JOIN [Cordonel_PressureTest_He] AS [PT_HE] ON [PT_HE].[CordonelPressureTestHe_TestID] = [PT].[CordonelPressureTest_Id]
|
||||
LEFT JOIN [Druckpruefung] AS [DP] ON [DP].[FabNr] = [PT].[CordonelPressureTest_PcbId]
|
||||
JOIN [MapPcbIdToSerialNumber] AS [PCB2SN] ON [PCB2SN].[MapPcbIdToSerialNumber_PcbId] = [PT].[CordonelPressureTest_PcbId]
|
||||
JOIN [AuftragPosition_Gesamt] AS [POS] ON [POS].[FertigungsauftragNr] = [PT].[CordonelPressureTest_FertigungsAuftragsNr]
|
||||
JOIN [Identnr] AS [ID] ON [ID].[IdentNr] = [POS].[Identnr]
|
||||
WHERE [CordonelPressureTest_IsDeleted] = 0
|
||||
AND {where.Query}
|
||||
ORDER BY {orderBy.Query}",
|
||||
parameters =>
|
||||
@@ -168,10 +167,7 @@
|
||||
reader.GetValue<bool>(15),
|
||||
$"{reader.GetValue<DateTimeOffset>(16):yyyy-MM-dd}",
|
||||
reader.GetString(17).Replace(',', ' '),
|
||||
reader.GetString(18).Replace(',', ' '),
|
||||
reader.GetValue<int>(19),
|
||||
$"{reader.GetValue<decimal>(20):0.000000000}",
|
||||
|
||||
reader.GetString(18).Replace(',', ' ')
|
||||
},
|
||||
columns => csvItems.Add(columns))
|
||||
.ToList();
|
||||
@@ -198,5 +194,141 @@
|
||||
PointNr = reader.GetValue<int>(1),
|
||||
Result = reader.GetValue<decimal>(2),
|
||||
});
|
||||
|
||||
public KottmannReportModel LoadKottmannPressureReport(KottmannReportModel model = null)
|
||||
{
|
||||
if (model is null)
|
||||
{
|
||||
model = new KottmannReportModel();
|
||||
}
|
||||
|
||||
var where = model.Filter.Where();
|
||||
var orderBy = model.Filter.OrderBy();
|
||||
|
||||
model.Items = this.sqlClient.ExecuteReader($@"
|
||||
SELECT [DP].[FertigungsauftragNr] AS [FertigungNr]
|
||||
, [PCB2SN].[MapPcbIdToSerialNumber_SerialNumber] AS [SerienNr]
|
||||
, [DP].[FabNr] AS [PcbId]
|
||||
, [ID].[Typ] AS [Typ]
|
||||
, [ID].[Nennweite] AS [Nennweite]
|
||||
, [ID].[Baulaenge] AS [Baulaenge]
|
||||
, [DP].[StartDruck] AS [StartDruck]
|
||||
, [DP].[EndDruck] AS [EndDruck]
|
||||
, [DP].[Pruefzeit] AS [Pruefzeit]
|
||||
, [DP].[Dicht] AS [Dicht]
|
||||
, [DP].[Datum] AS [Datum]
|
||||
, [DP].[Bemerkung] AS [Bemerkung]
|
||||
FROM [Druckpruefung] AS [DP]
|
||||
JOIN [AuftragPosition_Gesamt] AS [POS]
|
||||
ON [POS].[FertigungsauftragNr] = [DP].[FertigungsauftragNr]
|
||||
JOIN [Identnr] AS [ID]
|
||||
ON [ID].[IdentNr] = [POS].[Identnr]
|
||||
JOIN [MapPcbIdToSerialNumber] AS [PCB2SN]
|
||||
ON [PCB2SN].[MapPcbIdToSerialNumber_PcbId] = [DP].[FabNr]
|
||||
AND [PCB2SN].[MapPcbIdToSerialNumber_Deleted] = 0
|
||||
AND {where.Query}
|
||||
ORDER BY {orderBy.Query}",
|
||||
parameters =>
|
||||
{
|
||||
foreach (var kvp in where.Parameters)
|
||||
{
|
||||
parameters.Add(kvp.Key, kvp.Value);
|
||||
}
|
||||
|
||||
foreach (var kvp in orderBy.Parameters)
|
||||
{
|
||||
parameters.Add(kvp.Key, kvp.Value);
|
||||
}
|
||||
},
|
||||
reader => new KottmannReportItem
|
||||
{
|
||||
FertigungsNr = reader.GetValue<int?>(),
|
||||
SerialNr = reader.GetValue<int>(),
|
||||
PcbId = reader.GetValue<int>(),
|
||||
Typ = reader.GetString(),
|
||||
Nennweite = reader.GetValue<int?>(),
|
||||
Baulaenge = reader.GetValue<int?>(),
|
||||
StartDruck = reader.GetValue<double>(),
|
||||
EndDruck = reader.GetValue<double>(),
|
||||
DruckZeit = reader.GetValue<int>(),
|
||||
Dicht = reader.GetValue<bool>(),
|
||||
Datum = reader.GetValue<DateTime>(),
|
||||
Bemerkung = reader.GetValue<string>()
|
||||
});
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
public byte[] LoadKottmannPressureReportAsCSV(KottmannReportModel model)
|
||||
{
|
||||
if (model is null)
|
||||
{
|
||||
model = new KottmannReportModel();
|
||||
}
|
||||
|
||||
var where = model.Filter.Where();
|
||||
var orderBy = model.Filter.OrderBy();
|
||||
var csvItems = new List<object[]>();
|
||||
var headers = Array.Empty<string>();
|
||||
var items = this.sqlClient.ExecuteReader($@"
|
||||
SELECT [DP].[FertigungsauftragNr] AS [FertigungNr]
|
||||
, [PCB2SN].[MapPcbIdToSerialNumber_SerialNumber] AS [SerienNr]
|
||||
, [DP].[FabNr] AS [PcbId]
|
||||
, [ID].[Typ] AS [Typ]
|
||||
, [ID].[Nennweite] AS [Nennweite]
|
||||
, [ID].[Baulaenge] AS [Baulaenge]
|
||||
, [DP].[StartDruck] AS [StartDruck]
|
||||
, [DP].[EndDruck] AS [EndDruck]
|
||||
, [DP].[Pruefzeit] AS [Pruefzeit]
|
||||
, [DP].[Dicht] AS [Dicht]
|
||||
, [DP].[Datum] AS [Datum]
|
||||
, [DP].[Bemerkung] AS [Bemerkung]
|
||||
FROM [Druckpruefung] AS [DP]
|
||||
JOIN [AuftragPosition_Gesamt] AS [POS]
|
||||
ON [POS].[FertigungsauftragNr] = [DP].[FertigungsauftragNr]
|
||||
JOIN [Identnr] AS [ID]
|
||||
ON [ID].[IdentNr] = [POS].[Identnr]
|
||||
JOIN [MapPcbIdToSerialNumber] AS [PCB2SN]
|
||||
ON [PCB2SN].[MapPcbIdToSerialNumber_PcbId] = [DP].[FabNr]
|
||||
AND [PCB2SN].[MapPcbIdToSerialNumber_Deleted] = 0
|
||||
AND {where.Query}
|
||||
ORDER BY {orderBy.Query}",
|
||||
parameters =>
|
||||
{
|
||||
foreach (var kvp in where.Parameters)
|
||||
{
|
||||
parameters.Add(kvp.Key, kvp.Value);
|
||||
}
|
||||
|
||||
foreach (var kvp in orderBy.Parameters)
|
||||
{
|
||||
parameters.Add(kvp.Key, kvp.Value);
|
||||
}
|
||||
},
|
||||
reader => new object[]
|
||||
{
|
||||
reader.GetValue<int?>(),
|
||||
reader.GetValue<int>(),
|
||||
reader.GetValue<int>(),
|
||||
reader.GetString(),
|
||||
reader.GetValue<int?>(),
|
||||
reader.GetValue<int?>(),
|
||||
reader.GetValue<double>(),
|
||||
reader.GetValue<double>(),
|
||||
reader.GetValue<int>(),
|
||||
reader.GetValue<bool>(),
|
||||
$"{reader.GetValue<DateTime>():yyyy-MM-dd}",
|
||||
reader.GetValue<string>().Replace(',', ' ')
|
||||
},
|
||||
columns => csvItems.Add(columns))
|
||||
.ToList();
|
||||
|
||||
csvItems.AddRange(items);
|
||||
|
||||
var csvLines = csvItems.Select(x => string.Join(",", x));
|
||||
var csvContent = string.Join(Environment.NewLine, csvLines);
|
||||
|
||||
return Encoding.UTF8.GetBytes(csvContent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,5 +38,39 @@
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
public static IServiceCollection AddHttpClient(this IServiceCollection services, string baseAddress)
|
||||
=> services.AddSingleton<IHttpService>(_ => new HttpService(baseAddress));
|
||||
|
||||
public static IServiceCollection AddSingletonServices(this IServiceCollection services)
|
||||
{
|
||||
var transient = typeof(ISingleton);
|
||||
var assemblyServices = transient
|
||||
.Assembly
|
||||
.GetTypes()
|
||||
.Where(x => !x.IsAbstract
|
||||
&& transient.IsAssignableFrom(x));
|
||||
|
||||
foreach (var service in assemblyServices)
|
||||
{
|
||||
var interfaces = service
|
||||
.GetInterfaces()
|
||||
.Where(x => x != transient);
|
||||
|
||||
if (!interfaces.Any())
|
||||
{
|
||||
services.AddTransient(service);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var @interface in interfaces)
|
||||
{
|
||||
services.AddTransient(@interface, service);
|
||||
}
|
||||
}
|
||||
|
||||
return services;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class ShipmentsService : IShipmentsService
|
||||
{
|
||||
private readonly ISqlClient sqlClient;
|
||||
|
||||
@@ -9,6 +9,15 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LaaProductionWeb.Data", "La
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LaaProductionWeb.Services", "LaaProductionWeb.Services\LaaProductionWeb.Services.csproj", "{FF167011-431A-41A7-A7DB-560E08860388}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Documents", "Documents", "{59875741-02AA-4D9A-9B3C-683CA6DDBE7B}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
..\..\..\..\Downloads\SRS Wildcard Order Info Search.docx = ..\..\..\..\Downloads\SRS Wildcard Order Info Search.docx
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LaaProductionWeb.API", "LaaProductionWeb.API\LaaProductionWeb.API.csproj", "{66C33368-2ABC-4BB6-917C-FF949FAF043B}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LaaProductionWeb.API.UnitTests", "LaaProductionWeb.API.UnitTests\LaaProductionWeb.API.UnitTests.csproj", "{EF371C00-4452-4506-A7B6-C2F94C170D2C}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -27,6 +36,14 @@ Global
|
||||
{FF167011-431A-41A7-A7DB-560E08860388}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{FF167011-431A-41A7-A7DB-560E08860388}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{FF167011-431A-41A7-A7DB-560E08860388}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{66C33368-2ABC-4BB6-917C-FF949FAF043B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{66C33368-2ABC-4BB6-917C-FF949FAF043B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{66C33368-2ABC-4BB6-917C-FF949FAF043B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{66C33368-2ABC-4BB6-917C-FF949FAF043B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{EF371C00-4452-4506-A7B6-C2F94C170D2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{EF371C00-4452-4506-A7B6-C2F94C170D2C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{EF371C00-4452-4506-A7B6-C2F94C170D2C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{EF371C00-4452-4506-A7B6-C2F94C170D2C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -13,7 +13,7 @@
|
||||
if (filterContext.HttpContext.User is ClaimsPrincipal claimsPrincipal)
|
||||
{
|
||||
filterContext.Controller.TempData["Unauthorized"] = "Dir fehlen berechtigungen.";
|
||||
filterContext.Result = new RedirectResult($"/");
|
||||
filterContext.Result = new RedirectResult("~/");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -4,6 +4,10 @@
|
||||
|
||||
public class ApplicationSettings
|
||||
{
|
||||
public static string APIURL => ConfigurationManager.AppSettings.Get(nameof(APIURL));
|
||||
|
||||
public static string ConnectionString => ConfigurationManager.AppSettings.Get(nameof(ConnectionString));
|
||||
|
||||
public static int LoginTimeout => int.TryParse(ConfigurationManager.AppSettings.Get(nameof(LoginTimeout)), out int time) ? time : 0;
|
||||
}
|
||||
}
|
||||
@@ -1,34 +1,41 @@
|
||||
namespace LaaProductionWeb.App_Infrastructure
|
||||
{
|
||||
using LaaProductionWeb.Services.Interfaces;
|
||||
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.DirectoryServices.AccountManagement;
|
||||
using System.Security.Claims;
|
||||
using System.Security.Principal;
|
||||
using System.Web.Mvc;
|
||||
|
||||
public class AuthorizationFilter : IAuthorizationFilter
|
||||
{
|
||||
public void OnAuthorization(AuthorizationContext filterContext)
|
||||
{
|
||||
if (filterContext.HttpContext.User is WindowsPrincipal windowsPrincipal)
|
||||
var httpContext = filterContext.HttpContext;
|
||||
var userId = httpContext.UserId();
|
||||
var accountService = ServiceProvider.Current.GetService<IAccountService>();
|
||||
var employee = accountService.FindEmployee(userId);
|
||||
var claims = new List<Claim>();
|
||||
|
||||
httpContext.User = new ClaimsPrincipal(new ClaimsIdentity(new Claim[]
|
||||
{
|
||||
using (var principalContext = new PrincipalContext(ContextType.Domain))
|
||||
new Claim(ClaimTypes.Name, string.Empty),
|
||||
new Claim(ClaimTypes.Role, UserRoles.WEB_Anonymous),
|
||||
}, nameof(Claim), ClaimTypes.Name, ClaimTypes.Role));
|
||||
|
||||
if (employee.IsValid)
|
||||
{
|
||||
claims.Add(new Claim(ClaimTypes.NameIdentifier, $"{userId}"));
|
||||
claims.Add(new Claim(ClaimTypes.Name, employee.Name));
|
||||
|
||||
foreach (var permission in employee.Permissions)
|
||||
{
|
||||
var userPrincipal = UserPrincipal.FindByIdentity(principalContext, windowsPrincipal.Identity.Name);
|
||||
var accountService = ServiceProvider.Current.GetService<IAccountService>();
|
||||
var employee = accountService.FindEmployee(userPrincipal.GivenName, userPrincipal.Surname);
|
||||
var permissionsClaims = new List<Claim> { new Claim(ClaimTypes.Name, $"{userPrincipal.GivenName} {userPrincipal.Surname}") };
|
||||
|
||||
foreach (var permission in employee.Permissions)
|
||||
{
|
||||
permissionsClaims.Add(new Claim(ClaimTypes.Role, permission));
|
||||
}
|
||||
|
||||
windowsPrincipal.AddIdentity(new ClaimsIdentity(permissionsClaims, nameof(ClaimsPrincipal), ClaimTypes.Name, ClaimTypes.Role));
|
||||
claims.Add(new Claim(ClaimTypes.Role, permission));
|
||||
}
|
||||
|
||||
httpContext.User = new ClaimsPrincipal(new ClaimsIdentity(claims, nameof(Claim), ClaimTypes.Name, ClaimTypes.Role));
|
||||
}
|
||||
|
||||
httpContext.SetUrlReferer();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,12 @@
|
||||
namespace LaaProductionWeb.App_Infrastructure
|
||||
{
|
||||
using LaaProductionWeb.Controllers;
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
using System.Web.Routing;
|
||||
@@ -8,8 +14,8 @@
|
||||
|
||||
public class ControllerFactory : IControllerFactory
|
||||
{
|
||||
const string AREAS_PATTERN = "LaaProductionWeb.Areas.{0}.Controllers.{1}Controller";
|
||||
const string CONTROLLERS_PATTERN = "LaaProductionWeb.Controllers.{0}Controller";
|
||||
const string AREAS_PATTERN = "LaaProductionWeb.Areas.{0}.Controllers{1}.{2}Controller";
|
||||
const string CONTROLLERS_PATTERN = "LaaProductionWeb.Controllers{0}.{1}Controller";
|
||||
|
||||
private readonly IServiceProvider serviceProvider;
|
||||
|
||||
@@ -18,18 +24,52 @@
|
||||
|
||||
public IController CreateController(RequestContext requestContext, string controllerName)
|
||||
{
|
||||
var controllerTypeName = requestContext.RouteData.Values.TryGetValue("area", out object areaName)
|
||||
? string.Format(AREAS_PATTERN, areaName, controllerName)
|
||||
: string.Format(CONTROLLERS_PATTERN, controllerName);
|
||||
var controllerType = Type.GetType(controllerTypeName, throwOnError: false, ignoreCase: true);
|
||||
var controllerType = default(Type);
|
||||
var routeData = requestContext.RouteData;
|
||||
var routeUrl = string.Empty;
|
||||
|
||||
this.RedirectToDefault(controllerType, requestContext.HttpContext.Response);
|
||||
if (routeData.Route is Route route)
|
||||
{
|
||||
routeUrl = route.Url;
|
||||
}
|
||||
else if (routeData.Route is IEnumerable<RouteBase> routes && routes.FirstOrDefault() is Route _route)
|
||||
{
|
||||
routeUrl = _route.Url;
|
||||
}
|
||||
|
||||
var controller = this.serviceProvider.GetService(controllerType) as IController;
|
||||
var innerPath = string
|
||||
.Join(".", routeUrl
|
||||
.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries)
|
||||
.Where(x => !x.StartsWith("{") && !x.EndsWith("}")));
|
||||
|
||||
this.RedirectToDefault(controller, requestContext.HttpContext.Response);
|
||||
if (!string.IsNullOrWhiteSpace(innerPath))
|
||||
{
|
||||
innerPath = $".{innerPath}";
|
||||
}
|
||||
|
||||
return controller;
|
||||
var controllerTypeName = requestContext.RouteData.DataTokens.TryGetValue("area", out object areaName)
|
||||
? string.Format(AREAS_PATTERN, areaName, innerPath, controllerName)
|
||||
: string.Format(CONTROLLERS_PATTERN, innerPath, controllerName);
|
||||
|
||||
controllerType = Type.GetType(controllerTypeName, throwOnError: false, ignoreCase: true);
|
||||
|
||||
if (controllerType is null)
|
||||
{
|
||||
controllerTypeName = controllerTypeName.Replace(innerPath, string.Empty);
|
||||
controllerType = Type.GetType(controllerTypeName, throwOnError: false, ignoreCase: true);
|
||||
}
|
||||
|
||||
if (controllerType != null)
|
||||
{
|
||||
var controller = this.serviceProvider.GetService(controllerType) as IController;
|
||||
|
||||
if (controller != null)
|
||||
{
|
||||
return controller;
|
||||
}
|
||||
}
|
||||
|
||||
return this.serviceProvider.GetService<HomeController>() as IController;
|
||||
}
|
||||
|
||||
public SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, string controllerName)
|
||||
@@ -47,7 +87,7 @@
|
||||
{
|
||||
if (resource is null)
|
||||
{
|
||||
response.Redirect("/");
|
||||
response.Redirect("~/", true);
|
||||
response.End();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,23 +3,42 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Security.Claims;
|
||||
using System.Security.Principal;
|
||||
using System.Web.Mvc;
|
||||
|
||||
/// <summary>
|
||||
/// Static class with extension methods that run on controller contexts.
|
||||
/// </summary>
|
||||
public static class ControllersExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds controllers of type <see cref="IController"/> loaded by reflection from the current assembly to the <see cref="IServiceCollection"/>.
|
||||
/// On this way all required services are loaded into the controller constructors.
|
||||
/// </summary>
|
||||
/// <param name="services"><see cref="IServiceCollection"/> provided from the extension method.</param>
|
||||
/// <returns>The same <see cref="IServiceCollection"/> with added services.</returns>
|
||||
public static IServiceCollection AddControllers(this IServiceCollection services)
|
||||
{
|
||||
var controllersMap = typeof(ControllersExtensions)
|
||||
.Assembly
|
||||
.GetTypes()
|
||||
.Where(x => !x.IsAbstract && typeof(IController).IsAssignableFrom(x))
|
||||
.Select(x => new
|
||||
{
|
||||
x.Name,
|
||||
Path = x.FullName
|
||||
.Replace("LaaProductionWeb.Controllers.", string.Empty)
|
||||
.Replace(x.Name, string.Empty)
|
||||
})
|
||||
.GroupBy(x => x.Path)
|
||||
.ToList();
|
||||
|
||||
var controllers = typeof(ControllersExtensions)
|
||||
.Assembly
|
||||
.GetTypes()
|
||||
.Where(x => !x.IsAbstract
|
||||
&& typeof(IController).IsAssignableFrom(x));
|
||||
.Where(x => !x.IsAbstract && typeof(IController).IsAssignableFrom(x));
|
||||
|
||||
foreach (var controller in controllers)
|
||||
{
|
||||
@@ -38,7 +57,7 @@
|
||||
return serviceProvider;
|
||||
}
|
||||
|
||||
public static string Name(this IPrincipal principal)
|
||||
public static string ClaimName(this IPrincipal principal)
|
||||
{
|
||||
if (principal is ClaimsPrincipal claimsPrincipal)
|
||||
{
|
||||
@@ -49,25 +68,5 @@
|
||||
|
||||
return "<unknown>";
|
||||
}
|
||||
|
||||
public static string Display<T>(this T model, Expression<Func<T, object>> expression)
|
||||
{
|
||||
if (expression.Body is MemberExpression memberExpression)
|
||||
{
|
||||
return memberExpression
|
||||
.Member
|
||||
.GetCustomAttribute<DisplayAttribute>()
|
||||
.GetName();
|
||||
}
|
||||
else if (expression.Body is UnaryExpression unaryExpression && unaryExpression.Operand is MemberExpression operandExpression)
|
||||
{
|
||||
return operandExpression
|
||||
.Member
|
||||
.GetCustomAttribute<DisplayAttribute>()
|
||||
.GetName();
|
||||
}
|
||||
|
||||
return default(string);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
namespace LaaProductionWeb.App_Infrastructure
|
||||
{
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Web.Mvc;
|
||||
|
||||
public abstract class NestedController : Controller
|
||||
{
|
||||
protected ViewResult NestedView([CallerMemberName] string viewName = "", [CallerFilePath] string fileName = "")
|
||||
{
|
||||
var viewPath = fileName
|
||||
?.Split(new[] { "Controllers" }, StringSplitOptions.RemoveEmptyEntries)
|
||||
?.LastOrDefault()
|
||||
?.Replace("Controller.cs", $"\\{viewName}");
|
||||
|
||||
return this.View($"~\\Views{viewPath}.cshtml");
|
||||
}
|
||||
|
||||
protected ViewResult NestedView(object model, [CallerMemberName] string viewName = "", [CallerFilePath] string fileName = "")
|
||||
{
|
||||
var viewPath = fileName
|
||||
?.Split(new[] { "Controllers" }, StringSplitOptions.RemoveEmptyEntries)
|
||||
?.LastOrDefault()
|
||||
?.Replace("Controller.cs", $"\\{viewName}");
|
||||
|
||||
return this.View($"~\\Views{viewPath}.cshtml", model);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,14 +26,4 @@
|
||||
internal static void SetServiceProvider(IServiceProvider serviceProvider)
|
||||
=> Current = new ServiceProvider(serviceProvider);
|
||||
}
|
||||
|
||||
public static class ServiceProviderExtensions
|
||||
{
|
||||
public static IServiceProvider RegisterServiceProvider(this IServiceProvider serviceProvider)
|
||||
{
|
||||
ServiceProvider.SetServiceProvider(serviceProvider);
|
||||
|
||||
return serviceProvider;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
namespace LaaProductionWeb.App_Infrastructure
|
||||
{
|
||||
using System;
|
||||
|
||||
public static class ServiceProviderExtensions
|
||||
{
|
||||
public static IServiceProvider RegisterServiceProvider(this IServiceProvider serviceProvider)
|
||||
{
|
||||
ServiceProvider.SetServiceProvider(serviceProvider);
|
||||
|
||||
return serviceProvider;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
namespace LaaProductionWeb.App_Infrastructure
|
||||
{
|
||||
using System;
|
||||
using System.Web;
|
||||
|
||||
public class SessionUser
|
||||
{
|
||||
public SessionUser()
|
||||
=> this.UserId = -1;
|
||||
|
||||
public SessionUser(int userId, DateTime expires)
|
||||
{
|
||||
this.UserId = userId;
|
||||
this.Expires = expires;
|
||||
}
|
||||
|
||||
public int UserId { get; }
|
||||
|
||||
public DateTime Expires { get; }
|
||||
|
||||
public bool IsExpired => this.Expires < DateTime.Now.AddMinutes(30) || this.Expires > DateTime.Now;
|
||||
}
|
||||
|
||||
public static class SessionUserExtensions
|
||||
{
|
||||
public static int UserId(this HttpContextBase httpContext)
|
||||
{
|
||||
var cookieUserId = httpContext
|
||||
.Request
|
||||
.Cookies
|
||||
.Get(nameof(SessionUser))
|
||||
?.Value ?? string.Empty;
|
||||
|
||||
if (int.TryParse(cookieUserId, out int userId))
|
||||
{
|
||||
return userId;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static bool SignIn(this HttpContextBase httpContext, int userId)
|
||||
{
|
||||
if (userId > 0)
|
||||
{
|
||||
httpContext.Response.AppendCookie(new HttpCookie(nameof(SessionUser), $"{userId}")
|
||||
{
|
||||
Expires = DateTime.Now.AddSeconds(ApplicationSettings.LoginTimeout)
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void SignOut(this HttpContextBase httpContext)
|
||||
{
|
||||
var cookieUserId = httpContext
|
||||
.Request
|
||||
.Cookies
|
||||
.Get(nameof(SessionUser))
|
||||
?.Value ?? string.Empty;
|
||||
}
|
||||
|
||||
const string URL_REFERER = nameof(URL_REFERER);
|
||||
|
||||
public static void SetUrlReferer(this HttpContextBase httpContext)
|
||||
=> httpContext
|
||||
.Request
|
||||
.Cookies
|
||||
.Add(new HttpCookie(URL_REFERER, $"{httpContext.Request.Url}"));
|
||||
|
||||
public static string GetUrlReferer(this HttpContextBase httpContext)
|
||||
=> httpContext
|
||||
.Request
|
||||
.Cookies
|
||||
.Get(URL_REFERER)
|
||||
?.Value ?? "/";
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,8 @@
|
||||
public class UserRoles
|
||||
{
|
||||
public const string WEB_Admin = nameof(WEB_Admin);
|
||||
public const string WEB_Anonymous = nameof(WEB_Anonymous);
|
||||
public const string WEB_API_Explorer = nameof(WEB_API_Explorer);
|
||||
public const string WEB_HeReport = nameof(WEB_HeReport);
|
||||
public const string WEB_PalettenScan = nameof(WEB_PalettenScan);
|
||||
public const string WEB_ProdApproval = nameof(WEB_ProdApproval);
|
||||
|
||||
@@ -2,17 +2,25 @@
|
||||
{
|
||||
using System.Web.Optimization;
|
||||
|
||||
/// <summary>
|
||||
/// A class that configures all static assets (.css, .js, fonts, etc.) for the web application.
|
||||
/// </summary>
|
||||
public class BundleConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// Registers all configured static assets for the web application.
|
||||
/// </summary>
|
||||
/// <param name="bundles"><see cref="BundleCollection"/> - passed by calling this method.</param>
|
||||
public static void RegisterBundles(BundleCollection bundles)
|
||||
{
|
||||
bundles
|
||||
.Add(new StyleBundle("~/bootstrap_css")
|
||||
.Include("~/App_Content/css/bootstrap.min.css"));
|
||||
|
||||
bundles
|
||||
.Add(new StyleBundle("~/bootstrap_icons")
|
||||
.Include("~/App_Content/font/bootstrap-icons.min.css"));
|
||||
// not loaded - try throught cdn
|
||||
//bundles
|
||||
// .Add(new StyleBundle("~/bootstrap_icons")
|
||||
// .Include("~/App_Content/font/bootstrap-icons.min.css"));
|
||||
|
||||
bundles
|
||||
.Add(new StyleBundle("~/styles_css")
|
||||
|
||||
@@ -4,8 +4,15 @@
|
||||
|
||||
using System.Web.Mvc;
|
||||
|
||||
/// <summary>
|
||||
/// A class that configures custom filters for the application.
|
||||
/// </summary>
|
||||
public class FilterConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds custom filters to the <see cref="GlobalFilterCollection"/>.
|
||||
/// </summary>
|
||||
/// <param name="filters"><see cref="GlobalFilterCollection"/> - passed by calling this method.</param>
|
||||
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
|
||||
{
|
||||
filters.Add(new ExceptionFilter());
|
||||
|
||||
@@ -3,12 +3,21 @@
|
||||
using System.Web.Mvc;
|
||||
using System.Web.Routing;
|
||||
|
||||
/// <summary>
|
||||
/// A class that configures all view route templates for the web application.
|
||||
/// </summary>
|
||||
public class RouteConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// Registers all view route templates to the <see cref="RouteCollection"/>.
|
||||
/// </summary>
|
||||
/// <param name="bundles"><see cref="RouteCollection"/> - passed by calling this method.</param>
|
||||
public static void RegisterRoutes(RouteCollection routes)
|
||||
{
|
||||
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
|
||||
|
||||
routes.MapMvcAttributeRoutes();
|
||||
|
||||
routes.MapRoute(
|
||||
name: "MVC_Default",
|
||||
url: "{controller}/{action}/{id}",
|
||||
|
||||
@@ -6,8 +6,14 @@
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
/// <summary>
|
||||
/// A class for configuring and registering dependency injection.
|
||||
/// </summary>
|
||||
public static class ServicesConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// Builds and registers configured services to the service provider.
|
||||
/// </summary>
|
||||
public static void RegisterServices()
|
||||
=> new ServiceCollection()
|
||||
.ConfigureServices()
|
||||
@@ -15,11 +21,17 @@
|
||||
.BuildControllerFactory()
|
||||
.RegisterServiceProvider();
|
||||
|
||||
/// <summary>
|
||||
/// Allows developer to add services to the service collection.
|
||||
/// </summary>
|
||||
/// <param name="services"><see cref="IServiceCollection"/> provided from the extension method.</param>
|
||||
/// <returns>The same <see cref="IServiceCollection"/> with added services.</returns>
|
||||
static IServiceCollection ConfigureServices(this IServiceCollection services)
|
||||
{
|
||||
services
|
||||
.AddControllers()
|
||||
.AddTransientServices()
|
||||
.AddHttpClient(ApplicationSettings.APIURL)
|
||||
.AddDbContext(ApplicationSettings.ConnectionString);
|
||||
|
||||
return services;
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
namespace LaaProductionWeb
|
||||
{
|
||||
using System.Web.Http;
|
||||
|
||||
public static class WebApiConfig
|
||||
{
|
||||
public static void Register(HttpConfiguration config)
|
||||
{
|
||||
config.MapHttpAttributeRoutes();
|
||||
|
||||
config.Routes.MapHttpRoute(
|
||||
name: "DefaultApi",
|
||||
routeTemplate: "api/{controller}/{id}",
|
||||
defaults: new { id = RouteParameter.Optional });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,8 +4,7 @@
|
||||
using LaaProductionWeb.Services.Interfaces;
|
||||
|
||||
using System.Web.Mvc;
|
||||
|
||||
[Authorize]
|
||||
|
||||
[AllowedRoles(UserRoles.WEB_Admin)]
|
||||
public class AdminController : Controller
|
||||
{
|
||||
|
||||
@@ -6,8 +6,7 @@
|
||||
|
||||
using System;
|
||||
using System.Web.Mvc;
|
||||
|
||||
[Authorize]
|
||||
|
||||
[AllowedRoles(UserRoles.WEB_ProdApproval)]
|
||||
public class ApprovalsController : Controller
|
||||
{
|
||||
@@ -20,18 +19,17 @@
|
||||
public ActionResult Add()
|
||||
=> this.View(new ProductionApproval
|
||||
{
|
||||
ApproverName = this.User.Name(),
|
||||
ApproverName = this.User.ClaimName(),
|
||||
ApprovalDate = DateTime.Now
|
||||
});
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public ActionResult Add(ProductionApproval approval)
|
||||
{
|
||||
if (this.ModelState.IsValid)
|
||||
{
|
||||
approval.ApprovalDate = DateTime.Now;
|
||||
approval.ApproverName = this.User.Name();
|
||||
approval.ApproverName = this.User.ClaimName();
|
||||
|
||||
var addResult = this.approvals.Add(approval);
|
||||
|
||||
|
||||
@@ -1,11 +1,52 @@
|
||||
namespace LaaProductionWeb.Controllers
|
||||
{
|
||||
using LaaProductionWeb.App_Infrastructure;
|
||||
using LaaProductionWeb.Services.Interfaces;
|
||||
|
||||
using System.Web.Mvc;
|
||||
|
||||
[Authorize]
|
||||
|
||||
[AllowAnonymous]
|
||||
public class HomeController : Controller
|
||||
{
|
||||
private readonly IAccountService accountService;
|
||||
|
||||
public HomeController(IAccountService accountService)
|
||||
=> this.accountService = accountService;
|
||||
|
||||
[HttpGet]
|
||||
public ActionResult Index() => this.View();
|
||||
public ActionResult Index()
|
||||
=> this.View();
|
||||
|
||||
[HttpPost]
|
||||
public ActionResult Index(string username, string password)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(username))
|
||||
{
|
||||
this.ModelState.AddModelError(nameof(username), "Benutzername ist erforderlich.");
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(password))
|
||||
{
|
||||
this.ModelState.AddModelError(nameof(password), "Kennwort ist erforderlich.");
|
||||
}
|
||||
|
||||
if (this.ModelState.IsValid)
|
||||
{
|
||||
var userId = this.accountService.Login(username, password);
|
||||
|
||||
if (this.HttpContext.SignIn(userId))
|
||||
{
|
||||
return this.Redirect(this.HttpContext.GetUrlReferer());
|
||||
}
|
||||
}
|
||||
|
||||
return this.View();
|
||||
}
|
||||
|
||||
public ActionResult Logout()
|
||||
{
|
||||
this.HttpContext.SignOut();
|
||||
|
||||
return this.View(nameof(Index));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,8 +5,7 @@
|
||||
using LaaProductionWeb.Services.Models;
|
||||
|
||||
using System.Web.Mvc;
|
||||
|
||||
[Authorize]
|
||||
|
||||
[AllowedRoles(UserRoles.WEB_PuneProtokoll)]
|
||||
public class ProtocolController : Controller
|
||||
{
|
||||
@@ -88,7 +87,6 @@
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public ActionResult DeleteFile(int fileId, int orderId)
|
||||
{
|
||||
this.protocolService.DeleteFile(fileId);
|
||||
@@ -110,6 +108,7 @@
|
||||
return this.PartialView(clientsOrders);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public ActionResult Body(int orderId = 0)
|
||||
{
|
||||
var testStatus = this.protocolService.LoadTestStatus(orderId);
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
{
|
||||
using LaaProductionWeb.App_Infrastructure;
|
||||
using LaaProductionWeb.Services.Interfaces;
|
||||
using LaaProductionWeb.Services.Models;
|
||||
using LaaProductionWeb.Services.Models.Reports;
|
||||
|
||||
using System;
|
||||
using System.Web.Mvc;
|
||||
|
||||
[Authorize]
|
||||
|
||||
[AllowedRoles(UserRoles.WEB_HeReport)]
|
||||
public class ReportController : Controller
|
||||
{
|
||||
@@ -16,7 +16,7 @@
|
||||
=> this.reportService = reportService;
|
||||
|
||||
[HttpGet]
|
||||
public ActionResult Index()
|
||||
public ActionResult Helium()
|
||||
{
|
||||
var model = this.reportService.LoadHeliumPressureReport();
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public ActionResult Index(HeliumReportModel model)
|
||||
public ActionResult Helium(HeliumReportModel model)
|
||||
{
|
||||
model = this.reportService.LoadHeliumPressureReport(model);
|
||||
|
||||
@@ -32,8 +32,7 @@
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public ActionResult CSV(HeliumReportModel model)
|
||||
public ActionResult HeliumCSV(HeliumReportModel model)
|
||||
{
|
||||
var csvReport = this.reportService.LoadHeliumPressureReportAsCSV(model);
|
||||
var fileName = $"HeReport_{DateTime.Now:yyyyMMddhhmmss}.csv";
|
||||
@@ -43,11 +42,38 @@
|
||||
return this.File(csvReport, "application/csv");
|
||||
}
|
||||
|
||||
public ActionResult Results(int testId = 0)
|
||||
public ActionResult HeliumResults(int testId = 0)
|
||||
{
|
||||
var results = this.reportService.LoadHeliumPressureResults(testId);
|
||||
|
||||
return this.PartialView(results);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public ActionResult Kottmann()
|
||||
{
|
||||
var model = this.reportService.LoadKottmannPressureReport();
|
||||
|
||||
return this.View(model);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public ActionResult Kottmann(KottmannReportModel model)
|
||||
{
|
||||
model = this.reportService.LoadKottmannPressureReport(model);
|
||||
|
||||
return this.View(model);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public ActionResult KottmannCSV(KottmannReportModel model)
|
||||
{
|
||||
var csvReport = this.reportService.LoadKottmannPressureReportAsCSV(model);
|
||||
var fileName = $"KottmannReport_{DateTime.Now:yyyyMMddhhmmss}.csv";
|
||||
|
||||
this.Response.AddHeader("Content-Disposition", $"attachment;filename={fileName}");
|
||||
|
||||
return this.File(csvReport, "application/csv");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,26 @@
|
||||
namespace LaaProductionWeb.Controllers
|
||||
{
|
||||
using LaaProductionWeb.App_Infrastructure;
|
||||
using LaaProductionWeb.Services.Interfaces;
|
||||
using LaaProductionWeb.Services.Models.Search;
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web.Mvc;
|
||||
|
||||
[Authorize]
|
||||
|
||||
[AllowedRoles(UserRoles.WEB_API_Explorer)]
|
||||
public class SearchController : Controller
|
||||
{
|
||||
private readonly IOrdersService ordersService;
|
||||
private readonly IHttpService httpService;
|
||||
|
||||
public SearchController(IOrdersService ordersService)
|
||||
=> this.ordersService = ordersService;
|
||||
public SearchController(IOrdersService ordersService, IHttpService httpService)
|
||||
{
|
||||
this.ordersService = ordersService;
|
||||
this.httpService = httpService;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public ActionResult Orders(string search)
|
||||
@@ -35,5 +45,50 @@
|
||||
|
||||
return this.PartialView(model);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<ActionResult> Wildcard()
|
||||
{
|
||||
var httpOptions = await this.httpService.OptionsAsync("/Search/Wildcard");
|
||||
var model = new SearchWildcardModel();
|
||||
|
||||
if (httpOptions.Succeeded)
|
||||
{
|
||||
model.Fields = httpOptions
|
||||
.Deserialize<List<string>>()
|
||||
.ToDictionary(x => x, x => false);
|
||||
}
|
||||
|
||||
return this.View(model);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<ActionResult> Wildcard(SearchWildcardModel model)
|
||||
{
|
||||
var fields = string.Empty;
|
||||
|
||||
if (model.Fields.Any(x => x.Value))
|
||||
{
|
||||
fields = WebUtility.UrlEncode(string.Join(",", model.Fields.Where(x => x.Value).Select(x => x.Key)));
|
||||
}
|
||||
|
||||
var httpResult = await this.httpService.GetAsync($"/Search/Wildcard?token={model.Token}&fields={fields}");
|
||||
|
||||
if (httpResult.Succeeded)
|
||||
{
|
||||
model.Results = httpResult.Deserialize<List<Dictionary<string, object>>>();
|
||||
}
|
||||
else
|
||||
{
|
||||
var errors = httpResult.Deserialize<Dictionary<string, string>>();
|
||||
|
||||
foreach (var errorKVP in errors)
|
||||
{
|
||||
this.ModelState.AddModelError(errorKVP.Key, errorKVP.Value.Replace("Token", "'Search text'"));
|
||||
}
|
||||
}
|
||||
|
||||
return this.View(model);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,8 +12,7 @@
|
||||
using System.Web.Mvc;
|
||||
|
||||
using SystemFile = System.IO.File;
|
||||
|
||||
[Authorize]
|
||||
|
||||
[AllowedRoles(UserRoles.WEB_PalettenScan)]
|
||||
public class ShipmentsController : Controller
|
||||
{
|
||||
@@ -27,7 +26,6 @@
|
||||
=> this.View(new ShipmentModel());
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public ActionResult Index(ShipmentModel model)
|
||||
=> this.View(model);
|
||||
|
||||
@@ -51,7 +49,6 @@
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public ActionResult ScanPost(OrderScanModel model)
|
||||
{
|
||||
if (this.ModelState.IsValid)
|
||||
@@ -64,7 +61,6 @@
|
||||
|
||||
if (result)
|
||||
{
|
||||
model.PositionNr = null;
|
||||
model.SerialNr = default(string);
|
||||
}
|
||||
else
|
||||
@@ -80,7 +76,6 @@
|
||||
public ActionResult Delete(int id)
|
||||
{
|
||||
var orderScanModel = this.shipmentsService.DeletePalletEntry(id);
|
||||
orderScanModel.PositionNr = null;
|
||||
|
||||
return this.View(nameof(this.Index), new ShipmentModel(orderScanModel));
|
||||
}
|
||||
|
||||
@@ -3,18 +3,22 @@
|
||||
using LaaProductionWeb.App_Start;
|
||||
|
||||
using System.Web;
|
||||
using System.Web.Http;
|
||||
using System.Web.Mvc;
|
||||
using System.Web.Optimization;
|
||||
using System.Web.Routing;
|
||||
|
||||
/// <summary>
|
||||
/// MVC base class for registering and configuring user-defined or customized applications.
|
||||
/// </summary>
|
||||
public class MvcApplication : HttpApplication
|
||||
{
|
||||
/// <summary>
|
||||
/// Default launch method defined by the Asp.Net MVC framework.
|
||||
/// </summary>
|
||||
protected void Application_Start()
|
||||
{
|
||||
ServicesConfig.RegisterServices();
|
||||
AreaRegistration.RegisterAllAreas();
|
||||
GlobalConfiguration.Configure(WebApiConfig.Register);
|
||||
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
|
||||
RouteConfig.RegisterRoutes(RouteTable.Routes);
|
||||
BundleConfig.RegisterBundles(BundleTable.Bundles);
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
<UseIISExpress>true</UseIISExpress>
|
||||
<Use64BitIISExpress />
|
||||
<IISExpressSSLPort />
|
||||
<IISExpressAnonymousAuthentication>disabled</IISExpressAnonymousAuthentication>
|
||||
<IISExpressWindowsAuthentication>enabled</IISExpressWindowsAuthentication>
|
||||
<IISExpressAnonymousAuthentication>enabled</IISExpressAnonymousAuthentication>
|
||||
<IISExpressWindowsAuthentication>disabled</IISExpressWindowsAuthentication>
|
||||
<IISExpressUseClassicPipelineMode />
|
||||
<UseGlobalApplicationHostFile />
|
||||
<NuGetPackageImportStamp>
|
||||
@@ -60,25 +60,26 @@
|
||||
<Reference Include="Microsoft.Web.Infrastructure, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Web.Infrastructure.2.0.0\lib\net40\Microsoft.Web.Infrastructure.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
<Reference Include="Newtonsoft.Json, Version=11.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\..\..\..\Program Files\dotnet\sdk\NuGetFallbackFolder\newtonsoft.json\11.0.2\lib\netstandard2.0\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Data.OracleClient" />
|
||||
<Reference Include="System.DirectoryServices" />
|
||||
<Reference Include="System.DirectoryServices.AccountManagement" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Net.Http.Formatting, Version=5.2.9.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebApi.Client.5.2.9\lib\net45\System.Net.Http.Formatting.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Net" />
|
||||
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Security.Principal.Windows, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Security.Principal.Windows.5.0.0\lib\net461\System.Security.Principal.Windows.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Security" />
|
||||
<Reference Include="System.ServiceProcess" />
|
||||
<Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Transactions" />
|
||||
<Reference Include="System.Web.DynamicData" />
|
||||
<Reference Include="System.Web.Entity" />
|
||||
<Reference Include="System.Web.ApplicationServices" />
|
||||
@@ -88,12 +89,6 @@
|
||||
<Reference Include="System.Web.Helpers, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebPages.3.2.9\lib\net45\System.Web.Helpers.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.Http, Version=5.2.9.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebApi.Core.5.2.9\lib\net45\System.Web.Http.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.Http.WebHost, Version=5.2.9.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebApi.WebHost.5.2.9\lib\net45\System.Web.Http.WebHost.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.Mvc, Version=5.2.9.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.AspNet.Mvc.5.2.9\lib\net45\System.Web.Mvc.dll</HintPath>
|
||||
</Reference>
|
||||
@@ -132,6 +127,7 @@
|
||||
<Reference Include="WebGrease, Version=1.6.5135.21930, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\WebGrease.1.6.0\lib\WebGrease.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="WindowsBase" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="App_Infrastructure\ApplicationSettings.cs" />
|
||||
@@ -140,13 +136,15 @@
|
||||
<Compile Include="App_Infrastructure\ControllersExtensions.cs" />
|
||||
<Compile Include="App_Infrastructure\ExceptionFilter.cs" />
|
||||
<Compile Include="App_Infrastructure\AllowedRolesAttribute.cs" />
|
||||
<Compile Include="App_Infrastructure\NestedController.cs" />
|
||||
<Compile Include="App_Infrastructure\ServiceProvider.cs" />
|
||||
<Compile Include="App_Infrastructure\ServiceProviderExtensions.cs" />
|
||||
<Compile Include="App_Infrastructure\SessionUser.cs" />
|
||||
<Compile Include="App_Infrastructure\UserRoles.cs" />
|
||||
<Compile Include="App_Start\BundleConfig.cs" />
|
||||
<Compile Include="App_Start\FilterConfig.cs" />
|
||||
<Compile Include="App_Start\RouteConfig.cs" />
|
||||
<Compile Include="App_Start\ServicesConfig.cs" />
|
||||
<Compile Include="App_Start\WebApiConfig.cs" />
|
||||
<Compile Include="Controllers\AdminController.cs" />
|
||||
<Compile Include="Controllers\ApprovalsController.cs" />
|
||||
<Compile Include="Controllers\HomeController.cs" />
|
||||
@@ -167,29 +165,30 @@
|
||||
<Content Include="App_Content\js\jsbarcode.all.min.js" />
|
||||
<Content Include="App_Content\js\scripts.js" />
|
||||
<Content Include="App_Content\svg\sensus_xylem_logo.svg" />
|
||||
<Content Include="favicon.ico" />
|
||||
<Content Include="favicon.svg" />
|
||||
<Content Include="Global.asax" />
|
||||
<Content Include="Views\Home\Index.cshtml" />
|
||||
<Content Include="Web.config">
|
||||
<SubType>Designer</SubType>
|
||||
</Content>
|
||||
<Content Include="Views\Web.config" />
|
||||
<Content Include="Views\_ViewStart.cshtml" />
|
||||
<Content Include="Views\Shared\_Layout.cshtml" />
|
||||
<Content Include="Views\Home\Index.cshtml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
<Content Include="Views\Shared\_PrintLayout.cshtml" />
|
||||
<Content Include="Views\Report\Index.cshtml" />
|
||||
<Content Include="Views\Report\Helium.cshtml" />
|
||||
<Content Include="Views\Report\Filter.cshtml" />
|
||||
<Content Include="Views\Report\Results.cshtml" />
|
||||
<Content Include="Views\Report\HeliumResults.cshtml" />
|
||||
<Content Include="Views\Report\DateFilter.cshtml" />
|
||||
<None Include="Properties\PublishProfiles\FolderProfile.pubxml" />
|
||||
<Content Include="Views\Approvals\Add.cshtml" />
|
||||
<Content Include="Views\Search\Production.cshtml" />
|
||||
<Content Include="Views\Admin\Index.cshtml" />
|
||||
<Content Include="Views\Report\HiddenFilter.cshtml" />
|
||||
<Content Include="Views\Report\Kottmann.cshtml" />
|
||||
<Content Include="Views\Search\Wildcard.cshtml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="App_Content\font\fonts\bootstrap-icons.woff" />
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
**LaaProductionWeb**
|
||||
---
|
||||
[🠄 Go back to the parent directory](https://slm.sms-esaap.com/la_operations/laa_production/-/tree/main/LaaProductionWeb)
|
||||
|
||||
is a **ASP.Net MVC** **[local web application](http://sla12iis01.emea.sensus.net/LaaProductionWeb/)** written under **C# .Net Framework 6.4.2** that contains web services for digitization of the production processes.
|
||||
|
||||
- Authentication througth: username, password; initial session time: 10 min; configurable;
|
||||
- Loading content according to current user permissions
|
||||
|
||||
**1. Pallets scan**
|
||||
|
||||
- Used to save pallets with their loads in a database. This will help later when creating a pallet load file to ship with the pallet.
|
||||
|
||||
|
||||
**2. QAP test protocol**
|
||||
|
||||
- Used to create QAP test protocol automaticaly for particular customers. This protocol should be printet signed and uploaded to the particular order. Is unique for each order.
|
||||
|
||||
**3. Reports**
|
||||
|
||||
- [He] Report - Statistics for past helium tests, allows user to filter and sort all displayed data and then to download a csv file from that as well.
|
||||
- Cotman - Statistics for past pressure tests, allows user to filter and sort all displayed data and then to download a csv file from that as well.
|
||||
|
||||
**4. Production approval**
|
||||
|
||||
- Used to approve particular production orders with different characteristics and notes.
|
||||
|
||||
**5. Wildcard search**
|
||||
|
||||
- is a none public web interface for searching orders info from one of following: Radio Addresse, PcbId, SerialNr, ClientSerialNr.
|
||||
@@ -1,7 +1,6 @@
|
||||
@model LaaProductionWeb.Services.Models.ProductionApproval
|
||||
|
||||
<form action="/Approvals/Add" method="post" autocomplete="off">
|
||||
@this.Html.AntiForgeryToken()
|
||||
<form action="~/Approvals/Add" method="post" autocomplete="off">
|
||||
<div class="container my-3">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
@@ -138,7 +137,6 @@
|
||||
(function () {
|
||||
let fertigungNrMenu = document.getElementById('fertigungNrMenu');
|
||||
let orderNrInput = document.getElementById('OrderNr');
|
||||
|
||||
if (fertigungNrMenu && orderNrInput) {
|
||||
function loadDropdownItems(html) {
|
||||
fertigungNrMenu.innerHTML = html;
|
||||
@@ -152,7 +150,7 @@
|
||||
orderNrInput.oninput = (e) => {
|
||||
let value = e.target.value;
|
||||
if (value && value.length > 2) {
|
||||
fetch(`/Search/Production?productionNr=${orderNrInput.value}`)
|
||||
fetch(`@this.Url.Action("Production", "Search")?productionNr=${orderNrInput.value}`)
|
||||
.then(response => response.text())
|
||||
.then(html => loadDropdownItems(html))
|
||||
.catch(error => console.log(error));
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<div class="container my-5 py-5">
|
||||
@using LaaProductionWeb.App_Infrastructure
|
||||
|
||||
<div class="container my-5 py-5">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="jumbotron">
|
||||
@@ -30,4 +32,27 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if (this.User.IsInRole(UserRoles.WEB_Anonymous))
|
||||
{
|
||||
<div class="row">
|
||||
<div class="col-5">
|
||||
<form action="~/" method="post" autocomplete="off">
|
||||
<div class="form-floating mb-3">
|
||||
<input type="text" class="form-control" id="username" name="username" placeholder="Benutzername" autocomplete="off">
|
||||
<label for="username">Benutzername</label>
|
||||
@this.Html.ValidationMessage("username", new { @class = "small text-danger" })
|
||||
</div>
|
||||
<div class="form-floating mb-3">
|
||||
<input type="password" class="form-control" id="password" name="password" placeholder="Kennwort" autocomplete="off">
|
||||
<label for="password">Kennwort</label>
|
||||
@this.Html.ValidationMessage("password", new { @class = "small text-danger" })
|
||||
</div>
|
||||
<div class="d-flex mb-3">
|
||||
<input class="btn btn-success py-3 px-5" value="Anmelden" type="submit" />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
@@ -1,4 +1,4 @@
|
||||
@model IEnumerable<LaaProductionWeb.Services.Models.TestStatus>
|
||||
@model IEnumerable<LaaProductionWeb.Services.Models.Reports.TestStatus>
|
||||
|
||||
@{
|
||||
Func<bool?, bool, MvcHtmlString> testPassed = (testStatus, nullable) =>
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
@using LaaProductionWeb.Services.Models
|
||||
|
||||
<div class="d-flex flex-column h-100">
|
||||
<form action="/Protocol/DeleteFile" method="post" class="nav justify-content-end bg-whitesmoke">
|
||||
@this.Html.AntiForgeryToken()
|
||||
<form action="~/Protocol/DeleteFile" method="post" class="nav justify-content-end bg-whitesmoke">
|
||||
@this.Html.HiddenFor(x => x.FileId)
|
||||
@this.Html.HiddenFor(x => x.OrderId)
|
||||
<button class="btn btn-link text-danger nav-link">
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user