OIDC test - test jumbojett oidc round two change root paths
This commit is contained in:
1 parent
4b7abac7ca
commit
07d3895eb5
6 files changed
+6
-6
No files matched your search
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
use Jumbojett\OpenIDConnectClient;
|
||||
|
||||
session_start();
|
||||
$config = require __DIR__ . '/../config.php';
|
||||
|
||||
$oidc = new OpenIDConnectClient(
|
||||
$config['provider_url'],
|
||||
$config['client_id'],
|
||||
$config['client_secret']
|
||||
);
|
||||
|
||||
// Tell the library where to return after the user logs in
|
||||
$oidc->setRedirectURL($config['redirect_uri']);
|
||||
|
||||
// Tell it which scopes we want
|
||||
$oidc->addScope($config['scopes']);
|
||||
|
||||
// The OIDC flow we’ll use
|
||||
$oidc->setResponseTypes([$config['response_type']]);
|
||||
|
||||
// Optional: for local development you can relax TLS validation
|
||||
// $oidc->setVerifyHost(false);
|
||||
// $oidc->setVerifyPeer(false);
|
||||
|
||||
$oidc->authenticate(); // This automatically redirects to Authelia
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
use Jumbojett\OpenIDConnectClient;
|
||||
|
||||
session_start();
|
||||
$config = require __DIR__ . '/../config.php';
|
||||
|
||||
$oidc = new OpenIDConnectClient(
|
||||
$config['provider_url'],
|
||||
$config['client_id'],
|
||||
$config['client_secret']
|
||||
);
|
||||
$oidc->setRedirectURL($config['redirect_uri']);
|
||||
$oidc->addScope($config['scopes']);
|
||||
$oidc->setResponseTypes([$config['response_type']]);
|
||||
|
||||
// This will read the `code` query parameter, fetch the tokens
|
||||
// and validate everything.
|
||||
$oidc->authenticate();
|
||||
|
||||
|
||||
// Fetch the OpenID Connect userinfo claims
|
||||
$claims = $oidc->requestUserInfo(); // → stdClass with the claims
|
||||
|
||||
// Store what we need in the PHP session
|
||||
$_SESSION['authenticated'] = true;
|
||||
$_SESSION['name'] = $claims->name ?? $claims->given_name ?? $claims->family_name ?? '';
|
||||
$_SESSION['email'] = $claims->email ?? '';
|
||||
$_SESSION['groups'] = $claims->groups ?? [];
|
||||
|
||||
// Redirect back to the home page
|
||||
header('Location: ../');
|
||||
exit;
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
session_start();
|
||||
$config = require __DIR__ . '/../config.php';
|
||||
|
||||
if (!isset($_SESSION['authenticated'])) {
|
||||
// User not logged in – show a login button
|
||||
echo '<h1>Welcome to the demo</h1>';
|
||||
echo '<p><a href="auth.php">Login with Authelia SSO</a></p>';
|
||||
exit;
|
||||
}
|
||||
|
||||
// The user is logged in – display the attributes
|
||||
$name = $_SESSION['name'] ?? 'unknown';
|
||||
$email = $_SESSION['email'] ?? 'unknown';
|
||||
$groups = $_SESSION['groups'] ?? [];
|
||||
|
||||
echo '<h1>Logged in as ' . htmlspecialchars($name) . '</h1>';
|
||||
echo '<ul>';
|
||||
echo '<li><strong>Email:</strong> ' . htmlspecialchars($email) . '</li>';
|
||||
echo '<li><strong>Groups:</strong> ' . htmlspecialchars(implode(', ', $groups)) . '</li>';
|
||||
echo '</ul>';
|
||||
|
||||
echo '<p><a href="logout.php">Logout</a></p>';
|
||||
@@ -0,0 +1,38 @@
|
||||
<!-- index.html (served by PHP) -->
|
||||
<input type="file" id="photo" style="display:none;">
|
||||
<div id="drop" style="border:2px dashed #bbb; padding:20px;">
|
||||
Drag photo here or click to choose
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const drop = document.getElementById('drop');
|
||||
const photoInput = document.getElementById('photo');
|
||||
|
||||
drop.onclick = () => photoInput.click();
|
||||
|
||||
drop.addEventListener('dragover', e => { e.preventDefault(); drop.style.background='#eef'; });
|
||||
drop.addEventListener('dragleave', e => { e.preventDefault(); drop.style.background=''; });
|
||||
|
||||
drop.addEventListener('drop', e => {
|
||||
e.preventDefault();
|
||||
drop.style.background='';
|
||||
const file = e.dataTransfer.files[0];
|
||||
upload(file);
|
||||
});
|
||||
|
||||
photoInput.addEventListener('change', () => upload(photoInput.files[0]));
|
||||
|
||||
async function upload(file) {
|
||||
// 1️⃣ Send file to PHP, which will forward it to Flask
|
||||
const form = new FormData();
|
||||
form.append('photo', file);
|
||||
|
||||
const res = await fetch('/api/upload_photo', { // <-- PHP endpoint
|
||||
method: 'POST',
|
||||
body: form
|
||||
});
|
||||
|
||||
const json = await res.json();
|
||||
console.log('Uploaded:', json);
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,314 @@
|
||||
<?php
|
||||
/**
|
||||
* photos.php - Service Provider Photo Gallery Implementation
|
||||
* Requirements:
|
||||
* 1. Upload multiple images via PHP Frontend
|
||||
* 2. Display gallery with thumbnail selection
|
||||
* 3. Use Flask API for storage and metadata
|
||||
* 4. Store photos in file system (not database BLOBs)
|
||||
*/
|
||||
require_once __DIR__ . '/config.php';
|
||||
|
||||
// Validate provider ID
|
||||
if (!isset($_GET['id']) || empty($_GET['id'])) {
|
||||
die('Provider ID missing. Use: photos.php?id=123');
|
||||
}
|
||||
$provider_id = $_GET['id'];
|
||||
|
||||
// Fetch existing photos from API
|
||||
$api_url = BASE_API_URL . '/providers/' . urlencode($provider_id) . "/photos";
|
||||
$existing_photos = [];
|
||||
try {
|
||||
$response = file_get_contents($api_url);
|
||||
$existing_photos = json_decode($response, true);
|
||||
if (isset($existing_photos['error'])) {
|
||||
trigger_error($existing_photos['error'], E_USER_WARNING);
|
||||
$existing_photos = [];
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
trigger_error('API error: ' . $e->getMessage(), E_USER_WARNING);
|
||||
}
|
||||
|
||||
// Check upload permissions
|
||||
$has_upload_perm = true; // Add authorization logic here
|
||||
|
||||
// Generate unique token for upload (security)
|
||||
$upload_token = bin2hex(random_bytes(16));
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Photos for Service Provider #<?php echo htmlspecialchars($provider_id); ?></title>
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Arial, sans-serif;
|
||||
line-height: 1.5;
|
||||
color: #333;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
h1 {
|
||||
margin-bottom: 30px;
|
||||
border-bottom: 1px solid #eee;
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
.upload-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 15px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
.upload-btn {
|
||||
padding: 10px 20px;
|
||||
background: #3a86ff;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.upload-btn:hover {
|
||||
background: #1d66cc;
|
||||
}
|
||||
#preview-container {
|
||||
display: none;
|
||||
gap: 10px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
.photo-item {
|
||||
position: relative;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
margin: 5px;
|
||||
}
|
||||
.photo-item img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.main-indicator {
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
right: 2px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
background: #3a86ff;
|
||||
border-radius: 50%;
|
||||
}
|
||||
#gallery {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
||||
gap: 20px;
|
||||
margin-top: 30px;
|
||||
}
|
||||
.loading {
|
||||
text-align: center;
|
||||
padding: 20px;
|
||||
color: #666;
|
||||
}
|
||||
.no-photos {
|
||||
text-align: center;
|
||||
padding: 50px;
|
||||
color: #777;
|
||||
}
|
||||
.error {
|
||||
color: #e74c3c;
|
||||
margin: 20px 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Photos for Service Provider #<?php echo htmlspecialchars($provider_id); ?></h1>
|
||||
|
||||
<?php if (isset($existing_photos['error'])): ?>
|
||||
<div class="error">
|
||||
<?php echo htmlspecialchars($existing_photos['error']); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($has_upload_perm): ?>
|
||||
<div class="upload-section">
|
||||
<input type="file" id="photo-upload" name="photos[]" multiple accept="image/*">
|
||||
<button id="upload-btn" class="upload-btn">Upload Photos</button>
|
||||
</div>
|
||||
<div id="preview-container"></div>
|
||||
<?php else: ?>
|
||||
<p>Upload permissions disabled. Contact administrator.</p>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="loading" id="loading">
|
||||
Loading photos...
|
||||
</div>
|
||||
|
||||
<div id="gallery">
|
||||
<?php if (empty($existing_photos)): ?>
|
||||
<div class="no-photos">
|
||||
<h2>No photos uploaded yet</h2>
|
||||
<p>Upload images to display them here</p>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<?php foreach ($existing_photos as $photo): ?>
|
||||
<div class="photo-item">
|
||||
<input type="radio" name="main_photo" value="<?php echo htmlspecialchars($photo['path']); ?>" <?php echo $photo['is_main'] ? 'checked' : ''; ?> class="main-radio">
|
||||
<img src="<?php echo htmlspecialchars($photo['path']); ?>" alt="Service provider photo">
|
||||
<?php if ($photo['is_main']): ?>
|
||||
<div class="main-indicator"></div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const photoInput = document.getElementById('photo-upload');
|
||||
const previewContainer = document.getElementById('preview-container');
|
||||
const gallery = document.getElementById('gallery');
|
||||
const loading = document.getElementById('loading');
|
||||
|
||||
// Show preview on file selection
|
||||
photoInput.addEventListener('change', function(e) {
|
||||
if (this.files.length > 0) {
|
||||
previewContainer.style.display = 'flex';
|
||||
}
|
||||
|
||||
previewContainer.innerHTML = '';
|
||||
for (let i = 0; i < this.files.length; i++) {
|
||||
const file = this.files[i];
|
||||
const reader = new FileReader();
|
||||
|
||||
reader.onload = function(e) {
|
||||
const preview = document.createElement('div');
|
||||
preview.className = 'photo-item';
|
||||
|
||||
preview.innerHTML = `
|
||||
<input type="radio" name="main_photo" value="${file.name}"
|
||||
class="main-radio"
|
||||
style="position: absolute; top: 2px; left: 2px;">
|
||||
<img src="${e.target.result}"
|
||||
alt="Photo preview">
|
||||
<div style="position: absolute; top: 2px; right: 2px;
|
||||
width: 16px; height: 16px;
|
||||
background: #3a86ff;
|
||||
border-radius: 50%;"></div>
|
||||
`;
|
||||
|
||||
previewContainer.appendChild(preview);
|
||||
};
|
||||
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
});
|
||||
|
||||
// Handle upload button
|
||||
document.getElementById('upload-btn').addEventListener('click', async () => {
|
||||
const fileInput = document.getElementById('photo-upload');
|
||||
if (!fileInput.files.length) {
|
||||
alert('Please select at least one photo to upload');
|
||||
return;
|
||||
}
|
||||
|
||||
const formData = new FormData();
|
||||
for (let i = 0; i < fileInput.files.length; i++) {
|
||||
formData.append('photos[]', fileInput.files[i]);
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(
|
||||
BASE_API_URL . '/providers/<?php echo urlencode($provider_id); ?>/photos',
|
||||
{
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
headers: {
|
||||
'X-Upload-Token': '<?php echo $upload_token; ?>'
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`API error: ${response.status}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
// Add new photos to gallery
|
||||
data.paths.forEach(path => {
|
||||
const newPhoto = document.createElement('div');
|
||||
newPhoto.className = 'photo-item';
|
||||
|
||||
newPhoto.innerHTML = `
|
||||
<input type="radio" name="main_photo" value="${path}"
|
||||
class="main-radio"
|
||||
style="position: absolute; top: 2px; left: 2px;">
|
||||
<img src="${path}"
|
||||
alt="New photo"
|
||||
style="object-fit: cover;">
|
||||
<div style="position: absolute; top: 2px; right: 2px;
|
||||
width: 16px; height: 16px;
|
||||
background: #3a86ff;
|
||||
border-radius: 50%;"></div>
|
||||
`;
|
||||
|
||||
gallery.appendChild(newPhoto);
|
||||
});
|
||||
|
||||
// Reset form
|
||||
fileInput.value = '';
|
||||
previewContainer.style.display = 'none';
|
||||
|
||||
// Update main photo selection (if any)
|
||||
const mainRadios = gallery.querySelectorAll('.main-radio');
|
||||
if (mainRadios.length > 0) {
|
||||
mainRadios[0].checked = true;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Upload failed:', error);
|
||||
alert('Upload failed: ' + error.message);
|
||||
}
|
||||
});
|
||||
|
||||
// Handle main photo selection
|
||||
gallery.addEventListener('change', async (e) => {
|
||||
if (e.target.className === 'main-radio') {
|
||||
const mainPhoto = e.target.value;
|
||||
const providerId = '<?php echo $provider_id; ?>';
|
||||
|
||||
try {
|
||||
const response = await fetch(
|
||||
BASE_API_URL . '/providers/${providerId}/main_photo',
|
||||
{
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
photo_path: mainPhoto
|
||||
})
|
||||
}
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`API error: ${response.status}`);
|
||||
}
|
||||
|
||||
// Update visuals
|
||||
gallery.querySelectorAll('.main-indicator').forEach(ind => {
|
||||
ind.style.display = 'none';
|
||||
});
|
||||
e.target.parentElement.querySelector('.main-indicator').style.display = 'block';
|
||||
} catch (error) {
|
||||
console.error('Setting main photo failed:', error);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Hide loading message
|
||||
loading.style.display = 'none';
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in new issue
Block a user