This commit is contained in:
Jonathan Jenne 2024-01-16 09:44:48 +01:00
parent 0a01bf59ef
commit 6131948f2a
13 changed files with 223 additions and 61 deletions

View File

@ -39,6 +39,11 @@ Public Class Helpers
End Function End Function
Public Shared Function GetAccessCode() As String
Return Guid.NewGuid().ToString("d").Substring(1, 6).ToUpper()
End Function
Public Shared Function ColorTypeToColor(pColorType As ColorType) As Color Public Shared Function ColorTypeToColor(pColorType As ColorType) As Color
Select Case pColorType Select Case pColorType
Case ColorType.ReceiverColor1 Case ColorType.ReceiverColor1

View File

@ -7,16 +7,12 @@ Public Class TemplateService
Private _replaceDictionary As Dictionary(Of String, String) Private _replaceDictionary As Dictionary(Of String, String)
Private ReadOnly DbConfig As DbConfig Private ReadOnly DbConfig As DbConfig
Private ReadOnly LogConfig As LogConfig
Private ReadOnly Logger As Logger
Private ReadOnly EmailHtmlTemplateModel As EmailTemplateModel Private ReadOnly EmailHtmlTemplateModel As EmailTemplateModel
Public Sub New(pState As State) Public Sub New(pState As State)
MyBase.New(pState) MyBase.New(pState)
DbConfig = pState.DbConfig DbConfig = pState.DbConfig
LogConfig = pState.LogConfig
Logger = LogConfig.GetLogger()
EmailHtmlTemplateModel = New EmailTemplateModel(pState) EmailHtmlTemplateModel = New EmailTemplateModel(pState)
End Sub End Sub

View File

@ -12,7 +12,6 @@ Public Class EnvelopeEditorController
Public ReadOnly EmailService As EmailService Public ReadOnly EmailService As EmailService
Public ReadOnly ActionService As ActionService Public ReadOnly ActionService As ActionService
Public ReadOnly Thumbnail As Thumbnail Public ReadOnly Thumbnail As Thumbnail
Public Sub New(pState As State) Public Sub New(pState As State)

View File

@ -22,6 +22,10 @@ Partial Public Class frmEnvelopeEditor
Private Controller As EnvelopeEditorController Private Controller As EnvelopeEditorController
Private Logger As Logger Private Logger As Logger
Private Const COL_NAME = "Name"
Private Const COL_EMAIL = "Email"
Private Const COL_CODE = "AccessCode"
Public Property State As State Public Property State As State
Public Sub New() Public Sub New()
@ -447,7 +451,7 @@ Partial Public Class frmEnvelopeEditor
End Sub End Sub
Private Sub ViewReceivers_CellValueChanged(sender As Object, e As Views.Base.CellValueChangedEventArgs) Handles ViewReceivers.CellValueChanged Private Sub ViewReceivers_CellValueChanged(sender As Object, e As Views.Base.CellValueChangedEventArgs) Handles ViewReceivers.CellValueChanged
If e.Column.FieldName = "Email" Then If e.Column.FieldName = COL_EMAIL Then
If e.Value Is Nothing Then If e.Value Is Nothing Then
' Keine E-Mail-Adresse, also weg damit ' Keine E-Mail-Adresse, also weg damit
ViewReceivers.DeleteRow(ViewReceivers.FocusedRowHandle) ViewReceivers.DeleteRow(ViewReceivers.FocusedRowHandle)
@ -455,20 +459,16 @@ Partial Public Class frmEnvelopeEditor
' Doppelte E-Mail-Adresse? TODO ' Doppelte E-Mail-Adresse? TODO
'Dim oReceivers = Controller.Envelope.Receivers 'Dim oReceivers = Controller.Envelope.Receivers
Dim oNameCellValue = ViewReceivers.GetRowCellValue(e.RowHandle, "Name") Dim oNameCellValue = ViewReceivers.GetRowCellValue(e.RowHandle, COL_NAME)
If oNameCellValue Is Nothing Then If oNameCellValue Is Nothing Then
Dim oEmailAdress As String = DirectCast(e.Value, String) Dim oEmailAdress As String = DirectCast(e.Value, String)
Dim oLastName As String = Controller.GetLastNameByEmailAdress(oEmailAdress) Dim oLastName As String = Controller.GetLastNameByEmailAdress(oEmailAdress)
Dim oAccessCode As String = Guid.NewGuid().ToString("d").Substring(1, 6).ToUpper() Dim oAccessCode As String = Helpers.GetAccessCode()
ViewReceivers.SetRowCellValue(e.RowHandle, ViewReceivers.Columns("Name"), oLastName) ViewReceivers.SetRowCellValue(e.RowHandle, ViewReceivers.Columns.Item(COL_NAME), oLastName)
ViewReceivers.SetRowCellValue(e.RowHandle, ViewReceivers.Columns("AccessCode"), oAccessCode) ViewReceivers.SetRowCellValue(e.RowHandle, ViewReceivers.Columns.Item(COL_CODE), oAccessCode)
End If End If
End If End If
End If End If
End Sub End Sub
Private Sub RibbonControl1_Click(sender As Object, e As EventArgs) Handles RibbonControl1.Click
End Sub
End Class End Class

View File

@ -53,6 +53,12 @@ namespace EnvelopeGenerator.Web.Controllers
envelopeService.EnsureValidEnvelopeKey(envelopeKey); envelopeService.EnsureValidEnvelopeKey(envelopeKey);
EnvelopeResponse response = envelopeService.LoadEnvelope(envelopeKey); EnvelopeResponse response = envelopeService.LoadEnvelope(envelopeKey);
// Again check if receiver has already signed
if (envelopeService.ReceiverAlreadySigned(response.Envelope, response.Receiver.Id) == true)
{
return Problem(statusCode: 403);
}
var Request = ControllerContext.HttpContext.Request; var Request = ControllerContext.HttpContext.Request;
var document = envelopeService.GetDocument(Request, envelopeKey); var document = envelopeService.GetDocument(Request, envelopeKey);

View File

@ -19,10 +19,54 @@ namespace EnvelopeGenerator.Web.Controllers
[HttpGet] [HttpGet]
[Route("/")] [Route("/")]
public IActionResult Index() public IActionResult Index()
{ {
List<Envelope> envelopes = _envelopeService.LoadEnvelopes(); return View();
}
return View(envelopes); [HttpPost]
[Route("/")]
public IActionResult DebugEnvelopes()
{
try
{
StringValues passwordFromForm = HttpContext.Request.Form["password"];
string passwordFromConfig = database.GetAppSetting("Config:AdminPassword");
if (passwordFromConfig == null)
{
ViewData["error"] = "No admin password configured!";
return View("Index");
}
if (passwordFromForm.Count != 1)
{
ViewData["error"] = "No admin password configured!";
return View("Index");
}
string password = passwordFromForm[0];
if (password == null)
{
ViewData["error"] = "No password supplied!";
return View("Index");
}
if (password != passwordFromConfig)
{
ViewData["error"] = "Wrong Password!";
return View("Index");
}
List<Envelope> envelopes = _envelopeService.LoadEnvelopes();
return View(envelopes);
}
catch (Exception e)
{
ViewData["error"] = "Unknown error!";
return View("Index");
}
} }
[HttpGet] [HttpGet]

View File

@ -6,6 +6,7 @@ namespace EnvelopeGenerator.Web.Services
public class DatabaseService: BaseService public class DatabaseService: BaseService
{ {
public MSSQLServer MSSQL { get; set; } public MSSQLServer MSSQL { get; set; }
public IConfiguration Config { get; set; }
public State State { get; set; } public State State { get; set; }
@ -47,12 +48,13 @@ namespace EnvelopeGenerator.Web.Services
public readonly ModelContainer? Models; public readonly ModelContainer? Models;
public readonly ServiceContainer? Services; public readonly ServiceContainer? Services;
public DatabaseService(IConfiguration Config, LoggingService Logging) : base(Config, Logging) public DatabaseService(IConfiguration pConfig, LoggingService pLogging) : base(pConfig, pLogging)
{ {
logger = Logging.LogConfig.GetLogger(); logger = pLogging.LogConfig.GetLogger();
Config = pConfig;
logger.Debug("Establishing MSSQL Database connection.."); logger.Debug("Establishing MSSQL Database connection..");
MSSQL = new MSSQLServer(logConfig, Config["Config:ConnectionString"]); MSSQL = new MSSQLServer(logConfig, pConfig["Config:ConnectionString"]);
if (MSSQL.DBInitialized == true) if (MSSQL.DBInitialized == true)
{ {
@ -71,6 +73,11 @@ namespace EnvelopeGenerator.Web.Services
} }
} }
public string? GetAppSetting(string key)
{
return Config[key];
}
/// <summary> /// <summary>
/// There is a circular dependency between state and models /// There is a circular dependency between state and models
/// All models need a state object, including the config Model /// All models need a state object, including the config Model

View File

@ -0,0 +1,48 @@
@using EnvelopeGenerator.Common;
@using static EnvelopeGenerator.Common.Constants;
@{
ViewData["Title"] = "Debug";
}
@functions {
string encodeEnvelopeKey(Envelope envelope)
{
var receiver = envelope.Receivers.First();
return Helpers.EncodeEnvelopeReceiverId(envelope.Uuid, receiver.Signature);
}
IEnumerable<IGrouping<EnvelopeStatus, Envelope>> groupEnvelopes(List<Envelope> envelopes)
{
return envelopes.GroupBy(item => item.Status).OrderBy(item => (int)item.Key);
}
}
<div class="container">
<section>
@foreach (IGrouping<EnvelopeStatus, Envelope> group in groupEnvelopes((List<Envelope>)@Model))
{
<section>
<h2>@group.Key.ToString() @group.Count()</h2>
<details>
<summary>Show envelopes</summary>
@foreach (Envelope envelope in @group)
{
<section>
<article class="envelope">
<strong><a href="/EnvelopeKey/@encodeEnvelopeKey(envelope)">@envelope.Title</a></strong>
<div><strong>Ersteller</strong> @envelope.User.Email</div>
<div><strong>Datum</strong> @envelope.AddedWhen</div>
</article>
</section>
}
</details>
<hr />
</section>
}
</section>
</div>

View File

@ -2,9 +2,9 @@
ViewData["Title"] = "Dokument geschützt"; ViewData["Title"] = "Dokument geschützt";
} }
<div id="page-locked" class="container p-5"> <div class="page container p-5">
<header class="text-center"> <header class="text-center">
<div class="icon bg-warning text-black"> <div class="icon locked">
<svg xmlns="http://www.w3.org/2000/svg" width="72" height="72" fill="currentColor" class="bi bi-shield-lock" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" width="72" height="72" fill="currentColor" class="bi bi-shield-lock" viewBox="0 0 16 16">
<path d="M5.338 1.59a61 61 0 0 0-2.837.856.48.48 0 0 0-.328.39c-.554 4.157.726 7.19 2.253 9.188a10.7 10.7 0 0 0 2.287 2.233c.346.244.652.42.893.533q.18.085.293.118a1 1 0 0 0 .101.025 1 1 0 0 0 .1-.025q.114-.034.294-.118c.24-.113.547-.29.893-.533a10.7 10.7 0 0 0 2.287-2.233c1.527-1.997 2.807-5.031 2.253-9.188a.48.48 0 0 0-.328-.39c-.651-.213-1.75-.56-2.837-.855C9.552 1.29 8.531 1.067 8 1.067c-.53 0-1.552.223-2.662.524zM5.072.56C6.157.265 7.31 0 8 0s1.843.265 2.928.56c1.11.3 2.229.655 2.887.87a1.54 1.54 0 0 1 1.044 1.262c.596 4.477-.787 7.795-2.465 9.99a11.8 11.8 0 0 1-2.517 2.453 7 7 0 0 1-1.048.625c-.28.132-.581.24-.829.24s-.548-.108-.829-.24a7 7 0 0 1-1.048-.625 11.8 11.8 0 0 1-2.517-2.453C1.928 10.487.545 7.169 1.141 2.692A1.54 1.54 0 0 1 2.185 1.43 63 63 0 0 1 5.072.56" /> <path d="M5.338 1.59a61 61 0 0 0-2.837.856.48.48 0 0 0-.328.39c-.554 4.157.726 7.19 2.253 9.188a10.7 10.7 0 0 0 2.287 2.233c.346.244.652.42.893.533q.18.085.293.118a1 1 0 0 0 .101.025 1 1 0 0 0 .1-.025q.114-.034.294-.118c.24-.113.547-.29.893-.533a10.7 10.7 0 0 0 2.287-2.233c1.527-1.997 2.807-5.031 2.253-9.188a.48.48 0 0 0-.328-.39c-.651-.213-1.75-.56-2.837-.855C9.552 1.29 8.531 1.067 8 1.067c-.53 0-1.552.223-2.662.524zM5.072.56C6.157.265 7.31 0 8 0s1.843.265 2.928.56c1.11.3 2.229.655 2.887.87a1.54 1.54 0 0 1 1.044 1.262c.596 4.477-.787 7.795-2.465 9.99a11.8 11.8 0 0 1-2.517 2.453 7 7 0 0 1-1.048.625c-.28.132-.581.24-.829.24s-.548-.108-.829-.24a7 7 0 0 1-1.048-.625 11.8 11.8 0 0 1-2.517-2.453C1.928 10.487.545 7.169 1.141 2.692A1.54 1.54 0 0 1 2.185 1.43 63 63 0 0 1 5.072.56" />
<path d="M9.5 6.5a1.5 1.5 0 0 1-1 1.415l.385 1.99a.5.5 0 0 1-.491.595h-.788a.5.5 0 0 1-.49-.595l.384-1.99a1.5 1.5 0 1 1 2-1.415" /> <path d="M9.5 6.5a1.5 1.5 0 0 1-1 1.415l.385 1.99a.5.5 0 0 1-.491.595h-.788a.5.5 0 0 1-.49-.595l.384-1.99a1.5 1.5 0 1 1 2-1.415" />
@ -18,7 +18,7 @@
</section> </section>
<section> <section>
<form id="form-access-code" method="post"> <form id="form-access-code" class="form" method="post">
<div class="input"> <div class="input">
<label class="visually-hidden" for="access_code">Zugriffscode</label> <label class="visually-hidden" for="access_code">Zugriffscode</label>
<input type="password" class="form-control" name="access_code" placeholder="Zugriffscode" required="required"> <input type="password" class="form-control" name="access_code" placeholder="Zugriffscode" required="required">
@ -36,4 +36,6 @@
<p>Bitte überprüfen Sie Ihr Email Postfach inklusive Spam-Ordner. Sie können auch den Absender bitten, Ihnen den Code auf anderem Wege zukommen zu lassen.</p> <p>Bitte überprüfen Sie Ihr Email Postfach inklusive Spam-Ordner. Sie können auch den Absender bitten, Ihnen den Code auf anderem Wege zukommen zu lassen.</p>
</details> </details>
</section> </section>
</div> </div>
<footer class="container" id="page-footer">&copy; SignFlow 2023-2024 <a href="https://digitaldata.works">Digital Data GmbH</a></footer>

View File

@ -2,9 +2,9 @@
ViewData["Title"] = "Dokument unterschrieben"; ViewData["Title"] = "Dokument unterschrieben";
} }
<div id="page-success" class="container p-5"> <div class="page container p-5">
<header class="text-center"> <header class="text-center">
<div class="icon bg-success text-light"> <div class="icon signed">
<svg xmlns="http://www.w3.org/2000/svg" width="72" height="72" fill="currentColor" class="bi bi-check2-circle" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" width="72" height="72" fill="currentColor" class="bi bi-check2-circle" viewBox="0 0 16 16">
<path d="M2.5 8a5.5 5.5 0 0 1 8.25-4.764.5.5 0 0 0 .5-.866A6.5 6.5 0 1 0 14.5 8a.5.5 0 0 0-1 0 5.5 5.5 0 1 1-11 0z" /> <path d="M2.5 8a5.5 5.5 0 0 1 8.25-4.764.5.5 0 0 0 .5-.866A6.5 6.5 0 1 0 14.5 8a.5.5 0 0 0-1 0 5.5 5.5 0 1 1-11 0z" />
<path d="M15.354 3.354a.5.5 0 0 0-.708-.708L8 9.293 5.354 6.646a.5.5 0 1 0-.708.708l3 3a.5.5 0 0 0 .708 0l7-7z" /> <path d="M15.354 3.354a.5.5 0 0 0-.708-.708L8 9.293 5.354 6.646a.5.5 0 1 0-.708.708l3 3a.5.5 0 0 0 .708 0l7-7z" />
@ -19,3 +19,5 @@
</div> </div>
<footer class="container" id="page-footer">&copy; SignFlow 2023-2024 <a href="https://digitaldata.works">Digital Data GmbH</a></footer>

View File

@ -1,33 +1,37 @@
@using EnvelopeGenerator.Common; @{
@using static EnvelopeGenerator.Common.Constants; ViewData["Title"] = "Dokument geschützt";
@{
ViewData["Title"] = "Home Page";
} }
@functions { <div class="page container p-5">
string encodeEnvelopeKey(Envelope envelope) <header class="text-center">
<div class="icon admin">
<svg xmlns="http://www.w3.org/2000/svg" width="72" height="72" fill="currentColor" class="bi bi-cup-hot" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M.5 6a.5.5 0 0 0-.488.608l1.652 7.434A2.5 2.5 0 0 0 4.104 16h5.792a2.5 2.5 0 0 0 2.44-1.958l.131-.59a3 3 0 0 0 1.3-5.854l.221-.99A.5.5 0 0 0 13.5 6zM13 12.5a2 2 0 0 1-.316-.025l.867-3.898A2.001 2.001 0 0 1 13 12.5M2.64 13.825 1.123 7h11.754l-1.517 6.825A1.5 1.5 0 0 1 9.896 15H4.104a1.5 1.5 0 0 1-1.464-1.175" />
<path d="m4.4.8-.003.004-.014.019a4 4 0 0 0-.204.31 2 2 0 0 0-.141.267c-.026.06-.034.092-.037.103v.004a.6.6 0 0 0 .091.248c.075.133.178.272.308.445l.01.012c.118.158.26.347.37.543.112.2.22.455.22.745 0 .188-.065.368-.119.494a3 3 0 0 1-.202.388 5 5 0 0 1-.253.382l-.018.025-.005.008-.002.002A.5.5 0 0 1 3.6 4.2l.003-.004.014-.019a4 4 0 0 0 .204-.31 2 2 0 0 0 .141-.267c.026-.06.034-.092.037-.103a.6.6 0 0 0-.09-.252A4 4 0 0 0 3.6 2.8l-.01-.012a5 5 0 0 1-.37-.543A1.53 1.53 0 0 1 3 1.5c0-.188.065-.368.119-.494.059-.138.134-.274.202-.388a6 6 0 0 1 .253-.382l.025-.035A.5.5 0 0 1 4.4.8m3 0-.003.004-.014.019a4 4 0 0 0-.204.31 2 2 0 0 0-.141.267c-.026.06-.034.092-.037.103v.004a.6.6 0 0 0 .091.248c.075.133.178.272.308.445l.01.012c.118.158.26.347.37.543.112.2.22.455.22.745 0 .188-.065.368-.119.494a3 3 0 0 1-.202.388 5 5 0 0 1-.253.382l-.018.025-.005.008-.002.002A.5.5 0 0 1 6.6 4.2l.003-.004.014-.019a4 4 0 0 0 .204-.31 2 2 0 0 0 .141-.267c.026-.06.034-.092.037-.103a.6.6 0 0 0-.09-.252A4 4 0 0 0 6.6 2.8l-.01-.012a5 5 0 0 1-.37-.543A1.53 1.53 0 0 1 6 1.5c0-.188.065-.368.119-.494.059-.138.134-.274.202-.388a6 6 0 0 1 .253-.382l.025-.035A.5.5 0 0 1 7.4.8m3 0-.003.004-.014.019a4 4 0 0 0-.204.31 2 2 0 0 0-.141.267c-.026.06-.034.092-.037.103v.004a.6.6 0 0 0 .091.248c.075.133.178.272.308.445l.01.012c.118.158.26.347.37.543.112.2.22.455.22.745 0 .188-.065.368-.119.494a3 3 0 0 1-.202.388 5 5 0 0 1-.252.382l-.019.025-.005.008-.002.002A.5.5 0 0 1 9.6 4.2l.003-.004.014-.019a4 4 0 0 0 .204-.31 2 2 0 0 0 .141-.267c.026-.06.034-.092.037-.103a.6.6 0 0 0-.09-.252A4 4 0 0 0 9.6 2.8l-.01-.012a5 5 0 0 1-.37-.543A1.53 1.53 0 0 1 9 1.5c0-.188.065-.368.119-.494.059-.138.134-.274.202-.388a6 6 0 0 1 .253-.382l.025-.035A.5.5 0 0 1 10.4.8" />
</svg>
</div>
<h1>Administration</h1>
</header>
@if (ViewData["error"] != null)
{ {
var receiver = envelope.Receivers.First(); <section class="alert alert-danger">
return Helpers.EncodeEnvelopeReceiverId(envelope.Uuid, receiver.Signature); @ViewData["error"]
</section>
} }
}
<div class="container">
<section> <section>
@foreach (IGrouping<EnvelopeStatus, Envelope> group in ((List<Envelope>)@Model).GroupBy(item => item.Status).OrderBy(item => (int)item.Key)) <form id="form-access-code" class="form" method="post">
{ <div class="input">
<section> <label class="visually-hidden" for="access_code">Passwort</label>
<h2>@group.Key.ToString()</h2> <input type="password" class="form-control" name="password" placeholder="Passwort" required="required">
</div>
<ul> <div class="button">
@foreach (Envelope envelope in @group) <button type="submit" class="btn btn-primary">Öffnen</button>
{ </div>
<li><a href="/EnvelopeKey/@encodeEnvelopeKey(envelope)">@envelope.Title</a></li> </form>
}
</ul>
<hr />
</section>
}
</section> </section>
</div> </div>
<footer class="container" id="page-footer">&copy; SignFlow 2023-2024 <a href="https://digitaldata.works">Digital Data GmbH</a></footer>

View File

@ -10,6 +10,7 @@
"ConnectionString": "Server=sDD-VMP04-SQL17\\DD_DEVELOP01;Database=DD_ECM;User Id=sa;Password=dd;", "ConnectionString": "Server=sDD-VMP04-SQL17\\DD_DEVELOP01;Database=DD_ECM;User Id=sa;Password=dd;",
"LogPath": "E:\\EnvelopeGenerator\\Logs", "LogPath": "E:\\EnvelopeGenerator\\Logs",
"LogDebug": true, "LogDebug": true,
"LogJson": true "LogJson": true,
"AdminPassword": "dd"
} }
} }

View File

@ -41,26 +41,46 @@
color: white; color: white;
} }
body {
background-color: #bbb;
}
/* Success Page */ .page {
margin-top: 3rem;
background: white;
border-radius: 5px;
box-shadow: rgba(9, 30, 66, 0.25) 0px 4px 8px -2px, rgba(9, 30, 66, 0.08) 0px 0px 0px 1px;
max-width: 40rem;
}
#page-success header .icon { .page section {
max-width: 30rem;
margin: 0 auto;
}
.page header .icon {
display: inline-block; display: inline-block;
border-radius: 100px; border-radius: 100px;
padding: 15px; padding: 15px;
margin-bottom: 2rem; margin-bottom: 2rem;
} }
/* Locked Page */ .page header .icon.admin {
background-color: #331904;
color: #fecba1;
}
#page-locked header .icon { .page header .icon.locked {
display: inline-block; background-color: #ffc107;
border-radius: 10px; color: #000;
padding: 15px; }
margin-bottom: 2rem;
}
#form-access-code { .page header .icon.signed {
background-color: #146c43;
color: #fff;
}
.page .form {
max-width: 30rem; max-width: 30rem;
margin: 2rem auto; margin: 2rem auto;
@ -68,7 +88,35 @@
gap: 1rem; gap: 1rem;
} }
#form-access-code > .input { #form-access-code > .input,
#form-admin-password > .input {
flex-grow: 1; flex-grow: 1;
} }
#page-admin header .icon {
background-color: #331904;
color: #fecba1;
}
.envelope {
display: block;
border: 1px solid #eee;
margin-bottom: 1rem;
padding: 0.5rem;
}
footer#page-footer {
color: #333;
max-width: 40rem;
margin-top: 1rem;
font-size: 0.85rem;
}
footer#page-footer a,
footer#page-footer a:link,
footer#page-footer a:hover,
footer#page-footer a:visited,
footer#page-footer a:focus {
color: #444;
}