validation client and server
This commit is contained in:
parent
0ad1d214ba
commit
bdf7bdd37a
@ -9,8 +9,8 @@ Public Class Scheduler
|
||||
Inherits BaseClass
|
||||
|
||||
Private Scheduler As IScheduler
|
||||
Private ConnectionString As String
|
||||
Private LicenseKey As String
|
||||
Private ReadOnly ConnectionString As String
|
||||
Private ReadOnly LicenseKey As String
|
||||
|
||||
Private Const JobName = "CertificateDocumentJob"
|
||||
|
||||
|
||||
@ -58,7 +58,7 @@ namespace EnvelopeGenerator.Web.Controllers
|
||||
|
||||
actionService.OpenEnvelope(response.Envelope, response.Receiver);
|
||||
|
||||
return Ok();
|
||||
return Ok(new object());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
@ -26,6 +26,11 @@ namespace EnvelopeGenerator.Web.Controllers
|
||||
// Validate Envelope Key and load envelope
|
||||
envelopeService.EnsureValidEnvelopeKey(envelopeKey);
|
||||
EnvelopeResponse response = envelopeService.LoadEnvelope(envelopeKey);
|
||||
|
||||
if (envelopeService.ReceiverAlreadySigned(response.Envelope, response.Receiver.Id) == true)
|
||||
{
|
||||
return Problem(statusCode: 403);
|
||||
}
|
||||
|
||||
logger.Debug("Loaded envelope [{0}] for receiver [{1}]", response.Envelope.Id, response.Envelope.Id);
|
||||
return Json(response);
|
||||
@ -63,7 +68,7 @@ namespace EnvelopeGenerator.Web.Controllers
|
||||
|
||||
var signResult = actionService?.SignEnvelope(response.Envelope, response.Receiver);
|
||||
|
||||
return Ok();
|
||||
return Ok(new object());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
@ -10,6 +10,8 @@ namespace EnvelopeGenerator.Web.Services
|
||||
{
|
||||
private readonly ReceiverModel receiverModel;
|
||||
private readonly EnvelopeModel envelopeModel;
|
||||
private readonly HistoryModel historyModel;
|
||||
|
||||
private readonly DocumentStatusModel documentStatusModel;
|
||||
|
||||
public EnvelopeService(IConfiguration Config, LoggingService Logging, DatabaseService database) : base(Config, Logging)
|
||||
@ -23,6 +25,7 @@ namespace EnvelopeGenerator.Web.Services
|
||||
|
||||
receiverModel = database.Models.receiverModel;
|
||||
envelopeModel = database.Models.envelopeModel;
|
||||
historyModel = database.Models.historyModel;
|
||||
documentStatusModel = database.Models.documentStatusModel;
|
||||
}
|
||||
|
||||
@ -110,6 +113,11 @@ namespace EnvelopeGenerator.Web.Services
|
||||
return (List<Envelope>)envelopeModel.List(pReceiverId);
|
||||
}
|
||||
|
||||
public bool ReceiverAlreadySigned(Envelope envelope, int receiverId)
|
||||
{
|
||||
return historyModel.HasReceiverSigned(envelope.Id, receiverId);
|
||||
}
|
||||
|
||||
public async Task<string?> EnsureValidAnnotationData(HttpRequest request)
|
||||
{
|
||||
try
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
const annotations = []
|
||||
|
||||
document.elements.forEach((element) => {
|
||||
console.log('Creating annotation for element', element.id)
|
||||
console.debug('Creating annotation for element', element.id)
|
||||
|
||||
const [annotation, formField] = this.createAnnotationFromElement(element)
|
||||
annotations.push(annotation)
|
||||
@ -13,17 +13,20 @@
|
||||
return annotations
|
||||
}
|
||||
|
||||
async deleteAnnotations(instance) {
|
||||
let pageAnnotations = (
|
||||
await Promise.all(
|
||||
Array.from({ length: instance.totalPageCount }).map((_, pageIndex) =>
|
||||
instance.getAnnotations(pageIndex)
|
||||
)
|
||||
async getAnnotations(instance) {
|
||||
const array = await Promise.all(
|
||||
Array.from({ length: instance.totalPageCount }).map((_, pageIndex) =>
|
||||
instance.getAnnotations(pageIndex)
|
||||
)
|
||||
)
|
||||
.flatMap((annotations) =>
|
||||
annotations.reduce((acc, annotation) => acc.concat(annotation), [])
|
||||
)
|
||||
|
||||
return array.flatMap((annotations) =>
|
||||
annotations.reduce((acc, annotation) => acc.concat(annotation), [])
|
||||
)
|
||||
}
|
||||
|
||||
async deleteAnnotations(instance) {
|
||||
let pageAnnotations = this.getAnnotations(instance)
|
||||
.filter(
|
||||
(annotation) =>
|
||||
!!annotation.isSignature || annotation.description == 'FRAME'
|
||||
@ -33,16 +36,7 @@
|
||||
}
|
||||
|
||||
async validateAnnotations(instance) {
|
||||
let pageAnnotations = (
|
||||
await Promise.all(
|
||||
Array.from({ length: instance.totalPageCount }).map((_, pageIndex) =>
|
||||
instance.getAnnotations(pageIndex)
|
||||
)
|
||||
)
|
||||
)
|
||||
.flatMap((annotations) =>
|
||||
annotations.reduce((acc, annotation) => acc.concat(annotation), [])
|
||||
)
|
||||
let pageAnnotations = this.getAnnotations(instance)
|
||||
.map((annotation) => {
|
||||
console.log(annotation.toJS())
|
||||
return annotation
|
||||
|
||||
@ -23,17 +23,17 @@ class App {
|
||||
this.Instance = null
|
||||
this.currentDocument = null
|
||||
this.currentReceiver = null
|
||||
this.signatureCount = 0
|
||||
}
|
||||
|
||||
// This function will be called in the ShowEnvelope.razor page
|
||||
// This function will be called from the ShowEnvelope.razor page
|
||||
// and will trigger loading of the Editor Interface
|
||||
async init() {
|
||||
// Load the envelope from the database
|
||||
console.debug('Loading envelope from database..')
|
||||
const envelopeResponse = await this.Network.getEnvelope(this.envelopeKey)
|
||||
const envelopeError = !!envelopeResponse.error
|
||||
|
||||
if (envelopeError) {
|
||||
if (envelopeResponse.fatal) {
|
||||
return Swal.fire({
|
||||
title: 'Fehler',
|
||||
text: 'Umschlag konnte nicht geladen werden!',
|
||||
@ -41,6 +41,14 @@ class App {
|
||||
})
|
||||
}
|
||||
|
||||
if (envelopeResponse.error) {
|
||||
return Swal.fire({
|
||||
title: 'Warnung',
|
||||
text: 'Umschlag ist nicht mehr verfügbar.',
|
||||
icon: 'warning',
|
||||
})
|
||||
}
|
||||
|
||||
this.currentDocument = envelopeResponse.data.envelope.documents[0]
|
||||
this.currentReceiver = envelopeResponse.data.receiver
|
||||
|
||||
@ -50,9 +58,8 @@ class App {
|
||||
this.envelopeKey,
|
||||
this.currentDocument.id
|
||||
)
|
||||
const documentError = !!documentResponse.error
|
||||
|
||||
if (documentError) {
|
||||
if (documentResponse.fatal || documentResponse.error) {
|
||||
console.error(documentResponse.error)
|
||||
return Swal.fire({
|
||||
title: 'Fehler',
|
||||
@ -85,12 +92,21 @@ class App {
|
||||
console.debug('Loading annotations..')
|
||||
|
||||
try {
|
||||
this.signatureCount = this.currentDocument.elements.length
|
||||
const annotations = this.Annotation.createAnnotations(
|
||||
this.currentDocument
|
||||
)
|
||||
const createdAnnotations = await this.Instance.create(annotations)
|
||||
await this.Instance.create(annotations)
|
||||
|
||||
await this.Network.openDocument(this.envelopeKey)
|
||||
const openResponse = await this.Network.openDocument(this.envelopeKey)
|
||||
|
||||
if (openResponse.fatal || openResponse.error) {
|
||||
return Swal.fire({
|
||||
title: 'Fehler',
|
||||
text: 'Umschlag konnte nicht geöffnet werden!',
|
||||
icon: 'error',
|
||||
})
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
@ -169,8 +185,6 @@ class App {
|
||||
if (result == true) {
|
||||
// Redirect to success page after saving to database
|
||||
window.location.href = `/EnvelopeKey/${this.envelopeKey}/Success`
|
||||
} else {
|
||||
alert('Fehler beim Abschließen des Dokuments!')
|
||||
}
|
||||
|
||||
break
|
||||
@ -181,11 +195,28 @@ class App {
|
||||
}
|
||||
|
||||
async handleFinish(event) {
|
||||
|
||||
const validationResult = await this.validateAnnotations(this.signatureCount)
|
||||
if (validationResult === false) {
|
||||
Swal.fire({
|
||||
title: 'Warnung',
|
||||
text: 'Es wurden nicht alle Signaturfelder ausgefüllt!',
|
||||
icon: 'warning',
|
||||
})
|
||||
return false
|
||||
|
||||
}
|
||||
|
||||
// Save changes before doing anything
|
||||
try {
|
||||
await this.Instance.save()
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
Swal.fire({
|
||||
title: 'Fehler',
|
||||
text: 'Umschlag konnte nicht signiert werden!',
|
||||
icon: 'error',
|
||||
})
|
||||
return false
|
||||
}
|
||||
|
||||
@ -195,20 +226,64 @@ class App {
|
||||
const postEnvelopeResult = await this.Network.postEnvelope(
|
||||
this.envelopeKey,
|
||||
this.currentDocument.id,
|
||||
JSON.stringify(json)
|
||||
json
|
||||
)
|
||||
|
||||
console.log(postEnvelopeResult)
|
||||
|
||||
if (postEnvelopeResult === false) {
|
||||
if (postEnvelopeResult.fatal) {
|
||||
Swal.fire({
|
||||
title: 'Fehler',
|
||||
text: 'Umschlag konnte nicht signiert werden!',
|
||||
icon: 'error',
|
||||
})
|
||||
return false
|
||||
}
|
||||
|
||||
if (postEnvelopeResult.error) {
|
||||
Swal.fire({
|
||||
title: 'Warnung',
|
||||
text: 'Umschlag ist nicht mehr verfügbar.',
|
||||
icon: 'warning',
|
||||
})
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
|
||||
async validateAnnotations(totalSignatures) {
|
||||
const annotations = await this.Annotation.getAnnotations(this.Instance)
|
||||
const filtered = annotations
|
||||
.map(a => a.toJS())
|
||||
.filter(a => a.isSignature)
|
||||
|
||||
console.log(filtered.length, "Signatures signed!")
|
||||
|
||||
if (totalSignatures > filtered.length) {
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
|
||||
/*this.Instance.getFormFields().then(formFields => {
|
||||
formFields.forEach(formField => {
|
||||
console.log(formField.name, formField.toJS());
|
||||
});
|
||||
|
||||
// Filter form fields by type
|
||||
formFields.filter(formField => (
|
||||
formField instanceof PSPDFKit.FormFields.TextFormField
|
||||
));
|
||||
|
||||
// Get the total number of form fields
|
||||
const totalFormFields = formFields.size;
|
||||
|
||||
console.log(totalFormFields)
|
||||
})*/
|
||||
}
|
||||
|
||||
async handleReset(event) {
|
||||
|
||||
@ -1,107 +1,167 @@
|
||||
class Network {
|
||||
getEnvelope(envelopeKey) {
|
||||
return fetch(
|
||||
`/api/envelope/${envelopeKey}`,
|
||||
this.withCSRFToken({ credentials: 'include' })
|
||||
).then(this.wrapJsonResponse.bind(this))
|
||||
}
|
||||
|
||||
getDocument(envelopeKey, documentId) {
|
||||
return fetch(
|
||||
`/api/document/${envelopeKey}?index=${documentId}`,
|
||||
this.withCSRFToken({ credentials: 'include' })
|
||||
).then(this.wrapBinaryResponse.bind(this))
|
||||
}
|
||||
|
||||
postEnvelope(envelopeKey, documentId, jsonString) {
|
||||
const url = `/api/envelope/${envelopeKey}?index=${documentId}`
|
||||
const options = {
|
||||
credentials: 'include',
|
||||
method: 'POST',
|
||||
body: jsonString,
|
||||
/**
|
||||
* Load envelope json data
|
||||
* @param {any} envelopeKey
|
||||
*/
|
||||
async getEnvelope(envelopeKey) {
|
||||
console.log("getEnvelope")
|
||||
return this.getRequest(`/api/envelope/${envelopeKey}`)
|
||||
.then(this.wrapJsonResponse.bind(this))
|
||||
}
|
||||
|
||||
console.debug('PostEnvelope/Calling url: ' + url)
|
||||
return fetch(url, this.withCSRFToken(options))
|
||||
.then(this.handleResponse)
|
||||
.then((res) => {
|
||||
if (!res.ok) {
|
||||
return false
|
||||
/**
|
||||
* Save signature data to server
|
||||
* @param {any} envelopeKey
|
||||
* @param {any} documentId
|
||||
* @param {any} json
|
||||
*/
|
||||
async postEnvelope(envelopeKey, documentId, json) {
|
||||
console.log("postEnvelope")
|
||||
return this.postRequest(`/api/envelope/${envelopeKey}?index=${documentId}`, json)
|
||||
.then(this.wrapJsonResponse.bind(this))
|
||||
}
|
||||
|
||||
/**
|
||||
* Load document binary data
|
||||
* @param {any} envelopeKey
|
||||
* @param {any} documentId
|
||||
*/
|
||||
async getDocument(envelopeKey, documentId) {
|
||||
console.log("getDocument")
|
||||
return this.getRequest(`/api/document/${envelopeKey}?index=${documentId}`)
|
||||
.then(this.wrapBinaryResponse.bind(this))
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell the server that document has been seen
|
||||
* @param {any} envelopeKey
|
||||
*/
|
||||
async openDocument(envelopeKey) {
|
||||
console.log("openDocument")
|
||||
return this.postRequest(`/api/document/${envelopeKey}`, {})
|
||||
.then(this.wrapJsonResponse.bind(this))
|
||||
}
|
||||
|
||||
/**
|
||||
* Add CSRF Token to request headers
|
||||
* @param {any} options
|
||||
* @returns
|
||||
*/
|
||||
withCSRFToken(options) {
|
||||
const token = getCSRFToken
|
||||
let headers = options.headers
|
||||
|
||||
options.headers = {
|
||||
...headers,
|
||||
...token
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
openDocument(envelopeKey) {
|
||||
const url = `/api/document/${envelopeKey}`
|
||||
|
||||
const options = {
|
||||
credentials: 'include',
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json; charset=utf-8',
|
||||
},
|
||||
body: JSON.stringify({}),
|
||||
return options
|
||||
}
|
||||
|
||||
console.debug('OpenDocument/Calling url: ' + url)
|
||||
return fetch(url, this.withCSRFToken(options))
|
||||
.then(this.handleResponse)
|
||||
.then((res) => {
|
||||
if (!res.ok) {
|
||||
return false
|
||||
/**
|
||||
* Fetches CSRF Token from page
|
||||
* @returns
|
||||
*/
|
||||
getCSRFToken() {
|
||||
const token = document.getElementsByName('__RequestVerificationToken')[0].value
|
||||
return { 'X-XSRF-TOKEN': token }
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a GET HTTP request to `url`
|
||||
* @param {any} url
|
||||
*/
|
||||
getRequest(url) {
|
||||
const token = this.getCSRFToken()
|
||||
const options = {
|
||||
credentials: 'include',
|
||||
method: 'GET',
|
||||
headers: {
|
||||
...token
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
withCSRFToken(options) {
|
||||
const token = document.getElementsByName('__RequestVerificationToken')[0]
|
||||
.value
|
||||
let headers = options.headers
|
||||
options.headers = { ...headers, 'X-XSRF-TOKEN': token }
|
||||
|
||||
return options
|
||||
}
|
||||
|
||||
async wrapJsonResponse(response) {
|
||||
return await this.wrapResponse(response, async (res) => await res.json())
|
||||
}
|
||||
|
||||
async wrapBinaryResponse(response) {
|
||||
return await this.wrapResponse(
|
||||
response,
|
||||
async (res) => await res.arrayBuffer()
|
||||
)
|
||||
}
|
||||
|
||||
async wrapResponse(response, responseHandler) {
|
||||
let wrappedResponse
|
||||
|
||||
if (response.ok) {
|
||||
const data = await responseHandler(response)
|
||||
wrappedResponse = new WrappedResponse(data, null)
|
||||
} else {
|
||||
const error = await response.json()
|
||||
wrappedResponse = new WrappedResponse(null, error)
|
||||
return fetch(url, options)
|
||||
}
|
||||
|
||||
return wrappedResponse
|
||||
}
|
||||
/**
|
||||
* Creates a POST HTTP request for url
|
||||
* @param {any} url
|
||||
* @param {any} json
|
||||
* @returns
|
||||
*/
|
||||
postRequest(url, json) {
|
||||
const token = this.getCSRFToken()
|
||||
const options = {
|
||||
credentials: 'include',
|
||||
method: 'POST',
|
||||
headers: {
|
||||
...token,
|
||||
'Content-Type': 'application/json; charset=utf-8'
|
||||
},
|
||||
body: JSON.stringify(json)
|
||||
}
|
||||
|
||||
handleResponse(res) {
|
||||
if (!res.ok) {
|
||||
console.log(`Request failed with status ${res.status}`)
|
||||
return res
|
||||
} else {
|
||||
return res
|
||||
return fetch(url, options)
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads and wraps a json response
|
||||
* @param {any} response
|
||||
* @returns
|
||||
*/
|
||||
async wrapJsonResponse(response) {
|
||||
return await this.wrapResponse(
|
||||
response,
|
||||
async (res) => await res.json())
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads and wraps a binary response
|
||||
* @param {any} response
|
||||
* @returns
|
||||
*/
|
||||
async wrapBinaryResponse(response) {
|
||||
return await this.wrapResponse(
|
||||
response,
|
||||
async (res) => await res.arrayBuffer())
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps a fetch response depending on status code
|
||||
* @param {any} response
|
||||
* @param {any} responseHandler
|
||||
* @returns
|
||||
*/
|
||||
async wrapResponse(response, responseHandler) {
|
||||
let wrappedResponse
|
||||
|
||||
console.log("Handling response from", response.url)
|
||||
console.log("Status", response.status)
|
||||
console.log(response)
|
||||
|
||||
if (response.status === 200) {
|
||||
const data = await responseHandler(response)
|
||||
wrappedResponse = new WrappedResponse(data, null)
|
||||
} else if (response.status === 403) {
|
||||
const error = await response.json()
|
||||
wrappedResponse = new WrappedResponse(null, error)
|
||||
} else {
|
||||
wrappedResponse = new WrappedResponse(null, null)
|
||||
}
|
||||
|
||||
console.log("Wrapped response", wrappedResponse)
|
||||
|
||||
return wrappedResponse
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class WrappedResponse {
|
||||
constructor(data, error) {
|
||||
this.data = data
|
||||
this.error = error
|
||||
}
|
||||
constructor(data, error) {
|
||||
this.data = data
|
||||
this.error = error
|
||||
this.fatal = (data === null && error === null)
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user