using System; using System.Data; using System.Windows; using System.Windows.Controls; using System.Windows.Navigation; using MySql.Data.MySqlClient; namespace SkyTeam { public partial class AdminDashboard : Page { public AdminDashboard() { // Quelle: Im Unterricht gemacht InitializeComponent(); LoadUsers(); LoadFlights(); LoadCombos(); } private void LoadUsers() { // Quelle: Im Unterricht gemacht BindGrid("SELECT Id, Vorname, Nachname, Email, Rolle FROM users", AllUsersGrid); } private void AllUsersGrid_SelectionChanged(object sender, SelectionChangedEventArgs e) { if (AllUsersGrid.SelectedItem == null) return; // Quelle: Im Unterricht gemacht DataRowView row = (DataRowView)AllUsersGrid.SelectedItem; int userId = Convert.ToInt32(row["Id"]); BindGrid($"SELECT b.Id AS BuchungId, f.Flugnummer, f.Abflugort, f.Zielort, f.Abflugdatum FROM buchungen b JOIN fluege f ON b.FlugId = f.Id WHERE b.UserId = {userId}", UserBookingsGrid); } private void DeleteUser_Click(object sender, RoutedEventArgs e) { if (AllUsersGrid.SelectedItem == null) { MessageBox.Show("Bitte User wählen"); return; } DataRowView row = (DataRowView)AllUsersGrid.SelectedItem; int uid = Convert.ToInt32(row["Id"]); if (MessageBox.Show($"User {uid} löschen?", "Confirm", MessageBoxButton.YesNo) == MessageBoxResult.Yes) { // Quelle: AI Assistant (Claude ai) // Idee: Sicherheits Risiko Bewertung (Risk Assessment) // Die KI hat angemerkt, dass String Interpolation ($"DELETE... {uid}") bei SQL Queries // normalerweise ein No Go ist (SQL Injection Gefahr). Da wir hier aber sicherstellen, dass 'uid' // zwingend ein Integer (Convert.ToInt32) aus unserer eigenen Datenquelle ist, ist es in diesem // spezifischen Fall für ein Admin Tool vertretbar und spart Code. ExecuteSql($"DELETE FROM users WHERE Id={uid}"); LoadUsers(); UserBookingsGrid.ItemsSource = null; } } private void LoadFlights() { // Quelle: Im Unterricht gemacht string q = @"SELECT f.Id, f.Flugnummer, f.Abflugort, f.Zielort, f.Abflugdatum, f.Preis, z.Modell AS Plane, CONCAT(p.Vorname, ' ', p.Nachname) AS Pilot FROM fluege f JOIN flugzeuge z ON f.FlugzeugId = z.Id JOIN piloten p ON f.PilotId = p.Id ORDER BY f.Abflugdatum DESC"; BindGrid(q, AllFlightsGrid); } private void DeleteFlight_Click(object sender, RoutedEventArgs e) { if (AllFlightsGrid.SelectedItem == null) return; DataRowView row = (DataRowView)AllFlightsGrid.SelectedItem; if (MessageBox.Show("Flug löschen?", "Confirm", MessageBoxButton.YesNo) == MessageBoxResult.Yes) { ExecuteSql($"DELETE FROM fluege WHERE Id={row["Id"]}"); LoadFlights(); } } private void AddFlight_Click(object sender, RoutedEventArgs e) { // Quelle: Im Unterricht gemacht if (string.IsNullOrWhiteSpace(AddFromCombo.Text) || string.IsNullOrWhiteSpace(AddToCombo.Text) || AddDatePick.SelectedDate == null || PlaneCombo.SelectedValue == null || PilotCombo.SelectedValue == null) { MessageBox.Show("Bitte alle Felder ausfüllen."); return; } int creatorId = SessionManager.CurrentUserId; if (creatorId == 0) creatorId = 1; string flightNum = "SYJ-" + new Random().Next(100, 999); string query = @"INSERT INTO fluege (Abflugort, Zielort, Abflugdatum, Ankunftsdatum, Flugnummer, Preis, FlugzeugId, PilotId, ErstelltVon) VALUES (@from, @to, @date, @arr, @fnum, @price, @plane, @pilot, @admin)"; try { using (MySqlConnection conn = new MySqlConnection(DatenbankServices.GetConnection())) { conn.Open(); MySqlCommand cmd = new MySqlCommand(query, conn); cmd.Parameters.AddWithValue("@from", AddFromCombo.Text); cmd.Parameters.AddWithValue("@to", AddToCombo.Text); cmd.Parameters.AddWithValue("@date", AddDatePick.SelectedDate.Value); // Quelle: Microsoft Learn // Wir nutzen die eingebaute AddHours-Methode von DateTime, um automatisch // ein fiktives Ankunftsdatum zu generieren (Abflug + 4 Stunden) cmd.Parameters.AddWithValue("@arr", AddDatePick.SelectedDate.Value.AddHours(4)); cmd.Parameters.AddWithValue("@fnum", flightNum); cmd.Parameters.AddWithValue("@price", AddPriceTxt.Text); cmd.Parameters.AddWithValue("@plane", PlaneCombo.SelectedValue); cmd.Parameters.AddWithValue("@pilot", PilotCombo.SelectedValue); cmd.Parameters.AddWithValue("@admin", creatorId); cmd.ExecuteNonQuery(); MessageBox.Show($"Flug {flightNum} erstellt!"); LoadFlights(); } } catch (Exception ex) { MessageBox.Show("Error: " + ex.Message); } } private void LoadCombos() { BindComboBox("SELECT Id, Modell FROM flugzeuge WHERE IstDefekt=0", PlaneCombo, "Modell", "Id"); BindComboBox("SELECT Id, CONCAT(Vorname, ' ', Nachname) AS FullName FROM piloten WHERE IstVerfuegbar=1", PilotCombo, "FullName", "Id"); } // Quelle: AI Assistant (Gemini) // Idee: DRY Prinzip (Don't Repeat Yourself) / Refactoring // Die KI hat vorgeschlagen, die sehr repetitiven SQL-Verbindungs und Adapter Logiken // in universelle Hilfsmethoden (BindGrid, BindComboBox, ExecuteSql) auszulagern. // Das reduziert den Code der Hauptmethoden enorm und macht die Klasse wartbarer. private void BindGrid(string q, DataGrid g) { try { using (var c = new MySqlConnection(DatenbankServices.GetConnection())) { c.Open(); var a = new MySqlDataAdapter(q, c); var t = new DataTable(); a.Fill(t); g.ItemsSource = t.DefaultView; } } catch { } } // Quelle: Microsoft Learn // Hier nutzen wir DisplayMemberPath für den Text, den der User sieht (z.B. das Flugzeugmodell) // und SelectedValuePath für den Wert, der im Hintergrund für die Datenbankabfrage genutzt wird (z.B. die Id). private void BindComboBox(string q, ComboBox b, string d, string v) { try { using (var c = new MySqlConnection(DatenbankServices.GetConnection())) { c.Open(); var a = new MySqlDataAdapter(q, c); var t = new DataTable(); a.Fill(t); b.ItemsSource = t.DefaultView; b.DisplayMemberPath = d; b.SelectedValuePath = v; } } catch { } } private void ExecuteSql(string s) { try { using (var c = new MySqlConnection(DatenbankServices.GetConnection())) { c.Open(); new MySqlCommand(s, c).ExecuteNonQuery(); } } catch (Exception ex) { MessageBox.Show(ex.Message); } } // Quelle: Im Unterricht gemacht private void ShowUsers_Click(object sender, RoutedEventArgs e) { UserManagementGrid.Visibility = Visibility.Visible; FlightManagementGrid.Visibility = Visibility.Collapsed; } private void ShowFlights_Click(object sender, RoutedEventArgs e) { UserManagementGrid.Visibility = Visibility.Collapsed; FlightManagementGrid.Visibility = Visibility.Visible; LoadFlights(); } private void Logout_Click(object sender, RoutedEventArgs e) { SessionManager.CurrentUserId = 0; NavigationService.Navigate(new LogInPage()); } } }