first commit
This commit is contained in:
125
templates/email/activation.html
Normal file
125
templates/email/activation.html
Normal file
@@ -0,0 +1,125 @@
|
||||
{% load i18n %}
|
||||
|
||||
{% block subject %}
|
||||
Activate Your Account - {{ site_name }}
|
||||
{% endblock subject %}
|
||||
|
||||
{% block text_body %}
|
||||
Hi{% if user.first_name %} {{ user.first_name }}{% endif %},
|
||||
|
||||
Thank you for registering with {{ site_name }}!
|
||||
|
||||
To activate your account, please visit the following link:
|
||||
|
||||
http://{{ domain }}/{{ url }}
|
||||
|
||||
This activation link will expire in 24 hours for security reasons.
|
||||
|
||||
If you didn't create an account with us, you can safely ignore this email.
|
||||
|
||||
---
|
||||
This is an automated message, please do not reply to this email.
|
||||
© {{ site_name }} - All rights reserved
|
||||
{% endblock text_body %}
|
||||
|
||||
{% block html_body %}
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
line-height: 1.6;
|
||||
color: #333;
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
background-color: #f4f4f4;
|
||||
}
|
||||
.container {
|
||||
background-color: #ffffff;
|
||||
padding: 30px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
}
|
||||
.header {
|
||||
text-align: center;
|
||||
padding-bottom: 20px;
|
||||
border-bottom: 2px solid #4CAF50;
|
||||
}
|
||||
h1 {
|
||||
color: #4CAF50;
|
||||
margin: 0;
|
||||
}
|
||||
.content {
|
||||
margin: 30px 0;
|
||||
}
|
||||
.button {
|
||||
display: inline-block;
|
||||
padding: 12px 30px;
|
||||
background-color: #4CAF50;
|
||||
color: #ffffff !important;
|
||||
text-decoration: none;
|
||||
border-radius: 5px;
|
||||
margin: 20px 0;
|
||||
text-align: center;
|
||||
}
|
||||
.button:hover {
|
||||
background-color: #45a049;
|
||||
}
|
||||
.link-container {
|
||||
text-align: center;
|
||||
margin: 20px 0;
|
||||
}
|
||||
.footer {
|
||||
margin-top: 30px;
|
||||
padding-top: 20px;
|
||||
border-top: 1px solid #ddd;
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
text-align: center;
|
||||
}
|
||||
.code {
|
||||
background-color: #f5f5f5;
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
word-break: break-all;
|
||||
font-family: monospace;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>Welcome! 🎉</h1>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<p>Hi{% if user.first_name %} {{ user.first_name }}{% endif %},</p>
|
||||
|
||||
<p>Thank you for registering with {{ site_name }}! To complete your registration and activate your account, please click the button below:</p>
|
||||
|
||||
<div class="link-container">
|
||||
<a href="http://{{ domain }}/{{ url }}" class="button">Activate Your Account</a>
|
||||
</div>
|
||||
|
||||
<p>Or copy and paste this link into your browser:</p>
|
||||
<div class="code">
|
||||
http://{{ domain }}/{{ url }}
|
||||
</div>
|
||||
|
||||
<p><strong>Note:</strong> This activation link will expire in 24 hours for security reasons.</p>
|
||||
|
||||
<p>If you didn't create an account with us, you can safely ignore this email.</p>
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
<p>This is an automated message, please do not reply to this email.</p>
|
||||
<p>© {{ site_name }} - All rights reserved</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
{% endblock html_body %}
|
||||
23
templates/email/activation.txt
Normal file
23
templates/email/activation.txt
Normal file
@@ -0,0 +1,23 @@
|
||||
{% load i18n %}
|
||||
|
||||
{% block subject %}
|
||||
Activate Your Account - {{ site_name }}
|
||||
{% endblock subject %}
|
||||
|
||||
{% block text_body %}
|
||||
Hi{% if user.first_name %} {{ user.first_name }}{% endif %},
|
||||
|
||||
Thank you for registering with {{ site_name }}!
|
||||
|
||||
To activate your account, please visit the following link:
|
||||
|
||||
http://{{ domain }}/{{ url }}
|
||||
|
||||
This activation link will expire in 24 hours for security reasons.
|
||||
|
||||
If you didn't create an account with us, you can safely ignore this email.
|
||||
|
||||
---
|
||||
This is an automated message, please do not reply to this email.
|
||||
© {{ site_name }} - All rights reserved
|
||||
{% endblock text_body %}
|
||||
79
templates/email/confirmation.html
Normal file
79
templates/email/confirmation.html
Normal file
@@ -0,0 +1,79 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Account Activated</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
line-height: 1.6;
|
||||
color: #333;
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
background-color: #f4f4f4;
|
||||
}
|
||||
.container {
|
||||
background-color: #ffffff;
|
||||
padding: 30px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
}
|
||||
.header {
|
||||
text-align: center;
|
||||
padding-bottom: 20px;
|
||||
border-bottom: 2px solid #4CAF50;
|
||||
}
|
||||
h1 {
|
||||
color: #4CAF50;
|
||||
margin: 0;
|
||||
}
|
||||
.content {
|
||||
margin: 30px 0;
|
||||
}
|
||||
.footer {
|
||||
margin-top: 30px;
|
||||
padding-top: 20px;
|
||||
border-top: 1px solid #ddd;
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
text-align: center;
|
||||
}
|
||||
.success-icon {
|
||||
text-align: center;
|
||||
font-size: 48px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>Account Activated! ✅</h1>
|
||||
</div>
|
||||
|
||||
<div class="success-icon">
|
||||
🎉
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<p>Hi{% if user.first_name %} {{ user.first_name }}{% endif %},</p>
|
||||
|
||||
<p>Great news! Your account has been successfully activated.</p>
|
||||
|
||||
<p>You can now log in and start using all features of {{ site_name }}.</p>
|
||||
|
||||
<p>If you have any questions or need assistance, please don't hesitate to contact our support team.</p>
|
||||
|
||||
<p>Welcome aboard!</p>
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
<p>This is an automated message, please do not reply to this email.</p>
|
||||
<p>© {{ site_name }} - All rights reserved</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
16
templates/email/confirmation.txt
Normal file
16
templates/email/confirmation.txt
Normal file
@@ -0,0 +1,16 @@
|
||||
Account Activated!
|
||||
|
||||
Hi{% if user.first_name %} {{ user.first_name }}{% endif %},
|
||||
|
||||
Great news! Your account has been successfully activated.
|
||||
|
||||
You can now log in and start using all features of {{ site_name }}.
|
||||
|
||||
If you have any questions or need assistance, please don't hesitate to contact our support team.
|
||||
|
||||
Welcome aboard!
|
||||
|
||||
---
|
||||
This is an automated message, please do not reply to this email.
|
||||
© {{ site_name }} - All rights reserved
|
||||
|
||||
114
templates/email/password_reset.html
Normal file
114
templates/email/password_reset.html
Normal file
@@ -0,0 +1,114 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Password Reset</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
line-height: 1.6;
|
||||
color: #333;
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
background-color: #f4f4f4;
|
||||
}
|
||||
.container {
|
||||
background-color: #ffffff;
|
||||
padding: 30px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
}
|
||||
.header {
|
||||
text-align: center;
|
||||
padding-bottom: 20px;
|
||||
border-bottom: 2px solid #FF9800;
|
||||
}
|
||||
h1 {
|
||||
color: #FF9800;
|
||||
margin: 0;
|
||||
}
|
||||
.content {
|
||||
margin: 30px 0;
|
||||
}
|
||||
.button {
|
||||
display: inline-block;
|
||||
padding: 12px 30px;
|
||||
background-color: #FF9800;
|
||||
color: #ffffff;
|
||||
text-decoration: none;
|
||||
border-radius: 5px;
|
||||
margin: 20px 0;
|
||||
text-align: center;
|
||||
}
|
||||
.button:hover {
|
||||
background-color: #F57C00;
|
||||
}
|
||||
.link-container {
|
||||
text-align: center;
|
||||
margin: 20px 0;
|
||||
}
|
||||
.footer {
|
||||
margin-top: 30px;
|
||||
padding-top: 20px;
|
||||
border-top: 1px solid #ddd;
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
text-align: center;
|
||||
}
|
||||
.code {
|
||||
background-color: #f5f5f5;
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
word-break: break-all;
|
||||
font-family: monospace;
|
||||
}
|
||||
.warning {
|
||||
background-color: #fff3cd;
|
||||
border-left: 4px solid #FF9800;
|
||||
padding: 12px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>Password Reset 🔐</h1>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<p>Hi{% if user.first_name %} {{ user.first_name }}{% endif %},</p>
|
||||
|
||||
<p>We received a request to reset your password. Click the button below to choose a new password:</p>
|
||||
|
||||
<div class="link-container">
|
||||
<a href="{{ protocol }}://{{ domain }}/{{ url }}" class="button">Reset Password</a>
|
||||
</div>
|
||||
|
||||
<p>Or copy and paste this link into your browser:</p>
|
||||
<div class="code">
|
||||
{{ protocol }}://{{ domain }}/{{ url }}
|
||||
</div>
|
||||
|
||||
<div class="warning">
|
||||
<strong>⚠️ Security Note:</strong> This password reset link will expire in 1 hour. If you didn't request a password reset, please ignore this email and your password will remain unchanged.
|
||||
</div>
|
||||
|
||||
<p>For security reasons, we recommend that you:</p>
|
||||
<ul>
|
||||
<li>Choose a strong, unique password</li>
|
||||
<li>Don't reuse passwords from other sites</li>
|
||||
<li>Enable two-factor authentication if available</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
<p>This is an automated message, please do not reply to this email.</p>
|
||||
<p>© {{ site_name }} - All rights reserved</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
21
templates/email/password_reset.txt
Normal file
21
templates/email/password_reset.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
Password Reset Request
|
||||
|
||||
Hi{% if user.first_name %} {{ user.first_name }}{% endif %},
|
||||
|
||||
We received a request to reset your password. To choose a new password, please visit the following link:
|
||||
|
||||
{{ protocol }}://{{ domain }}/{{ url }}
|
||||
|
||||
This password reset link will expire in 1 hour for security reasons.
|
||||
|
||||
If you didn't request a password reset, please ignore this email and your password will remain unchanged.
|
||||
|
||||
For security reasons, we recommend that you:
|
||||
- Choose a strong, unique password
|
||||
- Don't reuse passwords from other sites
|
||||
- Enable two-factor authentication if available
|
||||
|
||||
---
|
||||
This is an automated message, please do not reply to this email.
|
||||
© {{ site_name }} - All rights reserved
|
||||
|
||||
168
templates/spa_test/activate.html
Normal file
168
templates/spa_test/activate.html
Normal file
@@ -0,0 +1,168 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Activating Account...</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.container {
|
||||
background: white;
|
||||
border-radius: 20px;
|
||||
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
|
||||
padding: 3rem;
|
||||
max-width: 500px;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.spinner {
|
||||
border: 4px solid #f3f3f3;
|
||||
border-top: 4px solid #667eea;
|
||||
border-radius: 50%;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
animation: spin 1s linear infinite;
|
||||
margin: 0 auto 2rem;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
.success {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.success-icon {
|
||||
font-size: 64px;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.error {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.error-icon {
|
||||
font-size: 64px;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #333;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
p {
|
||||
color: #666;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: inline-block;
|
||||
padding: 1rem 2rem;
|
||||
background: #667eea;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-radius: 8px;
|
||||
font-weight: 600;
|
||||
transition: background 0.3s;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background: #5568d3;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div id="loading">
|
||||
<div class="spinner"></div>
|
||||
<h1>Activating Your Account...</h1>
|
||||
<p>Please wait while we activate your account.</p>
|
||||
</div>
|
||||
|
||||
<div id="success" class="success">
|
||||
<div class="success-icon">✅</div>
|
||||
<h1>Account Activated!</h1>
|
||||
<p>Your account has been successfully activated. You can now log in.</p>
|
||||
<a href="/api/v1/spa/" class="btn">Go to Login</a>
|
||||
</div>
|
||||
|
||||
<div id="error" class="error">
|
||||
<div class="error-icon">❌</div>
|
||||
<h1>Activation Failed</h1>
|
||||
<p id="errorMessage">The activation link is invalid or has expired.</p>
|
||||
<a href="/api/v1/spa/" class="btn">Back to Login</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Get uid and token from Django template context
|
||||
const finalUid = '{{ uid }}';
|
||||
const finalToken = '{{ token }}';
|
||||
|
||||
console.log('Activating with:', { uid: finalUid, token: finalToken });
|
||||
|
||||
// Activate account
|
||||
async function activateAccount() {
|
||||
try {
|
||||
const response = await fetch('http://localhost:8000/api/v1/auth/users/activation/', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
uid: finalUid,
|
||||
token: finalToken
|
||||
})
|
||||
});
|
||||
|
||||
document.getElementById('loading').style.display = 'none';
|
||||
|
||||
if (response.ok || response.status === 204) {
|
||||
document.getElementById('success').style.display = 'block';
|
||||
} else {
|
||||
const data = await response.json().catch(() => ({}));
|
||||
document.getElementById('error').style.display = 'block';
|
||||
if (data.detail || data.token || data.uid) {
|
||||
document.getElementById('errorMessage').textContent =
|
||||
data.detail || data.token?.[0] || data.uid?.[0] || 'Activation failed.';
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Activation error:', error);
|
||||
document.getElementById('loading').style.display = 'none';
|
||||
document.getElementById('error').style.display = 'block';
|
||||
document.getElementById('errorMessage').textContent = 'Network error. Please try again.';
|
||||
}
|
||||
}
|
||||
|
||||
// Start activation
|
||||
if (finalUid && finalToken) {
|
||||
activateAccount();
|
||||
} else {
|
||||
document.getElementById('loading').style.display = 'none';
|
||||
document.getElementById('error').style.display = 'block';
|
||||
document.getElementById('errorMessage').textContent = 'Missing activation parameters.';
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
205
templates/spa_test/index.html
Normal file
205
templates/spa_test/index.html
Normal file
@@ -0,0 +1,205 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Django Auth - SPA Test (Token-Based)</title>
|
||||
<link rel="stylesheet" href="/static/spa-test.css">
|
||||
<!-- Google OAuth2 -->
|
||||
<script src="https://accounts.google.com/gsi/client" async defer></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<!-- Navigation -->
|
||||
<nav class="navbar" id="navbar" style="display: none;">
|
||||
<div class="nav-container">
|
||||
<div class="nav-brand">🔐 Django Auth</div>
|
||||
<div class="nav-menu">
|
||||
<span id="userEmail" class="user-email"></span>
|
||||
<button onclick="logout()" class="btn-logout">Logout</button>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- Login Page -->
|
||||
<div id="loginPage" class="page">
|
||||
<div class="container">
|
||||
<div class="card">
|
||||
<h1>Welcome Back! 👋</h1>
|
||||
<p class="subtitle">Sign in to continue</p>
|
||||
|
||||
<!-- Email/Password Login -->
|
||||
<form id="loginForm" onsubmit="handleLogin(event)">
|
||||
<div class="form-group">
|
||||
<label>Email</label>
|
||||
<input type="email" id="email" placeholder="your@email.com" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Password</label>
|
||||
<input type="password" id="password" placeholder="••••••••" required>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">
|
||||
Sign In
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<div class="divider">OR</div>
|
||||
|
||||
<!-- Social Login (Token-Based) -->
|
||||
<div class="social-buttons">
|
||||
<button onclick="loginWithGoogle()" class="btn btn-google">
|
||||
🔵 Continue with Google
|
||||
</button>
|
||||
<button onclick="loginWithGitHub()" class="btn btn-github">
|
||||
⚫ Continue with GitHub
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<p class="footer-text">
|
||||
Don't have an account? <a href="#" onclick="showRegister()">Sign up</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div id="errorAlert" class="alert alert-error" style="display: none;"></div>
|
||||
<div class="info-box">
|
||||
<strong>ℹ️ Token-Based Flow:</strong>
|
||||
<p>Bu sayfa Nuxt/Next.js gibi çalışır:</p>
|
||||
<ol>
|
||||
<li>Frontend'de Google/GitHub OAuth</li>
|
||||
<li>Access token alınır</li>
|
||||
<li>Token Django'ya POST edilir</li>
|
||||
<li>Django JWT token döner</li>
|
||||
<li>JWT localStorage'a kaydedilir</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Register Page -->
|
||||
<div id="registerPage" class="page" style="display: none;">
|
||||
<div class="container">
|
||||
<div class="card">
|
||||
<h1>Create Account 🎉</h1>
|
||||
<p class="subtitle">Join us today</p>
|
||||
|
||||
<form id="registerForm" onsubmit="handleRegister(event)">
|
||||
<div class="form-group">
|
||||
<label>Email</label>
|
||||
<input type="email" id="regEmail" placeholder="your@email.com" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>First Name</label>
|
||||
<input type="text" id="firstName" placeholder="John" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Last Name</label>
|
||||
<input type="text" id="lastName" placeholder="Doe" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Password</label>
|
||||
<input type="password" id="regPassword" placeholder="••••••••" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Confirm Password</label>
|
||||
<input type="password" id="regPasswordConfirm" placeholder="••••••••" required>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">
|
||||
Create Account
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<p class="footer-text">
|
||||
Already have an account? <a href="#" onclick="showLogin()">Sign in</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div id="registerSuccess" class="alert alert-success" style="display: none;">
|
||||
✅ Account created! Please check your email to activate your account.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Dashboard Page -->
|
||||
<div id="dashboardPage" class="page" style="display: none;">
|
||||
<div class="container">
|
||||
<div class="card">
|
||||
<h1>Dashboard 🎯</h1>
|
||||
<p class="subtitle">Welcome to your account</p>
|
||||
|
||||
<div class="profile-section">
|
||||
<div class="profile-avatar">👤</div>
|
||||
<div class="profile-info">
|
||||
<h2 id="profileName">Loading...</h2>
|
||||
<p id="profileEmail" class="text-muted">Loading...</p>
|
||||
<span id="profileStatus" class="badge"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="stats-grid">
|
||||
<div class="stat-card">
|
||||
<div class="stat-icon">📧</div>
|
||||
<div class="stat-info">
|
||||
<h3 id="userEmailStat">-</h3>
|
||||
<p>Email Address</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-icon">🔑</div>
|
||||
<div class="stat-info">
|
||||
<h3>JWT</h3>
|
||||
<p>Authentication</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-icon">📅</div>
|
||||
<div class="stat-info">
|
||||
<h3 id="joinedDate">-</h3>
|
||||
<p>Member Since</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="token-section">
|
||||
<h3>Your JWT Tokens 🔐</h3>
|
||||
<div class="token-box">
|
||||
<label>Access Token (from Django)</label>
|
||||
<textarea id="accessToken" readonly></textarea>
|
||||
<button onclick="copyToken('access')" class="btn btn-small">Copy</button>
|
||||
</div>
|
||||
<div class="token-box">
|
||||
<label>Refresh Token (from Django)</label>
|
||||
<textarea id="refreshToken" readonly></textarea>
|
||||
<button onclick="copyToken('refresh')" class="btn btn-small">Copy</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button onclick="testProtectedEndpoint()" class="btn btn-primary">
|
||||
🧪 Test Protected Endpoint
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Loading Overlay -->
|
||||
<div id="loadingOverlay" class="loading-overlay" style="display: none;">
|
||||
<div class="spinner"></div>
|
||||
<p>Loading...</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/static/spa-test.js"></script>
|
||||
|
||||
<!-- Google OAuth Initialization -->
|
||||
<script>
|
||||
window.onload = function() {
|
||||
// Initialize Google OAuth
|
||||
if (typeof google !== 'undefined') {
|
||||
google.accounts.id.initialize({
|
||||
client_id: '915364976256-691m0s87as2r5vdbqr96f6humblseobt.apps.googleusercontent.com',
|
||||
callback: handleGoogleCallback
|
||||
});
|
||||
}
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
353
templates/test_github_simple.html
Normal file
353
templates/test_github_simple.html
Normal file
@@ -0,0 +1,353 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>GitHub OAuth Test</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
background: linear-gradient(135deg, #24292e 0%, #1a1e22 100%);
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.container {
|
||||
background: white;
|
||||
border-radius: 20px;
|
||||
box-shadow: 0 20px 60px rgba(0,0,0,0.5);
|
||||
padding: 40px;
|
||||
max-width: 600px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #24292e;
|
||||
margin-bottom: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
color: #666;
|
||||
text-align: center;
|
||||
margin-bottom: 30px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.info-box {
|
||||
background: #f6f8fa;
|
||||
border: 2px solid #e1e4e8;
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.info-box h3 {
|
||||
color: #24292e;
|
||||
margin-bottom: 10px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.info-box ol {
|
||||
margin-left: 20px;
|
||||
color: #586069;
|
||||
font-size: 14px;
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
.info-box code {
|
||||
background: #fff;
|
||||
padding: 2px 6px;
|
||||
border-radius: 3px;
|
||||
font-family: 'Courier New', monospace;
|
||||
font-size: 12px;
|
||||
border: 1px solid #e1e4e8;
|
||||
}
|
||||
|
||||
.input-group {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.input-group label {
|
||||
display: block;
|
||||
color: #24292e;
|
||||
font-weight: 600;
|
||||
margin-bottom: 8px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.input-group input {
|
||||
width: 100%;
|
||||
padding: 12px 15px;
|
||||
border: 2px solid #e1e4e8;
|
||||
border-radius: 6px;
|
||||
font-size: 14px;
|
||||
font-family: 'Courier New', monospace;
|
||||
transition: border-color 0.3s;
|
||||
}
|
||||
|
||||
.input-group input:focus {
|
||||
outline: none;
|
||||
border-color: #0366d6;
|
||||
}
|
||||
|
||||
.btn {
|
||||
width: 100%;
|
||||
padding: 15px 20px;
|
||||
margin: 10px 0;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 5px 15px rgba(0,0,0,0.2);
|
||||
}
|
||||
|
||||
.btn-github {
|
||||
background: #24292e;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-github:hover {
|
||||
background: #1a1e22;
|
||||
}
|
||||
|
||||
.btn-github:disabled {
|
||||
background: #6a737d;
|
||||
cursor: not-allowed;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.result {
|
||||
margin-top: 30px;
|
||||
padding: 20px;
|
||||
background: #f8f9fa;
|
||||
border-radius: 8px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.result.show {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.result h3 {
|
||||
color: #333;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.result.success {
|
||||
background: #d4edda;
|
||||
border: 2px solid #c3e6cb;
|
||||
color: #155724;
|
||||
}
|
||||
|
||||
.result.error {
|
||||
background: #f8d7da;
|
||||
border: 2px solid #f5c6cb;
|
||||
color: #721c24;
|
||||
}
|
||||
|
||||
.json-output {
|
||||
background: #2d2d2d;
|
||||
color: #f8f8f2;
|
||||
padding: 15px;
|
||||
border-radius: 5px;
|
||||
overflow-x: auto;
|
||||
font-family: 'Courier New', monospace;
|
||||
font-size: 12px;
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.loading {
|
||||
text-align: center;
|
||||
padding: 20px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.loading.show {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.spinner {
|
||||
border: 3px solid #f3f3f3;
|
||||
border-top: 3px solid #24292e;
|
||||
border-radius: 50%;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
animation: spin 1s linear infinite;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
.link {
|
||||
color: #0366d6;
|
||||
text-decoration: none;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>🐙 GitHub OAuth Test</h1>
|
||||
<p class="subtitle">Django REST API - GitHub Authentication</p>
|
||||
|
||||
<div class="info-box">
|
||||
<h3>📝 GitHub Personal Access Token Nasıl Alınır?</h3>
|
||||
<ol>
|
||||
<li><a href="https://github.com/settings/tokens" target="_blank" class="link">GitHub Settings → Tokens</a> sayfasına git</li>
|
||||
<li><strong>Generate new token (classic)</strong> butonuna tıkla</li>
|
||||
<li>Scopes seç:
|
||||
<ul>
|
||||
<li>✅ <code>user</code></li>
|
||||
<li>✅ <code>user:email</code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Token'ı oluştur ve kopyala</li>
|
||||
<li>Aşağıdaki alana yapıştır</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<div class="input-group">
|
||||
<label for="githubToken">GitHub Personal Access Token:</label>
|
||||
<input
|
||||
type="text"
|
||||
id="githubToken"
|
||||
placeholder="ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
||||
autocomplete="off"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<button class="btn btn-github" onclick="testGitHubAuth()" id="testBtn">
|
||||
<span>⚫</span>
|
||||
Test GitHub Authentication
|
||||
</button>
|
||||
|
||||
<div class="loading" id="loading">
|
||||
<div class="spinner"></div>
|
||||
<p style="margin-top: 10px; color: #24292e;">Testing authentication...</p>
|
||||
</div>
|
||||
|
||||
<div class="result" id="result">
|
||||
<h3 id="resultTitle">Result</h3>
|
||||
<div id="resultContent"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const API_BASE = 'http://localhost:8000/api/v1';
|
||||
|
||||
async function testGitHubAuth() {
|
||||
const token = document.getElementById('githubToken').value.trim();
|
||||
|
||||
if (!token) {
|
||||
showResult('error', 'Error ❌', {
|
||||
error: 'Please enter a GitHub Personal Access Token'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
showLoading();
|
||||
|
||||
try {
|
||||
const response = await fetch(`${API_BASE}/auth/social/github/`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
access_token: token
|
||||
})
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
hideLoading();
|
||||
|
||||
if (response.ok) {
|
||||
showResult('success', 'GitHub Authentication Successful! ✅', data);
|
||||
} else {
|
||||
showResult('error', 'Authentication Failed ❌', data);
|
||||
}
|
||||
} catch (error) {
|
||||
hideLoading();
|
||||
showResult('error', 'Error ❌', {
|
||||
error: error.message,
|
||||
details: 'Make sure Django server is running on localhost:8000'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function showLoading() {
|
||||
document.getElementById('loading').classList.add('show');
|
||||
document.getElementById('result').classList.remove('show');
|
||||
document.getElementById('testBtn').disabled = true;
|
||||
}
|
||||
|
||||
function hideLoading() {
|
||||
document.getElementById('loading').classList.remove('show');
|
||||
document.getElementById('testBtn').disabled = false;
|
||||
}
|
||||
|
||||
function showResult(type, title, data) {
|
||||
const resultDiv = document.getElementById('result');
|
||||
const resultTitle = document.getElementById('resultTitle');
|
||||
const resultContent = document.getElementById('resultContent');
|
||||
|
||||
resultDiv.className = `result show ${type}`;
|
||||
resultTitle.textContent = title;
|
||||
|
||||
if (type === 'success' && data.user) {
|
||||
resultContent.innerHTML = `
|
||||
<p><strong>🎉 Başarılı! Kullanıcı bilgileri:</strong></p>
|
||||
<p><strong>Email:</strong> ${data.user.email}</p>
|
||||
<p><strong>Name:</strong> ${data.user.first_name} ${data.user.last_name}</p>
|
||||
<p><strong>ID:</strong> ${data.user.id}</p>
|
||||
<p><strong>Active:</strong> ${data.user.is_active}</p>
|
||||
<br>
|
||||
<p><strong>JWT Tokens:</strong></p>
|
||||
<div class="json-output">${JSON.stringify(data, null, 2)}</div>
|
||||
`;
|
||||
} else {
|
||||
resultContent.innerHTML = `
|
||||
<div class="json-output">${JSON.stringify(data, null, 2)}</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
// Enter key to submit
|
||||
document.getElementById('githubToken').addEventListener('keypress', function(e) {
|
||||
if (e.key === 'Enter') {
|
||||
testGitHubAuth();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
79
templates/test_oauth_error.html
Normal file
79
templates/test_oauth_error.html
Normal file
@@ -0,0 +1,79 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Authentication Error</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
background: linear-gradient(135deg, #e74c3c 0%, #c0392b 100%);
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 20px;
|
||||
}
|
||||
.container {
|
||||
background: white;
|
||||
border-radius: 20px;
|
||||
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
|
||||
padding: 40px;
|
||||
max-width: 600px;
|
||||
width: 100%;
|
||||
}
|
||||
h1 {
|
||||
color: #e74c3c;
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.error-icon {
|
||||
text-align: center;
|
||||
font-size: 64px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.error-message {
|
||||
background: #f8d7da;
|
||||
border: 2px solid #f5c6cb;
|
||||
color: #721c24;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
.btn {
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
margin-top: 20px;
|
||||
background: #667eea;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
}
|
||||
.btn:hover {
|
||||
background: #5568d3;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="error-icon">❌</div>
|
||||
<h1>Authentication Failed</h1>
|
||||
<div class="error-message" id="errorMessage">
|
||||
Something went wrong during authentication.
|
||||
</div>
|
||||
<a href="/api/v1/auth/social/test/" class="btn">Try Again</a>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const error = urlParams.get('error');
|
||||
if (error) {
|
||||
document.getElementById('errorMessage').textContent = error;
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
208
templates/test_oauth_flow.html
Normal file
208
templates/test_oauth_flow.html
Normal file
@@ -0,0 +1,208 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>OAuth Flow Test - Real Authentication</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.container {
|
||||
background: white;
|
||||
border-radius: 20px;
|
||||
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
|
||||
padding: 40px;
|
||||
max-width: 600px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #333;
|
||||
margin-bottom: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
color: #666;
|
||||
text-align: center;
|
||||
margin-bottom: 30px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.info {
|
||||
background: #e7f3ff;
|
||||
border: 2px solid #b3d9ff;
|
||||
color: #004085;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 30px;
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.info strong {
|
||||
display: block;
|
||||
margin-bottom: 10px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
width: 100%;
|
||||
padding: 18px 20px;
|
||||
margin: 10px 0;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 12px;
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 5px 15px rgba(0,0,0,0.3);
|
||||
}
|
||||
|
||||
.btn-google {
|
||||
background: #4285f4;
|
||||
}
|
||||
|
||||
.btn-google:hover {
|
||||
background: #357ae8;
|
||||
}
|
||||
|
||||
.btn-github {
|
||||
background: #24292e;
|
||||
}
|
||||
|
||||
.btn-github:hover {
|
||||
background: #1a1e22;
|
||||
}
|
||||
|
||||
.icon {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.setup-section {
|
||||
background: #fff3cd;
|
||||
border: 2px solid #ffc107;
|
||||
color: #856404;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
margin-top: 30px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.setup-section h3 {
|
||||
margin-bottom: 10px;
|
||||
color: #856404;
|
||||
}
|
||||
|
||||
.setup-section ol {
|
||||
margin-left: 20px;
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
.setup-section code {
|
||||
background: white;
|
||||
padding: 2px 6px;
|
||||
border-radius: 3px;
|
||||
font-family: 'Courier New', monospace;
|
||||
border: 1px solid #e0e0e0;
|
||||
}
|
||||
|
||||
.divider {
|
||||
text-align: center;
|
||||
margin: 30px 0;
|
||||
color: #999;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.divider::before,
|
||||
.divider::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
width: 45%;
|
||||
height: 1px;
|
||||
background: #ddd;
|
||||
}
|
||||
|
||||
.divider::before {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.divider::after {
|
||||
right: 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>🔐 OAuth Flow Test</h1>
|
||||
<p class="subtitle">Gerçek OAuth Authentication - Django REST API</p>
|
||||
|
||||
<div class="info">
|
||||
<strong>✨ Nasıl Çalışır?</strong>
|
||||
<p>
|
||||
Butona tıkladığınızda GitHub veya Google'ın kendi sayfasına yönlendirileceksiniz.
|
||||
Orada giriş yapıp izin verdikten sonra, otomatik olarak geri dönecek ve
|
||||
JWT token'larınız gösterilecek!
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<a href="http://localhost:8000/api/v1/social/login/google-oauth2/" class="btn btn-google">
|
||||
<span class="icon">🔵</span>
|
||||
Login with Google
|
||||
</a>
|
||||
|
||||
<div class="divider">VEYA</div>
|
||||
|
||||
<a href="http://localhost:8000/api/v1/social/login/github/" class="btn btn-github">
|
||||
<span class="icon">⚫</span>
|
||||
Login with GitHub
|
||||
</a>
|
||||
|
||||
<div class="setup-section">
|
||||
<h3>⚠️ GitHub OAuth App Ayarları</h3>
|
||||
<p>GitHub OAuth çalışması için callback URL'ini ayarlamalısınız:</p>
|
||||
<ol>
|
||||
<li><strong>Git:</strong> <a href="https://github.com/settings/developers" target="_blank">GitHub Settings → OAuth Apps</a></li>
|
||||
<li>OAuth App'inizi bulun veya yeni oluşturun</li>
|
||||
<li><strong>Authorization callback URL:</strong> <code>http://localhost:8000/api/v1/social/complete/github/</code></li>
|
||||
<li>Kaydet</li>
|
||||
</ol>
|
||||
|
||||
<h3 style="margin-top: 15px;">⚠️ Google OAuth App Ayarları</h3>
|
||||
<ol>
|
||||
<li><strong>Git:</strong> <a href="https://console.cloud.google.com/apis/credentials" target="_blank">Google Cloud Console</a></li>
|
||||
<li>OAuth 2.0 Client ID'nizi düzenleyin</li>
|
||||
<li><strong>Authorized redirect URIs:</strong> <code>http://localhost:8000/api/v1/social/complete/google-oauth2/</code></li>
|
||||
<li><strong>Authorized JavaScript origins:</strong> <code>http://localhost:8000</code></li>
|
||||
<li>Kaydet</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
307
templates/test_social_auth.html
Normal file
307
templates/test_social_auth.html
Normal file
@@ -0,0 +1,307 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Social Auth Test</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.container {
|
||||
background: white;
|
||||
border-radius: 20px;
|
||||
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
|
||||
padding: 40px;
|
||||
max-width: 500px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #333;
|
||||
margin-bottom: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
color: #666;
|
||||
text-align: center;
|
||||
margin-bottom: 30px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
width: 100%;
|
||||
padding: 15px 20px;
|
||||
margin: 10px 0;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 5px 15px rgba(0,0,0,0.2);
|
||||
}
|
||||
|
||||
.btn-google {
|
||||
background: #4285f4;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-google:hover {
|
||||
background: #357ae8;
|
||||
}
|
||||
|
||||
.btn-github {
|
||||
background: #24292e;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-github:hover {
|
||||
background: #1a1e22;
|
||||
}
|
||||
|
||||
.result {
|
||||
margin-top: 30px;
|
||||
padding: 20px;
|
||||
background: #f8f9fa;
|
||||
border-radius: 8px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.result.show {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.result h3 {
|
||||
color: #333;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.result.success {
|
||||
background: #d4edda;
|
||||
border: 1px solid #c3e6cb;
|
||||
color: #155724;
|
||||
}
|
||||
|
||||
.result.error {
|
||||
background: #f8d7da;
|
||||
border: 1px solid #f5c6cb;
|
||||
color: #721c24;
|
||||
}
|
||||
|
||||
.json-output {
|
||||
background: #2d2d2d;
|
||||
color: #f8f8f2;
|
||||
padding: 15px;
|
||||
border-radius: 5px;
|
||||
overflow-x: auto;
|
||||
font-family: 'Courier New', monospace;
|
||||
font-size: 12px;
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.loading {
|
||||
text-align: center;
|
||||
padding: 20px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.loading.show {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.spinner {
|
||||
border: 3px solid #f3f3f3;
|
||||
border-top: 3px solid #667eea;
|
||||
border-radius: 50%;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
animation: spin 1s linear infinite;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
.info {
|
||||
background: #e7f3ff;
|
||||
border: 1px solid #b3d9ff;
|
||||
color: #004085;
|
||||
padding: 15px;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 20px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.icon {
|
||||
font-size: 20px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>🔐 Social Auth Test</h1>
|
||||
<p class="subtitle">Django REST API - Social Authentication</p>
|
||||
|
||||
<div class="info">
|
||||
<strong>⚠️ Not:</strong> Bu sayfa sadece test amaçlıdır. Google için callback URL'ini Google Console'da ayarlamanız gerekiyor: <code>http://localhost:8000/api/v1/social/complete/google-oauth2/</code>
|
||||
</div>
|
||||
|
||||
<button class="btn btn-google" onclick="loginWithGoogle()">
|
||||
<span class="icon">🔵</span>
|
||||
Login with Google
|
||||
</button>
|
||||
|
||||
<button class="btn btn-github" onclick="loginWithGithub()">
|
||||
<span class="icon">⚫</span>
|
||||
Login with GitHub
|
||||
</button>
|
||||
|
||||
<div class="loading" id="loading">
|
||||
<div class="spinner"></div>
|
||||
<p style="margin-top: 10px;">Processing...</p>
|
||||
</div>
|
||||
|
||||
<div class="result" id="result">
|
||||
<h3 id="resultTitle">Result</h3>
|
||||
<div id="resultContent"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Google OAuth2 Library -->
|
||||
<script src="https://accounts.google.com/gsi/client" async defer></script>
|
||||
|
||||
<script>
|
||||
const API_BASE = 'http://localhost:8000/api/v1';
|
||||
const GOOGLE_CLIENT_ID = '915364976256-691m0s87as2r5vdbqr96f6humblseobt.apps.googleusercontent.com';
|
||||
|
||||
// Initialize Google OAuth
|
||||
function initGoogleAuth() {
|
||||
google.accounts.id.initialize({
|
||||
client_id: GOOGLE_CLIENT_ID,
|
||||
callback: handleGoogleCallback
|
||||
});
|
||||
}
|
||||
|
||||
// Google Login
|
||||
function loginWithGoogle() {
|
||||
showLoading();
|
||||
google.accounts.id.prompt();
|
||||
}
|
||||
|
||||
// Handle Google OAuth callback
|
||||
async function handleGoogleCallback(response) {
|
||||
console.log('Google OAuth Response:', response);
|
||||
|
||||
// Google'dan gelen credential (JWT token)
|
||||
const credential = response.credential;
|
||||
|
||||
try {
|
||||
// Backend'e gönder
|
||||
const result = await fetch(`${API_BASE}/auth/social/google-oauth2/`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
access_token: credential,
|
||||
id_token: credential
|
||||
})
|
||||
});
|
||||
|
||||
const data = await result.json();
|
||||
hideLoading();
|
||||
|
||||
if (result.ok) {
|
||||
showResult('success', 'Google Login Successful! ✅', data);
|
||||
} else {
|
||||
showResult('error', 'Google Login Failed ❌', data);
|
||||
}
|
||||
} catch (error) {
|
||||
hideLoading();
|
||||
showResult('error', 'Error', { message: error.message });
|
||||
}
|
||||
}
|
||||
|
||||
// GitHub Login
|
||||
async function loginWithGithub() {
|
||||
showResult('error', 'GitHub OAuth Flow', {
|
||||
message: 'GitHub OAuth requires server-side redirect flow.',
|
||||
instruction: 'Use this endpoint instead:',
|
||||
url: `${API_BASE}/social/login/github/`,
|
||||
note: 'Or use the curl command below for testing with a real GitHub token'
|
||||
});
|
||||
}
|
||||
|
||||
// Show loading
|
||||
function showLoading() {
|
||||
document.getElementById('loading').classList.add('show');
|
||||
document.getElementById('result').classList.remove('show');
|
||||
}
|
||||
|
||||
// Hide loading
|
||||
function hideLoading() {
|
||||
document.getElementById('loading').classList.remove('show');
|
||||
}
|
||||
|
||||
// Show result
|
||||
function showResult(type, title, data) {
|
||||
const resultDiv = document.getElementById('result');
|
||||
const resultTitle = document.getElementById('resultTitle');
|
||||
const resultContent = document.getElementById('resultContent');
|
||||
|
||||
resultDiv.className = `result show ${type}`;
|
||||
resultTitle.textContent = title;
|
||||
|
||||
if (type === 'success' && data.user) {
|
||||
resultContent.innerHTML = `
|
||||
<p><strong>User Info:</strong></p>
|
||||
<p>Email: ${data.user.email}</p>
|
||||
<p>Name: ${data.user.first_name} ${data.user.last_name}</p>
|
||||
<p>ID: ${data.user.id}</p>
|
||||
<p><strong>Tokens:</strong></p>
|
||||
<div class="json-output">${JSON.stringify(data, null, 2)}</div>
|
||||
`;
|
||||
} else {
|
||||
resultContent.innerHTML = `
|
||||
<div class="json-output">${JSON.stringify(data, null, 2)}</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize when page loads
|
||||
window.onload = function() {
|
||||
if (typeof google !== 'undefined') {
|
||||
initGoogleAuth();
|
||||
}
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user