diff --git a/AddOn/Calender_Google_User/exampelV2/GraphCalendarUserAuth.php b/AddOn/Calender_Google_User/exampelV2/GraphCalendarUserAuth.php new file mode 100644 index 00000000..ad5afb8f --- /dev/null +++ b/AddOn/Calender_Google_User/exampelV2/GraphCalendarUserAuth.php @@ -0,0 +1,308 @@ +clientId = $clientId; + $this->clientSecret = $clientSecret; + $this->tenantId = $tenantId; + $this->redirectUri = $redirectUri; + } + + public function getLoginUrl() { + $params = http_build_query([ + 'client_id' => $this->clientId, + 'response_type' => 'code', + 'redirect_uri' => $this->redirectUri, + 'response_mode' => 'query', + 'scope' => SCOPES, + 'prompt' => 'consent', // erzwingt Benutzer-Zustimmung beim ersten Mal + ]); + return "https://login.microsoftonline.com/{$this->tenantId}/oauth2/v2.0/authorize?$params"; + } + + public function handleCallback($code) { + $tokenUrl = "https://login.microsoftonline.com/{$this->tenantId}/oauth2/v2.0/token"; + + $data = [ + 'grant_type' => 'authorization_code', + 'code' => $code, + 'redirect_uri' => $this->redirectUri, + 'client_id' => $this->clientId, + 'client_secret' => $this->clientSecret, + 'scope' => SCOPES, + ]; + + $response = $this->post($tokenUrl, $data); + $tokens = json_decode($response, true); + + // === Fehlerbehandlung === + if (!isset($tokens['access_token'])) { + echo "
Fehler bei Token-Antwort:\n";
+            print_r($tokens);
+            echo "\nResponse RAW:\n" . htmlspecialchars($response);
+            echo "
"; + exit; + } + + $this->accessToken = $tokens['access_token']; + $user = $this->getUserInfo(); + + if (!isset($user['id'])) { + echo "
Fehler: Benutzerinformationen konnten nicht abgerufen werden.\n";
+            print_r($user);
+            echo "
"; + exit; + } + + // === E-Mail auslesen === + $email = $user['mail'] ?? $user['userPrincipalName'] ?? 'unknown@example.com'; + + // === Tokens + Zeit + E-Mail speichern === + $tokens['created_at'] = time(); + $this->saveTokensToFile($user['id'], $tokens, $email); + + // === User zurückgeben === + $user['email'] = $email; + return $user; + } + + public function refreshAccessTokenFromFile($userId) { + $tokenFile = TOKEN_DIR . "/$userId.json"; + if (!file_exists($tokenFile)) throw new Exception("Token nicht gefunden"); + + $stored = json_decode(file_get_contents($tokenFile), true); + + $data = [ + 'grant_type' => 'refresh_token', + 'refresh_token' => $stored['refresh_token'], + 'client_id' => $this->clientId, + 'client_secret' => $this->clientSecret, + 'redirect_uri' => $this->redirectUri, + 'scope' => SCOPES, + ]; + + $tokenUrl = "https://login.microsoftonline.com/{$this->tenantId}/oauth2/v2.0/token"; + $response = $this->post($tokenUrl, $data); + $tokens = json_decode($response, true); + + if (!isset($tokens['access_token'])) { + echo "
Fehler beim Refresh-Token:\n";
+            print_r($tokens);
+            echo "\nResponse RAW:\n" . htmlspecialchars($response);
+            echo "
"; + exit; + } + + $this->accessToken = $tokens['access_token']; + $tokens['created_at'] = time(); + $email = $stored['email'] ?? null; + $this->saveTokensToFile($userId, $tokens, $email); + } + + // =========================================== + // NEU: Automatischer Refresh / Offline Access + // =========================================== + public function getValidAccessToken($userId) { + $tokenFile = TOKEN_DIR . "/$userId.json"; + if (!file_exists($tokenFile)) { + throw new Exception("Token-Datei für Benutzer $userId nicht gefunden"); + } + + $stored = json_decode(file_get_contents($tokenFile), true); + + // Prüfen, ob Access Token noch gültig ist (mit 2-Minuten-Puffer) + $expiresAt = ($stored['created_at'] ?? 0) + ($stored['expires_in'] ?? 0) - 120; + if (time() < $expiresAt && isset($stored['access_token'])) { + $this->accessToken = $stored['access_token']; + return $this->accessToken; + } + + // Token ist abgelaufen → refresh + $data = [ + 'grant_type' => 'refresh_token', + 'refresh_token' => $stored['refresh_token'], + 'client_id' => $this->clientId, + 'client_secret' => $this->clientSecret, + 'redirect_uri' => $this->redirectUri, + 'scope' => SCOPES, + ]; + + $tokenUrl = "https://login.microsoftonline.com/{$this->tenantId}/oauth2/v2.0/token"; + $response = $this->post($tokenUrl, $data); + $tokens = json_decode($response, true); + + if (!isset($tokens['access_token'])) { + echo "
Fehler beim automatischen Refresh:\n";
+            print_r($tokens);
+            echo "\nResponse RAW:\n" . htmlspecialchars($response);
+            echo "
"; + throw new Exception("Access Token konnte nicht erneuert werden."); + } + + $tokens['created_at'] = time(); + $email = $stored['email'] ?? null; + $this->saveTokensToFile($userId, $tokens, $email); + $this->accessToken = $tokens['access_token']; + + return $this->accessToken; + } + + // =========================================== + // Hilfsfunktionen + // =========================================== + + private function saveTokensToFile($userId, $tokens, $email = null) { + $tokens['email'] = $email; + file_put_contents(TOKEN_DIR . "/$userId.json", json_encode($tokens, JSON_PRETTY_PRINT)); + } + + public function getUserInfo() { + $headers = [ + "Authorization: Bearer {$this->accessToken}", + "Content-Type: application/json" + ]; + + $ch = curl_init("https://graph.microsoft.com/v1.0/me"); + curl_setopt_array($ch, [ + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HTTPHEADER => $headers + ]); + $res = curl_exec($ch); + curl_close($ch); + return json_decode($res, true); + } + + public function getAccessToken() { + return $this->accessToken; + } + + private function post($url, $data) { + $ch = curl_init($url); + curl_setopt_array($ch, [ + CURLOPT_RETURNTRANSFER => true, + CURLOPT_POST => true, + CURLOPT_HTTPHEADER => ["Content-Type: application/x-www-form-urlencoded"], + CURLOPT_POSTFIELDS => http_build_query($data), + ]); + $response = curl_exec($ch); + curl_close($ch); + return $response; + } + + + // ======================= + // Kalender-Funktionen + // ======================= + + /** + * Holt die nächsten X Termine des Benutzers + * @param int $top Anzahl der Termine, default 10 + * @return array Termine + */ + public function getCalendarEvents($top = 10) { + // Sicherstellen, dass Access Token gültig ist + $token = $this->accessToken ?? null; + if (!$token) throw new Exception("Kein Access Token vorhanden."); + + $headers = [ + "Authorization: Bearer {$token}", + "Content-Type: application/json" + ]; + + $url = "https://graph.microsoft.com/v1.0/me/events?\$top={$top}&\$orderby=start/dateTime"; + + $ch = curl_init($url); + curl_setopt_array($ch, [ + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HTTPHEADER => $headers + ]); + + $res = curl_exec($ch); + curl_close($ch); + + $data = json_decode($res, true); + return $data['value'] ?? []; + } + + /** + * Erstellt einen neuen Termin + * @param string $subject Betreff + * @param string $start ISO8601 Startzeit, z.B. 2025-11-11T10:00:00 + * @param string $end ISO8601 Endzeit + * @param string $body Textinhalt des Termins + * @return array Microsoft Graph Antwort + */ + public function createCalendarEvent($subject, $start, $end, $body = '') { + $token = $this->accessToken ?? null; + if (!$token) throw new Exception("Kein Access Token vorhanden."); + + $headers = [ + "Authorization: Bearer {$token}", + "Content-Type: application/json" + ]; + + $data = [ + 'subject' => $subject, + 'start' => [ + 'dateTime' => $start, + 'timeZone' => 'UTC' + ], + 'end' => [ + 'dateTime' => $end, + 'timeZone' => 'UTC' + ], + 'body' => [ + 'contentType' => 'Text', + 'content' => $body + ] + ]; + + $ch = curl_init("https://graph.microsoft.com/v1.0/me/events"); + curl_setopt_array($ch, [ + CURLOPT_RETURNTRANSFER => true, + CURLOPT_POST => true, + CURLOPT_HTTPHEADER => $headers, + CURLOPT_POSTFIELDS => json_encode($data), + ]); + + $res = curl_exec($ch); + curl_close($ch); + + return json_decode($res, true); + } + + /** + * Löscht einen Termin anhand der Event-ID + * @param string $eventId ID des Termins + * @return bool Erfolg + */ + public function deleteCalendarEvent($eventId) { + $token = $this->accessToken ?? null; + if (!$token) throw new Exception("Kein Access Token vorhanden."); + + $headers = [ + "Authorization: Bearer {$token}" + ]; + + $ch = curl_init("https://graph.microsoft.com/v1.0/me/events/{$eventId}"); + curl_setopt_array($ch, [ + CURLOPT_CUSTOMREQUEST => "DELETE", + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HTTPHEADER => $headers + ]); + + curl_exec($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + + return $httpCode === 204; // 204 = gelöscht erfolgreich + } + +} +?>