mirror of
https://github.com/Kareadita/Kavita.git
synced 2025-07-09 03:04:19 -04:00
Fix Genre/Tag with spaces getting normalized (#3731)
This commit is contained in:
parent
55966f0b2a
commit
33221fee2b
@ -1,5 +1,6 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using API.Constants;
|
||||||
using API.Data;
|
using API.Data;
|
||||||
using API.Data.ManualMigrations;
|
using API.Data.ManualMigrations;
|
||||||
using API.DTOs;
|
using API.DTOs;
|
||||||
@ -16,12 +17,10 @@ namespace API.Controllers;
|
|||||||
public class AdminController : BaseApiController
|
public class AdminController : BaseApiController
|
||||||
{
|
{
|
||||||
private readonly UserManager<AppUser> _userManager;
|
private readonly UserManager<AppUser> _userManager;
|
||||||
private readonly IUnitOfWork _unitOfWork;
|
|
||||||
|
|
||||||
public AdminController(UserManager<AppUser> userManager, IUnitOfWork unitOfWork)
|
public AdminController(UserManager<AppUser> userManager)
|
||||||
{
|
{
|
||||||
_userManager = userManager;
|
_userManager = userManager;
|
||||||
_unitOfWork = unitOfWork;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -32,18 +31,7 @@ public class AdminController : BaseApiController
|
|||||||
[HttpGet("exists")]
|
[HttpGet("exists")]
|
||||||
public async Task<ActionResult<bool>> AdminExists()
|
public async Task<ActionResult<bool>> AdminExists()
|
||||||
{
|
{
|
||||||
var users = await _userManager.GetUsersInRoleAsync("Admin");
|
var users = await _userManager.GetUsersInRoleAsync(PolicyConstants.AdminRole);
|
||||||
return users.Count > 0;
|
return users.Count > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Set the progress information for a particular user
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
[Authorize("RequireAdminRole")]
|
|
||||||
[HttpPost("update-chapter-progress")]
|
|
||||||
public async Task<ActionResult<bool>> UpdateChapterProgress(UpdateUserProgressDto dto)
|
|
||||||
{
|
|
||||||
return Ok(await Task.FromResult(false));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace API.DTOs.Progress;
|
|
||||||
#nullable enable
|
|
||||||
|
|
||||||
public class UpdateUserProgressDto
|
|
||||||
{
|
|
||||||
public int PageNum { get; set; }
|
|
||||||
public DateTime LastModifiedUtc { get; set; }
|
|
||||||
public DateTime CreatedUtc { get; set; }
|
|
||||||
}
|
|
20
API/EmailTemplates/KavitaPlusDebug.html
Normal file
20
API/EmailTemplates/KavitaPlusDebug.html
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<tr>
|
||||||
|
<td valign="top" style="text-align: center; padding: 20px 0 10px 20px;">
|
||||||
|
<h1 style="margin: 0; font-family: 'Montserrat', sans-serif; font-size: 30px; line-height: 36px; font-weight: bold;">A User needs manual registration</h1> </td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td valign="top" align="center" style="text-align: center; padding: 15px 0px 20px 0px;">
|
||||||
|
<center>
|
||||||
|
<table role="presentation" align="center" cellspacing="0" cellpadding="0" border="0" class="center-on-narrow">
|
||||||
|
<tr>
|
||||||
|
<td class="button-td">
|
||||||
|
InstallId: {{InstallId}}
|
||||||
|
</td>
|
||||||
|
<td class="button-td">
|
||||||
|
Build: {{Build}}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</center>
|
||||||
|
</td>
|
||||||
|
</tr>
|
@ -18,9 +18,9 @@ public static class StringExtensions
|
|||||||
|
|
||||||
// Remove all newline and control characters
|
// Remove all newline and control characters
|
||||||
var sanitized = input
|
var sanitized = input
|
||||||
.Replace(Environment.NewLine, "")
|
.Replace(Environment.NewLine, string.Empty)
|
||||||
.Replace("\n", "")
|
.Replace("\n", string.Empty)
|
||||||
.Replace("\r", "");
|
.Replace("\r", string.Empty);
|
||||||
|
|
||||||
// Optionally remove other potentially unwanted characters
|
// Optionally remove other potentially unwanted characters
|
||||||
sanitized = Regex.Replace(sanitized, @"[^\u0020-\u007E]", string.Empty); // Removes non-printable ASCII
|
sanitized = Regex.Replace(sanitized, @"[^\u0020-\u007E]", string.Empty); // Removes non-printable ASCII
|
||||||
|
@ -16,14 +16,14 @@ public class GenreBuilder : IEntityBuilder<Genre>
|
|||||||
{
|
{
|
||||||
Title = name.Trim().SentenceCase(),
|
Title = name.Trim().SentenceCase(),
|
||||||
NormalizedTitle = name.ToNormalized(),
|
NormalizedTitle = name.ToNormalized(),
|
||||||
Chapters = new List<Chapter>(),
|
Chapters = [],
|
||||||
SeriesMetadatas = new List<SeriesMetadata>()
|
SeriesMetadatas = []
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public GenreBuilder WithSeriesMetadata(SeriesMetadata seriesMetadata)
|
public GenreBuilder WithSeriesMetadata(SeriesMetadata seriesMetadata)
|
||||||
{
|
{
|
||||||
_genre.SeriesMetadatas ??= new List<SeriesMetadata>();
|
_genre.SeriesMetadatas ??= [];
|
||||||
_genre.SeriesMetadatas.Add(seriesMetadata);
|
_genre.SeriesMetadatas.Add(seriesMetadata);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -16,8 +16,8 @@ public class TagBuilder : IEntityBuilder<Tag>
|
|||||||
{
|
{
|
||||||
Title = name.Trim().SentenceCase(),
|
Title = name.Trim().SentenceCase(),
|
||||||
NormalizedTitle = name.ToNormalized(),
|
NormalizedTitle = name.ToNormalized(),
|
||||||
Chapters = new List<Chapter>(),
|
Chapters = [],
|
||||||
SeriesMetadatas = new List<SeriesMetadata>()
|
SeriesMetadatas = []
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,7 +19,12 @@ public static class GenreHelper
|
|||||||
public static async Task UpdateChapterGenres(Chapter chapter, IEnumerable<string> genreNames, IUnitOfWork unitOfWork)
|
public static async Task UpdateChapterGenres(Chapter chapter, IEnumerable<string> genreNames, IUnitOfWork unitOfWork)
|
||||||
{
|
{
|
||||||
// Normalize genre names once and store them in a hash set for quick lookups
|
// Normalize genre names once and store them in a hash set for quick lookups
|
||||||
var normalizedGenresToAdd = new HashSet<string>(genreNames.Select(g => g.ToNormalized()));
|
var normalizedToOriginal = genreNames
|
||||||
|
.Select(g => new { Original = g, Normalized = g.ToNormalized() })
|
||||||
|
.GroupBy(x => x.Normalized)
|
||||||
|
.ToDictionary(g => g.Key, g => g.First().Original);
|
||||||
|
|
||||||
|
var normalizedGenresToAdd = new HashSet<string>(normalizedToOriginal.Keys);
|
||||||
|
|
||||||
// Remove genres that are no longer in the new list
|
// Remove genres that are no longer in the new list
|
||||||
var genresToRemove = chapter.Genres
|
var genresToRemove = chapter.Genres
|
||||||
@ -42,7 +47,7 @@ public static class GenreHelper
|
|||||||
// Find missing genres that are not in the database
|
// Find missing genres that are not in the database
|
||||||
var missingGenres = normalizedGenresToAdd
|
var missingGenres = normalizedGenresToAdd
|
||||||
.Where(nt => !existingGenreTitles.ContainsKey(nt))
|
.Where(nt => !existingGenreTitles.ContainsKey(nt))
|
||||||
.Select(title => new GenreBuilder(title).Build())
|
.Select(nt => new GenreBuilder(normalizedToOriginal[nt]).Build())
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
// Add missing genres to the database
|
// Add missing genres to the database
|
||||||
|
@ -20,7 +20,13 @@ public static class TagHelper
|
|||||||
public static async Task UpdateChapterTags(Chapter chapter, IEnumerable<string> tagNames, IUnitOfWork unitOfWork)
|
public static async Task UpdateChapterTags(Chapter chapter, IEnumerable<string> tagNames, IUnitOfWork unitOfWork)
|
||||||
{
|
{
|
||||||
// Normalize tag names once and store them in a hash set for quick lookups
|
// Normalize tag names once and store them in a hash set for quick lookups
|
||||||
var normalizedTagsToAdd = new HashSet<string>(tagNames.Select(t => t.ToNormalized()));
|
// Create a dictionary: normalized => original
|
||||||
|
var normalizedToOriginal = tagNames
|
||||||
|
.Select(t => new { Original = t, Normalized = t.ToNormalized() })
|
||||||
|
.GroupBy(x => x.Normalized) // in case of duplicates
|
||||||
|
.ToDictionary(g => g.Key, g => g.First().Original);
|
||||||
|
|
||||||
|
var normalizedTagsToAdd = new HashSet<string>(normalizedToOriginal.Keys);
|
||||||
var existingTagsSet = new HashSet<string>(chapter.Tags.Select(t => t.NormalizedTitle));
|
var existingTagsSet = new HashSet<string>(chapter.Tags.Select(t => t.NormalizedTitle));
|
||||||
|
|
||||||
var isModified = false;
|
var isModified = false;
|
||||||
@ -30,7 +36,7 @@ public static class TagHelper
|
|||||||
.Where(t => !normalizedTagsToAdd.Contains(t.NormalizedTitle))
|
.Where(t => !normalizedTagsToAdd.Contains(t.NormalizedTitle))
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
if (tagsToRemove.Any())
|
if (tagsToRemove.Count != 0)
|
||||||
{
|
{
|
||||||
foreach (var tagToRemove in tagsToRemove)
|
foreach (var tagToRemove in tagsToRemove)
|
||||||
{
|
{
|
||||||
@ -47,7 +53,7 @@ public static class TagHelper
|
|||||||
// Find missing tags that are not already in the database
|
// Find missing tags that are not already in the database
|
||||||
var missingTags = normalizedTagsToAdd
|
var missingTags = normalizedTagsToAdd
|
||||||
.Where(nt => !existingTagTitles.ContainsKey(nt))
|
.Where(nt => !existingTagTitles.ContainsKey(nt))
|
||||||
.Select(title => new TagBuilder(title).Build())
|
.Select(nt => new TagBuilder(normalizedToOriginal[nt]).Build())
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
// Add missing tags to the database if any
|
// Add missing tags to the database if any
|
||||||
@ -67,13 +73,11 @@ public static class TagHelper
|
|||||||
// Add the new or existing tags to the chapter
|
// Add the new or existing tags to the chapter
|
||||||
foreach (var normalizedTitle in normalizedTagsToAdd)
|
foreach (var normalizedTitle in normalizedTagsToAdd)
|
||||||
{
|
{
|
||||||
var tag = existingTagTitles[normalizedTitle];
|
if (existingTagsSet.Contains(normalizedTitle)) continue;
|
||||||
|
|
||||||
if (!existingTagsSet.Contains(normalizedTitle))
|
var tag = existingTagTitles[normalizedTitle];
|
||||||
{
|
chapter.Tags.Add(tag);
|
||||||
chapter.Tags.Add(tag);
|
isModified = true;
|
||||||
isModified = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Commit changes if modifications were made to the chapter's tags
|
// Commit changes if modifications were made to the chapter's tags
|
||||||
|
@ -4,6 +4,7 @@ using System.ComponentModel.DataAnnotations;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Web;
|
using System.Web;
|
||||||
using API.Data;
|
using API.Data;
|
||||||
@ -11,6 +12,7 @@ using API.DTOs.Email;
|
|||||||
using API.Entities;
|
using API.Entities;
|
||||||
using API.Services.Plus;
|
using API.Services.Plus;
|
||||||
using Kavita.Common;
|
using Kavita.Common;
|
||||||
|
using Kavita.Common.EnvironmentInfo;
|
||||||
using Kavita.Common.Extensions;
|
using Kavita.Common.Extensions;
|
||||||
using MailKit.Security;
|
using MailKit.Security;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
@ -52,6 +54,7 @@ public interface IEmailService
|
|||||||
|
|
||||||
Task<bool> SendTokenExpiredEmail(int userId, ScrobbleProvider provider);
|
Task<bool> SendTokenExpiredEmail(int userId, ScrobbleProvider provider);
|
||||||
Task<bool> SendTokenExpiringSoonEmail(int userId, ScrobbleProvider provider);
|
Task<bool> SendTokenExpiringSoonEmail(int userId, ScrobbleProvider provider);
|
||||||
|
Task<bool> SendKavitaPlusDebug();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class EmailService : IEmailService
|
public class EmailService : IEmailService
|
||||||
@ -72,6 +75,7 @@ public class EmailService : IEmailService
|
|||||||
public const string TokenExpiringSoonTemplate = "TokenExpiringSoon";
|
public const string TokenExpiringSoonTemplate = "TokenExpiringSoon";
|
||||||
public const string EmailConfirmTemplate = "EmailConfirm";
|
public const string EmailConfirmTemplate = "EmailConfirm";
|
||||||
public const string EmailPasswordResetTemplate = "EmailPasswordReset";
|
public const string EmailPasswordResetTemplate = "EmailPasswordReset";
|
||||||
|
public const string KavitaPlusDebugTemplate = "KavitaPlusDebug";
|
||||||
|
|
||||||
public EmailService(ILogger<EmailService> logger, IUnitOfWork unitOfWork, IDirectoryService directoryService,
|
public EmailService(ILogger<EmailService> logger, IUnitOfWork unitOfWork, IDirectoryService directoryService,
|
||||||
IHostEnvironment environment, ILocalizationService localizationService)
|
IHostEnvironment environment, ILocalizationService localizationService)
|
||||||
@ -259,6 +263,40 @@ public class EmailService : IEmailService
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sends information about Kavita install for Kavita+ registration
|
||||||
|
/// </summary>
|
||||||
|
/// <example>Users in China can have issues subscribing, this flow will allow me to register their instance on their behalf</example>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<bool> SendKavitaPlusDebug()
|
||||||
|
{
|
||||||
|
var settings = await _unitOfWork.SettingsRepository.GetSettingsDtoAsync();
|
||||||
|
if (!settings.IsEmailSetup()) return false;
|
||||||
|
|
||||||
|
var placeholders = new List<KeyValuePair<string, string>>
|
||||||
|
{
|
||||||
|
new ("{{InstallId}}", HashUtil.ServerToken()),
|
||||||
|
new ("{{Build}}", BuildInfo.Version.ToString()),
|
||||||
|
};
|
||||||
|
|
||||||
|
var emailOptions = new EmailOptionsDto()
|
||||||
|
{
|
||||||
|
Subject = UpdatePlaceHolders("Kavita+: A User needs manual registration", placeholders),
|
||||||
|
Template = KavitaPlusDebugTemplate,
|
||||||
|
Body = UpdatePlaceHolders(await GetEmailBody(KavitaPlusDebugTemplate), placeholders),
|
||||||
|
Preheader = UpdatePlaceHolders("Kavita+: A User needs manual registration", placeholders),
|
||||||
|
ToEmails =
|
||||||
|
[
|
||||||
|
// My kavita email
|
||||||
|
Encoding.UTF8.GetString(Convert.FromBase64String("a2F2aXRhcmVhZGVyQGdtYWlsLmNvbQ=="))
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
await SendEmail(emailOptions);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sends an invite email to a user to setup their account
|
/// Sends an invite email to a user to setup their account
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -304,10 +342,10 @@ public class EmailService : IEmailService
|
|||||||
Template = EmailPasswordResetTemplate,
|
Template = EmailPasswordResetTemplate,
|
||||||
Body = UpdatePlaceHolders(await GetEmailBody(EmailPasswordResetTemplate), placeholders),
|
Body = UpdatePlaceHolders(await GetEmailBody(EmailPasswordResetTemplate), placeholders),
|
||||||
Preheader = "Email confirmation is required for continued access. Click the button to confirm your email.",
|
Preheader = "Email confirmation is required for continued access. Click the button to confirm your email.",
|
||||||
ToEmails = new List<string>()
|
ToEmails =
|
||||||
{
|
[
|
||||||
dto.EmailAddress
|
dto.EmailAddress
|
||||||
}
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
await SendEmail(emailOptions);
|
await SendEmail(emailOptions);
|
||||||
|
15
UI/Web/package-lock.json
generated
15
UI/Web/package-lock.json
generated
@ -541,6 +541,7 @@
|
|||||||
"version": "19.2.5",
|
"version": "19.2.5",
|
||||||
"resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-19.2.5.tgz",
|
"resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-19.2.5.tgz",
|
||||||
"integrity": "sha512-b2cG41r6lilApXLlvja1Ra2D00dM3BxmQhoElKC1tOnpD6S3/krlH1DOnBB2I55RBn9iv4zdmPz1l8zPUSh7DQ==",
|
"integrity": "sha512-b2cG41r6lilApXLlvja1Ra2D00dM3BxmQhoElKC1tOnpD6S3/krlH1DOnBB2I55RBn9iv4zdmPz1l8zPUSh7DQ==",
|
||||||
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/core": "7.26.9",
|
"@babel/core": "7.26.9",
|
||||||
"@jridgewell/sourcemap-codec": "^1.4.14",
|
"@jridgewell/sourcemap-codec": "^1.4.14",
|
||||||
@ -568,6 +569,7 @@
|
|||||||
"version": "4.0.1",
|
"version": "4.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.1.tgz",
|
||||||
"integrity": "sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==",
|
"integrity": "sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==",
|
||||||
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"readdirp": "^4.0.1"
|
"readdirp": "^4.0.1"
|
||||||
},
|
},
|
||||||
@ -582,6 +584,7 @@
|
|||||||
"version": "4.0.2",
|
"version": "4.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.2.tgz",
|
||||||
"integrity": "sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==",
|
"integrity": "sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==",
|
||||||
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 14.16.0"
|
"node": ">= 14.16.0"
|
||||||
},
|
},
|
||||||
@ -4903,7 +4906,8 @@
|
|||||||
"node_modules/convert-source-map": {
|
"node_modules/convert-source-map": {
|
||||||
"version": "1.9.0",
|
"version": "1.9.0",
|
||||||
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
|
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
|
||||||
"integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="
|
"integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
|
||||||
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/cosmiconfig": {
|
"node_modules/cosmiconfig": {
|
||||||
"version": "8.3.6",
|
"version": "8.3.6",
|
||||||
@ -5350,6 +5354,7 @@
|
|||||||
"version": "0.1.13",
|
"version": "0.1.13",
|
||||||
"resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz",
|
"resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz",
|
||||||
"integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==",
|
"integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==",
|
||||||
|
"dev": true,
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"iconv-lite": "^0.6.2"
|
"iconv-lite": "^0.6.2"
|
||||||
@ -5359,6 +5364,7 @@
|
|||||||
"version": "0.6.3",
|
"version": "0.6.3",
|
||||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
|
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
|
||||||
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
|
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
|
||||||
|
"dev": true,
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
||||||
@ -8175,7 +8181,8 @@
|
|||||||
"node_modules/reflect-metadata": {
|
"node_modules/reflect-metadata": {
|
||||||
"version": "0.2.2",
|
"version": "0.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz",
|
||||||
"integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q=="
|
"integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==",
|
||||||
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/replace-in-file": {
|
"node_modules/replace-in-file": {
|
||||||
"version": "7.1.0",
|
"version": "7.1.0",
|
||||||
@ -8396,7 +8403,7 @@
|
|||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
||||||
"devOptional": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/sass": {
|
"node_modules/sass": {
|
||||||
"version": "1.85.0",
|
"version": "1.85.0",
|
||||||
@ -8461,6 +8468,7 @@
|
|||||||
"version": "7.7.1",
|
"version": "7.7.1",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
|
||||||
"integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==",
|
"integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==",
|
||||||
|
"dev": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"semver": "bin/semver.js"
|
"semver": "bin/semver.js"
|
||||||
},
|
},
|
||||||
@ -9085,6 +9093,7 @@
|
|||||||
"version": "5.5.4",
|
"version": "5.5.4",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz",
|
||||||
"integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==",
|
"integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==",
|
||||||
|
"dev": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
"tsserver": "bin/tsserver"
|
"tsserver": "bin/tsserver"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user