18 | Status: 19 | 20 | {takState.isInstalled && ( 21 | 22 | {takState.isRunning ? ( 23 | <> 24 | 25 | 26 | > 27 | ) : ( 28 | 29 | )} 30 | 31 | )} 32 | 33 | {takState.isInstalled ? (takState.isRunning ? 'Running' : 'Stopped') : 'Not Installed'} 34 | 35 | 36 |
37 | {takState.isInstalled && takState.version && ( 38 |39 | Version: {takState.version} 40 |
41 | )} 42 |{getStartButtonTooltip()}
37 |{isTransferRunning ? 'Stop current transfer' : 'No transfer in progress'}
58 |{error}
104 | )} 105 |Remove failed transfer from list
92 |161 | {body} 162 |
163 | ) 164 | }) 165 | FormMessage.displayName = "FormMessage" 166 | 167 | export { 168 | useFormField, 169 | Form, 170 | FormItem, 171 | FormLabel, 172 | FormControl, 173 | FormDescription, 174 | FormMessage, 175 | FormField, 176 | } 177 | -------------------------------------------------------------------------------- /server/backend/services/scripts/takserver/fix_database.py: -------------------------------------------------------------------------------- 1 | import os 2 | from backend.services.helpers.directories import DirectoryHelper 3 | from backend.config.logging_config import configure_logging 4 | from backend.services.helpers.run_command import RunCommand 5 | from backend.services.scripts.takserver.check_status import TakServerStatus 6 | 7 | logger = configure_logging(__name__) 8 | 9 | class FixDatabase: 10 | def __init__(self): 11 | self.directory_helper = DirectoryHelper() 12 | self.run_command = RunCommand() 13 | self.tak_server_status = TakServerStatus() 14 | 15 | def get_core_config_path(self) -> str: 16 | """Get the path to the CoreConfig.xml file.""" 17 | tak_directory = self.directory_helper.get_tak_directory() 18 | if tak_directory: 19 | path = os.path.join(tak_directory, "CoreConfig.xml") 20 | if not os.path.exists(path): 21 | logger.error(f"CoreConfig.xml not found at expected path: {path}") 22 | raise FileNotFoundError(f"CoreConfig.xml not found at expected path: {path}") 23 | return path 24 | logger.error("Failed to retrieve TAK directory while getting CoreConfig path") 25 | raise RuntimeError("Could not determine TAK directory location") 26 | 27 | def get_current_db_credentials(self) -> dict: 28 | """Read database credentials from CoreConfig.xml""" 29 | try: 30 | import xml.etree.ElementTree as ET 31 | 32 | config_path = self.get_core_config_path() 33 | tree = ET.parse(config_path) 34 | root = tree.getroot() 35 | 36 | ns = {'ns': 'http://bbn.com/marti/xml/config'} 37 | connection = root.find('.//ns:repository/ns:connection', ns) 38 | 39 | if connection is None: 40 | logger.error("Missing database connection configuration in CoreConfig.xml") 41 | raise ValueError("Missing database connection configuration in CoreConfig.xml") 42 | 43 | creds = { 44 | 'username': connection.get('username'), 45 | 'password': connection.get('password') 46 | } 47 | 48 | if not all(creds.values()): 49 | missing = [k for k, v in creds.items() if not v] 50 | logger.error(f"Empty credentials in CoreConfig.xml for: {', '.join(missing)}") 51 | raise ValueError(f"Empty credentials in CoreConfig.xml for: {', '.join(missing)}") 52 | 53 | return creds 54 | 55 | except ET.ParseError as e: 56 | logger.exception(f"Invalid XML structure in CoreConfig.xml at {config_path}") 57 | raise RuntimeError(f"Failed to parse CoreConfig.xml: {str(e)}") from e 58 | except Exception as e: 59 | logger.exception("Unexpected error reading database credentials") 60 | raise RuntimeError("Critical error retrieving database credentials") from e 61 | 62 | def get_database_container_name(self) -> str: 63 | """Get version-specific database container name""" 64 | try: 65 | version = self.directory_helper.get_takserver_version() 66 | if not version: 67 | logger.error("TAK Server version unavailable") 68 | raise ValueError("TAK Server version unavailable") 69 | return f"tak-database-{version}" 70 | except Exception as e: 71 | logger.exception("Failed to determine database container name") 72 | raise RuntimeError("Could not construct database container name") from e 73 | 74 | async def fix_database_password(self): 75 | """Resets PostgreSQL password for martiuser user in Docker container""" 76 | try: 77 | credentials = self.get_current_db_credentials() 78 | container_name = self.get_database_container_name() 79 | 80 | command = [ 81 | 'docker', 'exec', container_name, 82 | 'su', '-', 'postgres', 83 | '-c', 'psql -c "ALTER USER {0} WITH PASSWORD \'{1}\';"'.format( 84 | credentials['username'], 85 | credentials['password'] 86 | ) 87 | ] 88 | 89 | result = await self.run_command.run_command_async( 90 | command=command, 91 | event_type="database_password_reset", 92 | ignore_errors=False 93 | ) 94 | 95 | if not result.success: 96 | error_msg = ( 97 | f"Password reset failed for container {container_name}\n" 98 | f"Exit code: {result.returncode}\n" 99 | f"Error output: {result.stderr}" 100 | ) 101 | logger.error(error_msg) 102 | raise RuntimeError(error_msg) 103 | 104 | self.database_password = credentials['password'] 105 | logger.info(f"Successfully updated database password in {container_name}") 106 | 107 | # Restart the TAK Server after successful password reset 108 | await self.tak_server_status.restart_containers() 109 | 110 | return result 111 | 112 | except Exception as e: 113 | error_msg = f"Database password reset failed: {str(e)}" 114 | logger.exception(error_msg) 115 | raise RuntimeError(error_msg) from e 116 | -------------------------------------------------------------------------------- /client/src/components/takserver/AdvancedFeatures.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react'; 2 | import { Button } from '../shared/ui/shadcn/button'; 3 | import OtaPopups from './components/AdvancedFeatures/OtaPopups'; 4 | import OtaConfigurationForm from './components/AdvancedFeatures/OtaConfigurationForm'; 5 | import UpdatePluginsForm from './components/AdvancedFeatures/UpdatePluginsForm'; 6 | import { Copy, RefreshCw } from 'lucide-react'; 7 | import { Input } from '../shared/ui/shadcn/input'; 8 | import { toast } from "../shared/ui/shadcn/toast/use-toast" 9 | 10 | 11 | const AdvancedFeatures: React.FC = () => { 12 | const [showOtaForm, setShowOtaForm] = useState42 | Once configured, enter your server ip address and port below and paste into ATAK for update url to check for plugins and install them 43 |
44 |