Compare commits
11 Commits
f20243d02c
...
c479ea4179
| Author | SHA1 | Date | |
|---|---|---|---|
| c479ea4179 | |||
| 369d101d7b | |||
| 86eb687296 | |||
| aa8f46a303 | |||
| 2c825d2fe3 | |||
| 1e1517f88a | |||
| 124523ad88 | |||
| 9c48b230b4 | |||
| 95fe1aefcf | |||
| 1b7a42fd7e | |||
| 73da768ed3 |
@@ -1,5 +1,7 @@
|
||||
using EnvelopeGenerator.Application.Dto.EnvelopeReceiver;
|
||||
using EnvelopeGenerator.Domain.Constants;
|
||||
using MediatR;
|
||||
using Newtonsoft.Json;
|
||||
using System.Dynamic;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Notifications.DocSigned;
|
||||
@@ -8,12 +10,24 @@ namespace EnvelopeGenerator.Application.Notifications.DocSigned;
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="Original"></param>
|
||||
public record DocSignedNotification(EnvelopeReceiverDto Original) : EnvelopeReceiverDto(Original), INotification
|
||||
public record DocSignedNotification(EnvelopeReceiverDto Original) : EnvelopeReceiverDto(Original), INotification, ISendMailNotification
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public required ExpandoObject Annotations { get; init; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public EmailTemplateType TemplateType => EmailTemplateType.DocumentSigned;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string EmailAddress => Receiver?.EmailAddress
|
||||
?? throw new InvalidOperationException($"Receiver is null." +
|
||||
$"DocSignedNotification:\n{JsonConvert.SerializeObject(this, Format.Json.ForDiagnostics)}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
using DigitalData.Core.Abstraction.Application.Repository;
|
||||
using DigitalData.EmailProfilerDispatcher.Abstraction.Entities;
|
||||
using EnvelopeGenerator.Application.Configurations;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Notifications.DocSigned.Handlers;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class SendSignedMailHandler : SendMailHandler<DocSignedNotification>
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="tempRepo"></param>
|
||||
/// <param name="emailOutRepo"></param>
|
||||
/// <param name="mailParamsOptions"></param>
|
||||
/// <param name="dispatcherParamsOptions"></param>
|
||||
public SendSignedMailHandler(IRepository<EmailTemplate> tempRepo, IRepository<EmailOut> emailOutRepo, IOptions<MailParams> mailParamsOptions, IOptions<DispatcherParams> dispatcherParamsOptions) : base(tempRepo, emailOutRepo, mailParamsOptions, dispatcherParamsOptions)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="notification"></param>
|
||||
/// <param name="emailOut"></param>
|
||||
protected override void ConfigureEmailOut(DocSignedNotification notification, EmailOut emailOut)
|
||||
{
|
||||
emailOut.ReferenceString = notification.EmailAddress;
|
||||
emailOut.ReferenceId = notification.ReceiverId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
/// <param name="notification"></param>
|
||||
/// <returns></returns>
|
||||
protected override Dictionary<string, string> CreatePlaceHolders(DocSignedNotification notification)
|
||||
{
|
||||
var placeHolders = new Dictionary<string, string>()
|
||||
{
|
||||
{ "[NAME_RECEIVER]", notification.Name ?? string.Empty },
|
||||
{ "[DOCUMENT_TITLE]", notification.Envelope?.Title ?? string.Empty },
|
||||
};
|
||||
|
||||
return placeHolders;
|
||||
}
|
||||
}
|
||||
@@ -45,10 +45,17 @@ public abstract class SendMailHandler<TNotification> : INotificationHandler<TNot
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected virtual Dictionary<string, string> BodyPlaceHolders { get; } = new();
|
||||
protected abstract Dictionary<string, string> CreatePlaceHolders(TNotification notification);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
///{ "[MESSAGE]", notification.Message },<br/>
|
||||
///{ "[DOCUMENT_ACCESS_CODE]", notification.ReceiverAccessCode },<br/>
|
||||
///{ "[REASON]", pReason }<br/>
|
||||
///{ "[NAME_SENDER]", notification.Envelope.User?.FullName},<br/>
|
||||
///{ "[NAME_PORTAL]", DispatcherParams. },<br/>
|
||||
///{ "[SIGNATURE_TYPE]", "signieren" },<br/>
|
||||
///{ "[LINK_TO_DOCUMENT]", notification.SignatureLink },<br/>
|
||||
///{ "[LINK_TO_DOCUMENT_TEXT]", $"{notification.SignatureLink.Truncate(40)}.." },
|
||||
/// </summary>
|
||||
protected readonly MailParams MailParams;
|
||||
|
||||
@@ -60,14 +67,9 @@ public abstract class SendMailHandler<TNotification> : INotificationHandler<TNot
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected virtual Dictionary<string, string> SubjectPlaceHolders { get; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// ReferenceString = Envelope.Uuid
|
||||
/// </summary>
|
||||
/// <param name="notification"></param>
|
||||
/// <param name="emailOut"></param>
|
||||
/// <returns></returns>
|
||||
protected abstract void ConfigEmailOut(EmailOut emailOut);
|
||||
protected abstract void ConfigureEmailOut(TNotification notification, EmailOut emailOut);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
@@ -91,22 +93,24 @@ public abstract class SendMailHandler<TNotification> : INotificationHandler<TNot
|
||||
/// <param name="cancel"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
public async Task Handle(TNotification notification, CancellationToken cancel)
|
||||
public virtual async Task Handle(TNotification notification, CancellationToken cancel)
|
||||
{
|
||||
var placeHolders = CreatePlaceHolders(notification);
|
||||
|
||||
var temp = await TempRepo
|
||||
.ReadOnly()
|
||||
.SingleOrDefaultAsync(x => x.Name == notification.TemplateType.ToString(), cancel)
|
||||
?? throw new InvalidOperationException($"Receiver information is missing in the notification." +
|
||||
$"{typeof(TNotification)}:\n {JsonConvert.SerializeObject(notification, Format.Json.ForDiagnostics)}");
|
||||
|
||||
temp.Subject = ReplacePlaceHolders(temp.Subject, SubjectPlaceHolders, MailParams.Placeholders);
|
||||
temp.Subject = ReplacePlaceHolders(temp.Subject, placeHolders, MailParams.Placeholders);
|
||||
|
||||
temp.Body = ReplacePlaceHolders(temp.Body, BodyPlaceHolders, MailParams.Placeholders);
|
||||
temp.Body = ReplacePlaceHolders(temp.Body, placeHolders, MailParams.Placeholders);
|
||||
|
||||
var emailOut = new EmailOut
|
||||
{
|
||||
EmailAddress = notification.EmailAddress,
|
||||
EmailBody = temp.Body,
|
||||
EmailBody = TextToHtml(temp.Body),
|
||||
EmailSubj = temp.Subject,
|
||||
AddedWhen = DateTime.UtcNow,
|
||||
AddedWho = DispatcherParams.AddedWho,
|
||||
@@ -116,7 +120,7 @@ public abstract class SendMailHandler<TNotification> : INotificationHandler<TNot
|
||||
WfId = (int)EnvelopeStatus.MessageConfirmationSent,
|
||||
|
||||
};
|
||||
ConfigEmailOut(emailOut);
|
||||
ConfigureEmailOut(notification, emailOut);
|
||||
await EmailOutRepo.CreateAsync(emailOut, cancel);
|
||||
}
|
||||
|
||||
@@ -145,4 +149,4 @@ public abstract class SendMailHandler<TNotification> : INotificationHandler<TNot
|
||||
|
||||
return encoded;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,7 @@
|
||||
<PackageReference Include="NLog.Web.AspNetCore" Version="5.3.0" />
|
||||
<PackageReference Include="Scalar.AspNetCore" Version="2.2.1" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="8.1.1" />
|
||||
<PackageReference Include="DigitalData.EmailProfilerDispatcher.Abstraction" Version="3.1.1" />
|
||||
<PackageReference Include="DigitalData.EmailProfilerDispatcher.Abstraction" Version="3.2.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)' == 'net7.0'">
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
using EnvelopeGenerator.Web.Services;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace EnvelopeGenerator.Web.Controllers;
|
||||
|
||||
public class BaseController : Controller
|
||||
{
|
||||
protected readonly DatabaseService database;
|
||||
|
||||
protected readonly ILogger _logger;
|
||||
|
||||
public BaseController(DatabaseService database, ILogger logger)
|
||||
{
|
||||
this.database = database;
|
||||
_logger = logger;
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,8 @@
|
||||
using EnvelopeGenerator.CommonServices;
|
||||
using EnvelopeGenerator.Web.Services;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using EnvelopeGenerator.Application.Extensions;
|
||||
using EnvelopeGenerator.Application.Interfaces.Services;
|
||||
using EnvelopeGenerator.Domain.Constants;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
using DigitalData.Core.Abstraction.Application.DTO;
|
||||
using EnvelopeGenerator.Web.Extensions;
|
||||
using MediatR;
|
||||
@@ -19,11 +16,8 @@ namespace EnvelopeGenerator.Web.Controllers;
|
||||
[Authorize(Roles = ReceiverRole.FullyAuth)]
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class EnvelopeController : BaseController
|
||||
public class EnvelopeController : ControllerBase
|
||||
{
|
||||
private readonly EnvelopeOldService envelopeService;
|
||||
private readonly ActionService? actionService;
|
||||
|
||||
[Obsolete("Use MediatR")]
|
||||
private readonly IEnvelopeHistoryService _histService;
|
||||
[Obsolete("Use MediatR")]
|
||||
@@ -31,24 +25,24 @@ public class EnvelopeController : BaseController
|
||||
|
||||
private readonly IMediator _mediator;
|
||||
|
||||
private readonly ILogger<EnvelopeController> _logger;
|
||||
|
||||
[Obsolete("Use MediatR")]
|
||||
public EnvelopeController(DatabaseService database,
|
||||
EnvelopeOldService envelope,
|
||||
public EnvelopeController(
|
||||
ILogger<EnvelopeController> logger,
|
||||
IEnvelopeHistoryService envelopeHistoryService,
|
||||
IEnvelopeReceiverService envelopeReceiverService, IMediator mediator) : base(database, logger)
|
||||
IEnvelopeReceiverService envelopeReceiverService,
|
||||
IMediator mediator)
|
||||
{
|
||||
envelopeService = envelope;
|
||||
actionService = database?.Services?.actionService;
|
||||
_histService = envelopeHistoryService;
|
||||
_envRcvService = envelopeReceiverService;
|
||||
_mediator = mediator;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
[Authorize(Roles = ReceiverRole.FullyAuth)]
|
||||
[HttpPost("{envelopeKey}")]
|
||||
[Obsolete("Use MediatR")]
|
||||
public async Task<IActionResult> CreateOrUpdate([FromRoute] string envelopeKey, int index, [FromBody] ExpandoObject annotations, CancellationToken cancel = default)
|
||||
public async Task<IActionResult> CreateOrUpdate([FromRoute] string envelopeKey, [FromBody] ExpandoObject annotations, CancellationToken cancel = default)
|
||||
{
|
||||
// get claims
|
||||
var signature = User.GetAuthReceiverSignature();
|
||||
@@ -70,11 +64,7 @@ public class EnvelopeController : BaseController
|
||||
|
||||
await _mediator.Publish(notification, cancel);
|
||||
|
||||
EnvelopeReceiver response = await envelopeService.LoadEnvelope(envelopeKey);
|
||||
|
||||
var signResult = actionService?.SignEnvelope(response.Envelope, ReceiverVM.From(response));
|
||||
|
||||
return Ok(new object());
|
||||
return Ok();
|
||||
}
|
||||
|
||||
[Authorize(Roles = ReceiverRole.FullyAuth)]
|
||||
@@ -106,7 +96,7 @@ public class EnvelopeController : BaseController
|
||||
{
|
||||
_logger.LogEnvelopeError(uuid: uuid, signature: signature, message: "Unexpected error happend in api/envelope/reject");
|
||||
_logger.LogNotice(ntc);
|
||||
return this.ViewInnerServiceError();
|
||||
return StatusCode(500, mssg);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
using EnvelopeGenerator.Web.Services;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace EnvelopeGenerator.Web.Controllers.Test;
|
||||
|
||||
[Route("api/test/[controller]")]
|
||||
public class TestViewController : BaseController
|
||||
{
|
||||
private readonly EnvelopeOldService envelopeOldService;
|
||||
private readonly IConfiguration _config;
|
||||
|
||||
public TestViewController(DatabaseService databaseService, EnvelopeOldService envelopeOldService, ILogger<TestViewController> logger, IConfiguration configuration) : base(databaseService, logger)
|
||||
{
|
||||
this.envelopeOldService = envelopeOldService;
|
||||
_config = configuration;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public IActionResult Index()
|
||||
{
|
||||
return View("AnnotationIndex");
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public IActionResult DebugEnvelopes([FromForm] string? password)
|
||||
{
|
||||
try
|
||||
{
|
||||
var passwordFromConfig = _config["AdminPassword"];
|
||||
|
||||
if (passwordFromConfig == null)
|
||||
{
|
||||
ViewData["error"] = "No admin password configured!";
|
||||
return View("AnnotationIndex");
|
||||
}
|
||||
|
||||
if (password != passwordFromConfig)
|
||||
{
|
||||
ViewData["error"] = "Wrong Password!";
|
||||
return View("AnnotationIndex");
|
||||
}
|
||||
|
||||
List<Envelope> envelopes = envelopeOldService.LoadEnvelopes();
|
||||
|
||||
return View("DebugEnvelopes", envelopes);
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Unexpected error");
|
||||
ViewData["error"] = "Unknown error!";
|
||||
return View("AnnotationIndex");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,8 +41,6 @@
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="bundleconfig.json" />
|
||||
<None Include="wwwroot\lib\bootstrap-icons\bootstrap-icons.svg" />
|
||||
<None Include="wwwroot\lib\bootstrap-icons\font\bootstrap-icons.scss" />
|
||||
<None Include="wwwroot\lib\bootstrap-icons\font\fonts\bootstrap-icons.woff2" />
|
||||
<None Include="wwwroot\lib\bootstrap-icons\icons\0-circle-fill.svg" />
|
||||
<None Include="wwwroot\lib\bootstrap-icons\icons\0-circle.svg" />
|
||||
@@ -2094,8 +2092,6 @@
|
||||
<None Include="wwwroot\lib\bootstrap-icons\icons\youtube.svg" />
|
||||
<None Include="wwwroot\lib\bootstrap-icons\icons\zoom-in.svg" />
|
||||
<None Include="wwwroot\lib\bootstrap-icons\icons\zoom-out.svg" />
|
||||
<None Include="wwwroot\lib\bootstrap-icons\LICENSE" />
|
||||
<None Include="wwwroot\lib\bootstrap-icons\README.md" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -2104,9 +2100,6 @@
|
||||
<PackageReference Include="DigitalData.Core.API" Version="2.2.1" />
|
||||
<PackageReference Include="DigitalData.Core.Exceptions" Version="1.1.0" />
|
||||
<PackageReference Include="DigitalData.EmailProfilerDispatcher" Version="3.1.1" />
|
||||
<PackageReference Include="DigitalData.Modules.Base" Version="1.3.8" />
|
||||
<PackageReference Include="DigitalData.Modules.Config" Version="1.3.0" />
|
||||
<PackageReference Include="DigitalData.Modules.Database" Version="2.3.5.4" />
|
||||
<PackageReference Include="HtmlSanitizer" Version="8.0.865" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.4" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.20" />
|
||||
@@ -2135,7 +2128,6 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\EnvelopeGenerator.Application\EnvelopeGenerator.Application.csproj" />
|
||||
<ProjectReference Include="..\EnvelopeGenerator.CommonServices\EnvelopeGenerator.CommonServices.vbproj" />
|
||||
<ProjectReference Include="..\EnvelopeGenerator.Infrastructure\EnvelopeGenerator.Infrastructure.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using EnvelopeGenerator.Application.Services;
|
||||
using EnvelopeGenerator.Web.Services;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NLog;
|
||||
using Quartz;
|
||||
@@ -50,12 +49,6 @@ try
|
||||
});
|
||||
});
|
||||
|
||||
// Add base services
|
||||
builder.Services.AddScoped<DatabaseService>();
|
||||
|
||||
// Add higher order services
|
||||
builder.Services.AddScoped<EnvelopeOldService>();
|
||||
|
||||
builder.Services.AddHttpContextAccessor();
|
||||
|
||||
builder.ConfigureBySection<TFARegParams>();
|
||||
|
||||
@@ -1,93 +0,0 @@
|
||||
using DigitalData.Modules.Database;
|
||||
using DigitalData.Modules.Logging;
|
||||
using EnvelopeGenerator.Application;
|
||||
using EnvelopeGenerator.CommonServices;
|
||||
|
||||
namespace EnvelopeGenerator.Web.Services
|
||||
{
|
||||
public class DatabaseService
|
||||
{
|
||||
public MSSQLServer MSSQL { get; set; }
|
||||
|
||||
ILogger<DatabaseService> _logger;
|
||||
|
||||
public State? State { get; set; }
|
||||
|
||||
public class ServiceContainer
|
||||
{
|
||||
public ActionService actionService;
|
||||
public EmailService emailService;
|
||||
|
||||
public ServiceContainer(State state, MSSQLServer MSSQL)
|
||||
{
|
||||
actionService = new(state, MSSQL);
|
||||
emailService = new(state);
|
||||
}
|
||||
}
|
||||
|
||||
public class ModelContainer
|
||||
{
|
||||
public EnvelopeModel envelopeModel;
|
||||
public DocumentModel documentModel;
|
||||
public ReceiverModel receiverModel;
|
||||
public ElementModel elementModel;
|
||||
public HistoryModel historyModel;
|
||||
public DocumentStatusModel documentStatusModel;
|
||||
public EmailModel emailModel;
|
||||
public ConfigModel configModel;
|
||||
|
||||
public ModelContainer(State state)
|
||||
{
|
||||
envelopeModel = new(state);
|
||||
documentModel = new(state);
|
||||
receiverModel = new(state);
|
||||
elementModel = new(state);
|
||||
historyModel = new(state);
|
||||
documentStatusModel = new(state);
|
||||
emailModel = new(state);
|
||||
configModel = new(state);
|
||||
}
|
||||
}
|
||||
public readonly ModelContainer? Models;
|
||||
public readonly ServiceContainer? Services;
|
||||
|
||||
public DatabaseService(ILogger<DatabaseService> logger, IConfiguration config)
|
||||
{
|
||||
LogConfig logConfig = new LogConfig(LogConfig.PathType.CustomPath, config["NLog:variables:logDirectory"], null, "Digital Data", "ECM.EnvelopeGenerator.Web");
|
||||
_logger = logger;
|
||||
|
||||
_logger.LogInformation("Establishing MSSQL Database connection..");
|
||||
MSSQL = new MSSQLServer(logConfig, config.GetConnectionString("Default"));
|
||||
|
||||
if (MSSQL.DBInitialized == true)
|
||||
{
|
||||
_logger.LogInformation("MSSQL Connection established: [{0}]", MSSQL.MaskedConnectionString);
|
||||
|
||||
/// <summary>
|
||||
/// There is a circular dependency between state and models
|
||||
/// All models need a state object, including the config Model
|
||||
/// The state object needs to be filled with the DbConfig property,
|
||||
/// which is obtained by the config Model.
|
||||
/// So first, the config model is initialized with an incomplete state object,
|
||||
/// then all the other models with the DbConfig property filled.
|
||||
/// </summary>
|
||||
State = new State
|
||||
{
|
||||
Database = MSSQL,
|
||||
LogConfig = logConfig,
|
||||
UserId = 0,
|
||||
DbConfig = null
|
||||
};
|
||||
var configModel = new ConfigModel(State);
|
||||
State.DbConfig = configModel.LoadConfiguration();
|
||||
|
||||
Models = new(State);
|
||||
Services = new(State, MSSQL);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogInformation("Connection could not be established!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,167 +0,0 @@
|
||||
using EnvelopeGenerator.Application.Interfaces.Services;
|
||||
using EnvelopeGenerator.CommonServices;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
using System.Text;
|
||||
|
||||
namespace EnvelopeGenerator.Web.Services;
|
||||
|
||||
public class EnvelopeOldService
|
||||
{
|
||||
private readonly ReceiverModel receiverModel;
|
||||
private readonly EnvelopeModel envelopeModel;
|
||||
private readonly HistoryModel historyModel;
|
||||
|
||||
private readonly DocumentStatusModel documentStatusModel;
|
||||
|
||||
[Obsolete("Use MediatR")]
|
||||
private readonly IConfigService _configService;
|
||||
private readonly ILogger<EnvelopeOldService> _logger;
|
||||
|
||||
[Obsolete("Use MediatR")]
|
||||
public EnvelopeOldService(DatabaseService database, IConfigService configService, ILogger<EnvelopeOldService> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
|
||||
if (database.Models is null)
|
||||
throw new ArgumentNullException("Models not loaded.");
|
||||
|
||||
receiverModel = database.Models.receiverModel;
|
||||
envelopeModel = database.Models.envelopeModel;
|
||||
historyModel = database.Models.historyModel;
|
||||
documentStatusModel = database.Models.documentStatusModel;
|
||||
|
||||
_configService = configService;
|
||||
}
|
||||
|
||||
[Obsolete("Use MediatR")]
|
||||
public async Task<EnvelopeReceiver> LoadEnvelope(string pEnvelopeKey)
|
||||
{
|
||||
_logger.LogInformation("Loading Envelope by Key [{0}]", pEnvelopeKey);
|
||||
|
||||
Tuple<string, string> result = Helpers.DecodeEnvelopeReceiverId(pEnvelopeKey);
|
||||
var envelopeUuid = result.Item1;
|
||||
var receiverSignature = result.Item2;
|
||||
var receiverId = receiverModel.GetReceiverIdBySignature(receiverSignature);
|
||||
|
||||
_logger.LogInformation("Resolved receiver signature to receiverId [{0}]", receiverId);
|
||||
|
||||
_logger.LogInformation("Loading envelope..");
|
||||
Envelope? envelope = envelopeModel.GetByUuid(envelopeUuid);
|
||||
|
||||
if (envelope == null)
|
||||
{
|
||||
_logger.LogWarning("Envelope not found");
|
||||
throw new NullReferenceException("Envelope not found");
|
||||
}
|
||||
|
||||
_logger.LogInformation("Envelope loaded");
|
||||
|
||||
if (envelope.Receivers == null)
|
||||
{
|
||||
_logger.LogWarning("Receivers for envelope not loaded");
|
||||
throw new NullReferenceException("Receivers for envelope not loaded");
|
||||
}
|
||||
|
||||
_logger.LogInformation("Envelope receivers found: [{0}]", envelope.Receivers.Count);
|
||||
|
||||
Receiver? receiver = envelope.Receivers.Where(r => r.ReceiverId == receiverId).SingleOrDefault()?.Receiver;
|
||||
|
||||
if (receiver == null)
|
||||
{
|
||||
_logger.LogWarning("Receiver [{0}] not found", receiverId);
|
||||
throw new NullReferenceException("Receiver not found");
|
||||
}
|
||||
|
||||
_logger.LogInformation("Loading documents for receiver [{0}]", receiver.EmailAddress);
|
||||
|
||||
// filter elements by receiver
|
||||
envelope.Documents = envelope.Documents.Select((document) =>
|
||||
{
|
||||
document.Elements = document.Elements.Where((e) => e.ReceiverId == receiverId).ToList();
|
||||
return document;
|
||||
}).ToList();
|
||||
|
||||
//if documenet_path_dmz is existing in config, replace the path with it
|
||||
var config = await _configService.ReadDefaultAsync();
|
||||
|
||||
return new()
|
||||
{
|
||||
Receiver = receiver,
|
||||
Envelope = envelope
|
||||
};
|
||||
}
|
||||
|
||||
public List<Envelope> LoadEnvelopes()
|
||||
{
|
||||
var receivers = receiverModel.ListReceivers();
|
||||
List<Envelope> envelopes = new();
|
||||
|
||||
foreach (var receiver in receivers)
|
||||
{
|
||||
var envs = (List<Envelope>)envelopeModel.List(receiver.Id);
|
||||
envelopes.AddRange(envs);
|
||||
}
|
||||
|
||||
return envelopes;
|
||||
}
|
||||
|
||||
public bool ReceiverAlreadySigned(Envelope envelope, int receiverId)
|
||||
{
|
||||
return historyModel.HasReceiverSigned(envelope.Id, receiverId);
|
||||
}
|
||||
|
||||
public async Task<string?> EnsureValidAnnotationData(HttpRequest request)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("Parsing annotation data from request..");
|
||||
|
||||
using MemoryStream ms = new();
|
||||
await request.BodyReader.CopyToAsync(ms);
|
||||
var bytes = ms.ToArray();
|
||||
|
||||
_logger.LogInformation("Annotation data parsed, size: [{0}]", bytes.Length);
|
||||
|
||||
return Encoding.UTF8.GetString(bytes);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, "Inner Service Error");
|
||||
throw new ArgumentNullException("AnnotationData");
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete("Use MediatR")]
|
||||
public async Task<EnvelopeDocument> GetDocument(int documentId, string envelopeKey)
|
||||
{
|
||||
EnvelopeReceiver response = await LoadEnvelope(envelopeKey);
|
||||
|
||||
_logger.LogInformation("Loading document for Id [{0}]", documentId);
|
||||
|
||||
var document = response.Envelope.Documents.
|
||||
Where(d => d.Id == documentId).
|
||||
FirstOrDefault();
|
||||
|
||||
if (document == null)
|
||||
throw new ArgumentException("DocumentId");
|
||||
|
||||
_logger.LogInformation("Document [{0}] loaded!", documentId);
|
||||
|
||||
return document;
|
||||
}
|
||||
|
||||
public bool InsertDocumentStatus(DocumentStatus documentStatus)
|
||||
{
|
||||
_logger.LogInformation("Saving annotation data..");
|
||||
return documentStatusModel.InsertOrUpdate(documentStatus);
|
||||
}
|
||||
|
||||
public async Task<byte[]> GetDocumentContents(EnvelopeDocument document)
|
||||
{
|
||||
_logger.LogInformation("Loading file [{0}]", document.Filepath);
|
||||
var bytes = await File.ReadAllBytesAsync(document.Filepath);
|
||||
_logger.LogInformation("File loaded, size: [{0}]", bytes.Length);
|
||||
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
@using EnvelopeGenerator.CommonServices;
|
||||
@using EnvelopeGenerator.Domain.Entities;
|
||||
@using EnvelopeGenerator.Domain.Entities;
|
||||
@using EnvelopeGenerator.Domain.Constants;
|
||||
@using EnvelopeGenerator.Application.Extensions;
|
||||
@{
|
||||
ViewData["Title"] = "Debug";
|
||||
}
|
||||
@@ -9,7 +9,7 @@
|
||||
string encodeEnvelopeKey(Envelope envelope)
|
||||
{
|
||||
var receiver = envelope.Receivers!.First();
|
||||
return Helpers.EncodeEnvelopeReceiverId(envelope.Uuid, receiver.Receiver!.Signature);
|
||||
return (envelope.Uuid, receiver.Receiver!.Signature).ToEnvelopeKey();
|
||||
}
|
||||
|
||||
IEnumerable<IGrouping<EnvelopeStatus, Envelope>> groupEnvelopes(List<Envelope> envelopes)
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
# 📄 PSPDFKit-Integration – Vanilla JavaScript
|
||||
|
||||
Dieses Projekt zeigt, wie die PDF-Anzeige- und Signaturbibliothek [PSPDFKit](https://www.nutrient.io/sdk/web/getting-started/other-frameworks/javascript/) mithilfe von **Vanilla JavaScript** integriert werden kann.
|
||||
|
||||
## 🚀 Verwendungszweck
|
||||
|
||||
PSPDFKit wurde in der Webanwendung verwendet, um PDF-Dokumente:
|
||||
- anzuzeigen,
|
||||
- zu signieren,
|
||||
- mit Anmerkungen zu versehen,
|
||||
- Formularfelder auszufüllen.
|
||||
|
||||
Benutzer können Dokumente **direkt über den Browser signieren und versenden**.
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Wo und wie wurde PSPDFKit verwendet?
|
||||
|
||||
### 1. PSPDFKit laden
|
||||
|
||||
PSPDFKit wurde mit der Funktion `loadPSPDFKit` in `UI.js` gestartet:
|
||||
|
||||
```js
|
||||
PSPDFKit.load({
|
||||
container: ‚#app‘,
|
||||
document: arrayBuffer,
|
||||
licenseKey: ‚YOUR_LICENSE_KEY‘,
|
||||
...
|
||||
})
|
||||
```
|
||||
|
||||
### 2. Anmerkungen und Formularfelder
|
||||
|
||||
In `annotation.js` werden die folgenden Felder dynamisch zu PDF-Dokumenten hinzugefügt:
|
||||
|
||||
- **Signaturfeld** (`SignatureFormField`)
|
||||
- **Position** (`TextFormField`)
|
||||
- **Stadt** (`TextFormField`)
|
||||
- **Datum** (`TextFormField`, wird automatisch mit dem heutigen Datum ausgefüllt)
|
||||
- **Bezeichnungen** (`Ort`, `Position`, `Date`) – dies sind nur lesbare Textfelder.
|
||||
- **Rahmen für Signaturbild** – wird dynamisch erstellt und platziert, wenn der Benutzer unterschreibt.
|
||||
|
||||
Die Felder werden entsprechend ihrer Position auf dem PDF berechnet und für jedes Feld wird eine eindeutige ID erstellt.
|
||||
|
||||
---
|
||||
|
||||
### 3. Anpassungen der Symbolleiste
|
||||
|
||||
In `UI.js` ist die Standard-Symbolleiste (`toolbarItems`) von PSPDFKit konfiguriert:
|
||||
|
||||
- Es werden nur zulässige Elemente (`sidebar`, `zoom`, `pager`, `search` usw.) angezeigt.
|
||||
- Je nach Benutzerberechtigung (z. B. schreibgeschützt oder beschreibbar) werden die folgenden speziellen Schaltflächen dynamisch hinzugefügt:
|
||||
|
||||
**Beschreibbarer Modus:**
|
||||
- `Teilen` (SHARE)
|
||||
- `Logout` (LOGOUT)
|
||||
- `Zurücksetzen` (RESET)
|
||||
- `Ablehnen` (REJECT)
|
||||
- `Finalisieren` (FINISH)
|
||||
|
||||
**Nur-Lesemodus:**
|
||||
- Die Schaltfläche `Teilen` kopiert nur den Link in die Zwischenablage (COPY_URL)
|
||||
|
||||
Für mobile Geräte werden zusätzlich vereinfachte Schaltflächen angezeigt.
|
||||
|
||||
---
|
||||
|
||||
### 📁 Wichtige Dateien
|
||||
|
||||
| Datei | Beschreibung |
|
||||
|-------------------|-----------------------------------------------|
|
||||
| `app.js` | Hauptanwendungsklasse, Dokumentladen und -steuerung |
|
||||
| `ui.js` | PSPDFKit-UI-Einrichtung und Symbolleistenverwaltung |
|
||||
| `annotation.js` | Erstellen und Löschen von Anmerkungsfeldern |
|
||||
@@ -13,9 +13,6 @@ class App {
|
||||
constructor(envelopeKey, envelopeReceiver, documentBytes, licenseKey, locale, container) {
|
||||
this.container = container ?? `#${this.constructor.name.toLowerCase()}`;
|
||||
this.envelopeKey = envelopeKey
|
||||
|
||||
this.Network = new Network()
|
||||
|
||||
this.Instance = null
|
||||
this.currentDocument = null
|
||||
this.currentReceiver = null
|
||||
@@ -275,35 +272,30 @@ class App {
|
||||
|
||||
// Export annotation data and save to database
|
||||
try {
|
||||
const json = await iJSON
|
||||
const postEnvelopeResult = await this.Network.postEnvelope(
|
||||
this.currentDocument.id,
|
||||
json
|
||||
)
|
||||
const res = await postEnvelope(this.envelopeKey, await iJSON);
|
||||
|
||||
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
|
||||
if (!res.ok) {
|
||||
if (res.status === 403) {
|
||||
Swal.fire({
|
||||
title: 'Warnung',
|
||||
text: 'Umschlag ist nicht mehr verfügbar.',
|
||||
icon: 'warning',
|
||||
})
|
||||
return false
|
||||
}
|
||||
else {
|
||||
throw new Error()
|
||||
}
|
||||
} else
|
||||
return true
|
||||
} catch (e) {
|
||||
Swal.fire({
|
||||
title: 'Fehler',
|
||||
text: 'Umschlag konnte nicht signiert werden!',
|
||||
icon: 'error',
|
||||
})
|
||||
return false
|
||||
}
|
||||
//---
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
@@ -1,150 +1,30 @@
|
||||
class Network {
|
||||
|
||||
/**
|
||||
* Load envelope json data
|
||||
* @param {any} envelopeKey
|
||||
*/
|
||||
async getEnvelope(envelopeKey) {
|
||||
return this.getRequest(`/api/envelope/${envelopeKey}`)
|
||||
.then(this.wrapJsonResponse.bind(this))
|
||||
}
|
||||
|
||||
/**
|
||||
* Save signature data to server
|
||||
* @param {any} envelopeKey
|
||||
* @param {any} documentId
|
||||
* @param {any} json
|
||||
*/
|
||||
async postEnvelope(documentId, json) {
|
||||
return this.postRequest(`/api/envelope?index=${documentId}`, json)
|
||||
.then(this.wrapJsonResponse.bind(this))
|
||||
}
|
||||
|
||||
/**
|
||||
* Load document binary data
|
||||
* @param {any} envelopeKey
|
||||
* @param {any} documentId
|
||||
*/
|
||||
async getDocument(envelopeKey, documentId) {
|
||||
return this.getRequest(`/api/document/${envelopeKey}?index=${documentId}`)
|
||||
.then(this.wrapBinaryResponse.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 options
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 fetch(url, options)
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
return wrappedResponse
|
||||
}
|
||||
/**
|
||||
* Fetches CSRF Token from page
|
||||
* @returns
|
||||
*/
|
||||
function getCSRFToken() {
|
||||
const token = document.getElementsByName('__RequestVerificationToken')[0].value
|
||||
return { 'X-XSRF-TOKEN': token }
|
||||
}
|
||||
|
||||
class WrappedResponse {
|
||||
constructor(data, error) {
|
||||
this.data = data
|
||||
this.error = error
|
||||
this.fatal = (data === null && error === null)
|
||||
/**
|
||||
* Save signature data to server
|
||||
* @param {any} envelopeKey
|
||||
* @param {any} annotations
|
||||
*/
|
||||
function postEnvelope(envelopeKey, annotations) {
|
||||
const token = getCSRFToken()
|
||||
const options = {
|
||||
credentials: 'include',
|
||||
method: 'POST',
|
||||
headers: {
|
||||
...token,
|
||||
'Content-Type': 'application/json; charset=utf-8'
|
||||
},
|
||||
body: JSON.stringify(annotations)
|
||||
}
|
||||
|
||||
return fetch(`/api/envelope/${envelopeKey}`, options)
|
||||
}
|
||||
|
||||
async function setLangAsync(language, flagCode) {
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2019-2024 The Bootstrap Authors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
@@ -1,100 +0,0 @@
|
||||
<p align="center">
|
||||
<a href="https://getbootstrap.com/">
|
||||
<img src="https://getbootstrap.com/docs/5.2/assets/brand/bootstrap-logo-shadow.png" alt="Bootstrap logo" width="200" height="165">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<h3 align="center">Bootstrap Icons</h3>
|
||||
|
||||
<p align="center">
|
||||
Official open source SVG icon library for Bootstrap with over 2,000 icons.
|
||||
<br>
|
||||
<a href="https://icons.getbootstrap.com/"><strong>Explore Bootstrap Icons »</strong></a>
|
||||
<br>
|
||||
<br>
|
||||
<a href="https://getbootstrap.com/">Bootstrap</a>
|
||||
·
|
||||
<a href="https://themes.getbootstrap.com/">Themes</a>
|
||||
·
|
||||
<a href="https://blog.getbootstrap.com/">Blog</a>
|
||||
<br>
|
||||
</p>
|
||||
|
||||
[](https://icons.getbootstrap.com/)
|
||||
|
||||
## Install
|
||||
|
||||
Bootstrap Icons are packaged up and published to npm. We only include the processed SVGs in this package—it's up to you and your team to implement. [Read our docs](https://icons.getbootstrap.com/) for usage instructions.
|
||||
|
||||
```shell
|
||||
npm i bootstrap-icons
|
||||
```
|
||||
|
||||
For those [using Packagist](https://packagist.org/packages/twbs/bootstrap-icons), you can also install Bootstrap Icons via Composer:
|
||||
|
||||
```shell
|
||||
composer require twbs/bootstrap-icons
|
||||
```
|
||||
|
||||
[Also available in Figma](https://www.figma.com/community/file/1042482994486402696/Bootstrap-Icons).
|
||||
|
||||
## Usage
|
||||
|
||||
Depending on your setup, you can include Bootstrap Icons in a handful of ways.
|
||||
|
||||
- Copy-paste SVGs as embedded HTML
|
||||
- Reference via `<img>` element
|
||||
- Use the SVG sprite
|
||||
- Include via CSS
|
||||
|
||||
[See the docs for more information](https://icons.getbootstrap.com/#usage).
|
||||
|
||||
## Development
|
||||
|
||||
[](https://github.com/twbs/icons/actions/workflows/test.yml?query=workflow%3ATests+branch%3Amain)
|
||||
[](https://www.npmjs.com/package/bootstrap-icons)
|
||||
|
||||
Clone the repo, install dependencies, and start the Hugo server locally.
|
||||
|
||||
```shell
|
||||
git clone https://github.com/twbs/icons/
|
||||
cd icons
|
||||
npm i
|
||||
npm start
|
||||
```
|
||||
|
||||
Then open `http://localhost:4000` in your browser.
|
||||
|
||||
### npm scripts
|
||||
|
||||
Here are some key scripts you'll use during development. Be sure to look to our `package.json` or `npm run` output for a complete list of scripts.
|
||||
|
||||
| Script | Description |
|
||||
|--------------|-------------------------------------------------------------------------------|
|
||||
| `start` | Alias for running `docs-serve` |
|
||||
| `docs-serve` | Starts a local Hugo server |
|
||||
| `pages` | Generates permalink pages for each icon with template Markdown |
|
||||
| `icons` | Processes and optimizes SVGs in `icons` directory, generates fonts and sprite |
|
||||
|
||||
## Adding SVGs
|
||||
|
||||
Icons are typically only added by @mdo, but exceptions can be made. New glyphs are designed in Figma first on a 16x16px grid, then exported as flattened SVGs with `fill` (no stroke). Once a new SVG icon has been added to the `icons` directory, we use an npm script to:
|
||||
|
||||
1. Optimize our SVGs with SVGO.
|
||||
2. Modify the SVGs source code, removing all attributes before setting new attributes and values in our preferred order.
|
||||
|
||||
Use `npm run icons` to run the script, run `npm run pages` to build permalink pages, complete those pages, and, finally, commit the results in a new branch for updating.
|
||||
|
||||
**Warning**: Please exclude any auto-generated files, like `font/**` and `bootstrap-icons.svg` from your branch because they cause conflicts, and we generally update the dist files before a release.
|
||||
|
||||
## Publishing
|
||||
|
||||
Documentation is published automatically when a new Git tag is published. See our [GitHub Actions](https://github.com/twbs/icons/tree/main/.github/workflows) and [`package.json`](https://github.com/twbs/icons/blob/main/package.json) for more information.
|
||||
|
||||
## License
|
||||
|
||||
[MIT](LICENSE)
|
||||
|
||||
## Author
|
||||
|
||||
[@mdo](https://github.com/mdo)
|
||||
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 1.0 MiB |
File diff suppressed because it is too large
Load Diff
@@ -1,91 +0,0 @@
|
||||
{
|
||||
"name": "bootstrap-icons",
|
||||
"version": "1.11.3",
|
||||
"description": "Official open source SVG icon library for Bootstrap",
|
||||
"author": "mdo",
|
||||
"license": "MIT",
|
||||
"homepage": "https://icons.getbootstrap.com/",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/twbs/icons.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/twbs/icons/issues"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/twbs"
|
||||
},
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/bootstrap"
|
||||
}
|
||||
],
|
||||
"keywords": [
|
||||
"bootstrap",
|
||||
"icons",
|
||||
"svg",
|
||||
"font",
|
||||
"sprite",
|
||||
"woff",
|
||||
"woff2"
|
||||
],
|
||||
"style": "font/bootstrap-icons.css",
|
||||
"sass": "font/bootstrap-icons.scss",
|
||||
"files": [
|
||||
"icons/*.svg",
|
||||
"bootstrap-icons.svg",
|
||||
"font",
|
||||
"!.DS_Store"
|
||||
],
|
||||
"hugo-bin": {
|
||||
"buildTags": "extended"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "npm run docs-serve",
|
||||
"docs-serve": "hugo server --port 4000 --disableFastRender",
|
||||
"docs-build": "hugo --cleanDestinationDir --printUnusedTemplates",
|
||||
"docs-test": "npm-run-all docs-build docs-test:vnu",
|
||||
"docs-test:vnu": "node build/vnu-jar.mjs",
|
||||
"pages": "node build/build-pages.mjs",
|
||||
"icons": "npm-run-all icons-main --aggregate-output --parallel icons-sprite icons-font",
|
||||
"icons-main": "node build/build-svgs.mjs",
|
||||
"icons-zip": "cross-env-shell \"rm -rf bootstrap-icons-$npm_package_version bootstrap-icons-$npm_package_version.zip && cp -r icons/ bootstrap-icons-$npm_package_version && cp bootstrap-icons.svg bootstrap-icons-$npm_package_version && cp -r font/ bootstrap-icons-$npm_package_version && zip -qr9 bootstrap-icons-$npm_package_version.zip bootstrap-icons-$npm_package_version && rm -rf bootstrap-icons-$npm_package_version\"",
|
||||
"icons-sprite": "svg-sprite --config svg-sprite.json --log=info \"icons/*.svg\"",
|
||||
"icons-font": "npm-run-all icons-font-*",
|
||||
"icons-font-main": "fantasticon",
|
||||
"icons-font-min": "cleancss -O1 --format breakWith=lf --with-rebase --output font/bootstrap-icons.min.css font/bootstrap-icons.css",
|
||||
"release": "npm-run-all icons docs-build icons-zip",
|
||||
"release-version": "node build/bump-version.mjs",
|
||||
"netlify": "cross-env-shell HUGO_BASEURL=$DEPLOY_PRIME_URL npm-run-all icons docs-build",
|
||||
"test:fusv": "fusv docs/assets/scss/",
|
||||
"test:eslint": "eslint --cache --cache-location .cache/.eslintcache --report-unused-disable-directives --ext .js,.mjs .",
|
||||
"test:stylelint": "stylelint docs/assets/scss/ --cache --cache-location .cache/.stylelintcache",
|
||||
"test:lockfile-lint": "lockfile-lint --allowed-hosts npm --allowed-schemes https: --empty-hostname false --type npm --path package-lock.json",
|
||||
"test:check-icons": "node build/check-icons.mjs",
|
||||
"test": "npm-run-all --parallel --aggregate-output --continue-on-error test:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@twbs/fantasticon": "^2.7.2",
|
||||
"autoprefixer": "^10.4.16",
|
||||
"bootstrap": "^5.3.2",
|
||||
"clean-css-cli": "^5.6.3",
|
||||
"clipboard": "^2.0.11",
|
||||
"cross-env": "^7.0.3",
|
||||
"eslint": "^8.56.0",
|
||||
"find-unused-sass-variables": "^5.0.0",
|
||||
"fuse.js": "^7.0.0",
|
||||
"hugo-bin": "^0.118.0",
|
||||
"lockfile-lint": "^4.12.1",
|
||||
"npm-run-all2": "^6.1.1",
|
||||
"picocolors": "^1.0.0",
|
||||
"postcss": "^8.4.32",
|
||||
"postcss-cli": "^11.0.0",
|
||||
"stylelint": "^16.1.0",
|
||||
"stylelint-config-twbs-bootstrap": "^13.0.0",
|
||||
"svg-sprite": "^3.0.0-beta3",
|
||||
"svgo": "^3.2.0",
|
||||
"vnu-jar": "23.4.11"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user