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
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
Select Case pColorType
Case ColorType.ReceiverColor1

View File

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

View File

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

View File

@ -22,6 +22,10 @@ Partial Public Class frmEnvelopeEditor
Private Controller As EnvelopeEditorController
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 Sub New()
@ -447,7 +451,7 @@ Partial Public Class frmEnvelopeEditor
End Sub
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
' Keine E-Mail-Adresse, also weg damit
ViewReceivers.DeleteRow(ViewReceivers.FocusedRowHandle)
@ -455,20 +459,16 @@ Partial Public Class frmEnvelopeEditor
' Doppelte E-Mail-Adresse? TODO
'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
Dim oEmailAdress As String = DirectCast(e.Value, String)
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("AccessCode"), oAccessCode)
ViewReceivers.SetRowCellValue(e.RowHandle, ViewReceivers.Columns.Item(COL_NAME), oLastName)
ViewReceivers.SetRowCellValue(e.RowHandle, ViewReceivers.Columns.Item(COL_CODE), oAccessCode)
End If
End If
End If
End Sub
Private Sub RibbonControl1_Click(sender As Object, e As EventArgs) Handles RibbonControl1.Click
End Sub
End Class

View File

@ -53,6 +53,12 @@ namespace EnvelopeGenerator.Web.Controllers
envelopeService.EnsureValidEnvelopeKey(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 document = envelopeService.GetDocument(Request, envelopeKey);

View File

@ -20,10 +20,54 @@ namespace EnvelopeGenerator.Web.Controllers
[Route("/")]
public IActionResult Index()
{
return View();
}
[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]
[Route("/EnvelopeKey/{EnvelopeReceiverId}")]

View File

@ -6,6 +6,7 @@ namespace EnvelopeGenerator.Web.Services
public class DatabaseService: BaseService
{
public MSSQLServer MSSQL { get; set; }
public IConfiguration Config { get; set; }
public State State { get; set; }
@ -47,12 +48,13 @@ namespace EnvelopeGenerator.Web.Services
public readonly ModelContainer? Models;
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..");
MSSQL = new MSSQLServer(logConfig, Config["Config:ConnectionString"]);
MSSQL = new MSSQLServer(logConfig, pConfig["Config:ConnectionString"]);
if (MSSQL.DBInitialized == true)
{
@ -71,6 +73,11 @@ namespace EnvelopeGenerator.Web.Services
}
}
public string? GetAppSetting(string key)
{
return Config[key];
}
/// <summary>
/// There is a circular dependency between state and models
/// 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";
}
<div id="page-locked" class="container p-5">
<div class="page container p-5">
<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">
<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" />
@ -18,7 +18,7 @@
</section>
<section>
<form id="form-access-code" method="post">
<form id="form-access-code" class="form" method="post">
<div class="input">
<label class="visually-hidden" for="access_code">Zugriffscode</label>
<input type="password" class="form-control" name="access_code" placeholder="Zugriffscode" required="required">
@ -37,3 +37,5 @@
</details>
</section>
</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";
}
<div id="page-success" class="container p-5">
<div class="page container p-5">
<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">
<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" />
@ -19,3 +19,5 @@
</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"] = "Home Page";
@{
ViewData["Title"] = "Dokument geschützt";
}
@functions {
string encodeEnvelopeKey(Envelope envelope)
{
var receiver = envelope.Receivers.First();
return Helpers.EncodeEnvelopeReceiverId(envelope.Uuid, receiver.Signature);
}
}
<div class="page container p-5">
<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>
<div class="container">
<section>
@foreach (IGrouping<EnvelopeStatus, Envelope> group in ((List<Envelope>)@Model).GroupBy(item => item.Status).OrderBy(item => (int)item.Key))
@if (ViewData["error"] != null)
{
<section>
<h2>@group.Key.ToString()</h2>
<ul>
@foreach (Envelope envelope in @group)
{
<li><a href="/EnvelopeKey/@encodeEnvelopeKey(envelope)">@envelope.Title</a></li>
}
</ul>
<hr />
<section class="alert alert-danger">
@ViewData["error"]
</section>
}
<section>
<form id="form-access-code" class="form" method="post">
<div class="input">
<label class="visually-hidden" for="access_code">Passwort</label>
<input type="password" class="form-control" name="password" placeholder="Passwort" required="required">
</div>
<div class="button">
<button type="submit" class="btn btn-primary">Öffnen</button>
</div>
</form>
</section>
</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;",
"LogPath": "E:\\EnvelopeGenerator\\Logs",
"LogDebug": true,
"LogJson": true
"LogJson": true,
"AdminPassword": "dd"
}
}

View File

@ -41,26 +41,46 @@
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;
border-radius: 100px;
padding: 15px;
margin-bottom: 2rem;
}
/* Locked Page */
#page-locked header .icon {
display: inline-block;
border-radius: 10px;
padding: 15px;
margin-bottom: 2rem;
.page header .icon.admin {
background-color: #331904;
color: #fecba1;
}
#form-access-code {
.page header .icon.locked {
background-color: #ffc107;
color: #000;
}
.page header .icon.signed {
background-color: #146c43;
color: #fff;
}
.page .form {
max-width: 30rem;
margin: 2rem auto;
@ -68,7 +88,35 @@
gap: 1rem;
}
#form-access-code > .input {
#form-access-code > .input,
#form-admin-password > .input {
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;
}