diff --git a/README.md b/README.md index 022a873..3db7fe4 100644 --- a/README.md +++ b/README.md @@ -85,7 +85,8 @@ services: - [ ] Infrastructure Server Monitoring - [ ] Operational Status / Public Status Pages - [ ] Uptime monitoring (TCP, PING, DNS) -- [ ] User Permission Roles & Service Group +- [x] System Setting Panel and Mail Settings +- [x] User Permission Roles - [ ] Notifications (Email/Slack/Discord/Signal) - [x] Open-source release with full documentation @@ -122,4 +123,8 @@ CheckCle is released under the MIT License. --- +## Star History + +[![Star History Chart](https://api.star-history.com/svg?repos=operacle/checkcle&type=Date)](https://www.star-history.com/#operacle/checkcle&Date) + Stay informed, stay online, with CheckCle! 🌐 diff --git a/application/src/components/profile/ChangePasswordForm.tsx b/application/src/components/profile/ChangePasswordForm.tsx index 41ccb45..5e84220 100644 --- a/application/src/components/profile/ChangePasswordForm.tsx +++ b/application/src/components/profile/ChangePasswordForm.tsx @@ -1,4 +1,3 @@ - import { useState } from "react"; import { z } from "zod"; import { useForm } from "react-hook-form"; @@ -10,6 +9,7 @@ import { useToast } from "@/hooks/use-toast"; import { Eye, EyeOff } from "lucide-react"; import { pb } from "@/lib/pocketbase"; import { authService } from "@/services/authService"; +import { useNavigate } from "react-router-dom"; // Password change form schema const passwordFormSchema = z.object({ @@ -34,6 +34,7 @@ export function ChangePasswordForm({ userId }: ChangePasswordFormProps) { const [showConfirmPassword, setShowConfirmPassword] = useState(false); const { toast } = useToast(); + const navigate = useNavigate(); const form = useForm({ resolver: zodResolver(passwordFormSchema), @@ -44,12 +45,35 @@ export function ChangePasswordForm({ userId }: ChangePasswordFormProps) { }, }); + // Function to determine which collection the user belongs to + const getUserCollection = async (userId: string): Promise => { + try { + // First try to find the user in the regular users collection + await pb.collection('users').getOne(userId); + return 'users'; + } catch (error) { + try { + // If not found, try the superadmin collection + await pb.collection('_superusers').getOne(userId); + return '_superusers'; + } catch (error) { + throw new Error('User not found in any collection'); + } + } + }; + async function onSubmit(data: PasswordFormValues) { setIsSubmitting(true); try { + console.log("Starting password change for user:", userId); + + // Determine which collection the user belongs to + const collection = await getUserCollection(userId); + console.log("User found in collection:", collection); + // PocketBase requires the old password along with the new one - await pb.collection('users').update(userId, { + await pb.collection(collection).update(userId, { oldPassword: data.currentPassword, password: data.newPassword, passwordConfirm: data.confirmPassword, @@ -60,17 +84,31 @@ export function ChangePasswordForm({ userId }: ChangePasswordFormProps) { toast({ title: "Password updated", - description: "Your password has been changed successfully.", + description: "Your password has been changed successfully. You will be logged out in 3 seconds for security.", }); // Reset the form form.reset(); + + // Auto logout after successful password change + setTimeout(() => { + console.log("Auto logout after password change"); + authService.logout(); + navigate("/login"); + }, 3000); + } catch (error) { console.error("Password change error:", error); let errorMessage = "Failed to update password. Please try again."; if (error instanceof Error) { - errorMessage = error.message; + if (error.message.includes("Failed to authenticate")) { + errorMessage = "Current password is incorrect. Please try again."; + } else if (error.message.includes("User not found")) { + errorMessage = "User account not found. Please contact your administrator."; + } else { + errorMessage = error.message; + } } toast({ @@ -188,4 +226,4 @@ export function ChangePasswordForm({ userId }: ChangePasswordFormProps) { ); -} +} \ No newline at end of file diff --git a/application/src/components/settings/general/SystemSettingsTab.tsx b/application/src/components/settings/general/SystemSettingsTab.tsx index 1f16f23..c48a5e7 100644 --- a/application/src/components/settings/general/SystemSettingsTab.tsx +++ b/application/src/components/settings/general/SystemSettingsTab.tsx @@ -1,7 +1,6 @@ import React from 'react'; import { Input } from "@/components/ui/input"; -import { Switch } from "@/components/ui/switch"; import { FormControl, FormField, FormItem, FormLabel } from "@/components/ui/form"; import { useLanguage } from "@/contexts/LanguageContext"; import { SettingsTabProps } from "./types"; @@ -48,7 +47,7 @@ const SystemSettingsTab: React.FC = ({ form, isEditing, settin @@ -57,72 +56,6 @@ const SystemSettingsTab: React.FC = ({ form, isEditing, settin /> - -
- ( - - - {t("senderName", "settings")} - - - - - - )} - /> -
- -
- ( - - - {t("senderEmail", "settings")} - - - - - - )} - /> -
- -
- ( - - - - - - {t("hideControls", "settings")} - - - )} - /> -
); }; diff --git a/application/src/translations/de/about.ts b/application/src/translations/de/about.ts index 218c972..ba49c4e 100644 --- a/application/src/translations/de/about.ts +++ b/application/src/translations/de/about.ts @@ -12,9 +12,9 @@ export const aboutTranslations: AboutTranslations = { viewDocumentation: "Dokumentation ansehen", followOnX: "Auf X folgen", joinDiscord: "Discord beitreten", - quickActions: "Quick Actions", - quickActionsDescription: "Access common monitoring operations and features quickly. Select an action below to get started.", - quickTips: "Quick Tips", + quickActions: "Schnelle Aktionen", + quickActionsDescription: "Greifen Sie schnell auf gängige Überwachungsvorgänge und -funktionen zu. Wählen Sie unten eine Aktion aus, um loszulegen.", + quickTips: "Schnelle Tipps", }; diff --git a/application/src/translations/de/common.ts b/application/src/translations/de/common.ts index a104def..0e69d07 100644 --- a/application/src/translations/de/common.ts +++ b/application/src/translations/de/common.ts @@ -11,19 +11,19 @@ export const commonTranslations: CommonTranslations = { goodMorning: "Guten Morgen", goodAfternoon: "Guten Nachmittag", goodEvening: "Guten Abend", - profile: "Profile", - settings: "Settings", - documentation: "Documentation", - notifications: "Notifications", - close: "Close", - cancel: "Cancel", - view: "View", - edit: "Edit", - delete: "Delete", + profile: "Profil", + settings: "Einstellungen", + documentation: "Dokumentation", + notifications: "Benachrichtigungen", + close: "Schließen", + cancel: "Abbrechen", + view: "Anzeigen", + edit: "Bearbeiten", + delete: "Löschen", status: "Status", - time: "Time", - title: "Title", - description: "Description", - success: "Success", - error: "Error", + time: "Zeit", + title: "Titel", + description: "Beschreibung", + success: "Erfolg", + error: "Fehler", }; diff --git a/application/src/translations/de/incident.ts b/application/src/translations/de/incident.ts index 461babd..9236dab 100644 --- a/application/src/translations/de/incident.ts +++ b/application/src/translations/de/incident.ts @@ -1,55 +1,54 @@ - import { IncidentTranslations } from '../types/incident'; export const incidentTranslations: IncidentTranslations = { - incidentManagement: 'Incident Management', - incidentsManagementDesc: 'Track and manage service incidents and their resolutions', - unresolvedIncidents: 'Unresolved', - resolvedIncidents: 'Resolved', - activeIncidents: 'Active Incidents', - criticalIssues: 'Critical Issues', - avgResolutionTime: 'Avg. Resolution Time', - noIncidents: 'No Active Incidents', - createIncident: 'Create Incident', - investigating: 'Investigating', - identified: 'Identified', - monitoring: 'Monitoring', - resolved: 'Resolved', - scheduleIncidentManagement: 'Schedule & Incident Management', - incidentName: 'Incident Name', - incidentStatus: 'Incident Status', - highPriority: 'High Priority', - configurationSettings: 'Configuration Settings', - incidentCreatedSuccess: 'Incident created successfully', - basicInfo: 'Basic Information', - serviceId: 'Service ID', - assignedTo: 'Assigned To', - unassigned: 'Unassigned', - timeline: 'Timeline', - incidentTime: 'Incident Time', - resolutionTime: 'Resolution Time', - systems: 'Systems', - noSystems: 'No systems affected', - impactAnalysis: 'Impact Analysis', - rootCause: 'Root Cause', - resolutionSteps: 'Resolution Steps', - lessonsLearned: 'Lessons Learned', - resolutionDetails: 'Resolution Details', - assignment: 'Assignment', - download: 'Download', - downloadPdf: 'Download PDF', - print: 'Print', - confidentialNote: 'This document is confidential and intended for internal use only.', - generatedOn: 'Generated on', - enterResolutionSteps: 'Enter steps taken to resolve the incident', - enterLessonsLearned: 'Enter lessons learned from this incident', - editIncident: 'Edit Incident', - editIncidentDesc: 'Update details for this incident', - updating: 'Updating...', - update: 'Update', - create: 'Create', - creating: 'Creating...', - configuration: 'Configuration', - failedToUpdateStatus: 'Failed to update status', - inProgress: 'In Progress', + incidentManagement: 'Vorfallmanagement', + incidentsManagementDesc: 'Verfolgen und Verwalten von Servicevorfällen und deren Lösungen', + unresolvedIncidents: 'Ungelöst', + resolvedIncidents: 'Gelöst', + activeIncidents: 'Aktive Vorfälle', + criticalIssues: 'Kritische Probleme', + avgResolutionTime: 'Durchschn. Lösungszeit', + noIncidents: 'Keine aktiven Vorfälle', + createIncident: 'Vorfall erstellen', + investigating: 'Untersuchung läuft', + identified: 'Identifiziert', + monitoring: 'Überwachung', + resolved: 'Gelöst', + scheduleIncidentManagement: 'Zeitplanung & Vorfallmanagement', + incidentName: 'Vorfallname', + incidentStatus: 'Vorfallstatus', + highPriority: 'Hohe Priorität', + configurationSettings: 'Konfigurationseinstellungen', + incidentCreatedSuccess: 'Vorfall erfolgreich erstellt', + basicInfo: 'Grundinformationen', + serviceId: 'Service-ID', + assignedTo: 'Zugewiesen an', + unassigned: 'Nicht zugewiesen', + timeline: 'Zeitverlauf', + incidentTime: 'Vorfallszeit', + resolutionTime: 'Lösungszeit', + systems: 'Systeme', + noSystems: 'Keine betroffenen Systeme', + impactAnalysis: 'Auswirkungsanalyse', + rootCause: 'Ursache', + resolutionSteps: 'Lösungsschritte', + lessonsLearned: 'Erkenntnisse', + resolutionDetails: 'Details zur Lösung', + assignment: 'Zuweisung', + download: 'Herunterladen', + downloadPdf: 'PDF herunterladen', + print: 'Drucken', + confidentialNote: 'Dieses Dokument ist vertraulich und nur für den internen Gebrauch bestimmt.', + generatedOn: 'Erstellt am', + enterResolutionSteps: 'Geben Sie die zur Lösung ergriffenen Schritte ein', + enterLessonsLearned: 'Geben Sie die aus diesem Vorfall gewonnenen Erkenntnisse ein', + editIncident: 'Vorfall bearbeiten', + editIncidentDesc: 'Details zu diesem Vorfall aktualisieren', + updating: 'Aktualisiere...', + update: 'Aktualisieren', + create: 'Erstellen', + creating: 'Erstelle...', + configuration: 'Konfiguration', + failedToUpdateStatus: 'Fehler beim Aktualisieren des Status', + inProgress: 'In Bearbeitung', }; diff --git a/application/src/translations/de/maintenance.ts b/application/src/translations/de/maintenance.ts index c056eea..0b7caf3 100644 --- a/application/src/translations/de/maintenance.ts +++ b/application/src/translations/de/maintenance.ts @@ -1,68 +1,67 @@ - import { MaintenanceTranslations } from '../types/maintenance'; export const maintenanceTranslations: MaintenanceTranslations = { - scheduledMaintenance: 'Scheduled Maintenance', - scheduledMaintenanceDesc: 'View and manage planned maintenance windows for your systems and services', - upcomingMaintenance: 'Upcoming', - ongoingMaintenance: 'Ongoing', - completedMaintenance: 'Completed', - createMaintenanceWindow: 'Create Maintenance', - totalScheduledHours: 'Total Scheduled Hours', - maintenanceName: 'Maintenance Name', + scheduledMaintenance: 'Geplante Wartung', + scheduledMaintenanceDesc: 'Anzeigen und Verwalten geplanter Wartungsfenster für Ihre Systeme und Dienste', + upcomingMaintenance: 'Bevorstehend', + ongoingMaintenance: 'Laufend', + completedMaintenance: 'Abgeschlossen', + createMaintenanceWindow: 'Wartung erstellen', + totalScheduledHours: 'Geplante Gesamtstunden', + maintenanceName: 'Wartungsname', maintenanceStatus: 'Status', - scheduledStart: 'Scheduled Start', - scheduledEnd: 'Scheduled End', - affectedServices: 'Affected Services', - impact: 'Impact', - minor: 'Minor', - major: 'Major', - critical: 'Critical', - none: 'None', - actions: 'Actions', - scheduled: 'Scheduled', - inprogress: 'In Progress', - completed: 'Completed', - cancelled: 'Cancelled', - markAsInProgress: 'Mark as In Progress', - markAsCompleted: 'Mark as Completed', - markAsCancelled: 'Mark as Cancelled', - confirmDelete: 'Confirm Delete', - deleteMaintenanceConfirmation: 'Are you sure you want to delete this maintenance window?', - thisActionCannotBeUndone: 'This action cannot be undone.', - maintenanceDeleted: 'Maintenance Deleted', - maintenanceDeletedDesc: 'The maintenance window has been deleted successfully.', - errorDeletingMaintenance: 'There was an error deleting the maintenance window.', - statusUpdated: 'Status Updated', - maintenanceStatusUpdated: 'Maintenance status has been updated successfully.', - errorUpdatingMaintenanceStatus: 'There was an error updating the maintenance status.', - createMaintenance: 'Create Maintenance', - createMaintenanceDesc: 'Schedule a new maintenance window for your services', - enterTitle: 'Enter maintenance title', - enterDescription: 'Enter detailed description of the maintenance', - startTime: 'Start Time', - endTime: 'End Time', - selectDate: 'Select a date', - enterAffectedServices: 'Enter affected services', - separateServicesWithComma: 'Separate multiple services with commas', - priority: 'Priority', - selectPriority: 'Select priority', - selectStatus: 'Select status', - selectImpact: 'Select impact', - notifySubscribers: 'Notify Subscribers', - notifySubscribersDesc: 'Send notifications to all subscribers when this maintenance starts', - maintenanceCreated: 'Maintenance Created', - maintenanceCreatedDesc: 'The maintenance window has been scheduled successfully.', - errorCreatingMaintenance: 'There was an error creating the maintenance window.', - errorFetchingMaintenanceData: 'There was an error fetching maintenance data.', - low: 'Low', - medium: 'Medium', - high: 'High', - created: 'Created', - lastUpdated: 'Last Updated', - subscribersWillBeNotified: 'Subscribers will be notified when maintenance begins', - noNotifications: 'No notifications will be sent', - noScheduledMaintenance: 'No Scheduled Maintenance', - noMaintenanceWindows: 'There are no maintenance windows for this period. Create one by clicking the "Create Maintenance" button.', - maintenanceCreatedSuccess: 'Maintenance window created successfully', + scheduledStart: 'Geplanter Start', + scheduledEnd: 'Geplantes Ende', + affectedServices: 'Betroffene Dienste', + impact: 'Auswirkung', + minor: 'Geringfügig', + major: 'Gravierend', + critical: 'Kritisch', + none: 'Keine', + actions: 'Aktionen', + scheduled: 'Geplant', + inprogress: 'In Bearbeitung', + completed: 'Abgeschlossen', + cancelled: 'Abgebrochen', + markAsInProgress: 'Als in Bearbeitung markieren', + markAsCompleted: 'Als abgeschlossen markieren', + markAsCancelled: 'Als abgebrochen markieren', + confirmDelete: 'Löschen bestätigen', + deleteMaintenanceConfirmation: 'Möchten Sie dieses Wartungsfenster wirklich löschen?', + thisActionCannotBeUndone: 'Diese Aktion kann nicht rückgängig gemacht werden.', + maintenanceDeleted: 'Wartung gelöscht', + maintenanceDeletedDesc: 'Das Wartungsfenster wurde erfolgreich gelöscht.', + errorDeletingMaintenance: 'Fehler beim Löschen des Wartungsfensters.', + statusUpdated: 'Status aktualisiert', + maintenanceStatusUpdated: 'Wartungsstatus wurde erfolgreich aktualisiert.', + errorUpdatingMaintenanceStatus: 'Fehler beim Aktualisieren des Wartungsstatus.', + createMaintenance: 'Wartung erstellen', + createMaintenanceDesc: 'Planen Sie ein neues Wartungsfenster für Ihre Dienste', + enterTitle: 'Wartungstitel eingeben', + enterDescription: 'Geben Sie eine detaillierte Beschreibung der Wartung ein', + startTime: 'Startzeit', + endTime: 'Endzeit', + selectDate: 'Datum auswählen', + enterAffectedServices: 'Betroffene Dienste eingeben', + separateServicesWithComma: 'Mehrere Dienste durch Kommas trennen', + priority: 'Priorität', + selectPriority: 'Priorität auswählen', + selectStatus: 'Status auswählen', + selectImpact: 'Auswirkung auswählen', + notifySubscribers: 'Abonnenten benachrichtigen', + notifySubscribersDesc: 'Beim Start dieser Wartung eine Benachrichtigung an alle Abonnenten senden', + maintenanceCreated: 'Wartung erstellt', + maintenanceCreatedDesc: 'Das Wartungsfenster wurde erfolgreich geplant.', + errorCreatingMaintenance: 'Fehler beim Erstellen des Wartungsfensters.', + errorFetchingMaintenanceData: 'Fehler beim Abrufen der Wartungsdaten.', + low: 'Niedrig', + medium: 'Mittel', + high: 'Hoch', + created: 'Erstellt', + lastUpdated: 'Zuletzt aktualisiert', + subscribersWillBeNotified: 'Abonnenten werden benachrichtigt, wenn die Wartung beginnt', + noNotifications: 'Es werden keine Benachrichtigungen gesendet', + noScheduledMaintenance: 'Keine geplanten Wartungen', + noMaintenanceWindows: 'Für diesen Zeitraum sind keine Wartungsfenster vorhanden. Erstellen Sie eines über die Schaltfläche „Wartung erstellen“.', + maintenanceCreatedSuccess: 'Wartungsfenster erfolgreich erstellt', }; diff --git a/application/src/translations/de/services.ts b/application/src/translations/de/services.ts index 917de48..0dee15a 100644 --- a/application/src/translations/de/services.ts +++ b/application/src/translations/de/services.ts @@ -9,5 +9,5 @@ export const servicesTranslations: ServicesTranslations = { responseTime: "Antwortzeit", uptime: "Betriebszeit", lastChecked: "Zuletzt überprüft", - noServices: "No services match your filter criteria.", + noServices: "Keine Dienste entsprechen Ihren Filterkriterien.", }; diff --git a/application/src/translations/de/settings.ts b/application/src/translations/de/settings.ts index a25746e..0940c78 100644 --- a/application/src/translations/de/settings.ts +++ b/application/src/translations/de/settings.ts @@ -1,35 +1,34 @@ - import { SettingsTranslations } from '../types/settings'; export const settingsTranslations: SettingsTranslations = { // Tabs - systemSettings: "System Settings", - mailSettings: "Mail Settings", - + systemSettings: "Systemeinstellungen", + mailSettings: "E-Mail-Einstellungen", + // System Settings - appName: "Application Name", - appURL: "Application URL", - senderName: "Sender Name", - senderEmail: "Sender Email Address", - hideControls: "Hide Controls", - + appName: "Anwendungsname", + appURL: "Anwendungs-URL", + senderName: "Absendername", + senderEmail: "Absender-E-Mail-Adresse", + hideControls: "Steuerelemente ausblenden", + // Mail Settings - smtpSettings: "SMTP Configuration", - smtpEnabled: "Enable SMTP", - smtpHost: "SMTP Host", - smtpPort: "SMTP Port", - smtpUsername: "SMTP Username", - smtpAuthMethod: "Authentication Method", - enableTLS: "Enable TLS", - localName: "Local Name", - + smtpSettings: "SMTP-Konfiguration", + smtpEnabled: "SMTP aktivieren", + smtpHost: "SMTP-Host", + smtpPort: "SMTP-Port", + smtpUsername: "SMTP-Benutzername", + smtpAuthMethod: "Authentifizierungsmethode", + enableTLS: "TLS aktivieren", + localName: "Lokaler Name", + // Actions and status - save: "Save Changes", - saving: "Saving...", - settingsUpdated: "Settings updated successfully", - errorSavingSettings: "Error saving settings", - testConnection: "Test Connection", - testingConnection: "Testing Connection...", - connectionSuccess: "Connection successful", - connectionFailed: "Connection failed" -}; \ No newline at end of file + save: "Änderungen speichern", + saving: "Speichere...", + settingsUpdated: "Einstellungen erfolgreich aktualisiert", + errorSavingSettings: "Fehler beim Speichern der Einstellungen", + testConnection: "Verbindung testen", + testingConnection: "Verbindung wird getestet...", + connectionSuccess: "Verbindung erfolgreich", + connectionFailed: "Verbindung fehlgeschlagen" +}; diff --git a/application/src/translations/de/ssl.ts b/application/src/translations/de/ssl.ts index d2715b4..7a2f9a2 100644 --- a/application/src/translations/de/ssl.ts +++ b/application/src/translations/de/ssl.ts @@ -43,65 +43,66 @@ export const sslTranslations: SSLTranslations = { expirationDate: "Ablaufdatum", daysLeft: "Verbleibende Tage", status: "Status", - lastNotified: "Last Notified", - actions: "Actions", - validFrom: "Valid From", - validUntil: "Valid Until", - validityDays: "Validity Days", - organization: "Organization", - commonName: "Common Name", - serialNumber: "Serial Number", - algorithm: "Algorithm", - subjectAltNames: "Subject Alternative Names", + lastNotified: "Zuletzt benachrichtigt", + actions: "Aktionen", + validFrom: "Gültig von", + validUntil: "Gültig bis", + validityDays: "Gültigkeitsdauer Tage", + organization: "Organisation", + commonName: "Allgemeiner Name", + serialNumber: "Seriennummer", + algorithm: "Algorithmus", + subjectAltNames: "Thema Alternative Bezeichnungen", // Buttons and actions - addDomain: "Add Domain", - refreshAll: "Refresh All", - cancel: "Cancel", - addCertificate: "Add Certificate", - check: "Check", - view: "View", - edit: "Edit", - delete: "Delete", - close: "Close", - saveChanges: "Save Changes", - updating: "Updating", - + addDomain: "Domain hinzufügen", + refreshAll: "Alle aktualisieren", + cancel: "Abbrechen", + addCertificate: "Zertifikat hinzufügen", + check: "Prüfen", + view: "Ansehen", + edit: "Bearbeiten", + delete: "Löschen", + close: "Schließen", + saveChanges: "Änderungen speichern", + updating: "Aktualisiere", + // Sections in detail view - basicInformation: "Basic Information", - validity: "Validity", - issuerInfo: "Issuer Information", - technicalDetails: "Technical Details", - monitoringConfig: "Monitoring Configuration", - recordInfo: "Record Information", - + basicInformation: "Basisinformationen", + validity: "Gültigkeit", + issuerInfo: "Informationen zum Aussteller", + technicalDetails: "Technische Details", + monitoringConfig: "Monitoring-Konfiguration", + recordInfo: "Aufzeichnungsinformationen", + // Notifications and messages - sslCertificateAdded: "SSL Certificate added successfully", - sslCertificateUpdated: "SSL Certificate updated successfully", - sslCertificateDeleted: "SSL Certificate deleted successfully", - sslCertificateRefreshed: "SSL Certificate for {domain} refreshed successfully", - allCertificatesRefreshed: "All {count} certificates refreshed successfully", - someCertificatesFailed: "{success} certificates refreshed, {failed} failed", - failedToAddCertificate: "Failed to add SSL certificate", - failedToLoadCertificates: "Failed to load SSL certificates", - failedToUpdateCertificate: "Failed to update SSL certificate", - failedToDeleteCertificate: "Failed to delete SSL certificate", - failedToCheckCertificate: "Failed to check SSL certificate", - noCertificatesToRefresh: "No certificates to refresh", - startingRefreshAll: "Starting refresh of {count} certificates", - checkingSSLCertificate: "Checking SSL certificate...", - deleteConfirmation: "Are you sure you want to delete the certificate for", - deleteWarning: "This action cannot be undone. This will permanently delete the certificate.", - + sslCertificateAdded: "SSL-Zertifikat erfolgreich hinzugefügt", + sslCertificateUpdated: "SSL-Zertifikat erfolgreich aktualisiert", + sslCertificateDeleted: "SSL-Zertifikat erfolgreich gelöscht", + sslCertificateRefreshed: "SSL-Zertifikat für {domain} erfolgreich aktualisiert", + allCertificatesRefreshed: "Alle {count} Zertifikate wurden erfolgreich aktualisiert", + someCertificatesFailed: "{success} Zertifikate aktualisiert, {failed} fehlgeschlagen", + failedToAddCertificate: "Fehler beim Hinzufügen des SSL-Zertifikats", + failedToLoadCertificates: "Fehler beim Laden der SSL-Zertifikate", + failedToUpdateCertificate: "Fehler beim Aktualisieren des SSL-Zertifikats", + failedToDeleteCertificate: "Fehler beim Löschen des SSL-Zertifikats", + failedToCheckCertificate: "Fehler beim Prüfen des SSL-Zertifikats", + noCertificatesToRefresh: "Keine Zertifikate zum Aktualisieren vorhanden", + startingRefreshAll: "Starte Aktualisierung von {count} Zertifikaten", + checkingSSLCertificate: "SSL-Zertifikat wird überprüft...", + deleteConfirmation: "Möchten Sie das Zertifikat für wirklich löschen?", + deleteWarning: "Diese Aktion kann nicht rückgängig gemacht werden. Das Zertifikat wird dauerhaft gelöscht.", + // Misc - unknown: "Unknown", - never: "Never", - none: "None", - loadingChannels: "Loading channels...", - noChannelsFound: "No notification channels found", - noSSLCertificates: "No SSL certificates found", - created: "Created", - lastUpdated: "Last Updated", - lastNotification: "Last Notification", - collectionId: "Collection ID" -}; + unknown: "Unbekannt", + never: "Nie", + none: "Keine", + loadingChannels: "Lade Kanäle...", + noChannelsFound: "Keine Benachrichtigungskanäle gefunden", + noSSLCertificates: "Keine SSL-Zertifikate gefunden", + created: "Erstellt", + lastUpdated: "Zuletzt aktualisiert", + lastNotification: "Letzte Benachrichtigung", + collectionId: "Sammlungs-ID" +} + diff --git a/scripts/setup.sh b/scripts/setup.sh index 5ef28b2..43a9737 100644 --- a/scripts/setup.sh +++ b/scripts/setup.sh @@ -2,82 +2,59 @@ set -e -echo "🚀 Starting Checkcle Installation..." +REPO_URL="https://github.com/operacle/checkcle.git" +CLONE_DIR="/opt/checkcle" +DATA_DIR="/opt/pb_data" +PORT=8090 -# Check if npm is installed -if ! command -v npm &> /dev/null; then - echo "📦 npm is not installed. Installing Node.js and npm..." - - # Install Node.js and npm (Ubuntu/Debian-based systems) - curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash - - sudo apt-get install -y nodejs -fi +echo "🚀 Installing Checkcle from $REPO_URL" -# Clone the repo -if [ ! -d "checkcle" ]; then - echo "📁 Cloning repository..." - git clone https://github.com/operacle/checkcle.git +# Step 1: Check if port 8090 is already in use +if lsof -i :"$PORT" &>/dev/null; then + echo "❗ ERROR: Port $PORT is already in use. Please free the port or change the Docker Compose configuration." + exit 1 fi -cd checkcle - -# Set up paths -PROJECT_DIR=$(pwd) -APP_DIR="$PROJECT_DIR/application" -PB_DIR="$PROJECT_DIR/server" -PB_BINARY="$PB_DIR/pocketbase" - -# Install web dependencies -echo "📦 Installing Web Application dependencies..." -cd "$APP_DIR" -npm install - -# Create systemd service for frontend -echo "🛠️ Setting up systemd service for Web Application..." -sudo tee /etc/systemd/system/checkcle-web.service > /dev/null < /dev/null; then + echo "🔧 Docker not found. Installing Docker..." + curl -fsSL https://get.docker.com | sh +fi -# Create systemd service for PocketBase -echo "🛠️ Setting up systemd service for PocketBase..." -sudo tee /etc/systemd/system/checkcle-pb.service > /dev/null < /dev/null; then + echo "❗ Docker Compose v2 not found. Please install Docker Compose v2 and rerun this script." + exit 1 +fi -[Service] -Type=simple -WorkingDirectory=$PB_DIR -ExecStart=$PB_BINARY serve --dir pb_data -Restart=on-failure -User=$USER +# Step 4: Clone the repository +if [ -d "$CLONE_DIR" ]; then + echo "📁 Directory $CLONE_DIR already exists. Pulling latest changes..." + git -C "$CLONE_DIR" pull +else + echo "📥 Cloning repo to $CLONE_DIR" + git clone "$REPO_URL" "$CLONE_DIR" +fi -[Install] -WantedBy=multi-user.target -EOF +# Step 5: Create data volume directory if it doesn’t exist +if [ ! -d "$DATA_DIR" ]; then + echo "📁 Creating data volume directory at $DATA_DIR" + sudo mkdir -p "$DATA_DIR" + sudo chown "$(whoami)":"$(whoami)" "$DATA_DIR" +fi -# Reload systemd and start services -echo "🔄 Enabling and starting services..." -sudo systemctl daemon-reexec -sudo systemctl daemon-reload -sudo systemctl enable --now checkcle-web -sudo systemctl enable --now checkcle-pb +# Step 6: Start the service +cd "$CLONE_DIR" +echo "📦 Starting Checkcle service with Docker Compose..." +docker compose up -d +# Step 7: Show success output +echo "" +echo "✅ Checkcle has been successfully installed and started." echo "" -echo "✅ All done!" -echo "🌐 Admin Panel: http://0.0.0.0:8090" +echo "🛠️ Admin Web Management" +echo "🔗 Default URL: http://0.0.0.0:$PORT" echo "👤 User: admin@example.com" echo "🔑 Passwd: Admin123456" +echo "" +echo "📌 Make sure port $PORT is accessible from your host system or cloud firewall." diff --git a/server/pb_data/auxiliary.db-shm b/server/pb_data/auxiliary.db-shm index fcd9ec8..7d723da 100644 Binary files a/server/pb_data/auxiliary.db-shm and b/server/pb_data/auxiliary.db-shm differ diff --git a/server/pb_data/auxiliary.db-wal b/server/pb_data/auxiliary.db-wal index bd7c60c..55633bf 100644 Binary files a/server/pb_data/auxiliary.db-wal and b/server/pb_data/auxiliary.db-wal differ diff --git a/server/pb_data/data.db b/server/pb_data/data.db index c53732c..39d9f9f 100644 Binary files a/server/pb_data/data.db and b/server/pb_data/data.db differ