574 lines
14 KiB
Markdown
574 lines
14 KiB
Markdown
# 🎉 User Create & Update - Avatar Upload Desteği
|
||
|
||
## ✨ Yeni Özellik
|
||
|
||
Artık yeni kullanıcı oluştururken ve mevcut kullanıcıyı güncellerken **aynı request'te avatar da yükleyebilirsiniz!**
|
||
|
||
---
|
||
|
||
## 📋 Güncellenen Endpoint'ler
|
||
|
||
### 1. POST /v1/admin/users (Create User)
|
||
|
||
**Artık Multipart/Form-Data Destekliyor!**
|
||
|
||
**Önceden:**
|
||
```bash
|
||
# Sadece JSON
|
||
curl -X POST http://localhost:8080/v1/admin/users \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"email":"user@example.com","password":"Pass123!","user_name":"john"}'
|
||
```
|
||
|
||
**Şimdi:**
|
||
```bash
|
||
# Multipart ile avatar da ekleyebilirsiniz!
|
||
curl -X POST http://localhost:8080/v1/admin/users \
|
||
-H "Authorization: Bearer ADMIN_TOKEN" \
|
||
-F "email=user@example.com" \
|
||
-F "password=Pass123!" \
|
||
-F "user_name=john" \
|
||
-F "email_verified=true" \
|
||
-F "roles=admin,user" \
|
||
-F "avatar=@/path/to/photo.jpg"
|
||
```
|
||
|
||
**Response:**
|
||
```json
|
||
{
|
||
"id": "new-user-uuid",
|
||
"username": "john",
|
||
"email": "user@example.com",
|
||
"avatar": "/uploads/avatars/new-user-uuid_1707012345.jpg",
|
||
"email_verified": true,
|
||
"roles": [
|
||
{"name": "admin"},
|
||
{"name": "user"}
|
||
],
|
||
"created_at": "2026-02-04T..."
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 2. PUT /v1/admin/users/:id (Update User)
|
||
|
||
**Hem JSON hem Multipart Destekliyor!**
|
||
|
||
**JSON ile (avatar URL):**
|
||
```bash
|
||
curl -X PUT http://localhost:8080/v1/admin/users/USER_ID \
|
||
-H "Authorization: Bearer ADMIN_TOKEN" \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"email": "new@example.com",
|
||
"user_name": "newname",
|
||
"roles": ["admin"]
|
||
}'
|
||
```
|
||
|
||
**Multipart ile (avatar dosya):**
|
||
```bash
|
||
curl -X PUT http://localhost:8080/v1/admin/users/USER_ID \
|
||
-H "Authorization: Bearer ADMIN_TOKEN" \
|
||
-F "email=new@example.com" \
|
||
-F "user_name=newname" \
|
||
-F "roles=admin,user" \
|
||
-F "avatar=@/path/to/new-photo.jpg"
|
||
```
|
||
|
||
**Response:**
|
||
```json
|
||
{
|
||
"message": "User updated successfully",
|
||
"user": {
|
||
"id": "user-uuid",
|
||
"username": "newname",
|
||
"email": "new@example.com",
|
||
"avatar": "/uploads/avatars/user-uuid_1707012346.jpg",
|
||
"roles": [
|
||
{"name": "admin"},
|
||
{"name": "user"}
|
||
],
|
||
"updated_at": "2026-02-04T..."
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 🎯 Form Fields
|
||
|
||
### Create User (POST)
|
||
|
||
| Field | Type | Required | Açıklama |
|
||
|-------|------|----------|----------|
|
||
| `email` | string | ✅ | Email adresi |
|
||
| `password` | string | ✅ | Şifre (min 6 karakter) |
|
||
| `user_name` | string | ✅ | Kullanıcı adı |
|
||
| `email_verified` | boolean | ❌ | Email doğrulanmış mı? (true/false) |
|
||
| `roles` | string | ❌ | Roller (comma separated: "admin,user") |
|
||
| `avatar` | file | ❌ | Avatar dosyası (max 5MB, jpg/png/gif/webp) |
|
||
|
||
### Update User (PUT)
|
||
|
||
| Field | Type | Required | Açıklama |
|
||
|-------|------|----------|----------|
|
||
| `email` | string | ❌ | Yeni email |
|
||
| `password` | string | ❌ | Yeni şifre |
|
||
| `user_name` | string | ❌ | Yeni kullanıcı adı |
|
||
| `email_verified` | boolean | ❌ | Email doğrulama durumu |
|
||
| `roles` | string | ❌ | Yeni roller (comma separated) |
|
||
| `avatar` | file | ❌ | Yeni avatar dosyası |
|
||
|
||
**Not:** Tüm alanlar optional, sadece güncellemek istediklerinizi gönderin.
|
||
|
||
---
|
||
|
||
## 💻 Frontend Kullanımı
|
||
|
||
### HTML Form - Yeni Kullanıcı Oluştur
|
||
|
||
```html
|
||
<form id="createUserForm">
|
||
<input type="email" name="email" required placeholder="Email">
|
||
<input type="password" name="password" required placeholder="Password">
|
||
<input type="text" name="user_name" required placeholder="Username">
|
||
|
||
<label>
|
||
<input type="checkbox" name="email_verified" value="true">
|
||
Email Verified
|
||
</label>
|
||
|
||
<select name="roles" multiple>
|
||
<option value="admin">Admin</option>
|
||
<option value="user">User</option>
|
||
</select>
|
||
|
||
<input type="file" name="avatar" accept="image/*">
|
||
|
||
<button type="submit">Create User</button>
|
||
</form>
|
||
|
||
<script>
|
||
document.getElementById('createUserForm').onsubmit = async (e) => {
|
||
e.preventDefault();
|
||
|
||
const formData = new FormData(e.target);
|
||
|
||
// Roles'ü comma separated yap
|
||
const rolesSelect = e.target.roles;
|
||
const selectedRoles = Array.from(rolesSelect.selectedOptions).map(opt => opt.value);
|
||
formData.set('roles', selectedRoles.join(','));
|
||
|
||
const token = localStorage.getItem('admin_token');
|
||
|
||
const response = await fetch('http://localhost:8080/v1/admin/users', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Authorization': `Bearer ${token}`
|
||
},
|
||
body: formData
|
||
});
|
||
|
||
const data = await response.json();
|
||
|
||
if (response.ok) {
|
||
console.log('User created:', data);
|
||
alert('User created successfully!');
|
||
if (data.avatar) {
|
||
console.log('Avatar URL:', data.avatar);
|
||
}
|
||
} else {
|
||
alert('Error: ' + data.error);
|
||
}
|
||
};
|
||
</script>
|
||
```
|
||
|
||
### React - Kullanıcı Güncelle
|
||
|
||
```jsx
|
||
import { useState } from 'react';
|
||
|
||
function UpdateUserForm({ userId }) {
|
||
const [formData, setFormData] = useState({
|
||
email: '',
|
||
user_name: '',
|
||
password: '',
|
||
email_verified: false,
|
||
roles: [],
|
||
avatar: null
|
||
});
|
||
|
||
const handleSubmit = async (e) => {
|
||
e.preventDefault();
|
||
|
||
const data = new FormData();
|
||
|
||
if (formData.email) data.append('email', formData.email);
|
||
if (formData.user_name) data.append('user_name', formData.user_name);
|
||
if (formData.password) data.append('password', formData.password);
|
||
if (formData.email_verified) data.append('email_verified', 'true');
|
||
if (formData.roles.length > 0) data.append('roles', formData.roles.join(','));
|
||
if (formData.avatar) data.append('avatar', formData.avatar);
|
||
|
||
const token = localStorage.getItem('admin_token');
|
||
|
||
try {
|
||
const response = await fetch(`http://localhost:8080/v1/admin/users/${userId}`, {
|
||
method: 'PUT',
|
||
headers: {
|
||
'Authorization': `Bearer ${token}`
|
||
},
|
||
body: data
|
||
});
|
||
|
||
const result = await response.json();
|
||
|
||
if (response.ok) {
|
||
console.log('User updated:', result.user);
|
||
alert('User updated successfully!');
|
||
} else {
|
||
alert('Error: ' + result.error);
|
||
}
|
||
} catch (error) {
|
||
console.error('Update failed:', error);
|
||
}
|
||
};
|
||
|
||
return (
|
||
<form onSubmit={handleSubmit}>
|
||
<input
|
||
type="email"
|
||
placeholder="Email"
|
||
value={formData.email}
|
||
onChange={(e) => setFormData({...formData, email: e.target.value})}
|
||
/>
|
||
|
||
<input
|
||
type="text"
|
||
placeholder="Username"
|
||
value={formData.user_name}
|
||
onChange={(e) => setFormData({...formData, user_name: e.target.value})}
|
||
/>
|
||
|
||
<input
|
||
type="password"
|
||
placeholder="New Password"
|
||
value={formData.password}
|
||
onChange={(e) => setFormData({...formData, password: e.target.value})}
|
||
/>
|
||
|
||
<label>
|
||
<input
|
||
type="checkbox"
|
||
checked={formData.email_verified}
|
||
onChange={(e) => setFormData({...formData, email_verified: e.target.checked})}
|
||
/>
|
||
Email Verified
|
||
</label>
|
||
|
||
<select
|
||
multiple
|
||
value={formData.roles}
|
||
onChange={(e) => setFormData({
|
||
...formData,
|
||
roles: Array.from(e.target.selectedOptions).map(opt => opt.value)
|
||
})}
|
||
>
|
||
<option value="admin">Admin</option>
|
||
<option value="user">User</option>
|
||
</select>
|
||
|
||
<input
|
||
type="file"
|
||
accept="image/*"
|
||
onChange={(e) => setFormData({...formData, avatar: e.target.files[0]})}
|
||
/>
|
||
|
||
<button type="submit">Update User</button>
|
||
</form>
|
||
);
|
||
}
|
||
```
|
||
|
||
### Vue.js - Yeni Kullanıcı Oluştur
|
||
|
||
```vue
|
||
<template>
|
||
<form @submit.prevent="createUser">
|
||
<input v-model="formData.email" type="email" required placeholder="Email">
|
||
<input v-model="formData.password" type="password" required placeholder="Password">
|
||
<input v-model="formData.user_name" type="text" required placeholder="Username">
|
||
|
||
<label>
|
||
<input v-model="formData.email_verified" type="checkbox">
|
||
Email Verified
|
||
</label>
|
||
|
||
<select v-model="formData.roles" multiple>
|
||
<option value="admin">Admin</option>
|
||
<option value="user">User</option>
|
||
</select>
|
||
|
||
<input type="file" @change="handleFileChange" accept="image/*">
|
||
|
||
<button type="submit">Create User</button>
|
||
</form>
|
||
</template>
|
||
|
||
<script>
|
||
export default {
|
||
data() {
|
||
return {
|
||
formData: {
|
||
email: '',
|
||
password: '',
|
||
user_name: '',
|
||
email_verified: false,
|
||
roles: [],
|
||
avatar: null
|
||
}
|
||
}
|
||
},
|
||
methods: {
|
||
handleFileChange(e) {
|
||
this.formData.avatar = e.target.files[0];
|
||
},
|
||
|
||
async createUser() {
|
||
const data = new FormData();
|
||
|
||
data.append('email', this.formData.email);
|
||
data.append('password', this.formData.password);
|
||
data.append('user_name', this.formData.user_name);
|
||
data.append('email_verified', this.formData.email_verified ? 'true' : 'false');
|
||
|
||
if (this.formData.roles.length > 0) {
|
||
data.append('roles', this.formData.roles.join(','));
|
||
}
|
||
|
||
if (this.formData.avatar) {
|
||
data.append('avatar', this.formData.avatar);
|
||
}
|
||
|
||
const token = localStorage.getItem('admin_token');
|
||
|
||
try {
|
||
const response = await fetch('http://localhost:8080/v1/admin/users', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Authorization': `Bearer ${token}`
|
||
},
|
||
body: data
|
||
});
|
||
|
||
const result = await response.json();
|
||
|
||
if (response.ok) {
|
||
console.log('User created:', result);
|
||
alert('User created successfully!');
|
||
this.$emit('userCreated', result);
|
||
} else {
|
||
alert('Error: ' + result.error);
|
||
}
|
||
} catch (error) {
|
||
console.error('Error:', error);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
```
|
||
|
||
---
|
||
|
||
## 🧪 Test Örnekleri
|
||
|
||
### Test 1: Yeni Kullanıcı + Avatar Oluştur
|
||
|
||
```bash
|
||
# Admin token al
|
||
curl -X POST http://localhost:8080/v1/auth/login \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"email":"admin@gauth.local","password":"Admin@123"}'
|
||
|
||
# Token'ı kaydet
|
||
TOKEN="eyJhbGci..."
|
||
|
||
# Yeni kullanıcı oluştur (avatar ile)
|
||
curl -X POST http://localhost:8080/v1/admin/users \
|
||
-H "Authorization: Bearer $TOKEN" \
|
||
-F "email=newuser@example.com" \
|
||
-F "password=NewUser123!" \
|
||
-F "user_name=newuser" \
|
||
-F "email_verified=true" \
|
||
-F "roles=user" \
|
||
-F "avatar=@./user-photo.jpg"
|
||
|
||
# Response'da avatar URL göreceksiniz!
|
||
```
|
||
|
||
### Test 2: Kullanıcı Güncelle + Yeni Avatar
|
||
|
||
```bash
|
||
USER_ID="user-uuid-here"
|
||
|
||
curl -X PUT http://localhost:8080/v1/admin/users/$USER_ID \
|
||
-H "Authorization: Bearer $TOKEN" \
|
||
-F "email=updated@example.com" \
|
||
-F "user_name=updatedname" \
|
||
-F "roles=admin,user" \
|
||
-F "avatar=@./new-avatar.jpg"
|
||
```
|
||
|
||
### Test 3: Sadece Avatar Değiştir
|
||
|
||
```bash
|
||
# Diğer alanları göndermeden sadece avatar
|
||
curl -X PUT http://localhost:8080/v1/admin/users/$USER_ID \
|
||
-H "Authorization: Bearer $TOKEN" \
|
||
-F "avatar=@./profile-pic.jpg"
|
||
```
|
||
|
||
### Test 4: Avatar Olmadan Güncelle
|
||
|
||
```bash
|
||
# Avatar olmadan da güncelleme yapabilirsiniz
|
||
curl -X PUT http://localhost:8080/v1/admin/users/$USER_ID \
|
||
-H "Authorization: Bearer $TOKEN" \
|
||
-F "email=another@example.com" \
|
||
-F "user_name=anothername"
|
||
```
|
||
|
||
---
|
||
|
||
## 📊 Özellikler
|
||
|
||
### ✅ Create User
|
||
- **Multipart/form-data** ile avatar yükleme
|
||
- Email, password, username **required**
|
||
- Roles optional (comma separated: "admin,user")
|
||
- Email verified optional (true/false)
|
||
- Avatar optional (max 5MB)
|
||
- **Tek request**te hem kullanıcı hem avatar oluşturulur
|
||
|
||
### ✅ Update User
|
||
- **Hem JSON hem multipart** destekliyor
|
||
- Tüm alanlar optional
|
||
- Avatar dosya ile veya URL ile güncellenebilir
|
||
- Eski avatar otomatik silinir (local ise)
|
||
- OAuth avatar'ları korunur
|
||
|
||
### ✅ Avatar Validasyonu
|
||
- Format: JPG, JPEG, PNG, GIF, WebP
|
||
- Maksimum boyut: 5MB
|
||
- Otomatik dosya ismi: `{user_id}_{timestamp}.{ext}`
|
||
|
||
---
|
||
|
||
## 🔄 Content-Type Desteği
|
||
|
||
### Create User
|
||
```
|
||
Content-Type: multipart/form-data
|
||
```
|
||
|
||
### Update User
|
||
```
|
||
Content-Type: application/json (JSON için)
|
||
Content-Type: multipart/form-data (Avatar upload için)
|
||
```
|
||
|
||
Handler otomatik olarak Content-Type'a göre parse eder!
|
||
|
||
---
|
||
|
||
## ⚠️ Önemli Notlar
|
||
|
||
### 1. Roles Format
|
||
|
||
**Multipart:**
|
||
```
|
||
roles=admin,user
|
||
```
|
||
|
||
**JSON:**
|
||
```json
|
||
{
|
||
"roles": ["admin", "user"]
|
||
}
|
||
```
|
||
|
||
### 2. Boolean Fields
|
||
|
||
**Multipart:**
|
||
```
|
||
email_verified=true
|
||
```
|
||
|
||
**JSON:**
|
||
```json
|
||
{
|
||
"email_verified": true
|
||
}
|
||
```
|
||
|
||
### 3. Avatar Önceliği
|
||
|
||
1. Dosya upload (multipart) → En yüksek öncelik
|
||
2. Avatar URL (JSON) → Dosya yoksa
|
||
3. Mevcut avatar → Değişiklik yoksa
|
||
|
||
### 4. Eski Avatar Temizleme
|
||
|
||
```go
|
||
// Otomatik temizlik
|
||
if user.Avatar != "" && strings.HasPrefix(user.Avatar, "/uploads/") {
|
||
os.Remove("." + user.Avatar) // Eski local dosya silinir
|
||
}
|
||
|
||
// OAuth avatar'lar korunur
|
||
// https://... ile başlayanlar silinmez
|
||
```
|
||
|
||
---
|
||
|
||
## ✅ Özet
|
||
|
||
### Artık Yapabilirsiniz
|
||
|
||
1. ✅ **Yeni kullanıcı oluştururken avatar yükleyin**
|
||
2. ✅ **Kullanıcı güncellerken avatar değiştirin**
|
||
3. ✅ **Hem JSON hem multipart desteği**
|
||
4. ✅ **Tek request'te tüm işlemler**
|
||
5. ✅ **Otomatik dosya temizleme**
|
||
6. ✅ **Validation ve error handling**
|
||
|
||
### Build Durumu
|
||
|
||
```bash
|
||
✅ go build -o main .
|
||
✅ Build successful
|
||
✅ CreateUser multipart destekliyor
|
||
✅ UpdateUser multipart + JSON destekliyor
|
||
```
|
||
|
||
### Test Edin
|
||
|
||
```bash
|
||
# Uygulamayı başlat
|
||
./main
|
||
|
||
# Yeni kullanıcı + avatar
|
||
curl -X POST http://localhost:8080/v1/admin/users \
|
||
-H "Authorization: Bearer TOKEN" \
|
||
-F "email=test@example.com" \
|
||
-F "password=Test123!" \
|
||
-F "user_name=testuser" \
|
||
-F "avatar=@photo.jpg"
|
||
```
|
||
|
||
**Artık user create ve update'te avatar yükleyebilirsiniz! 🎉**
|