first commit
This commit is contained in:
481
AVATAR_FEATURE.md
Normal file
481
AVATAR_FEATURE.md
Normal file
@@ -0,0 +1,481 @@
|
||||
# 🖼️ 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! 🎉**
|
||||
Reference in New Issue
Block a user