Compare commits

..

6 Commits

Author SHA1 Message Date
Wayne
3a6800bc98 Merge branch 'main' into docs 2025-09-06 18:06:34 +03:00
Wayne
413188dc81 Code formatting 2025-09-06 18:04:53 +03:00
Wayne
a1239e6303 Resolve conflict 2025-09-06 17:56:09 +03:00
Wayne
adb548e184 Merge branch 'main' into docs 2025-09-06 17:55:35 +03:00
Wayne
f1c33b548e update rate limiting docs 2025-09-06 17:50:20 +03:00
Wayne
1b59af64c6 Adding rate limiting docs 2025-09-04 17:43:27 +03:00
11 changed files with 533 additions and 231 deletions

1
.github/FUNDING.yml vendored
View File

@@ -1 +0,0 @@
github: [wayneshn]

View File

@@ -1,6 +1,5 @@
{
"name": "open-archiver",
"version": "0.3.1",
"private": true,
"scripts": {
"dev": "dotenv -- pnpm --filter \"./packages/*\" --parallel dev",

View File

@@ -59,7 +59,7 @@
"reflect-metadata": "^0.2.2",
"sqlite3": "^5.1.7",
"tsconfig-paths": "^4.2.0",
"xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz",
"xlsx": "^0.18.5",
"yauzl": "^3.2.0",
"zod": "^4.1.5"
},
@@ -74,6 +74,7 @@
"@types/multer": "^2.0.0",
"@types/node": "^24.0.12",
"@types/yauzl": "^2.10.3",
"bull-board": "^2.1.3",
"ts-node-dev": "^2.0.0",
"typescript": "^5.8.3"
}

View File

@@ -15,14 +15,13 @@
"dependencies": {
"@iconify/svelte": "^5.0.1",
"@open-archiver/types": "workspace:*",
"@sveltejs/kit": "^2.38.1",
"@sveltejs/kit": "^2.16.0",
"bits-ui": "^2.8.10",
"clsx": "^2.1.1",
"d3-shape": "^3.2.0",
"jose": "^6.0.1",
"lucide-svelte": "^0.525.0",
"postal-mime": "^2.4.4",
"semver": "^7.7.2",
"svelte-persisted-store": "^0.12.0",
"sveltekit-i18n": "^2.4.2",
"tailwind-merge": "^3.3.1",
@@ -36,7 +35,6 @@
"@sveltejs/vite-plugin-svelte": "^5.0.0",
"@tailwindcss/vite": "^4.0.0",
"@types/d3-shape": "^3.1.7",
"@types/semver": "^7.7.1",
"dotenv": "^17.2.0",
"layerchart": "2.0.0-next.27",
"mode-watcher": "^1.1.0",

View File

@@ -52,16 +52,16 @@
<div class="mt-2 rounded-md border bg-white p-4">
{#if isLoading}
<p>{$t('app.components.email_preview.loading')}</p>
<p>{$t('components.email_preview.loading')}</p>
{:else if emailHtml}
<iframe
title={$t('app.archive.email_preview')}
title={$t('archive.email_preview')}
srcdoc={emailHtml()}
class="h-[600px] w-full border-none"
></iframe>
{:else if raw}
<p>{$t('app.components.email_preview.render_error')}</p>
<p>{$t('components.email_preview.render_error')}</p>
{:else}
<p class="text-gray-500">{$t('app.components.email_preview.not_available')}</p>
<p class="text-gray-500">{$t('components.email_preview.not_available')}</p>
{/if}
</div>

View File

@@ -1,39 +1,18 @@
<script lang="ts">
import { t } from '$lib/translations';
import * as Alert from '$lib/components/ui/alert';
import { Info } from 'lucide-svelte';
export let currentVersion: string;
export let newVersionInfo: { version: string; description: string; url: string } | null = null;
</script>
<footer class="bg-muted py-6 md:py-0">
<div class="container mx-auto flex flex-col items-center justify-center gap-4 py-8 md:flex-row">
<div
class="container mx-auto flex flex-col items-center justify-center gap-4 md:h-24 md:flex-row"
>
<div class="flex flex-col items-center gap-2">
{#if newVersionInfo}
<Alert.Root>
<Alert.Title class="flex items-center gap-2">
<Info class="h-4 w-4" />
{$t('app.components.footer.new_version_available')}
<a
href={newVersionInfo.url}
target="_blank"
class=" text-muted-foreground underline"
>
{newVersionInfo.description}
</a>
</Alert.Title>
</Alert.Root>
{/if}
<p class="text-balance text-center text-xs font-medium leading-loose">
© {new Date().getFullYear()}
<a href="https://openarchiver.com/" target="_blank">Open Archiver</a>. {$t(
'app.components.footer.all_rights_reserved'
)}
</p>
<p class="text-balance text-center text-xs font-medium leading-loose">
Version: {currentVersion}
</p>
</div>
</div>
</footer>

View File

@@ -163,8 +163,7 @@
"not_available": "Raw .eml file not available for this email."
},
"footer": {
"all_rights_reserved": "All rights reserved.",
"new_version_available": "New version available"
"all_rights_reserved": "All rights reserved."
},
"ingestion_source_form": {
"provider_generic_imap": "Generic IMAP",

View File

@@ -1,17 +1,17 @@
{
"app": {
"auth": {
"login": "Accedi",
"login": "Accesso",
"login_tip": "Inserisci la tua email qui sotto per accedere al tuo account.",
"email": "Email",
"password": "Password"
},
"common": {
"working": "In corso"
"working": "In lavorazione"
},
"archive": {
"title": "Archivio",
"no_subject": "Nessun Oggetto",
"no_subject": "Nessun oggetto",
"from": "Da",
"sent": "Inviato",
"recipients": "Destinatari",
@@ -20,27 +20,27 @@
"folder": "Cartella",
"tags": "Tag",
"size": "Dimensione",
"email_preview": "Anteprima Email",
"email_preview": "Anteprima email",
"attachments": "Allegati",
"download": "Scarica",
"actions": "Azioni",
"download_eml": "Scarica Email (.eml)",
"delete_email": "Elimina Email",
"email_thread": "Thread Email",
"download_eml": "Scarica email (.eml)",
"delete_email": "Elimina email",
"email_thread": "Thread email",
"delete_confirmation_title": "Sei sicuro di voler eliminare questa email?",
"delete_confirmation_description": "Questa azione non può essere annullata e rimuoverà permanentemente l'email e i suoi allegati.",
"delete_confirmation_description": "Questa azione non può essere annullata ed eliminerà permanentemente l'email e i suoi allegati.",
"deleting": "Eliminazione in corso",
"confirm": "Conferma",
"cancel": "Annulla",
"not_found": "Email non trovata."
},
"ingestions": {
"title": "Sorgenti di Ingestione",
"ingestion_sources": "Sorgenti di Ingestione",
"bulk_actions": "Azioni di Massa",
"force_sync": "Forza Sincronizzazione",
"title": "Fonti di ingestione",
"ingestion_sources": "Fonti di ingestione",
"bulk_actions": "Azioni di massa",
"force_sync": "Forza sincronizzazione",
"delete": "Elimina",
"create_new": "Crea Nuovo",
"create_new": "Crea nuovo",
"name": "Nome",
"provider": "Provider",
"status": "Stato",
@@ -52,28 +52,28 @@
"open_menu": "Apri menu",
"edit": "Modifica",
"create": "Crea",
"ingestion_source": "Sorgente di Ingestione",
"edit_description": "Apporta modifiche alla tua sorgente di ingestione qui.",
"create_description": "Aggiungi una nuova sorgente di ingestione per iniziare ad archiviare le email.",
"ingestion_source": "Fonte di ingestione",
"edit_description": "Apporta modifiche alla tua fonte di ingestione qui.",
"create_description": "Aggiungi una nuova fonte di ingestione per iniziare ad archiviare le email.",
"read": "Leggi",
"docs_here": "documenti qui",
"delete_confirmation_title": "Sei sicuro di voler eliminare questa ingestione?",
"delete_confirmation_description": "Questo cancellerà tutte le email archiviate, gli allegati, l'indicizzazione e i file associati a questa ingestione. Se vuoi solo interrompere la sincronizzazione di nuove email, puoi mettere in pausa l'ingestione.",
"delete_confirmation_description": "Questo eliminerà tutte le email archiviate, gli allegati, l'indicizzazione e i file associati a questa ingestione. Se desideri solo interrompere la sincronizzazione di nuove email, puoi invece mettere in pausa l'ingestione.",
"deleting": "Eliminazione in corso",
"confirm": "Conferma",
"cancel": "Annulla",
"bulk_delete_confirmation_title": "Sei sicuro di voler eliminare {{count}} ingestioni selezionate?",
"bulk_delete_confirmation_description": "Questo cancellerà tutte le email archiviate, gli allegati, l'indicizzazione e i file associati a queste ingestioni. Se vuoi solo interrompere la sincronizzazione di nuove email, puoi mettere in pausa le ingestioni."
"bulk_delete_confirmation_description": "Questo eliminerà tutte le email archiviate, gli allegati, l'indicizzazione e i file associati a queste ingestioni. Se desideri solo interrompere la sincronizzazione di nuove email, puoi invece mettere in pausa le ingestioni."
},
"search": {
"title": "Ricerca",
"description": "Ricerca email archiviate.",
"email_search": "Ricerca Email",
"title": "Cerca",
"description": "Cerca email archiviate.",
"email_search": "Ricerca email",
"placeholder": "Cerca per parola chiave, mittente, destinatario...",
"search_button": "Cerca",
"search_options": "Opzioni di ricerca",
"strategy_fuzzy": "Approssimativa",
"strategy_verbatim": "Esatta",
"strategy_fuzzy": "Fuzzy",
"strategy_verbatim": "Verbatim",
"strategy_frequency": "Frequenza",
"select_strategy": "Seleziona una strategia",
"error": "Errore",
@@ -87,18 +87,18 @@
"next": "Succ"
},
"roles": {
"title": "Gestione Ruoli",
"role_management": "Gestione Ruoli",
"create_new": "Crea Nuovo",
"title": "Gestione ruoli",
"role_management": "Gestione ruoli",
"create_new": "Crea nuovo",
"name": "Nome",
"created_at": "Creato il",
"actions": "Azioni",
"open_menu": "Apri menu",
"view_policy": "Visualizza Policy",
"view_policy": "Visualizza policy",
"edit": "Modifica",
"delete": "Elimina",
"no_roles_found": "Nessun ruolo trovato.",
"role_policy": "Policy Ruolo",
"role_policy": "Policy ruolo",
"viewing_policy_for_role": "Visualizzazione policy per il ruolo: {{name}}",
"create": "Crea",
"role": "Ruolo",
@@ -111,22 +111,22 @@
"cancel": "Annulla"
},
"system_settings": {
"title": "Impostazioni di Sistema",
"system_settings": "Impostazioni di Sistema",
"title": "Impostazioni di sistema",
"system_settings": "Impostazioni di sistema",
"description": "Gestisci le impostazioni globali dell'applicazione.",
"language": "Lingua",
"default_theme": "Tema predefinito",
"light": "Chiaro",
"dark": "Scuro",
"system": "Sistema",
"support_email": "Email di Supporto",
"saving": "Salvataggio in corso",
"save_changes": "Salva Modifiche"
"support_email": "Email di supporto",
"saving": "Salvataggio",
"save_changes": "Salva modifiche"
},
"users": {
"title": "Gestione Utenti",
"user_management": "Gestione Utenti",
"create_new": "Crea Nuovo",
"title": "Gestione utenti",
"user_management": "Gestione utenti",
"create_new": "Crea nuovo",
"name": "Nome",
"email": "Email",
"role": "Ruolo",
@@ -146,10 +146,33 @@
"confirm": "Conferma",
"cancel": "Annulla"
},
"setup": {
"title": "Configurazione",
"description": "Configura l'account amministratore iniziale per Open Archiver.",
"welcome": "Benvenuto",
"create_admin_account": "Crea il primo account amministratore per iniziare.",
"first_name": "Nome",
"last_name": "Cognome",
"email": "Email",
"password": "Password",
"creating_account": "Creazione account",
"create_account": "Crea account"
},
"layout": {
"dashboard": "Dashboard",
"ingestions": "Ingestioni",
"archived_emails": "Email archiviate",
"search": "Cerca",
"settings": "Impostazioni",
"system": "Sistema",
"users": "Utenti",
"roles": "Ruoli",
"logout": "Esci"
},
"components": {
"charts": {
"emails_ingested": "Email Acquisite",
"storage_used": "Spazio di Archiviazione Utilizzato",
"emails_ingested": "Email ingerite",
"storage_used": "Spazio di archiviazione utilizzato",
"emails": "Email"
},
"common": {
@@ -159,36 +182,35 @@
},
"email_preview": {
"loading": "Caricamento anteprima email...",
"render_error": "Impossibile renderizzare l'anteprima dell'email.",
"not_available": "File .eml grezzo non disponibile per questa email."
"render_error": "Impossibile visualizzare l'anteprima dell'email.",
"not_available": "File .eml non disponibile per questa email."
},
"footer": {
"all_rights_reserved": "Tutti i diritti riservati."
},
"ingestion_source_form": {
"provider_generic_imap": "IMAP Generico",
"provider_generic_imap": "IMAP generico",
"provider_google_workspace": "Google Workspace",
"provider_microsoft_365": "Microsoft 365",
"provider_pst_import": "Importazione PST",
"provider_eml_import": "Importazione EML",
"select_provider": "Seleziona un provider",
"service_account_key": "Chiave Account di Servizio (JSON)",
"service_account_key_placeholder": "Incolla il contenuto JSON della chiave del tuo account di servizio",
"impersonated_admin_email": "Email dell'Amministratore Impersonato",
"client_id": "ID Applicazione (Client)",
"client_secret": "Valore Segreto Client",
"client_secret_placeholder": "Inserisci il Valore segreto, non l'ID Segreto",
"tenant_id": "ID Directory (Tenant)",
"service_account_key": "Chiave account di servizio (JSON)",
"service_account_key_placeholder": "Incolla il contenuto JSON della tua chiave account di servizio",
"impersonated_admin_email": "Email amministratore impersonata",
"client_id": "ID applicazione (client)",
"client_secret": "Valore segreto client",
"client_secret_placeholder": "Inserisci il valore segreto, non l'ID segreto",
"tenant_id": "ID directory (tenant)",
"host": "Host",
"port": "Porta",
"username": "Nome Utente",
"username": "Nome utente",
"use_tls": "Usa TLS",
"allow_insecure_cert": "Consenti certificato non sicuro",
"pst_file": "File PST",
"eml_file": "File EML",
"heads_up": "Attenzione!",
"org_wide_warning": "Si prega di notare che questa è un'operazione a livello di organizzazione. Questo tipo di ingestione importerà e indicizzerà <b>tutte</b> le caselle di posta elettronica nella tua organizzazione. Se vuoi importare solo caselle di posta elettronica specifiche, usa il connettore IMAP.",
"upload_failed": "Caricamento Fallito, riprova"
"org_wide_warning": "Si prega di notare che questa è un'operazione a livello di organizzazione. Questo tipo di ingestione importerà e indicizzerà <b>tutte</b> le caselle di posta elettronica della tua organizzazione. Se desideri importare solo caselle di posta elettronica specifiche, utilizza il connettore IMAP.",
"upload_failed": "Caricamento non riuscito, riprova"
},
"role_form": {
"policies_json": "Policy (JSON)",
@@ -201,61 +223,28 @@
"select_role": "Seleziona un ruolo"
}
},
"setup": {
"title": "Configurazione",
"description": "Configura l'account amministratore iniziale per Open Archiver.",
"welcome": "Benvenuto",
"create_admin_account": "Crea il primo account amministratore per iniziare.",
"first_name": "Nome",
"last_name": "Cognome",
"email": "Email",
"password": "Password",
"creating_account": "Creazione Account",
"create_account": "Crea Account"
},
"layout": {
"dashboard": "Dashboard",
"ingestions": "Ingestioni",
"archived_emails": "Email archiviate",
"search": "Ricerca",
"settings": "Impostazioni",
"system": "Sistema",
"users": "Utenti",
"roles": "Ruoli",
"api_keys": "Chiavi API",
"logout": "Esci"
},
"api_keys_page": {
"title": "Chiavi API",
"header": "Chiavi API",
"generate_new_key": "Genera Nuova Chiave",
"name": "Nome",
"key": "Chiave",
"expires_at": "Scade il",
"created_at": "Creato il",
"actions": "Azioni",
"delete": "Elimina",
"no_keys_found": "Nessuna chiave API trovata.",
"generate_modal_title": "Genera Nuova Chiave API",
"generate_modal_description": "Fornisci un nome e una scadenza per la tua nuova chiave API.",
"expires_in": "Scade Tra",
"select_expiration": "Seleziona una scadenza",
"30_days": "30 Giorni",
"60_days": "60 Giorni",
"6_months": "6 Mesi",
"12_months": "12 Mesi",
"24_months": "24 Mesi",
"generate": "Genera",
"new_api_key": "Nuova Chiave API",
"failed_to_delete": "Impossibile eliminare la chiave API",
"api_key_deleted": "Chiave API eliminata",
"generated_title": "Chiave API Generata",
"generated_message": "La tua chiave API è stata generata, per favore copiala e salvala in un luogo sicuro. Questa chiave verrà mostrata solo una volta."
"dashboard_page": {
"title": "Dashboard",
"meta_description": "Panoramica del tuo archivio email.",
"header": "Dashboard",
"create_ingestion": "Crea un'ingestione",
"no_ingestion_header": "Non hai alcuna fonte di ingestione configurata.",
"no_ingestion_text": "Aggiungi una fonte di ingestione per iniziare ad archiviare le tue caselle di posta.",
"total_emails_archived": "Email totali archiviate",
"total_storage_used": "Spazio di archiviazione totale utilizzato",
"failed_ingestions": "Ingestioni non riuscite (ultimi 7 giorni)",
"ingestion_history": "Cronologia ingestioni",
"no_ingestion_history": "Nessuna cronologia di ingestione disponibile.",
"storage_by_source": "Archiviazione per fonte di ingestione",
"no_ingestion_sources": "Nessuna fonte di ingestione disponibile.",
"indexed_insights": "Approfondimenti indicizzati",
"top_10_senders": "Top 10 mittenti",
"no_indexed_insights": "Nessun approfondimento indicizzato disponibile."
},
"archived_emails_page": {
"title": "Email archiviate",
"header": "Email Archiviate",
"select_ingestion_source": "Seleziona una sorgente di ingestione",
"header": "Email archiviate",
"select_ingestion_source": "Seleziona una fonte di ingestione",
"date": "Data",
"subject": "Oggetto",
"sender": "Mittente",
@@ -266,24 +255,6 @@
"no_emails_found": "Nessuna email archiviata trovata.",
"prev": "Prec",
"next": "Succ"
},
"dashboard_page": {
"title": "Dashboard",
"meta_description": "Panoramica del tuo archivio email.",
"header": "Dashboard",
"create_ingestion": "Crea un'ingestione",
"no_ingestion_header": "Non hai impostato nessuna sorgente di ingestione.",
"no_ingestion_text": "Aggiungi una sorgente di ingestione per iniziare ad archiviare le tue caselle di posta.",
"total_emails_archived": "Totale Email Archiviate",
"total_storage_used": "Spazio di Archiviazione Totale Utilizzato",
"failed_ingestions": "Ingestioni Fallite (Ultimi 7 Giorni)",
"ingestion_history": "Cronologia Ingestioni",
"no_ingestion_history": "Nessuna cronologia delle ingestioni disponibile.",
"storage_by_source": "Spazio di Archiviazione per Sorgente di Ingestione",
"no_ingestion_sources": "Nessuna sorgente di ingestione disponibile.",
"indexed_insights": "Approfondimenti indicizzati",
"top_10_senders": "I 10 Mittenti Principali",
"no_indexed_insights": "Nessun approfondimento indicizzato disponibile."
}
}
}

View File

@@ -3,11 +3,6 @@ import type { LayoutServerLoad } from './$types';
import 'dotenv/config';
import { api } from '$lib/server/api';
import type { SystemSettings } from '@open-archiver/types';
import { version } from '../../../../package.json';
import semver from 'semver';
let newVersionInfo: { version: string; description: string; url: string } | null = null;
let lastChecked: Date | null = null;
export const load: LayoutServerLoad = async (event) => {
const { locals, url } = event;
@@ -37,35 +32,10 @@ export const load: LayoutServerLoad = async (event) => {
? await systemSettingsResponse.json()
: null;
const now = new Date();
if (!lastChecked || now.getTime() - lastChecked.getTime() > 1000 * 60 * 60) {
try {
const res = await fetch(
'https://api.github.com/repos/LogicLabs-OU/OpenArchiver/releases/latest'
);
if (res.ok) {
const latestRelease = await res.json();
const latestVersion = latestRelease.tag_name.replace('v', '');
if (semver.gt(latestVersion, version)) {
newVersionInfo = {
version: latestVersion,
description: latestRelease.name,
url: latestRelease.html_url,
};
}
}
lastChecked = now;
} catch (error) {
console.error('Failed to fetch latest version from GitHub:', error);
}
}
return {
user: locals.user,
accessToken: locals.accessToken,
isDemo: process.env.IS_DEMO === 'true',
systemSettings,
currentVersion: version,
newVersionInfo: newVersionInfo,
};
};

View File

@@ -35,5 +35,5 @@
<main class="flex-1">
{@render children()}
</main>
<Footer currentVersion={data.currentVersion} newVersionInfo={data.newVersionInfo} />
<Footer />
</div>

470
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff