482 lines
9.8 KiB
Markdown
482 lines
9.8 KiB
Markdown
# 🖼️ Avatar Özelliği Eklendi!
|
||
|
||
## ✨ Yeni Özellikler
|
||
|
||
### User Modeline Avatar Eklendi
|
||
|
||
```go
|
||
type User struct {
|
||
ID uuid.UUID `json:"id"`
|
||
UserName string `json:"username"`
|
||
Email string `json:"email"`
|
||
Avatar string `json:"avatar,omitempty"` // ✅ YENİ!
|
||
// ...diğer alanlar
|
||
}
|
||
```
|
||
|
||
### SocialAccount Modeline Avatar ve Name Eklendi
|
||
|
||
```go
|
||
type SocialAccount struct {
|
||
ID uuid.UUID `json:"id"`
|
||
UserID uuid.UUID `json:"user_id"`
|
||
Provider string `json:"provider"`
|
||
ProviderID string `json:"provider_id"`
|
||
Email string `json:"email"`
|
||
Name string `json:"name,omitempty"` // ✅ YENİ!
|
||
AvatarURL string `json:"avatar_url,omitempty"` // ✅ YENİ!
|
||
// ...
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 🎯 Nasıl Çalışıyor?
|
||
|
||
### 1. OAuth ile Giriş (Google/GitHub)
|
||
|
||
Kullanıcı OAuth ile giriş yaptığında:
|
||
|
||
1. ✅ Provider'dan avatar URL alınır (`gothUser.AvatarURL`)
|
||
2. ✅ User tablosuna `avatar` field'ına kaydedilir
|
||
3. ✅ SocialAccount tablosuna `avatar_url` ve `name` kaydedilir
|
||
4. ✅ Her giriş yaptığında avatar güncel değilse güncellenir
|
||
|
||
**Örnek Response:**
|
||
```json
|
||
{
|
||
"access_token": "eyJhbGci...",
|
||
"refresh_token": "eyJhbGci...",
|
||
"user": {
|
||
"id": "uuid",
|
||
"email": "user@gmail.com",
|
||
"username": "John Doe",
|
||
"avatar": "https://lh3.googleusercontent.com/a/ACg8ocK...",
|
||
"email_verified": true,
|
||
"roles": [{"name": "user"}],
|
||
"social_accounts": [
|
||
{
|
||
"provider": "google",
|
||
"name": "John Doe",
|
||
"avatar_url": "https://lh3.googleusercontent.com/a/ACg8ocK..."
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
### 2. Manuel Avatar Güncelleme (Admin)
|
||
|
||
Admin kullanıcılar avatar URL'sini manuel olarak güncelleyebilir:
|
||
|
||
```bash
|
||
curl -X PUT http://localhost:8080/v1/admin/users/USER_ID \
|
||
-H "Authorization: Bearer ADMIN_TOKEN" \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"avatar": "https://example.com/avatars/user123.jpg"
|
||
}'
|
||
```
|
||
|
||
---
|
||
|
||
## 📋 Avatar Kaynakları
|
||
|
||
### Google OAuth
|
||
```
|
||
https://lh3.googleusercontent.com/a/ACg8ocK...
|
||
```
|
||
|
||
### GitHub OAuth
|
||
```
|
||
https://avatars.githubusercontent.com/u/1234567?v=4
|
||
```
|
||
|
||
### Manuel Upload (Gelecekte)
|
||
```
|
||
https://yourdomain.com/uploads/avatars/user-uuid.jpg
|
||
```
|
||
|
||
---
|
||
|
||
## 🔄 API Response'larında Avatar
|
||
|
||
### GET /v1/auth/me
|
||
|
||
```json
|
||
{
|
||
"id": "uuid",
|
||
"email": "user@example.com",
|
||
"username": "username",
|
||
"avatar": "https://lh3.googleusercontent.com/a/...",
|
||
"email_verified": true,
|
||
"roles": [{"name": "user"}]
|
||
}
|
||
```
|
||
|
||
### GET /v1/admin/users
|
||
|
||
```json
|
||
{
|
||
"users": [
|
||
{
|
||
"id": "uuid",
|
||
"email": "user@example.com",
|
||
"username": "username",
|
||
"avatar": "https://lh3.googleusercontent.com/a/...",
|
||
"social_accounts": [
|
||
{
|
||
"provider": "google",
|
||
"name": "John Doe",
|
||
"avatar_url": "https://lh3.googleusercontent.com/a/..."
|
||
}
|
||
]
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
### POST /v1/auth/login (OAuth Callback)
|
||
|
||
```json
|
||
{
|
||
"access_token": "...",
|
||
"refresh_token": "...",
|
||
"user": {
|
||
"id": "uuid",
|
||
"email": "user@gmail.com",
|
||
"username": "John Doe",
|
||
"avatar": "https://lh3.googleusercontent.com/a/...",
|
||
"roles": [{"name": "user"}]
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 🧪 Test Örnekleri
|
||
|
||
### Test 1: Google ile Giriş Yap
|
||
|
||
```bash
|
||
# 1. OAuth URL'sine git
|
||
http://localhost:8080/v1/auth/google
|
||
|
||
# 2. Google'da izin ver
|
||
|
||
# 3. Callback'te avatar ile kullanıcı dönecek
|
||
{
|
||
"access_token": "...",
|
||
"user": {
|
||
"avatar": "https://lh3.googleusercontent.com/...",
|
||
"email": "user@gmail.com",
|
||
"username": "Your Name"
|
||
}
|
||
}
|
||
```
|
||
|
||
### Test 2: GitHub ile Giriş Yap
|
||
|
||
```bash
|
||
# 1. OAuth URL'sine git
|
||
http://localhost:8080/v1/auth/github
|
||
|
||
# 2. GitHub'da izin ver
|
||
|
||
# 3. Callback'te avatar ile kullanıcı dönecek
|
||
{
|
||
"access_token": "...",
|
||
"user": {
|
||
"avatar": "https://avatars.githubusercontent.com/u/...",
|
||
"email": "user@github.com",
|
||
"username": "githubusername"
|
||
}
|
||
}
|
||
```
|
||
|
||
### Test 3: Avatar Güncelleme (Admin)
|
||
|
||
```bash
|
||
TOKEN="admin_token_here"
|
||
USER_ID="user_uuid"
|
||
|
||
curl -X PUT "http://localhost:8080/v1/admin/users/$USER_ID" \
|
||
-H "Authorization: Bearer $TOKEN" \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"avatar": "https://example.com/new-avatar.jpg"
|
||
}'
|
||
```
|
||
|
||
**Response:**
|
||
```json
|
||
{
|
||
"message": "User updated successfully",
|
||
"user": {
|
||
"id": "uuid",
|
||
"email": "user@example.com",
|
||
"username": "username",
|
||
"avatar": "https://example.com/new-avatar.jpg",
|
||
"updated_at": "2026-02-04T..."
|
||
}
|
||
}
|
||
```
|
||
|
||
### Test 4: Kullanıcı Bilgilerini Getir
|
||
|
||
```bash
|
||
curl -X GET http://localhost:8080/v1/auth/me \
|
||
-H "Authorization: Bearer USER_TOKEN"
|
||
```
|
||
|
||
**Response:**
|
||
```json
|
||
{
|
||
"id": "uuid",
|
||
"email": "user@gmail.com",
|
||
"username": "John Doe",
|
||
"avatar": "https://lh3.googleusercontent.com/a/...",
|
||
"email_verified": true,
|
||
"created_at": "2026-02-04T...",
|
||
"social_accounts": [
|
||
{
|
||
"provider": "google",
|
||
"name": "John Doe",
|
||
"avatar_url": "https://lh3.googleusercontent.com/a/..."
|
||
}
|
||
],
|
||
"roles": [{"name": "user"}]
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 💻 Frontend Kullanımı
|
||
|
||
### React Örneği
|
||
|
||
```jsx
|
||
function UserAvatar({ user }) {
|
||
const defaultAvatar = 'https://ui-avatars.com/api/?name=' +
|
||
encodeURIComponent(user.username);
|
||
|
||
return (
|
||
<img
|
||
src={user.avatar || defaultAvatar}
|
||
alt={user.username}
|
||
className="w-10 h-10 rounded-full"
|
||
onError={(e) => {
|
||
e.target.src = defaultAvatar;
|
||
}}
|
||
/>
|
||
);
|
||
}
|
||
|
||
// Kullanım
|
||
function Header() {
|
||
const [user, setUser] = useState(null);
|
||
|
||
useEffect(() => {
|
||
fetch('http://localhost:8080/v1/auth/me', {
|
||
headers: {
|
||
'Authorization': `Bearer ${localStorage.getItem('token')}`
|
||
}
|
||
})
|
||
.then(res => res.json())
|
||
.then(data => setUser(data));
|
||
}, []);
|
||
|
||
return (
|
||
<div className="flex items-center gap-2">
|
||
<UserAvatar user={user} />
|
||
<span>{user?.username}</span>
|
||
</div>
|
||
);
|
||
}
|
||
```
|
||
|
||
### Vue.js Örneği
|
||
|
||
```vue
|
||
<template>
|
||
<div class="user-profile">
|
||
<img
|
||
:src="userAvatar"
|
||
:alt="user.username"
|
||
class="avatar"
|
||
@error="handleImageError"
|
||
/>
|
||
<span>{{ user.username }}</span>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
export default {
|
||
data() {
|
||
return {
|
||
user: null,
|
||
imageError: false
|
||
}
|
||
},
|
||
computed: {
|
||
userAvatar() {
|
||
if (this.imageError || !this.user?.avatar) {
|
||
return `https://ui-avatars.com/api/?name=${encodeURIComponent(this.user?.username || 'U')}`;
|
||
}
|
||
return this.user.avatar;
|
||
}
|
||
},
|
||
methods: {
|
||
handleImageError() {
|
||
this.imageError = true;
|
||
},
|
||
async fetchUser() {
|
||
const token = localStorage.getItem('token');
|
||
const response = await fetch('http://localhost:8080/v1/auth/me', {
|
||
headers: { 'Authorization': `Bearer ${token}` }
|
||
});
|
||
this.user = await response.json();
|
||
}
|
||
},
|
||
mounted() {
|
||
this.fetchUser();
|
||
}
|
||
}
|
||
</script>
|
||
```
|
||
|
||
---
|
||
|
||
## 🎨 Avatar Fallback Stratejileri
|
||
|
||
### 1. UI Avatars (İsim baş harfleri)
|
||
|
||
```
|
||
https://ui-avatars.com/api/?name=John+Doe&background=0D8ABC&color=fff
|
||
```
|
||
|
||
### 2. Gravatar (Email hash)
|
||
|
||
```javascript
|
||
import md5 from 'md5';
|
||
|
||
function getGravatarUrl(email) {
|
||
const hash = md5(email.toLowerCase().trim());
|
||
return `https://www.gravatar.com/avatar/${hash}?d=identicon`;
|
||
}
|
||
```
|
||
|
||
### 3. Default Avatar
|
||
|
||
```
|
||
/assets/default-avatar.png
|
||
```
|
||
|
||
---
|
||
|
||
## 📊 Database Migration
|
||
|
||
Avatar field'ı otomatik olarak eklenecek (GORM AutoMigrate).
|
||
|
||
Mevcut kullanıcılar için avatar `null` veya `""` olacak.
|
||
|
||
**Migration Sonrası:**
|
||
```sql
|
||
-- users tablosu
|
||
ALTER TABLE users ADD COLUMN avatar VARCHAR(500);
|
||
|
||
-- social_accounts tablosu
|
||
ALTER TABLE social_accounts ADD COLUMN name VARCHAR(255);
|
||
ALTER TABLE social_accounts ADD COLUMN avatar_url VARCHAR(500);
|
||
```
|
||
|
||
---
|
||
|
||
## 🔄 Avatar Güncelleme Mantığı
|
||
|
||
### Yeni Kullanıcı (OAuth ile ilk giriş)
|
||
1. User oluşturulur
|
||
2. `user.avatar` = OAuth provider avatar URL
|
||
3. SocialAccount oluşturulur
|
||
4. `social_account.avatar_url` = OAuth provider avatar URL
|
||
|
||
### Mevcut Kullanıcı (OAuth ile tekrar giriş)
|
||
1. Avatar değişmiş mi kontrol edilir
|
||
2. Değişmişse `user.avatar` güncellenir
|
||
3. Her zaman güncel avatar kullanılır
|
||
|
||
### Mevcut Kullanıcıya OAuth Ekleme (Email aynı)
|
||
1. User bulunur
|
||
2. Avatar yoksa veya farklıysa güncellenir
|
||
3. SocialAccount oluşturulur
|
||
|
||
---
|
||
|
||
## 🎯 Özellikler
|
||
|
||
### ✅ Otomatik Avatar
|
||
- Google ile giriş → Google profil fotoğrafı
|
||
- GitHub ile giriş → GitHub profil fotoğrafı
|
||
|
||
### ✅ Avatar Güncelleme
|
||
- Her OAuth girişinde güncellik kontrolü
|
||
- Manuel güncelleme (Admin)
|
||
|
||
### ✅ Çoklu Provider Desteği
|
||
- Her provider için avatar_url ayrı saklanır
|
||
- User tablosunda tek avatar (son kullanılan)
|
||
|
||
### ✅ JSON Response
|
||
- Avatar her API response'unda döner
|
||
- `omitempty` ile null ise gösterilmez
|
||
|
||
---
|
||
|
||
## 📝 Güncellenebilir Alanlar
|
||
|
||
Admin tarafından kullanıcı güncellerken:
|
||
|
||
| Field | Type | Açıklama |
|
||
|-------|------|----------|
|
||
| `email` | string | Email adresi |
|
||
| `user_name` | string | Kullanıcı adı |
|
||
| `password` | string | Şifre |
|
||
| `avatar` | string | Avatar URL ✅ YENİ |
|
||
| `email_verified` | boolean | Email doğrulama |
|
||
| `roles` | string[] | Roller |
|
||
|
||
---
|
||
|
||
## ✅ Özet
|
||
|
||
### Yapılan Değişiklikler
|
||
|
||
1. ✅ **User Model** - `avatar` field eklendi
|
||
2. ✅ **SocialAccount Model** - `name` ve `avatar_url` eklendi
|
||
3. ✅ **Auth Service** - OAuth'ta avatar kaydedilir
|
||
4. ✅ **User Management** - Avatar güncellenebilir
|
||
5. ✅ **API Responses** - Avatar her yerde dönüyor
|
||
|
||
### Özellikler
|
||
|
||
- ✅ Google OAuth ile avatar
|
||
- ✅ GitHub OAuth ile avatar
|
||
- ✅ Avatar güncelleme (auto & manual)
|
||
- ✅ Çoklu provider desteği
|
||
- ✅ JSON response'larda avatar
|
||
|
||
### Test
|
||
|
||
```bash
|
||
# 1. Google ile giriş
|
||
open http://localhost:8080/v1/auth/google
|
||
|
||
# 2. Kullanıcı bilgilerini getir
|
||
curl http://localhost:8080/v1/auth/me \
|
||
-H "Authorization: Bearer TOKEN"
|
||
|
||
# Avatar field'ında Google profil fotoğrafı olacak! ✅
|
||
```
|
||
|
||
**Avatar özelliği başarıyla eklendi! 🎉**
|