450 lines
10 KiB
Markdown
450 lines
10 KiB
Markdown
# ✅ Avatar Artık Tüm Endpoint'lerde Dönüyor!
|
||
|
||
## 🎯 Sorun Çözüldü
|
||
|
||
Avatar field'ı login, register ve me endpoint'lerinde dönmüyordu. Şimdi **tüm authentication endpoint'lerinde** avatar döndürülüyor.
|
||
|
||
---
|
||
|
||
## 📋 Güncellenen Endpoint'ler
|
||
|
||
### 1. POST /v1/auth/register ✅
|
||
|
||
**Response (201):**
|
||
```json
|
||
{
|
||
"message": "User created. Please verify your email.",
|
||
"user_id": "uuid",
|
||
"username": "john_doe",
|
||
"email": "john@example.com",
|
||
"avatar": "",
|
||
"roles": [],
|
||
"email_verified": false,
|
||
"verification_token": "token123"
|
||
}
|
||
```
|
||
|
||
**Not:** Register'da OAuth olmadığı için avatar başlangıçta boş olacak. Daha sonra admin tarafından güncellenebilir.
|
||
|
||
---
|
||
|
||
### 2. POST /v1/auth/login ✅
|
||
|
||
**Response (200):**
|
||
```json
|
||
{
|
||
"user_id": "uuid",
|
||
"username": "john_doe",
|
||
"email": "john@example.com",
|
||
"avatar": "https://lh3.googleusercontent.com/a/...",
|
||
"roles": [
|
||
{
|
||
"id": "role-uuid",
|
||
"name": "user",
|
||
"description": "Default user role"
|
||
}
|
||
],
|
||
"access_token": "eyJhbGci...",
|
||
"refresh_token": "eyJhbGci..."
|
||
}
|
||
```
|
||
|
||
**Not:** Eğer kullanıcı daha önce OAuth ile giriş yaptıysa, avatar URL'si döner.
|
||
|
||
---
|
||
|
||
### 3. GET /v1/auth/me ✅
|
||
|
||
**Response (200):**
|
||
```json
|
||
{
|
||
"id": "uuid",
|
||
"username": "john_doe",
|
||
"email": "john@example.com",
|
||
"avatar": "https://lh3.googleusercontent.com/a/...",
|
||
"email_verified": true,
|
||
"created_at": "2026-02-04T00:00:00Z",
|
||
"updated_at": "2026-02-04T00:00:00Z",
|
||
"roles": [
|
||
{
|
||
"id": "role-uuid",
|
||
"name": "user"
|
||
}
|
||
],
|
||
"social_accounts": [
|
||
{
|
||
"provider": "google",
|
||
"name": "John Doe",
|
||
"avatar_url": "https://lh3.googleusercontent.com/a/..."
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
**Not:** Me endpoint'i zaten user objesini döndürüyordu, bu yüzden avatar otomatik olarak eklendi.
|
||
|
||
---
|
||
|
||
### 4. GET /v1/auth/:provider/callback ✅ YENİ!
|
||
|
||
**Response (200):**
|
||
```json
|
||
{
|
||
"access_token": "eyJhbGci...",
|
||
"refresh_token": "eyJhbGci...",
|
||
"user": {
|
||
"id": "uuid",
|
||
"username": "John Doe",
|
||
"email": "john@gmail.com",
|
||
"avatar": "https://lh3.googleusercontent.com/a/...",
|
||
"email_verified": true,
|
||
"roles": [
|
||
{
|
||
"id": "role-uuid",
|
||
"name": "user"
|
||
}
|
||
],
|
||
"social_accounts": [
|
||
{
|
||
"id": "social-uuid",
|
||
"provider": "google",
|
||
"provider_id": "1234567890",
|
||
"email": "john@gmail.com",
|
||
"name": "John Doe",
|
||
"avatar_url": "https://lh3.googleusercontent.com/a/...",
|
||
"created_at": "2026-02-04T00:00:00Z"
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
**Not:** OAuth callback artık user bilgilerini de döndürüyor, avatar dahil!
|
||
|
||
---
|
||
|
||
## 🔄 Değişiklikler
|
||
|
||
### 1. Auth Handler - Register
|
||
```go
|
||
c.JSON(http.StatusCreated, gin.H{
|
||
"message": "User created. Please verify your email.",
|
||
"user_id": user.ID,
|
||
"username": user.UserName,
|
||
"email": user.Email,
|
||
"avatar": user.Avatar, // ✅ Eklendi
|
||
"roles": roles,
|
||
"email_verified": false,
|
||
"verification_token": verifyToken,
|
||
})
|
||
```
|
||
|
||
### 2. Auth Handler - Login
|
||
```go
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"user_id": user.ID,
|
||
"username": user.UserName,
|
||
"email": user.Email,
|
||
"avatar": user.Avatar, // ✅ Eklendi
|
||
"roles": roles,
|
||
"access_token": accessToken,
|
||
"refresh_token": refreshToken,
|
||
})
|
||
```
|
||
|
||
### 3. Auth Service - FindOrCreateSocialUser
|
||
```go
|
||
// Return type değişti
|
||
func FindOrCreateSocialUser(gothUser goth.User, provider string) (*models.User, string, string, error)
|
||
|
||
// User objesini de döndürüyor
|
||
return &user, accessToken, refreshToken, nil
|
||
```
|
||
|
||
### 4. Auth Handler - OAuth Callback
|
||
```go
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"access_token": accessToken,
|
||
"refresh_token": refreshToken,
|
||
"user": gin.H{ // ✅ User bilgileri eklendi
|
||
"id": user.ID,
|
||
"username": user.UserName,
|
||
"email": user.Email,
|
||
"avatar": user.Avatar, // ✅ Avatar dahil
|
||
"email_verified": user.EmailVerified,
|
||
"roles": roles,
|
||
"social_accounts": user.SocialAccounts,
|
||
},
|
||
})
|
||
```
|
||
|
||
---
|
||
|
||
## 🧪 Test Senaryoları
|
||
|
||
### Test 1: Email/Password ile Register
|
||
```bash
|
||
curl -X POST http://localhost:8080/v1/auth/register \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"username": "testuser",
|
||
"email": "test@example.com",
|
||
"password": "Test123!"
|
||
}'
|
||
```
|
||
|
||
**Response:**
|
||
```json
|
||
{
|
||
"message": "User created. Please verify your email.",
|
||
"username": "testuser",
|
||
"email": "test@example.com",
|
||
"avatar": "", // ✅ Boş string
|
||
"email_verified": false
|
||
}
|
||
```
|
||
|
||
### Test 2: Email/Password ile Login
|
||
```bash
|
||
curl -X POST http://localhost:8080/v1/auth/login \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"email": "test@example.com",
|
||
"password": "Test123!"
|
||
}'
|
||
```
|
||
|
||
**Response:**
|
||
```json
|
||
{
|
||
"username": "testuser",
|
||
"email": "test@example.com",
|
||
"avatar": "", // ✅ Eğer OAuth kullanmadıysa boş
|
||
"access_token": "...",
|
||
"refresh_token": "..."
|
||
}
|
||
```
|
||
|
||
### Test 3: Google OAuth ile Giriş
|
||
```bash
|
||
# 1. OAuth başlat
|
||
open http://localhost:8080/v1/auth/google
|
||
|
||
# 2. Google'da izin ver
|
||
|
||
# 3. Callback response
|
||
```
|
||
|
||
**Response:**
|
||
```json
|
||
{
|
||
"access_token": "...",
|
||
"refresh_token": "...",
|
||
"user": {
|
||
"username": "John Doe",
|
||
"email": "john@gmail.com",
|
||
"avatar": "https://lh3.googleusercontent.com/a/...", // ✅ Google avatar
|
||
"email_verified": true,
|
||
"social_accounts": [
|
||
{
|
||
"provider": "google",
|
||
"name": "John Doe",
|
||
"avatar_url": "https://lh3.googleusercontent.com/a/..."
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
### Test 4: /me Endpoint
|
||
```bash
|
||
curl -X GET http://localhost:8080/v1/auth/me \
|
||
-H "Authorization: Bearer YOUR_TOKEN"
|
||
```
|
||
|
||
**Response:**
|
||
```json
|
||
{
|
||
"id": "uuid",
|
||
"username": "John Doe",
|
||
"email": "john@gmail.com",
|
||
"avatar": "https://lh3.googleusercontent.com/a/...", // ✅ Avatar var
|
||
"email_verified": true
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 💻 Frontend Kullanımı
|
||
|
||
### Login Sonrası
|
||
```javascript
|
||
async function login(email, password) {
|
||
const response = await fetch('http://localhost:8080/v1/auth/login', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({ email, password })
|
||
});
|
||
|
||
const data = await response.json();
|
||
|
||
// Avatar artık login response'unda!
|
||
console.log('Avatar:', data.avatar);
|
||
|
||
// Token'ları sakla
|
||
localStorage.setItem('access_token', data.access_token);
|
||
localStorage.setItem('refresh_token', data.refresh_token);
|
||
|
||
// User bilgilerini sakla
|
||
localStorage.setItem('user', JSON.stringify({
|
||
id: data.user_id,
|
||
username: data.username,
|
||
email: data.email,
|
||
avatar: data.avatar // ✅ Avatar
|
||
}));
|
||
|
||
return data;
|
||
}
|
||
```
|
||
|
||
### OAuth Callback Sonrası
|
||
```javascript
|
||
// OAuth callback sayfasında
|
||
async function handleOAuthCallback() {
|
||
// URL'den token ve user bilgilerini al
|
||
const urlParams = new URLSearchParams(window.location.search);
|
||
|
||
// veya callback API'sinden direkt response gelir
|
||
const response = await fetch(callbackUrl);
|
||
const data = await response.json();
|
||
|
||
// Avatar ve tüm user bilgileri var!
|
||
console.log('User:', data.user);
|
||
console.log('Avatar:', data.user.avatar);
|
||
console.log('Social Accounts:', data.user.social_accounts);
|
||
|
||
// Token'ları sakla
|
||
localStorage.setItem('access_token', data.access_token);
|
||
localStorage.setItem('user', JSON.stringify(data.user));
|
||
|
||
// Ana sayfaya yönlendir
|
||
window.location.href = '/dashboard';
|
||
}
|
||
```
|
||
|
||
### Me Endpoint ile Avatar Göster
|
||
```javascript
|
||
async function getCurrentUser() {
|
||
const token = localStorage.getItem('access_token');
|
||
|
||
const response = await fetch('http://localhost:8080/v1/auth/me', {
|
||
headers: { 'Authorization': `Bearer ${token}` }
|
||
});
|
||
|
||
const user = await response.json();
|
||
|
||
// Avatar göster
|
||
const avatarEl = document.querySelector('#user-avatar');
|
||
avatarEl.src = user.avatar || `https://ui-avatars.com/api/?name=${user.username}`;
|
||
|
||
return user;
|
||
}
|
||
```
|
||
|
||
### React Component
|
||
```jsx
|
||
function UserProfile() {
|
||
const [user, setUser] = useState(null);
|
||
|
||
useEffect(() => {
|
||
// Login sonrası user bilgileri localStorage'dan
|
||
const userData = JSON.parse(localStorage.getItem('user'));
|
||
setUser(userData);
|
||
}, []);
|
||
|
||
if (!user) return null;
|
||
|
||
return (
|
||
<div className="flex items-center gap-2">
|
||
<img
|
||
src={user.avatar || `https://ui-avatars.com/api/?name=${user.username}`}
|
||
alt={user.username}
|
||
className="w-10 h-10 rounded-full"
|
||
/>
|
||
<span>{user.username}</span>
|
||
</div>
|
||
);
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 📊 Avatar Field Durumları
|
||
|
||
| Senaryo | Avatar Değeri |
|
||
|---------|---------------|
|
||
| Email/Password Register | `""` (boş string) |
|
||
| Email/Password Login (OAuth yok) | `""` (boş string) |
|
||
| Google OAuth ile giriş | `https://lh3.googleusercontent.com/a/...` |
|
||
| GitHub OAuth ile giriş | `https://avatars.githubusercontent.com/u/...` |
|
||
| Admin tarafından manuel set | Custom URL |
|
||
| Avatar hiç set edilmemişse | `null` veya `""` |
|
||
|
||
---
|
||
|
||
## ✅ Özet
|
||
|
||
### Güncellenen Endpoint'ler
|
||
1. ✅ **POST /v1/auth/register** - Avatar field eklendi
|
||
2. ✅ **POST /v1/auth/login** - Avatar field eklendi
|
||
3. ✅ **GET /v1/auth/me** - Avatar zaten vardı (model değişikliği ile)
|
||
4. ✅ **GET /v1/auth/:provider/callback** - User bilgileri ve avatar eklendi
|
||
|
||
### Değişiklikler
|
||
- ✅ `auth_handler.go` - Register response'a avatar eklendi
|
||
- ✅ `auth_handler.go` - Login response'a avatar eklendi
|
||
- ✅ `auth_handler.go` - OAuth callback'e user bilgileri eklendi
|
||
- ✅ `auth_service.go` - FindOrCreateSocialUser user döndürüyor
|
||
|
||
### Avatar Kaynakları
|
||
- ✅ Google OAuth → Google profil fotoğrafı
|
||
- ✅ GitHub OAuth → GitHub profil fotoğrafı
|
||
- ✅ Manuel upload → Custom URL (gelecekte)
|
||
- ✅ Fallback → UI Avatars API
|
||
|
||
### Build
|
||
```bash
|
||
✅ go build -o main .
|
||
✅ No errors
|
||
```
|
||
|
||
---
|
||
|
||
## 🚀 Hemen Test Edin
|
||
|
||
```bash
|
||
# 1. Uygulamayı başlat
|
||
./main
|
||
|
||
# 2. Register test
|
||
curl -X POST http://localhost:8080/v1/auth/register \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"username":"test","email":"test@test.com","password":"Test123!"}'
|
||
|
||
# Response'da "avatar": "" göreceksiniz ✅
|
||
|
||
# 3. Login test
|
||
curl -X POST http://localhost:8080/v1/auth/login \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"email":"test@test.com","password":"Test123!"}'
|
||
|
||
# Response'da "avatar": "" göreceksiniz ✅
|
||
|
||
# 4. Google OAuth test
|
||
open http://localhost:8080/v1/auth/google
|
||
|
||
# Callback'te avatar ve tüm user bilgileri olacak ✅
|
||
```
|
||
|
||
**Avatar artık tüm endpoint'lerde dönüyor! 🎉**
|