1
0
mirror of https://github.com/hrfee/jfa-go.git synced 2024-09-19 19:00:11 +00:00

Compare commits

..

No commits in common. "f81224a2a67cbbccbe8443b134726697d9bc92dc" and "cc3871adf6b0d79dda4b91c07160835c361ea68f" have entirely different histories.

18 changed files with 330 additions and 1024 deletions

View File

@ -490,10 +490,10 @@ a:hover:not(.lang-link):not(.\~urge), a:active:not(.lang-link):not(.\~urge) {
text-align: center;
}
/* .search {
.search {
max-width: 15rem;
min-width: 10rem;
} */
}
td.img-circle {
width: 32px;
@ -548,11 +548,6 @@ div.card:contains(section.banner.footer) {
padding-bottom: 0px !important
}
.mx-0i {
margin-left: 0px !important;
margin-right: 0px !important
}
.text-center-i {
text-align: center !important;
}

View File

@ -579,71 +579,58 @@
</div>
</div>
<div id="tab-accounts" class="unfocused">
<div class="card @low dark:~d_neutral accounts mb-4 overflow-visible">
<div class="flex-expand align-middle">
<span class="text-3xl font-bold mr-4">{{ .strings.accounts }}</span>
<div id="accounts-filter-dropdown" class="dropdown z-10" tabindex="0">
<span class="h-100 button ~neutral @low center" id="accounts-filter-button">{{ .strings.filters }}</span>
<div class="dropdown-display">
<div class="card ~neutral @low mt-2" id="accounts-filter-list">
<p class="supra pb-2">{{ .strings.filters }}</p>
<div class="card @low dark:~d_neutral accounts mb-4">
<div class="flex-expand row">
<div class="row">
<span class="text-3xl font-bold mr-2 col">{{ .strings.accounts }}</span>
<input type="search" class="col sm field ~neutral @low input search ml-2 mr-2" id="accounts-search" placeholder="{{ .strings.search }}">
</div>
<div class="row">
<span class="col sm button ~neutral @low center mb-2" id="accounts-add-user">{{ .quantityStrings.addUser.Singular }}</span>
<div id="accounts-announce-dropdown" class="col sm dropdown pb-0i" tabindex="0">
<span class="h-100 sm button ~info @low center mb-2" id="accounts-announce">{{ .strings.announce }}</span>
<div class="dropdown-display">
<div class="card ~neutral @low">
<span class="supra sm">{{ .strings.templates }}</span>
<div id="accounts-announce-templates"></div>
</div>
</div>
</div>
</div>
<input type="search" class="field ~neutral @low input search ml-2 mr-2" id="accounts-search" placeholder="{{ .strings.search }}">
<span class="button ~neutral @low center -ml-8" id="accounts-search-clear" aria-label="{{ .strings.clearSearch }}" text="{{ .strings.clearSearch }}"><i class="ri-close-line"></i></span>
</div>
<div class="supra py-1 sm hidden" id="accounts-search-options-header">{{ .strings.searchOptions }}</div>
<div class="row -mx-2">
<button type="button" class="button ~neutral @low center m-2 hidden"><span id="accounts-sort-by-field"></span> <i class="ri-close-line ml-2 text-2xl"></i></button>
<span id="accounts-filter-area"></span>
</div>
<div class="supra py-1 sm">{{ .strings.actions }}</div>
<div class="row -mx-2">
<span class="col button ~neutral @low center max-w-[20%]" id="accounts-add-user">{{ .quantityStrings.addUser.Singular }}</span>
<div id="accounts-announce-dropdown" class="col dropdown pb-0i max-w-[20%]" tabindex="0">
<span class="w-100 button ~info @low center" id="accounts-announce">{{ .strings.announce }}</span>
<div class="dropdown-display">
<div class="card ~neutral @low">
<span class="supra sm">{{ .strings.templates }}</span>
<div id="accounts-announce-templates"></div>
<span class="col sm button ~urge @low center mb-2" id="accounts-modify-user">{{ .strings.modifySettings }}</span>
<span class="col sm button ~warning @low center mb-2" id="accounts-extend-expiry">{{ .strings.extendExpiry }}</span>
<div id="accounts-disable-enable-dropdown" class="col sm dropdown manual pb-0i" tabindex="0">
<span class="h-100 sm button ~positive @low center mb-2" id="accounts-disable-enable">{{ .strings.disable }}</span>
<div class="dropdown-display">
<div class="card ~neutral @low">
<span class="button ~urge sm full-width accounts-announce-template-button" id="accounts-enable-expiry">{{ .strings.setExpiry }}</span>
</div>
</div>
</div>
<span class="col sm button ~info @low center mb-2 unfocused" id="accounts-send-pwr">{{ .strings.sendPWR }}</span>
<span class="col sm button ~critical @low center mb-2" id="accounts-delete-user">{{ .quantityStrings.deleteUser.Singular }}</span>
</div>
<span class="col button ~urge @low center max-w-[20%]" id="accounts-modify-user">{{ .strings.modifySettings }}</span>
<span class="col button ~warning @low center max-w-[20%]" id="accounts-extend-expiry">{{ .strings.extendExpiry }}</span>
<div id="accounts-disable-enable-dropdown" class="col dropdown manual pb-0i max-w-[20%]" tabindex="0">
<span class="w-100 button ~positive @low center" id="accounts-disable-enable">{{ .strings.disable }}</span>
<div class="dropdown-display">
<div class="card ~neutral @low">
<span class="button ~urge full-width accounts-announce-template-button" id="accounts-enable-expiry">{{ .strings.setExpiry }}</span>
</div>
</div>
</div>
<span class="col button ~info @low center unfocused max-w-[20%]" id="accounts-send-pwr">{{ .strings.sendPWR }}</span>
<span class="col button ~critical @low center max-w-[20%]" id="accounts-delete-user">{{ .quantityStrings.deleteUser.Singular }}</span>
</div>
<div class="card @low accounts-header table-responsive mt-2">
<div class="card @low accounts-header table-responsive mt-8">
<table class="table text-base leading-4">
<thead>
<tr>
<th><input type="checkbox" value="" id="accounts-select-all"></th>
<th class="table-inline my-2 grid gap-4 place-items-stretch accounts-header-username">{{ .strings.username }}</th>
<th class="table-inline my-2">{{ .strings.username }}</th>
{{ if .jellyfinLogin }}
<th class="text-center-i grid gap-4 place-items-stretch accounts-header-access-jfa">{{ .strings.accessJFA }}</th>
<th class="text-center-i">{{ .strings.accessJFA }}</th>
{{ end }}
<th class="grid gap-4 place-items-stretch accounts-header-email">{{ .strings.emailAddress }}</th>
<th>{{ .strings.emailAddress }}</th>
{{ if .telegramEnabled }}
<th class="text-center-i grid gap-4 place-items-stretch accounts-header-telegram">Telegram</th>
<th class="text-center-i">Telegram</th>
{{ end }}
{{ if .matrixEnabled }}
<th class="text-center-i grid gap-4 place-items-stretch accounts-header-matrix">Matrix</th>
<th class="text-center-i">Matrix</th>
{{ end }}
{{ if .discordEnabled }}
<th class="text-center-i grid gap-4 place-items-stretch accounts-header-discord">Discord</th>
<th class="text-center-i">Discord</th>
{{ end }}
<th class="grid gap-4 place-items-stretch accounts-header-expiry">{{ .strings.expiry }}</th>
<th class="grid gap-4 place-items-stretch accounts-header-last-active">{{ .strings.lastActiveTime }}</th>
<th>{{ .strings.expiry }}</th>
<th>{{ .strings.lastActiveTime }}</th>
</tr>
</thead>
<tbody id="accounts-list"></tbody>

View File

@ -37,8 +37,6 @@
"advancedSettings": "Advanced Settings",
"lastActiveTime": "Last Active",
"from": "From",
"after": "After",
"before": "Before",
"user": "User",
"expiry": "Expiry",
"userExpiry": "User Expiry",
@ -116,15 +114,7 @@
"deleteTemplate": "Delete template",
"templateEnterName": "Enter a name to save this template.",
"accessJFA": "Access jfa-go",
"accessJFASettings": "Cannot be changed as either \"Admin Only\" or \"Allow All\" has been set in Settings > General.",
"sortingBy": "Sorting By",
"filters": "Filters",
"clickToRemoveFilter": "Click to remove this filter.",
"clearSearch": "Clear search",
"actions": "Actions",
"searchOptions": "Search Options",
"matchText": "Match Text",
"jellyfinID": "Jellyfin ID"
"accessJFASettings": "Cannot be changed as either \"Admin Only\" or \"Allow All\" has been set in Settings > General."
},
"notifications": {
"changedEmailAddress": "Changed email address of {n}.",

View File

@ -7,7 +7,7 @@
"username": "Nom d'utilisateur",
"name": "Nom",
"password": "Mot de passe",
"emailAddress": "Adresse e-mail",
"emailAddress": "Addresse Email",
"submit": "Soumettre",
"success": "Succès",
"continue": "Continuer",
@ -23,8 +23,6 @@
"linkDiscord": "Lier Discord",
"linkMatrix": "Lier Matrix",
"send": "Envoyer",
"contactDiscord": "Contacter par Discord",
"refresh": "Actualiser",
"required": "Requis"
"contactDiscord": "Contacter par Discord"
}
}

View File

@ -33,9 +33,7 @@
"errorCaptcha": "كلمة التحقق غير صحيحة.",
"errorPassword": "تحقق من متطلبات كلمة المرور.",
"errorNoMatch": "كلمات المرور غير متطابقة.",
"verified": "تم التحقق من الحساب.",
"errorAccountLinked": "الحساب موجود مسبقا.",
"errorEmailLinked": "الايميل مستعمل مسبقا."
"verified": "تم التحقق من الحساب."
},
"validationStrings": {
"length": {

View File

@ -33,9 +33,7 @@
"errorNoEmail": "Correo electrónico requerido.",
"errorCaptcha": "Captcha Incorrecto.",
"errorPassword": "Requisitos para la contraseña.",
"errorNoMatch": "Las contraseñas no coinciden.",
"errorAccountLinked": "La cuenta ya está en uso.",
"errorEmailLinked": "El correo electrónico ya está en uso."
"errorNoMatch": "Las contraseñas no coinciden."
},
"validationStrings": {
"length": {

View File

@ -53,12 +53,6 @@
"errorDiscordVerification": "Vérification Discord requise.",
"errorMatrixVerification": "Vérification Matrix requise.",
"errorUnknown": "Erreur inconnue.",
"verified": "Compte vérifié.",
"errorEmailLinked": "E-mail déjà utilisé.",
"errorNoEmail": "E-mail requis.",
"errorCaptcha": "Captcha incorrect.",
"errorPassword": "Vérifiez les exigences relatives au mot de passe.",
"errorNoMatch": "Les mots de passe ne correspondent pas.",
"errorAccountLinked": "Compte déjà utilisé."
"verified": "Compte vérifié."
}
}

View File

@ -10,15 +10,15 @@
"username": "Felhasználónév",
"password": "Jelszó",
"reEnterPassword": "Jelszó megerősítése",
"reEnterPasswordInvalid": "A jelszavak nem egyeznek",
"reEnterPasswordInvalid": "A jelszók nem egyeznek",
"createAccountButton": "Fiók létrehozása",
"passwordRequirementsHeader": "Jelszó követelmények",
"successHeader": "Siker!",
"confirmationRequired": "E-mail megerősítés szükséges",
"confirmationRequiredMessage": "Kérjük ellenőrizze az e-mail címére küldött üzenetet, a fiók ellenőrzéséhez.",
"yourAccountIsValidUntil": "A fiókja eddig lesz érvényes: {date}.",
"sendPIN": "Az alábbi PIN-t küldje el a botnak, majd itt csatolja össze a fiókját.",
"sendPINDiscord": "Írja be a {command} parancsot a {server_channel} Discord csatornába, adja meg a PIN-t.",
"sendPIN": "Az alábbi kódot küldje el a botnak, majd itt csatolja össze a fiókját.",
"sendPINDiscord": "Discordon haszánlja a {command} parancsot, a {server_channel} csatornában, majd írja be a PIN-t.",
"matrixEnterUser": "Írja be a felhasználója azonosítóját majd nyomja meg a beküldés gombot. A kapott kódot ide írja be."
},
"notifications": {
@ -33,14 +33,12 @@
"verified": "Fiók ellenőrizve.",
"errorPassword": "Ellenőrizze a jelszó követelményeket.",
"errorCaptcha": "Hibás Captcha.",
"errorNoMatch": "A jelszavak nem egyeznek.",
"errorEmailLinked": "Az e-mail cím már használatban van.",
"errorAccountLinked": "A fiók már használatban van."
"errorNoMatch": "A jelszavak nem egyeznek."
},
"validationStrings": {
"length": {
"singular": "Legalább {n} karakter",
"plural": "Legalább {n} karakter szükséges."
"plural": "Legalább {n} karakter."
},
"uppercase": {
"singular": "Legalább {n} nagybetűs karakter",

View File

@ -34,9 +34,7 @@
"errorNoEmail": "Email necessário.",
"errorCaptcha": "Captcha incorreto.",
"errorPassword": "Verifique os requisitos de senha.",
"errorNoMatch": "As senhas não coincidem.",
"errorEmailLinked": "Este E-mail já está sendo utilizado.",
"errorAccountLinked": "Esta conta já está sendo utilizada."
"errorNoMatch": "As senhas não coincidem."
},
"validationStrings": {
"length": {

View File

@ -19,8 +19,7 @@
"errorUserDisabled": "L'utilisateur est peut-être désactivé.",
"error404": "404, vérifiez l'URL interne.",
"errorInvalidUserPass": "Nom d'utilisateur/mot de passe invalide.",
"errorNotAdmin": "L'utilisateur n'est pas autorisé à gérer le serveur.",
"errorConnectionRefused": "Connexion refusée."
"errorNotAdmin": "L'utilisateur n'est pas autorisé à gérer le serveur."
},
"startPage": {
"welcome": "Bienvenue !",
@ -59,9 +58,7 @@
"authorizeWithJellyfin": "Autoriser avec Jellyfin/Emby : Les Informations de connexion sont partagées avec Jellyfin, ce qui permet plusieurs utilisateurs.",
"authorizeManual": "Utilisateur et Mot de passe : Renseignez manuellement le nom d'utilisateur et le mot de passe.",
"adminOnly": "Administrateurs seulement (recommandé)",
"emailNotice": "Votre adresse e-mail peut être utilisée pour recevoir des notifications.",
"allowAll": "Autoriser tous les utilisateurs de Jellyfin à se connecter",
"allowAllDescription": "Non recommandé, vous devez autoriser individuellement les utilisateurs à se connecter une fois la configuration effectuée."
"emailNotice": "Votre adresse e-mail peut être utilisée pour recevoir des notifications."
},
"jellyfinEmby": {
"title": "Jellyfin/Emby",

View File

@ -3,7 +3,7 @@
"name": "العربية (AR)"
},
"strings": {
"startMessage": "مرحبا!\nضع رقمك السري للتحقق من حسابك.",
"startMessage": "مرحبا!\nضع رقمك السري للتحقق من حسابك",
"discordStartMessage": "مرحبا!\nضع رقمك السري `/pin <PIN>` للتحقق من حسابك.",
"matrixStartMessage": "أهلا\nأدخل رقم التعريف الشخصي أدناه في صفحة الاشتراك في Jellyfin للتحقق من حسابك.",
"invalidPIN": "رقم التعريف الشخصي هذا غير صالح ، حاول مرة أخرى.",

View File

@ -4,13 +4,9 @@
},
"strings": {
"startMessage": "Salut !\nEntrez votre code PIN Jellyfin ici pour vérifier votre compte.",
"matrixStartMessage": "Salut !\nEntrez le code PIN ci-dessous dans la page dinscription Jellyfin pour vérifier votre compte.",
"matrixStartMessage": "Salut !\nEntre votre code PIN Jellyfin dans la page dinscription pour vérifier votre compte.",
"invalidPIN": "Ce code PIN est invalide, réessayez.",
"pinSuccess": "Succès ! Vous pouvez maintenant retourner à la page dinscription.",
"languageMessage": "Note : Découvrez les langues disponibles avec {command} et paramétrez la langue souhaitée avec {command} <language code>.",
"discordStartMessage": "Salut!\n Entrez votre code PIN avec '/pin <PIN>' pour vérifier votre compte.",
"discordDMs": "Veuillez vérifier vos DM pour une réponse.",
"languageSet": "Langue définie sur {language}.",
"languageMessageDiscord": "Note: définissez votre langue avec /lang <nom de la langue>."
"languageMessage": "Note : Découvrez les langues disponibles avec {command} et paramétrez la langue souhaitée avec {command} <language code>."
}
}

377
package-lock.json generated
View File

@ -12,10 +12,9 @@
"@ts-stack/markdown": "^1.4.0",
"@types/node": "^20.3.0",
"a17t": "^0.10.1",
"any-date-parser": "^1.5.4",
"browserslist": "^4.21.7",
"cheerio": "^1.0.0-rc.12",
"esbuild": "^0.18.2",
"esbuild": "^0.18.1",
"fs-cheerio": "^3.0.0",
"inline-source": "^8.0.2",
"jsdom": "^22.1.0",
@ -57,9 +56,9 @@
}
},
"node_modules/@esbuild/android-arm": {
"version": "0.18.2",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.2.tgz",
"integrity": "sha512-YAnQBHlY0IvYtvY0avnXjI8ywW23emEjk5XExqbFmypath+Snq9MgY1IS47rnqBKVSqnl0ElDt221ZgaeRrkXg==",
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.1.tgz",
"integrity": "sha512-8+QS98jqdreHLvCojIke8NjcuelB+Osysazr15EhkUIuG0Ov5WK26XgPYWViCTjHnKQxbpS86/JryBOkEpyrBA==",
"cpu": [
"arm"
],
@ -72,9 +71,9 @@
}
},
"node_modules/@esbuild/android-arm64": {
"version": "0.18.2",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.2.tgz",
"integrity": "sha512-1Y2pb0hLdmji8I0zBwNsYSDN7zJSQqufgLOuOsrrod00WEAgKywQR5MB/E046Is/YTP4bgcPS4BioaSDBaLaTg==",
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.1.tgz",
"integrity": "sha512-l5V0IWGTYfQMzl4ulgIHKMZPwabIS4a39ZvtkPwL6LYiX3UtL76sylA6eFKufJCB43mwEYqbXoBSMn++NpxILw==",
"cpu": [
"arm64"
],
@ -87,9 +86,9 @@
}
},
"node_modules/@esbuild/android-x64": {
"version": "0.18.2",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.2.tgz",
"integrity": "sha512-P047Mh3pj8uYVE3A/B3QDX6nG8dKbHLJ+48R6Y0CRXCJ5PkXJxdHOTaS8SYs6eSR3FFU6/YQ5TishQXVHX7F5A==",
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.1.tgz",
"integrity": "sha512-1y8/bRek6EYxQeGTUfwL2mmj6NAeXZ3h5YSc4W2Y/kduI1B8VhT4x5X0VxrcGkIKef4N5qCdziRxvei/YUfESg==",
"cpu": [
"x64"
],
@ -102,9 +101,9 @@
}
},
"node_modules/@esbuild/darwin-arm64": {
"version": "0.18.2",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.2.tgz",
"integrity": "sha512-a3Rkqd0tGVYMEKNy9SstWEdeBmM60l8FVD5o4rmwHr3xO1LbLqtCJSrWGbnf37hevo6m437mURVmpEHOmkXeTA==",
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.1.tgz",
"integrity": "sha512-FFT/on9qQTOntdloQvgfwFkRhNI5l/TCNXZS1CpH6JQd0boR637aThi9g9FYs4o31Ao72/jPZFDiRln5Cu6R2A==",
"cpu": [
"arm64"
],
@ -117,9 +116,9 @@
}
},
"node_modules/@esbuild/darwin-x64": {
"version": "0.18.2",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.2.tgz",
"integrity": "sha512-cvH58adz9L10JNsIcgtkWNS/1eutjRTi3rtWz1s3ZhR64BpdmkxJBAXE/UjqybyNAWLhaN8mPJdlYI2f+tQA7g==",
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.1.tgz",
"integrity": "sha512-p/ZIUt+NlW8qRNVTXoKJgRuc49teazvmXBquoGOm5D6IAimTfWJVJrEivqpoMKyDS/0/PxDMRM2lrkxlSa7XeQ==",
"cpu": [
"x64"
],
@ -132,9 +131,9 @@
}
},
"node_modules/@esbuild/freebsd-arm64": {
"version": "0.18.2",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.2.tgz",
"integrity": "sha512-68rGMGUdgmq+c5IvseCMqY4yaa2CAY/DIILMBA6bEU1caISF7fXnV69B1uU4s3ERuVDcasVVwiAFyNxCtkS6Zg==",
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.1.tgz",
"integrity": "sha512-eYUDR3thO96ULRf4rJcG9TJ/sQc6Z/YNe16mC/KvVeAOtzmeTXiPMETEv/iMqTCxZhYkHyQG/mYbAxPBWC2mcg==",
"cpu": [
"arm64"
],
@ -147,9 +146,9 @@
}
},
"node_modules/@esbuild/freebsd-x64": {
"version": "0.18.2",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.2.tgz",
"integrity": "sha512-ZSR9On/rXoYuAtrXo5hYKy7OuZwKZyFh2rr6L3TX4UeR1tWLf84aLyAFt7e0tlRbh4zNgqFx+ePWmsSHw7L9Bw==",
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.1.tgz",
"integrity": "sha512-w03zjxyg51qktv0JKsV+AbY3uSb1Awifs8IkKQSUXdP3sdPxxmPzZLrlJ1+LjKZRiSa4yP/Haayi/hriNVoIdQ==",
"cpu": [
"x64"
],
@ -162,9 +161,9 @@
}
},
"node_modules/@esbuild/linux-arm": {
"version": "0.18.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.2.tgz",
"integrity": "sha512-jAbA75qJ70T5AOdmw9X8675ppeRfj7j57sOypoZ4mQlfQ/LKF8eoeLzTYVo8+aqLKqeIIl0vQ4hKOB0FyG98Zg==",
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.1.tgz",
"integrity": "sha512-d6FXeb8F/cuXtSZuVHQN0Rz3gs3g2Xy/M4KJJRzbKsBx3pwCQuRdSrYxcr7g0PFN8geIOspiLQnUzwONyMA3Bw==",
"cpu": [
"arm"
],
@ -177,9 +176,9 @@
}
},
"node_modules/@esbuild/linux-arm64": {
"version": "0.18.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.2.tgz",
"integrity": "sha512-DFKavAzbu/n9HXWuetxmYN10XnfzW7FgOgpcrGD8eXaiu77KdgB+OVWA83x9FtDYtsoFpfdlDuVFAQFfrhu77A==",
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.1.tgz",
"integrity": "sha512-dHlvkKAVlYNt5LPg1GUha99QiaEGKEC21zpHVAxs7hhW6EkR8nN3iWmyndGXxVJm4K7e4lKAzl8ekPqSr5gAXQ==",
"cpu": [
"arm64"
],
@ -192,9 +191,9 @@
}
},
"node_modules/@esbuild/linux-ia32": {
"version": "0.18.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.2.tgz",
"integrity": "sha512-VEaK3Z+vJyDwwPsP0sovaEw1foDzrMs7XQNYEIFkOwMjSe2BipKRKUUyrznil0p8qqsK7U8W+T7oNqZpgdnD2Q==",
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.1.tgz",
"integrity": "sha512-QHS4duBPuAsLZP82sNeoqTXAJ1mNU4QcfmYtBN/jNvQJXb6n0im8F4ljFSAQbivt1jl1OnKL8HhlLUeKY75nLg==",
"cpu": [
"ia32"
],
@ -207,9 +206,9 @@
}
},
"node_modules/@esbuild/linux-loong64": {
"version": "0.18.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.2.tgz",
"integrity": "sha512-Af1uZdB0oeJo4PW67l9aw94oakSamFxhC6ltC2eDkndozd9QygVNMTF7s7uxTLjo+BJqyVqG9wjmLCYF1o4NmA==",
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.1.tgz",
"integrity": "sha512-g4YSiF/qBvXvJhSowxaR7Ei/79otL48Qfjviuo+FpXREykA9nSe407T5ZvezFXryFgdf44Fe8lWpjvtQ+n42cQ==",
"cpu": [
"loong64"
],
@ -222,9 +221,9 @@
}
},
"node_modules/@esbuild/linux-mips64el": {
"version": "0.18.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.2.tgz",
"integrity": "sha512-WcTbt61+9dREuOFKXac4Qg+3OuRhLxPL9lmkI2P7fGuq/fWS2qq+AvGGVLMyk+OtXGDjyQolcEDeYlRoOmjRYQ==",
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.1.tgz",
"integrity": "sha512-/G1fzmaR5u2S9wgQhiQEhWRct0+GMpuNjhll59uv5Tjojlma9MUPinVnvpw9Re+Idb6gxe6kmzUxFP2YkC/svg==",
"cpu": [
"mips64el"
],
@ -237,9 +236,9 @@
}
},
"node_modules/@esbuild/linux-ppc64": {
"version": "0.18.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.2.tgz",
"integrity": "sha512-Ov+VHayvCPb52axma6+xm8QDawRjwHscPXedHg4U92DxlhKQ0H+6onRiC3J9kKI50p8pKKypprpCWrRrXjZN7Q==",
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.1.tgz",
"integrity": "sha512-NkDjIvleUc3lSV1VI3QE9Oh5mz3nY11H5TCbi4DJ8X09FGwHN5pDVXdAsQYPGjlt/frXZzq6x7vMmTOb5VyBog==",
"cpu": [
"ppc64"
],
@ -252,9 +251,9 @@
}
},
"node_modules/@esbuild/linux-riscv64": {
"version": "0.18.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.2.tgz",
"integrity": "sha512-qW37zzKKN9C5l5LnVDriOK0eZRzQeixhtrfd5C78PAsTE15GeHU9G0oyT/u/IkNjEBjXWpTZOOHKNbjhrvuL9g==",
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.1.tgz",
"integrity": "sha512-IhN7Nz+HyDRnMQOLcCl6m5BgQMITMhS9O1hOqgAUIy6FI0m/0zTSkZHtvMmSIpOy1uleaGqfNDA9SM3nBeTATQ==",
"cpu": [
"riscv64"
],
@ -267,9 +266,9 @@
}
},
"node_modules/@esbuild/linux-s390x": {
"version": "0.18.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.2.tgz",
"integrity": "sha512-izzEFMRO8LaQIlX22+fTgP5I7Os3T51mtAWsRNpZ5pMfQIa9PqtgFAoRcb10DV+/YkH/TMMxQIlevUvDS6E4vw==",
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.1.tgz",
"integrity": "sha512-u9iRg0eUUIyBbg5hANvRBYRaAnhVemAA2+pi3IgrzQTMeR/uPHQtJI3XInNZkNR6ACA4Fdl8N941p81XygeqWQ==",
"cpu": [
"s390x"
],
@ -282,9 +281,9 @@
}
},
"node_modules/@esbuild/linux-x64": {
"version": "0.18.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.2.tgz",
"integrity": "sha512-y5yqQ1ww4FfI9bQ1ZP/0k1rcgA6Ql2/AgzvqpowN0Q5tXDZkCavPdJbFXKrqA43vd1UTXt+AutTHYJ7km6e2Eg==",
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.1.tgz",
"integrity": "sha512-0QeWU0a0+RmxPCDt+plXS7/hVMJtfde/LaSzs6X3UTr4FYA0hYpnwDzGXxumcPLzt5c8ctugPuKat0tmRb7noQ==",
"cpu": [
"x64"
],
@ -297,9 +296,9 @@
}
},
"node_modules/@esbuild/netbsd-x64": {
"version": "0.18.2",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.2.tgz",
"integrity": "sha512-usNjpKFf83X4o60gdMD47NCblaSZ6DARf31/FyCzxOgnF80mJ+RhDs9RTqgyfH8KyduO5mjgInw9+ct286ayYA==",
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.1.tgz",
"integrity": "sha512-eFL7sxibN8wKuwrRf3HRkcjELALlfl/TavJ8P4J+BJfnkXOITF7zx4tTmGkzK8OwAR9snT2kEfp1Ictc80atGw==",
"cpu": [
"x64"
],
@ -312,9 +311,9 @@
}
},
"node_modules/@esbuild/openbsd-x64": {
"version": "0.18.2",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.2.tgz",
"integrity": "sha512-6urzy1+VwcPuhG+5jwHA8lD9E87E5+ey3qKw2EhRS+qUmMxLvfwP8szWC2JHVGZDPEDge6fgn0pBj+y9rxDLwQ==",
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.1.tgz",
"integrity": "sha512-riCQUnngF2xYUzr0XDdrGEEz0nqnocch0No7SBIQM22wTRi5gt5WqTQexGd/2u2Z19d0rVYQbKBelaJ1dwe9bg==",
"cpu": [
"x64"
],
@ -327,9 +326,9 @@
}
},
"node_modules/@esbuild/sunos-x64": {
"version": "0.18.2",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.2.tgz",
"integrity": "sha512-SMZPTACsvpKYAIl9o8nhnmMn6/lp62iMeV/2EBMtj+sW6dXwW9b0cLjihkBv4PG1CCRlwWKPZo43imqZxC95ZA==",
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.1.tgz",
"integrity": "sha512-6lTop2k+GMkWlrwMy2+55xIBXKfXOi6uzWYypXZZP8HxXG3Mb5N4O71z2KzisVNJtYK2VlQRNbmGtUzIQIhHAw==",
"cpu": [
"x64"
],
@ -342,9 +341,9 @@
}
},
"node_modules/@esbuild/win32-arm64": {
"version": "0.18.2",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.2.tgz",
"integrity": "sha512-H2zzjPdzSDNwUnZdZf9/xfm0CYqHFXuenCMAx+tRzIRqWUT6MmZ9/q7722KnAZ6uPpq0RLs7EjCIIfmt6CaRGg==",
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.1.tgz",
"integrity": "sha512-d6wt4g9GluZp7xCmgpm7gY6wy0mjcBHbKeeK9MYrlWNFJd8KBcD2uCil8kFuaH3Dt6AUz62D0wIoDETFsZ01Tg==",
"cpu": [
"arm64"
],
@ -357,9 +356,9 @@
}
},
"node_modules/@esbuild/win32-ia32": {
"version": "0.18.2",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.2.tgz",
"integrity": "sha512-lfyjTN+FrKgvNvrH7nOLtaz58J/8coZOo4LQwgBMP4D7ZOurhvluXS3GjePLzq9GbWnJDZdKCKbMKhZPPcdJJA==",
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.1.tgz",
"integrity": "sha512-z51DOtcwECu4WlqJUhu39AVnnpaVmTvXei0EQxc99QK7ZJyn4tj0EelYkMBZckpqzqB/GyGSLwEclKtRJ0l2uw==",
"cpu": [
"ia32"
],
@ -372,9 +371,9 @@
}
},
"node_modules/@esbuild/win32-x64": {
"version": "0.18.2",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.2.tgz",
"integrity": "sha512-Q4nIjqWXjxkELwd7kVepsJxbQ/6ERNsHpjz1j+IKjwSYw+g06U0RQOy5xh848AHvgr9itnGLa3cT2G5t0dBFsw==",
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.1.tgz",
"integrity": "sha512-6tdeuCLT+l9QuCFaYsNtULO6xH2fgJObvICMCsOZvkqIey6FUXVVju5aO+OZjxswy7WgKadhI1k/nq2wQSmB+Q==",
"cpu": [
"x64"
],
@ -631,11 +630,6 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/any-date-parser": {
"version": "1.5.4",
"resolved": "https://registry.npmjs.org/any-date-parser/-/any-date-parser-1.5.4.tgz",
"integrity": "sha512-S4gl9UmXNk9XXSQxp5w5harUD6aM0fepyL3dZM/B3znX57sWf792hS2UvvCFIHECfpsqfKbQ+cqWBky4AKyRIg=="
},
"node_modules/any-promise": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
@ -1647,9 +1641,9 @@
}
},
"node_modules/esbuild": {
"version": "0.18.2",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.2.tgz",
"integrity": "sha512-1P4sK9gXVcjvrrUjE94Hbo9goU+T6U1sdzLf+JJ+3uI6GEb4e4n3Wrqto9hZHUWabblpT2ifmC61LhZnLyTNFw==",
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.1.tgz",
"integrity": "sha512-ZUvsIx2wPjpj86b805UwbGJu47Kxgr2UTio9rGhWpBr1oOVk88exzoieOgTweX0UcVCwSAk3z2WvNALpTcpQZw==",
"hasInstallScript": true,
"bin": {
"esbuild": "bin/esbuild"
@ -1658,28 +1652,28 @@
"node": ">=12"
},
"optionalDependencies": {
"@esbuild/android-arm": "0.18.2",
"@esbuild/android-arm64": "0.18.2",
"@esbuild/android-x64": "0.18.2",
"@esbuild/darwin-arm64": "0.18.2",
"@esbuild/darwin-x64": "0.18.2",
"@esbuild/freebsd-arm64": "0.18.2",
"@esbuild/freebsd-x64": "0.18.2",
"@esbuild/linux-arm": "0.18.2",
"@esbuild/linux-arm64": "0.18.2",
"@esbuild/linux-ia32": "0.18.2",
"@esbuild/linux-loong64": "0.18.2",
"@esbuild/linux-mips64el": "0.18.2",
"@esbuild/linux-ppc64": "0.18.2",
"@esbuild/linux-riscv64": "0.18.2",
"@esbuild/linux-s390x": "0.18.2",
"@esbuild/linux-x64": "0.18.2",
"@esbuild/netbsd-x64": "0.18.2",
"@esbuild/openbsd-x64": "0.18.2",
"@esbuild/sunos-x64": "0.18.2",
"@esbuild/win32-arm64": "0.18.2",
"@esbuild/win32-ia32": "0.18.2",
"@esbuild/win32-x64": "0.18.2"
"@esbuild/android-arm": "0.18.1",
"@esbuild/android-arm64": "0.18.1",
"@esbuild/android-x64": "0.18.1",
"@esbuild/darwin-arm64": "0.18.1",
"@esbuild/darwin-x64": "0.18.1",
"@esbuild/freebsd-arm64": "0.18.1",
"@esbuild/freebsd-x64": "0.18.1",
"@esbuild/linux-arm": "0.18.1",
"@esbuild/linux-arm64": "0.18.1",
"@esbuild/linux-ia32": "0.18.1",
"@esbuild/linux-loong64": "0.18.1",
"@esbuild/linux-mips64el": "0.18.1",
"@esbuild/linux-ppc64": "0.18.1",
"@esbuild/linux-riscv64": "0.18.1",
"@esbuild/linux-s390x": "0.18.1",
"@esbuild/linux-x64": "0.18.1",
"@esbuild/netbsd-x64": "0.18.1",
"@esbuild/openbsd-x64": "0.18.1",
"@esbuild/sunos-x64": "0.18.1",
"@esbuild/win32-arm64": "0.18.1",
"@esbuild/win32-ia32": "0.18.1",
"@esbuild/win32-x64": "0.18.1"
}
},
"node_modules/escalade": {
@ -6797,135 +6791,135 @@
}
},
"@esbuild/android-arm": {
"version": "0.18.2",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.2.tgz",
"integrity": "sha512-YAnQBHlY0IvYtvY0avnXjI8ywW23emEjk5XExqbFmypath+Snq9MgY1IS47rnqBKVSqnl0ElDt221ZgaeRrkXg==",
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.1.tgz",
"integrity": "sha512-8+QS98jqdreHLvCojIke8NjcuelB+Osysazr15EhkUIuG0Ov5WK26XgPYWViCTjHnKQxbpS86/JryBOkEpyrBA==",
"optional": true
},
"@esbuild/android-arm64": {
"version": "0.18.2",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.2.tgz",
"integrity": "sha512-1Y2pb0hLdmji8I0zBwNsYSDN7zJSQqufgLOuOsrrod00WEAgKywQR5MB/E046Is/YTP4bgcPS4BioaSDBaLaTg==",
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.1.tgz",
"integrity": "sha512-l5V0IWGTYfQMzl4ulgIHKMZPwabIS4a39ZvtkPwL6LYiX3UtL76sylA6eFKufJCB43mwEYqbXoBSMn++NpxILw==",
"optional": true
},
"@esbuild/android-x64": {
"version": "0.18.2",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.2.tgz",
"integrity": "sha512-P047Mh3pj8uYVE3A/B3QDX6nG8dKbHLJ+48R6Y0CRXCJ5PkXJxdHOTaS8SYs6eSR3FFU6/YQ5TishQXVHX7F5A==",
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.1.tgz",
"integrity": "sha512-1y8/bRek6EYxQeGTUfwL2mmj6NAeXZ3h5YSc4W2Y/kduI1B8VhT4x5X0VxrcGkIKef4N5qCdziRxvei/YUfESg==",
"optional": true
},
"@esbuild/darwin-arm64": {
"version": "0.18.2",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.2.tgz",
"integrity": "sha512-a3Rkqd0tGVYMEKNy9SstWEdeBmM60l8FVD5o4rmwHr3xO1LbLqtCJSrWGbnf37hevo6m437mURVmpEHOmkXeTA==",
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.1.tgz",
"integrity": "sha512-FFT/on9qQTOntdloQvgfwFkRhNI5l/TCNXZS1CpH6JQd0boR637aThi9g9FYs4o31Ao72/jPZFDiRln5Cu6R2A==",
"optional": true
},
"@esbuild/darwin-x64": {
"version": "0.18.2",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.2.tgz",
"integrity": "sha512-cvH58adz9L10JNsIcgtkWNS/1eutjRTi3rtWz1s3ZhR64BpdmkxJBAXE/UjqybyNAWLhaN8mPJdlYI2f+tQA7g==",
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.1.tgz",
"integrity": "sha512-p/ZIUt+NlW8qRNVTXoKJgRuc49teazvmXBquoGOm5D6IAimTfWJVJrEivqpoMKyDS/0/PxDMRM2lrkxlSa7XeQ==",
"optional": true
},
"@esbuild/freebsd-arm64": {
"version": "0.18.2",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.2.tgz",
"integrity": "sha512-68rGMGUdgmq+c5IvseCMqY4yaa2CAY/DIILMBA6bEU1caISF7fXnV69B1uU4s3ERuVDcasVVwiAFyNxCtkS6Zg==",
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.1.tgz",
"integrity": "sha512-eYUDR3thO96ULRf4rJcG9TJ/sQc6Z/YNe16mC/KvVeAOtzmeTXiPMETEv/iMqTCxZhYkHyQG/mYbAxPBWC2mcg==",
"optional": true
},
"@esbuild/freebsd-x64": {
"version": "0.18.2",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.2.tgz",
"integrity": "sha512-ZSR9On/rXoYuAtrXo5hYKy7OuZwKZyFh2rr6L3TX4UeR1tWLf84aLyAFt7e0tlRbh4zNgqFx+ePWmsSHw7L9Bw==",
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.1.tgz",
"integrity": "sha512-w03zjxyg51qktv0JKsV+AbY3uSb1Awifs8IkKQSUXdP3sdPxxmPzZLrlJ1+LjKZRiSa4yP/Haayi/hriNVoIdQ==",
"optional": true
},
"@esbuild/linux-arm": {
"version": "0.18.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.2.tgz",
"integrity": "sha512-jAbA75qJ70T5AOdmw9X8675ppeRfj7j57sOypoZ4mQlfQ/LKF8eoeLzTYVo8+aqLKqeIIl0vQ4hKOB0FyG98Zg==",
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.1.tgz",
"integrity": "sha512-d6FXeb8F/cuXtSZuVHQN0Rz3gs3g2Xy/M4KJJRzbKsBx3pwCQuRdSrYxcr7g0PFN8geIOspiLQnUzwONyMA3Bw==",
"optional": true
},
"@esbuild/linux-arm64": {
"version": "0.18.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.2.tgz",
"integrity": "sha512-DFKavAzbu/n9HXWuetxmYN10XnfzW7FgOgpcrGD8eXaiu77KdgB+OVWA83x9FtDYtsoFpfdlDuVFAQFfrhu77A==",
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.1.tgz",
"integrity": "sha512-dHlvkKAVlYNt5LPg1GUha99QiaEGKEC21zpHVAxs7hhW6EkR8nN3iWmyndGXxVJm4K7e4lKAzl8ekPqSr5gAXQ==",
"optional": true
},
"@esbuild/linux-ia32": {
"version": "0.18.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.2.tgz",
"integrity": "sha512-VEaK3Z+vJyDwwPsP0sovaEw1foDzrMs7XQNYEIFkOwMjSe2BipKRKUUyrznil0p8qqsK7U8W+T7oNqZpgdnD2Q==",
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.1.tgz",
"integrity": "sha512-QHS4duBPuAsLZP82sNeoqTXAJ1mNU4QcfmYtBN/jNvQJXb6n0im8F4ljFSAQbivt1jl1OnKL8HhlLUeKY75nLg==",
"optional": true
},
"@esbuild/linux-loong64": {
"version": "0.18.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.2.tgz",
"integrity": "sha512-Af1uZdB0oeJo4PW67l9aw94oakSamFxhC6ltC2eDkndozd9QygVNMTF7s7uxTLjo+BJqyVqG9wjmLCYF1o4NmA==",
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.1.tgz",
"integrity": "sha512-g4YSiF/qBvXvJhSowxaR7Ei/79otL48Qfjviuo+FpXREykA9nSe407T5ZvezFXryFgdf44Fe8lWpjvtQ+n42cQ==",
"optional": true
},
"@esbuild/linux-mips64el": {
"version": "0.18.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.2.tgz",
"integrity": "sha512-WcTbt61+9dREuOFKXac4Qg+3OuRhLxPL9lmkI2P7fGuq/fWS2qq+AvGGVLMyk+OtXGDjyQolcEDeYlRoOmjRYQ==",
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.1.tgz",
"integrity": "sha512-/G1fzmaR5u2S9wgQhiQEhWRct0+GMpuNjhll59uv5Tjojlma9MUPinVnvpw9Re+Idb6gxe6kmzUxFP2YkC/svg==",
"optional": true
},
"@esbuild/linux-ppc64": {
"version": "0.18.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.2.tgz",
"integrity": "sha512-Ov+VHayvCPb52axma6+xm8QDawRjwHscPXedHg4U92DxlhKQ0H+6onRiC3J9kKI50p8pKKypprpCWrRrXjZN7Q==",
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.1.tgz",
"integrity": "sha512-NkDjIvleUc3lSV1VI3QE9Oh5mz3nY11H5TCbi4DJ8X09FGwHN5pDVXdAsQYPGjlt/frXZzq6x7vMmTOb5VyBog==",
"optional": true
},
"@esbuild/linux-riscv64": {
"version": "0.18.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.2.tgz",
"integrity": "sha512-qW37zzKKN9C5l5LnVDriOK0eZRzQeixhtrfd5C78PAsTE15GeHU9G0oyT/u/IkNjEBjXWpTZOOHKNbjhrvuL9g==",
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.1.tgz",
"integrity": "sha512-IhN7Nz+HyDRnMQOLcCl6m5BgQMITMhS9O1hOqgAUIy6FI0m/0zTSkZHtvMmSIpOy1uleaGqfNDA9SM3nBeTATQ==",
"optional": true
},
"@esbuild/linux-s390x": {
"version": "0.18.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.2.tgz",
"integrity": "sha512-izzEFMRO8LaQIlX22+fTgP5I7Os3T51mtAWsRNpZ5pMfQIa9PqtgFAoRcb10DV+/YkH/TMMxQIlevUvDS6E4vw==",
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.1.tgz",
"integrity": "sha512-u9iRg0eUUIyBbg5hANvRBYRaAnhVemAA2+pi3IgrzQTMeR/uPHQtJI3XInNZkNR6ACA4Fdl8N941p81XygeqWQ==",
"optional": true
},
"@esbuild/linux-x64": {
"version": "0.18.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.2.tgz",
"integrity": "sha512-y5yqQ1ww4FfI9bQ1ZP/0k1rcgA6Ql2/AgzvqpowN0Q5tXDZkCavPdJbFXKrqA43vd1UTXt+AutTHYJ7km6e2Eg==",
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.1.tgz",
"integrity": "sha512-0QeWU0a0+RmxPCDt+plXS7/hVMJtfde/LaSzs6X3UTr4FYA0hYpnwDzGXxumcPLzt5c8ctugPuKat0tmRb7noQ==",
"optional": true
},
"@esbuild/netbsd-x64": {
"version": "0.18.2",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.2.tgz",
"integrity": "sha512-usNjpKFf83X4o60gdMD47NCblaSZ6DARf31/FyCzxOgnF80mJ+RhDs9RTqgyfH8KyduO5mjgInw9+ct286ayYA==",
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.1.tgz",
"integrity": "sha512-eFL7sxibN8wKuwrRf3HRkcjELALlfl/TavJ8P4J+BJfnkXOITF7zx4tTmGkzK8OwAR9snT2kEfp1Ictc80atGw==",
"optional": true
},
"@esbuild/openbsd-x64": {
"version": "0.18.2",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.2.tgz",
"integrity": "sha512-6urzy1+VwcPuhG+5jwHA8lD9E87E5+ey3qKw2EhRS+qUmMxLvfwP8szWC2JHVGZDPEDge6fgn0pBj+y9rxDLwQ==",
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.1.tgz",
"integrity": "sha512-riCQUnngF2xYUzr0XDdrGEEz0nqnocch0No7SBIQM22wTRi5gt5WqTQexGd/2u2Z19d0rVYQbKBelaJ1dwe9bg==",
"optional": true
},
"@esbuild/sunos-x64": {
"version": "0.18.2",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.2.tgz",
"integrity": "sha512-SMZPTACsvpKYAIl9o8nhnmMn6/lp62iMeV/2EBMtj+sW6dXwW9b0cLjihkBv4PG1CCRlwWKPZo43imqZxC95ZA==",
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.1.tgz",
"integrity": "sha512-6lTop2k+GMkWlrwMy2+55xIBXKfXOi6uzWYypXZZP8HxXG3Mb5N4O71z2KzisVNJtYK2VlQRNbmGtUzIQIhHAw==",
"optional": true
},
"@esbuild/win32-arm64": {
"version": "0.18.2",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.2.tgz",
"integrity": "sha512-H2zzjPdzSDNwUnZdZf9/xfm0CYqHFXuenCMAx+tRzIRqWUT6MmZ9/q7722KnAZ6uPpq0RLs7EjCIIfmt6CaRGg==",
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.1.tgz",
"integrity": "sha512-d6wt4g9GluZp7xCmgpm7gY6wy0mjcBHbKeeK9MYrlWNFJd8KBcD2uCil8kFuaH3Dt6AUz62D0wIoDETFsZ01Tg==",
"optional": true
},
"@esbuild/win32-ia32": {
"version": "0.18.2",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.2.tgz",
"integrity": "sha512-lfyjTN+FrKgvNvrH7nOLtaz58J/8coZOo4LQwgBMP4D7ZOurhvluXS3GjePLzq9GbWnJDZdKCKbMKhZPPcdJJA==",
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.1.tgz",
"integrity": "sha512-z51DOtcwECu4WlqJUhu39AVnnpaVmTvXei0EQxc99QK7ZJyn4tj0EelYkMBZckpqzqB/GyGSLwEclKtRJ0l2uw==",
"optional": true
},
"@esbuild/win32-x64": {
"version": "0.18.2",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.2.tgz",
"integrity": "sha512-Q4nIjqWXjxkELwd7kVepsJxbQ/6ERNsHpjz1j+IKjwSYw+g06U0RQOy5xh848AHvgr9itnGLa3cT2G5t0dBFsw==",
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.1.tgz",
"integrity": "sha512-6tdeuCLT+l9QuCFaYsNtULO6xH2fgJObvICMCsOZvkqIey6FUXVVju5aO+OZjxswy7WgKadhI1k/nq2wQSmB+Q==",
"optional": true
},
"@jridgewell/gen-mapping": {
@ -7116,11 +7110,6 @@
"color-convert": "^2.0.1"
}
},
"any-date-parser": {
"version": "1.5.4",
"resolved": "https://registry.npmjs.org/any-date-parser/-/any-date-parser-1.5.4.tgz",
"integrity": "sha512-S4gl9UmXNk9XXSQxp5w5harUD6aM0fepyL3dZM/B3znX57sWf792hS2UvvCFIHECfpsqfKbQ+cqWBky4AKyRIg=="
},
"any-promise": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
@ -7896,32 +7885,32 @@
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="
},
"esbuild": {
"version": "0.18.2",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.2.tgz",
"integrity": "sha512-1P4sK9gXVcjvrrUjE94Hbo9goU+T6U1sdzLf+JJ+3uI6GEb4e4n3Wrqto9hZHUWabblpT2ifmC61LhZnLyTNFw==",
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.1.tgz",
"integrity": "sha512-ZUvsIx2wPjpj86b805UwbGJu47Kxgr2UTio9rGhWpBr1oOVk88exzoieOgTweX0UcVCwSAk3z2WvNALpTcpQZw==",
"requires": {
"@esbuild/android-arm": "0.18.2",
"@esbuild/android-arm64": "0.18.2",
"@esbuild/android-x64": "0.18.2",
"@esbuild/darwin-arm64": "0.18.2",
"@esbuild/darwin-x64": "0.18.2",
"@esbuild/freebsd-arm64": "0.18.2",
"@esbuild/freebsd-x64": "0.18.2",
"@esbuild/linux-arm": "0.18.2",
"@esbuild/linux-arm64": "0.18.2",
"@esbuild/linux-ia32": "0.18.2",
"@esbuild/linux-loong64": "0.18.2",
"@esbuild/linux-mips64el": "0.18.2",
"@esbuild/linux-ppc64": "0.18.2",
"@esbuild/linux-riscv64": "0.18.2",
"@esbuild/linux-s390x": "0.18.2",
"@esbuild/linux-x64": "0.18.2",
"@esbuild/netbsd-x64": "0.18.2",
"@esbuild/openbsd-x64": "0.18.2",
"@esbuild/sunos-x64": "0.18.2",
"@esbuild/win32-arm64": "0.18.2",
"@esbuild/win32-ia32": "0.18.2",
"@esbuild/win32-x64": "0.18.2"
"@esbuild/android-arm": "0.18.1",
"@esbuild/android-arm64": "0.18.1",
"@esbuild/android-x64": "0.18.1",
"@esbuild/darwin-arm64": "0.18.1",
"@esbuild/darwin-x64": "0.18.1",
"@esbuild/freebsd-arm64": "0.18.1",
"@esbuild/freebsd-x64": "0.18.1",
"@esbuild/linux-arm": "0.18.1",
"@esbuild/linux-arm64": "0.18.1",
"@esbuild/linux-ia32": "0.18.1",
"@esbuild/linux-loong64": "0.18.1",
"@esbuild/linux-mips64el": "0.18.1",
"@esbuild/linux-ppc64": "0.18.1",
"@esbuild/linux-riscv64": "0.18.1",
"@esbuild/linux-s390x": "0.18.1",
"@esbuild/linux-x64": "0.18.1",
"@esbuild/netbsd-x64": "0.18.1",
"@esbuild/openbsd-x64": "0.18.1",
"@esbuild/sunos-x64": "0.18.1",
"@esbuild/win32-arm64": "0.18.1",
"@esbuild/win32-ia32": "0.18.1",
"@esbuild/win32-x64": "0.18.1"
}
},
"escalade": {

View File

@ -20,10 +20,9 @@
"@ts-stack/markdown": "^1.4.0",
"@types/node": "^20.3.0",
"a17t": "^0.10.1",
"any-date-parser": "^1.5.4",
"browserslist": "^4.21.7",
"cheerio": "^1.0.0-rc.12",
"esbuild": "^0.18.2",
"esbuild": "^0.18.1",
"fs-cheerio": "^3.0.0",
"inline-source": "^8.0.2",
"jsdom": "^22.1.0",

View File

@ -1,5 +0,0 @@
module github.com/hrfee/jfa-go/scripts/account-gen
go 1.20
require github.com/hrfee/mediabrowser v0.3.8 // indirect

View File

@ -1,2 +0,0 @@
github.com/hrfee/mediabrowser v0.3.8 h1:y0iBCb6jE3QKcsiCJSYva2fFPHRn4UA+sGRzoPuJ/Dk=
github.com/hrfee/mediabrowser v0.3.8/go.mod h1:PnHZbdxmbv1wCVdAQyM7nwPwpVj9fdKx2EcET7sAk+U=

View File

@ -1,122 +0,0 @@
package main
import (
"bufio"
"fmt"
"log"
"math/rand"
"os"
"strconv"
"strings"
"time"
"github.com/hrfee/mediabrowser"
)
var (
names = []string{"Aaron", "Agnes", "Bridget", "Brandon", "Dolly", "Drake", "Elizabeth", "Erika", "Geoff", "Graham", "Haley", "Halsey", "Josie", "John", "Kayleigh", "Luka", "Melissa", "Nasreen", "Paul", "Ross", "Sam", "Talib", "Veronika", "Zaynab"}
)
const (
PASSWORD = "test"
COUNT = 10
)
func main() {
fmt.Println("Usage: account-gen <server> <username> <password, or file://path to file containing password>")
var server, username, password string
reader := bufio.NewReader(os.Stdin)
if len(os.Args) > 1 {
server = os.Args[1]
} else {
fmt.Print("Server Address: ")
server, _ = reader.ReadString('\n')
server = strings.TrimSuffix(server, "\n")
}
if len(os.Args) > 2 {
username = os.Args[2]
} else {
fmt.Print("Username: ")
username, _ = reader.ReadString('\n')
username = strings.TrimSuffix(username, "\n")
}
if len(os.Args) > 3 {
password = os.Args[3]
if strings.HasPrefix(password, "file://") {
p, err := os.ReadFile(strings.TrimPrefix(password, "file://"))
if err != nil {
log.Fatalf("Failed to read password file \"%s\": %+v\n", password, err)
}
password = strings.TrimSuffix(string(p), "\n")
}
} else {
fmt.Print("Password: ")
password, _ = reader.ReadString('\n')
password = strings.TrimSuffix(password, "\n")
}
jf, err := mediabrowser.NewServer(
mediabrowser.JellyfinServer,
server,
"jfa-go-account-gen-script",
"0.0.1",
"testing",
"my_left_foot",
mediabrowser.NewNamedTimeoutHandler("Jellyfin Account Gen", "\""+server+"\"", true),
30,
)
if err != nil {
log.Fatalf("Failed to connect to Jellyin @ \"%s\": %+v\n", server, err)
}
_, status, err := jf.Authenticate(username, password)
if status != 200 || err != nil {
log.Fatalf("Failed to authenticate: %+v\n", err)
}
jfTemp, err := mediabrowser.NewServer(
mediabrowser.JellyfinServer,
server,
"jfa-go-account-gen-script",
"0.0.1",
"fake-activity",
"my_left_foot",
mediabrowser.NewNamedTimeoutHandler("Jellyfin Account Gen", "\""+server+"\"", true),
30,
)
if err != nil {
log.Fatalf("Failed to connect to Jellyin @ \"%s\": %+v\n", server, err)
}
rand.Seed(time.Now().Unix())
for i := 0; i < COUNT; i++ {
name := names[rand.Intn(len(names))] + strconv.Itoa(rand.Intn(100))
user, status, err := jf.NewUser(name, PASSWORD)
if (status != 200 && status != 201 && status != 204) || err != nil {
log.Fatalf("Failed to create user \"%s\" (%d): %+v\n", name, status, err)
}
if rand.Intn(100) > 65 {
user.Policy.IsAdministrator = true
}
if rand.Intn(100) > 80 {
user.Policy.IsDisabled = true
}
status, err = jf.SetPolicy(user.ID, user.Policy)
if (status != 200 && status != 201 && status != 204) || err != nil {
log.Fatalf("Failed to set policy for user \"%s\" (%d): %+v\n", name, status, err)
}
if rand.Intn(100) > 20 {
jfTemp.Authenticate(name, PASSWORD)
}
}
}

View File

@ -3,7 +3,6 @@ import { templateEmail } from "../modules/settings.js";
import { Marked } from "@ts-stack/markdown";
import { stripMarkdown } from "../modules/stripmd.js";
import { DiscordUser, newDiscordSearch } from "../modules/discord.js";
const dateParser = require("any-date-parser");
interface User {
id: string;
@ -39,7 +38,6 @@ interface announcementTemplate {
var addDiscord: (passData: string) => void;
class user implements User {
private _id = "";
private _row: HTMLTableRowElement;
private _check: HTMLInputElement;
private _username: HTMLSpanElement;
@ -68,6 +66,7 @@ class user implements User {
private _userLabel: string;
private _labelEditButton: HTMLElement;
private _accounts_admin: HTMLInputElement
id = "";
private _selected: boolean;
lastNotifyMethod = (): string => {
@ -460,20 +459,6 @@ class user implements User {
this._label.classList.add("chip", "~gray", "mr-2");
}
}
matchesSearch = (query: string): boolean => {
return (
this.name.includes(query) ||
this.label.includes(query) ||
this.discord.includes(query) ||
this.email.includes(query) ||
this.id.includes(query) ||
this.label.includes(query) ||
this.matrix.includes(query) ||
this.telegram.includes(query)
);
}
private _checkEvent = new CustomEvent("accountCheckEvent");
private _uncheckEvent = new CustomEvent("accountUncheckEvent");
@ -690,9 +675,6 @@ class user implements User {
}
});
get id() { return this._id; }
set id(v: string) { this._id = v; }
update = (user: User) => {
this.id = user.id;
@ -755,7 +737,7 @@ export class accountsList {
private _selectAll = document.getElementById("accounts-select-all") as HTMLInputElement;
private _users: { [id: string]: user };
private _ordering: string[] = [];
private _sortedByName: string[] = [];
private _checkCount: number = 0;
private _inSearch = false;
// Whether the enable/disable button should enable or not.
@ -766,14 +748,6 @@ export class accountsList {
private _addUserEmail = this._addUserForm.querySelector("input[type=email]") as HTMLInputElement;
private _addUserPassword = this._addUserForm.querySelector("input[type=password]") as HTMLInputElement;
// Columns for sorting.
private _columns: { [className: string]: Column } = {};
private _activeSortColumn: string;
private _sortingByButton = document.getElementById("accounts-sort-by-field") as HTMLButtonElement;
private _filterArea = document.getElementById("accounts-filter-area");
private _searchOptionsHeader = document.getElementById("accounts-search-options-header");
// Whether the "Extend expiry" is extending or setting an expiry.
private _settingExpiry = false;
@ -794,339 +768,42 @@ export class accountsList {
}
}
}
showHideSearchOptionsHeader = () => {
const sortingBy = !(this._sortingByButton.parentElement.classList.contains("hidden"));
const hasFilters = this._filterArea.textContent != "";
console.log("sortingBy", sortingBy, "hasFilters", hasFilters);
if (sortingBy || hasFilters) {
this._searchOptionsHeader.classList.remove("hidden");
} else {
this._searchOptionsHeader.classList.add("hidden");
search = (query: string): string[] => {
query = query.toLowerCase()
let result: string[] = [];
if (query.includes(":")) { // Support admin:<true/false> and disabled:<true/false>
const words = query.split(" ");
query = "";
for (let word of words) {
if (word.includes(":")) {
const querySplit = word.split(":")
let state = false;
if (querySplit[1] == "true" || querySplit[1] == "yes") {
state = true;
}
for (let id in this._users) {
const user = this._users[id];
let attrib: boolean;
if (querySplit[0] == "admin") { attrib = user.admin; }
else if (querySplit[0] == "disabled") { attrib = user.disabled; }
if (attrib == state) { result.push(id); }
}
} else { query += word + " "; }
}
}
if (query == "") { return result; }
for (let id in this._users) {
const user = this._users[id];
if (user.name.toLowerCase().includes(query)) {
result.push(id);
} else if (user.email.toLowerCase().includes(query)) {
result.push(id);
}
}
return result;
}
private _queries: { [field: string]: { name: string, getter: string, bool: boolean, string: boolean, date: boolean, dependsOnTableHeader?: string, show?: boolean }} = {
"id": {
// We don't use a translation here to circumvent the name substitution feature.
name: "Jellyfin/Emby ID",
getter: "id",
bool: false,
string: true,
date: false
},
"label": {
name: window.lang.strings("label"),
getter: "label",
bool: true,
string: true,
date: false
},
"username": {
name: window.lang.strings("username"),
getter: "name",
bool: false,
string: true,
date: false
},
"name": {
name: window.lang.strings("username"),
getter: "name",
bool: false,
string: true,
date: false,
show: false
},
"admin": {
name: window.lang.strings("admin"),
getter: "admin",
bool: true,
string: false,
date: false
},
"disabled": {
name: window.lang.strings("disabled"),
getter: "disabled",
bool: true,
string: false,
date: false
},
"access-jfa": {
name: window.lang.strings("accessJFA"),
getter: "accounts_admin",
bool: true,
string: false,
date: false,
dependsOnTableHeader: "accounts-header-access-jfa"
},
"email": {
name: window.lang.strings("emailAddress"),
getter: "email",
bool: true,
string: true,
date: false,
dependsOnTableHeader: "accounts-header-email"
},
"telegram": {
name: "Telegram",
getter: "telegram",
bool: true,
string: true,
date: false,
dependsOnTableHeader: "accounts-header-telegram"
},
"matrix": {
name: "Matrix",
getter: "matrix",
bool: true,
string: true,
date: false,
dependsOnTableHeader: "accounts-header-matrix"
},
"discord": {
name: "Discord",
getter: "discord",
bool: true,
string: true,
date: false,
dependsOnTableHeader: "accounts-header-discord"
},
"expiry": {
name: window.lang.strings("expiry"),
getter: "expiry",
bool: true,
string: false,
date: true,
dependsOnTableHeader: "accounts-header-expiry"
},
"last-active": {
name: window.lang.strings("lastActiveTime"),
getter: "last_active",
bool: true,
string: false,
date: true
}
}
search = (query: String): string[] => {
console.log(this._queries);
this._filterArea.textContent = "";
query = query.toLowerCase();
let result: string[] = [...this._ordering];
// console.log("initial:", result);
// const words = query.split(" ");
let words: string[] = [];
// FIXME: SPLIT BY SPACE, UNLESS IN QUOTES
let quoteSymbol = ``;
let queryStart = -1;
let lastQuote = -1;
for (let i = 0; i < query.length; i++) {
if (queryStart == -1 && query[i] != " " && query[i] != `"` && query[i] != `'`) {
queryStart = i;
}
if ((query[i] == `"` || query[i] == `'`) && (quoteSymbol == `` || query[i] == quoteSymbol)) {
if (lastQuote != -1) {
lastQuote = -1;
quoteSymbol = ``;
} else {
lastQuote = i;
quoteSymbol = query[i];
}
}
if (query[i] == " " || i == query.length-1) {
if (lastQuote != -1) {
continue;
} else {
let end = i+1;
if (query[i] == " ") {
end = i;
while (i+1 < query.length && query[i+1] == " ") {
i += 1;
}
}
words.push(query.substring(queryStart, end).replace(/['"]/g, ""));
console.log("pushed", words);
queryStart = -1;
}
}
}
query = "";
for (let word of words) {
if (!word.includes(":")) {
let cachedResult = [...result];
for (let id of cachedResult) {
const u = this._users[id];
if (!u.matchesSearch(word)) {
result.splice(result.indexOf(id), 1);
}
}
continue;
}
const split = [word.substring(0, word.indexOf(":")), word.substring(word.indexOf(":")+1)];
if (!(split[0] in this._queries)) continue;
const queryFormat = this._queries[split[0]];
if (queryFormat.bool) {
let isBool = false;
let boolState = false;
if (split[1] == "true" || split[1] == "yes" || split[1] == "t" || split[1] == "y") {
isBool = true;
boolState = true;
} else if (split[1] == "false" || split[1] == "no" || split[1] == "f" || split[1] == "n") {
isBool = true;
boolState = false;
}
if (isBool) {
// FIXME: Generate filter card for each filter class
const filterCard = document.createElement("span");
filterCard.ariaLabel = window.lang.strings("clickToRemoveFilter");
filterCard.classList.add("button", "~" + (boolState ? "positive" : "critical"), "@high", "center", "m-2");
filterCard.innerHTML = `
<span class="font-bold mr-2">${queryFormat.name}</span>
<i class="text-2xl ri-${boolState? "checkbox" : "close"}-circle-fill"></i>
`;
filterCard.addEventListener("click", () => {
for (let quote of [`"`, `'`, ``]) {
this._search.value = this._search.value.replace(split[0] + ":" + quote + split[1] + quote, "");
}
this._search.oninput((null as Event));
})
this._filterArea.appendChild(filterCard);
// console.log("is bool, state", boolState);
// So removing elements doesn't affect us
let cachedResult = [...result];
for (let id of cachedResult) {
const u = this._users[id];
const value = Object.getOwnPropertyDescriptor(user.prototype, queryFormat.getter).get.call(u);
// console.log("got", queryFormat.getter + ":", value);
// Remove from result if not matching query
if (!((value && boolState) || (!value && !boolState))) {
// console.log("not matching, result is", result);
result.splice(result.indexOf(id), 1);
}
}
continue
}
}
if (queryFormat.string) {
const filterCard = document.createElement("span");
filterCard.ariaLabel = window.lang.strings("clickToRemoveFilter");
filterCard.classList.add("button", "~neutral", "@low", "center", "m-2", "h-full");
filterCard.innerHTML = `
<span class="font-bold mr-2">${queryFormat.name}:</span> "${split[1]}"
`;
filterCard.addEventListener("click", () => {
for (let quote of [`"`, `'`, ``]) {
let regex = new RegExp(split[0] + ":" + quote + split[1] + quote, "ig");
this._search.value = this._search.value.replace(regex, "");
}
this._search.oninput((null as Event));
})
this._filterArea.appendChild(filterCard);
let cachedResult = [...result];
for (let id of cachedResult) {
const u = this._users[id];
const value = Object.getOwnPropertyDescriptor(user.prototype, queryFormat.getter).get.call(u);
if (!(value.includes(split[1]))) {
result.splice(result.indexOf(id), 1);
}
}
continue;
}
if (queryFormat.date) {
// -1 = Before, 0 = On, 1 = After, 2 = No symbol, assume 0
let compareType = (split[1][0] == ">") ? 1 : ((split[1][0] == "<") ? -1 : ((split[1][0] == "=") ? 0 : 2));
let unmodifiedValue = split[1];
if (compareType != 2) {
split[1] = split[1].substring(1);
}
if (compareType == 2) compareType = 0;
let attempt: { year?: number, month?: number, day?: number, hour?: number, minute?: number } = dateParser.attempt(split[1]);
// Month in Date objects is 0-based, so make our parsed date that way too
if ("month" in attempt) attempt["month"] -= 1;
let date: Date = (Date as any).fromString(split[1]) as Date;
console.log("Read", attempt, "and", date);
if ("invalid" in (date as any)) continue;
const filterCard = document.createElement("span");
filterCard.ariaLabel = window.lang.strings("clickToRemoveFilter");
filterCard.classList.add("button", "~neutral", "@low", "center", "m-2", "h-full");
filterCard.innerHTML = `
<span class="font-bold mr-2">${queryFormat.name}:</span> ${(compareType == 1) ? window.lang.strings("after")+" " : ((compareType == -1) ? window.lang.strings("before")+" " : "")}${split[1]}
`;
filterCard.addEventListener("click", () => {
for (let quote of [`"`, `'`, ``]) {
let regex = new RegExp(split[0] + ":" + quote + unmodifiedValue + quote, "ig");
this._search.value = this._search.value.replace(regex, "");
}
this._search.oninput((null as Event));
})
this._filterArea.appendChild(filterCard);
let cachedResult = [...result];
for (let id of cachedResult) {
const u = this._users[id];
const unixValue = Object.getOwnPropertyDescriptor(user.prototype, queryFormat.getter).get.call(u);
if (unixValue == 0) {
result.splice(result.indexOf(id), 1);
continue;
}
let value = new Date(unixValue*1000);
const getterPairs: [string, () => number][] = [["year", Date.prototype.getFullYear], ["month", Date.prototype.getMonth], ["day", Date.prototype.getDate], ["hour", Date.prototype.getHours], ["minute", Date.prototype.getMinutes]];
// When doing > or < <time> with no date, we need to ignore the rest of the Date object
if (compareType != 0 && Object.keys(attempt).length == 2 && "hour" in attempt && "minute" in attempt) {
const temp = new Date(date.valueOf());
temp.setHours(value.getHours(), value.getMinutes());
value = temp;
console.log("just hours/minutes workaround, value set to", value);
}
let match = true;
if (compareType == 0) {
for (let pair of getterPairs) {
if (pair[0] in attempt) {
if (compareType == 0 && attempt[pair[0]] != pair[1].call(value)) {
match = false;
break;
}
}
}
} else if (compareType == -1) {
match = (value < date);
} else if (compareType == 1) {
match = (value > date);
}
if (!match) {
result.splice(result.indexOf(id), 1);
}
}
}
}
return result
};
get selectAll(): boolean { return this._selectAll.checked; }
set selectAll(state: boolean) {
let count = 0;
@ -1144,6 +821,36 @@ export class accountsList {
add = (u: User) => {
let domAccount = new user(u);
this._users[u.id] = domAccount;
this.unhide(u.id);
}
unhide = (id: string) => {
const keys = Object.keys(this._users);
if (keys.length == 0) {
this._table.appendChild(this._users[id].asElement());
return;
}
this._sortedByName = keys.sort((a, b) => this._users[a].name.localeCompare(this._users[b].name));
let index = this._sortedByName.indexOf(id)+1;
if (index == this._sortedByName.length-1) {
this._table.appendChild(this._users[id].asElement());
return;
}
while (index < this._sortedByName.length) {
if (this._table.contains(this._users[this._sortedByName[index]].asElement())) {
this._table.insertBefore(this._users[id].asElement(), this._users[this._sortedByName[index]].asElement());
return;
}
index++;
}
this._table.appendChild(this._users[id].asElement());
}
hide = (id: string) => {
const el = this._users[id].asElement();
if (this._table.contains(el)) {
this._table.removeChild(this._users[id].asElement());
}
}
private _checkCheckCount = () => {
@ -1155,10 +862,10 @@ export class accountsList {
this._modifySettings.classList.add("unfocused");
this._deleteUser.classList.add("unfocused");
if (window.emailEnabled || window.telegramEnabled) {
this._announceButton.parentElement.classList.add("unfocused");
this._announceButton.classList.add("unfocused");
}
this._extendExpiry.classList.add("unfocused");
this._disableEnable.parentElement.classList.add("unfocused");
this._disableEnable.classList.add("unfocused");
this._sendPWR.classList.add("unfocused");
} else {
let visibleCount = 0;
@ -1178,7 +885,7 @@ export class accountsList {
this._deleteUser.classList.remove("unfocused");
this._deleteUser.textContent = window.lang.quantity("deleteUser", list.length);
if (window.emailEnabled || window.telegramEnabled) {
this._announceButton.parentElement.classList.remove("unfocused");
this._announceButton.classList.remove("unfocused");
}
let anyNonExpiries = list.length == 0 ? true : false;
let allNonExpiries = true;
@ -1196,7 +903,7 @@ export class accountsList {
}
if (showDisableEnable && this._users[id].disabled != this._shouldEnable) {
showDisableEnable = false;
this._disableEnable.parentElement.classList.add("unfocused");
this._disableEnable.classList.add("unfocused");
}
if (!showDisableEnable && anyNonExpiries) { break; }
if (!this._users[id].lastNotifyMethod()) {
@ -1232,7 +939,7 @@ export class accountsList {
this._disableEnable.classList.add("~warning");
this._disableEnable.classList.remove("~positive");
}
this._disableEnable.parentElement.classList.remove("unfocused");
this._disableEnable.classList.remove("unfocused");
this._disableEnable.textContent = message;
}
}
@ -1720,18 +1427,6 @@ export class accountsList {
}
window.modals.extendExpiry.show();
}
setVisibility = (users: string[], visible: boolean) => {
this._table.textContent = "";
for (let id of this._ordering) {
if (visible && users.indexOf(id) != -1) {
this._table.appendChild(this._users[id].asElement());
} else if (!visible && users.indexOf(id) == -1) {
this._table.appendChild(this._users[id].asElement());
}
}
}
constructor() {
this._populateNumbers();
@ -1781,13 +1476,13 @@ export class accountsList {
this._deleteUser.classList.add("unfocused");
this._announceButton.onclick = this.announce;
this._announceButton.parentElement.classList.add("unfocused");
this._announceButton.classList.add("unfocused");
this._extendExpiry.onclick = () => { this.extendExpiry(); };
this._extendExpiry.classList.add("unfocused");
this._disableEnable.onclick = this.enableDisableUsers;
this._disableEnable.parentElement.classList.add("unfocused");
this._disableEnable.classList.add("unfocused");
this._enableExpiry.onclick = () => { this.extendExpiry(true); };
this._enableExpiryNotify.onchange = () => {
@ -1813,26 +1508,35 @@ export class accountsList {
this._deleteNotify.checked = false;
}*/
const onchange = () => {
const setVisibility = (users: string[], visible: boolean) => {
for (let id in this._users) {
if (users.indexOf(id) != -1) {
if (visible) {
this.unhide(id);
} else {
this.hide(id);
}
} else {
if (visible) {
this.hide(id);
} else {
this.unhide(id);
}
}
}
}
this._search.oninput = () => {
const query = this._search.value;
if (!query) {
// this.setVisibility(this._ordering, true);
setVisibility(Object.keys(this._users), true);
this._inSearch = false;
} else {
this._inSearch = true;
// this.setVisibility(this.search(query), true);
setVisibility(this.search(query), true);
}
this.setVisibility(this.search(query), true);
this._checkCheckCount();
this.showHideSearchOptionsHeader();
};
this._search.oninput = onchange;
const clearSearchButton = document.getElementById("accounts-search-clear") as HTMLSpanElement;
clearSearchButton.addEventListener("click", () => {
this._search.value = "";
onchange();
});
this._announceTextarea.onkeyup = this.loadPreview;
addDiscord = newDiscordSearch(window.lang.strings("linkDiscord"), window.lang.strings("searchDiscordUser"), window.lang.strings("add"), (user: DiscordUser, id: string) => {
@ -1855,123 +1559,6 @@ export class accountsList {
insertText(this._announceTextarea, announceVarUsername.children[0].textContent);
this.loadPreview();
};
const headerNames: string[] = ["username", "access-jfa", "email", "telegram", "matrix", "discord", "expiry", "last-active"];
const headerGetters: string[] = ["name", "accounts_admin", "email", "telegram", "matrix", "discord", "expiry", "last_active"];
for (let i = 0; i < headerNames.length; i++) {
const header: HTMLTableHeaderCellElement = document.querySelector(".accounts-header-" + headerNames[i]) as HTMLTableHeaderCellElement;
if (header !== null) {
this._columns[header.className] = new Column(header, Object.getOwnPropertyDescriptor(user.prototype, headerGetters[i]).get);
}
}
// Start off sorting by Name
const defaultSort = () => {
this._activeSortColumn = document.getElementsByClassName("accounts-header-" + headerNames[0])[0].className;
document.dispatchEvent(new CustomEvent("header-click", { detail: this._activeSortColumn }));
this._columns[this._activeSortColumn].ascending = true;
this._columns[this._activeSortColumn].hideIcon();
this._sortingByButton.parentElement.classList.add("hidden");
this.showHideSearchOptionsHeader();
};
this._sortingByButton.parentElement.addEventListener("click", defaultSort);
document.addEventListener("header-click", (event: CustomEvent) => {
this._ordering = this._columns[event.detail].sort(this._users);
this._activeSortColumn = event.detail;
this._sortingByButton.innerHTML = this._columns[event.detail].buttonContent;
this._sortingByButton.parentElement.classList.remove("hidden");
// console.log("ordering by", event.detail, ": ", this._ordering);
if (!(this._inSearch)) {
this.setVisibility(this._ordering, true);
} else {
this.setVisibility(this.search(this._search.value), true);
}
this.showHideSearchOptionsHeader();
});
defaultSort();
this.showHideSearchOptionsHeader();
const filterList = document.getElementById("accounts-filter-list");
const fillInFilter = (name: string, value: string, offset?: number) => {
this._search.value = name + ":" + value + " " + this._search.value;
this._search.focus();
let newPos = name.length + 1 + value.length;
if (typeof offset !== 'undefined')
newPos += offset;
this._search.setSelectionRange(newPos, newPos);
this._search.oninput(null as any);
};
// Generate filter buttons
for (let queryName of Object.keys(this._queries)) {
const query = this._queries[queryName];
if ("show" in query && !query.show) continue;
if ("dependsOnTableHeader" in query && query.dependsOnTableHeader) {
const el = document.querySelector("."+query.dependsOnTableHeader);
if (el === null) continue;
}
const container = document.createElement("span") as HTMLSpanElement;
container.classList.add("button", "button-xl", "~neutral", "@low", "mb-1", "mr-2");
container.innerHTML = `<span class="mr-2">${query.name}</span>`;
if (query.bool) {
const pos = document.createElement("button") as HTMLButtonElement;
pos.type = "button";
pos.ariaLabel = `Filter by "${query.name}": True`;
pos.classList.add("button", "~positive", "ml-2");
pos.innerHTML = `<i class="ri-checkbox-circle-fill"></i>`;
pos.addEventListener("click", () => fillInFilter(queryName, "true"));
const neg = document.createElement("button") as HTMLButtonElement;
neg.type = "button";
neg.ariaLabel = `Filter by "${query.name}": False`;
neg.classList.add("button", "~critical", "ml-2");
neg.innerHTML = `<i class="ri-close-circle-fill"></i>`;
neg.addEventListener("click", () => fillInFilter(queryName, "false"));
container.appendChild(pos);
container.appendChild(neg);
}
if (query.string) {
const button = document.createElement("button") as HTMLButtonElement;
button.type = "button";
button.classList.add("button", "~urge", "ml-2");
button.innerHTML = `<i class="ri-equal-line mr-2"></i>${window.lang.strings("matchText")}`;
// Position cursor between quotes
button.addEventListener("click", () => fillInFilter(queryName, `""`, -1));
container.appendChild(button);
}
if (query.date) {
const onDate = document.createElement("button") as HTMLButtonElement;
onDate.type = "button";
onDate.classList.add("button", "~urge", "ml-2");
onDate.innerHTML = `<i class="ri-calendar-check-line mr-2"></i>On Date`;
onDate.addEventListener("click", () => fillInFilter(queryName, `"="`, -1));
const beforeDate = document.createElement("button") as HTMLButtonElement;
beforeDate.type = "button";
beforeDate.classList.add("button", "~urge", "ml-2");
beforeDate.innerHTML = `<i class="ri-calendar-check-line mr-2"></i>Before Date`;
beforeDate.addEventListener("click", () => fillInFilter(queryName, `"<"`, -1));
const afterDate = document.createElement("button") as HTMLButtonElement;
afterDate.type = "button";
afterDate.classList.add("button", "~urge", "ml-2");
afterDate.innerHTML = `<i class="ri-calendar-check-line mr-2"></i>After Date`;
afterDate.addEventListener("click", () => fillInFilter(queryName, `">"`, -1));
container.appendChild(onDate);
container.appendChild(beforeDate);
container.appendChild(afterDate);
}
filterList.appendChild(container);
}
}
reload = () => {
@ -1992,98 +1579,9 @@ export class accountsList {
this._users[id].remove();
delete this._users[id];
}
// console.log("reload, so sorting by", this._activeSortColumn);
this._ordering = this._columns[this._activeSortColumn].sort(this._users);
if (!(this._inSearch)) {
this.setVisibility(this._ordering, true);
} else {
this.setVisibility(this.search(this._search.value), true);
}
this._checkCheckCount();
}
});
this.loadTemplates();
}
}
type GetterReturnType = Boolean | boolean | String | Number | number;
type Getter = () => GetterReturnType;
// When a column is clicked, it broadcasts it's name and ordering to be picked up and stored by accountsList
// When list is refreshed, accountList calls method of the specific Column and re-orders accordingly.
// Listen for broadcast event from others, check its not us by comparing the header className in the message, then hide the arrow icon
class Column {
private _header: HTMLTableHeaderCellElement;
private _headerContent: string;
private _getter: Getter;
private _ascending: boolean;
private _active: boolean;
constructor(header: HTMLTableHeaderCellElement, getter: Getter) {
this._header = header;
this._headerContent = this._header.textContent;
this._getter = getter;
this._ascending = true;
this._active = false;
this._header.addEventListener("click", () => {
// If we are the active sort column, a click means to switch between ascending/descending.
if (this._active) {
this._ascending = !this._ascending;
console.log("was already active, switching direction to", this._ascending ? "ascending" : "descending");
} else {
console.log("wasn't active keeping direction as", this._ascending ? "ascending" : "descending");
}
this._active = true;
this._header.setAttribute("aria-sort", this._headerContent);
this.updateHeader();
document.dispatchEvent(new CustomEvent("header-click", { detail: this._header.className }));
});
document.addEventListener("header-click", (event: CustomEvent) => {
if (event.detail != this._header.className) {
this._active = false;
this._header.removeAttribute("aria-sort");
this.hideIcon();
}
});
}
hideIcon = () => {
this._header.textContent = this._headerContent;
}
updateHeader = () => {
this._header.innerHTML = `
<span class="">${this._headerContent}</span>
<i class="ri-arrow-${this._ascending? "up" : "down"}-s-line" aria-hidden="true"></i>
`;
}
// Returns the inner HTML to show in the "Sorting By" button.
get buttonContent() {
return `<span class="font-bold">` + window.lang.strings("sortingBy") + ": " + `</span>` + this._headerContent;
}
get ascending() { return this._ascending; }
set ascending(v: boolean) {
this._ascending = v;
if (!this._active) return;
this.updateHeader();
this._header.setAttribute("aria-sort", this._headerContent);
document.dispatchEvent(new CustomEvent("header-click", { detail: this._header.className }));
}
// Sorts the user list. previouslyActive is whether this column was previously sorted by, indicating that the direction should change.
sort = (users: { [id: string]: user }): string[] => {
let userIDs = Object.keys(users);
userIDs.sort((a: string, b: string): number => {
const av: GetterReturnType = this._getter.call(users[a]);
const bv: GetterReturnType = this._getter.call(users[b]);
if (av < bv) return this._ascending ? -1 : 1;
if (av > bv) return this._ascending ? 1 : -1;
return 0;
});
return userIDs;
}
}