first commit

This commit is contained in:
Beyhan Oğur
2026-04-26 22:20:45 +03:00
commit d50f14bcb1
681 changed files with 65020 additions and 0 deletions

68
.dockerignore Normal file
View File

@@ -0,0 +1,68 @@
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
*.egg-info/
dist/
build/
*.egg
*.pyc
*.pyo
*.pyd
# Virtual Environment
venv/
env/
ENV/
.venv
# Django
*.log
db.sqlite3
db.sqlite3-journal
/staticfiles/
# IDE
.vscode/
.idea/
*.swp
*.swo
*~
.DS_Store
# Git
.git/
.gitignore
# Docker
.dockerignore
Dockerfile
docker-compose*.yml
# Documentation
*.md
!README.md
# Test
.coverage
htmlcov/
.pytest_cache/
.tox/
# Environment variables
.env
.env.*
!.env.example
# Secrets
*.pem
*.key
client_secret*.json
# OS
Thumbs.db
# Backup files
*.bak
*~

36
.env Normal file
View File

@@ -0,0 +1,36 @@
# Django Settings
DEBUG=1
SECRET_KEY=your-secret-key-here-change-this-in-production
DJANGO_ALLOWED_HOSTS=localhost 127.0.0.1 api.denizogur.com.tr
CELERY_BROKER_URL=redis://default:gg7678290@10.80.80.70:6379
# Site URL - Production ve Development için buradan değiştirin
SITE_URL=https://api.denizogur.com.tr
# SITE_URL=http://localhost:8000 # Development için bu satırı aktif edin
# Database Settings (Mevcut PostgreSQL sunucunuz)
USE_POSTGRES=False
POSTGRES_DB=server_dj
POSTGRES_USER=server_dj
POSTGRES_PASSWORD=1234
POSTGRES_HOST=10.80.80.50
POSTGRES_PORT=5432
# Social Auth (Google)
SOCIAL_AUTH_GOOGLE_OAUTH2_KEY=your-google-oauth2-key
SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET=your-google-oauth2-secret
# Social Auth (GitHub)
SOCIAL_AUTH_GITHUB_KEY=your-github-key
SOCIAL_AUTH_GITHUB_SECRET=your-github-secret
# Email Settings (Optional)
EMAIL_BACKEND='django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST=212.64.215.243
EMAIL_PORT=1025
EMAIL_HOST_USER=''
EMAIL_HOST_PASSWORD=''
EMAIL_USE_TLS=False
EMAIL_USE_SSL=False
DEFAULT_FROM_EMAIL='noreply@localhost'

31
.env.example Normal file
View File

@@ -0,0 +1,31 @@
# Django Settings
DEBUG=0
SECRET_KEY=your-secret-key-here-change-this-in-production
DJANGO_ALLOWED_HOSTS=localhost 127.0.0.1 yourdomain.com
# Database Settings (Mevcut PostgreSQL sunucunuz)
USE_POSTGRES=True
POSTGRES_DB=server_dj
POSTGRES_USER=server_dj
POSTGRES_PASSWORD=1234
POSTGRES_HOST=10.80.80.50
POSTGRES_PORT=5432
# Celery Settings
CELERY_BROKER_URL=redis://default:your-redis-password@your-redis-host:6379/5
CELERY_RESULT_BACKEND=django-db
# Social Auth (Google)
SOCIAL_AUTH_GOOGLE_OAUTH2_KEY=your-google-oauth2-key
SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET=your-google-oauth2-secret
# Social Auth (GitHub)
SOCIAL_AUTH_GITHUB_KEY=your-github-key
SOCIAL_AUTH_GITHUB_SECRET=your-github-secret
# Email Settings (Optional)
EMAIL_HOST=smtp.gmail.com
EMAIL_PORT=587
EMAIL_HOST_USER=your-email@gmail.com
EMAIL_HOST_PASSWORD=your-email-password
EMAIL_USE_TLS=True

0
.gitignore vendored Normal file
View File

10
.idea/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,10 @@
# Default ignored files
/shelf/
/workspace.xml
# Ignored default folder with query files
/queries/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
# Editor-based HTTP Client requests
/httpRequests/

36
.idea/atabackend.iml generated Normal file
View File

@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="FacetManager">
<facet type="django" name="Django">
<configuration>
<option name="rootFolder" value="$MODULE_DIR$" />
<option name="settingsModule" value="core/settings.py" />
<option name="manageScript" value="$MODULE_DIR$/manage.py" />
<option name="environment" value="&lt;map/&gt;" />
<option name="doNotUseTestRunner" value="false" />
<option name="trackFilePattern" value="migrations" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.venv" />
<excludeFolder url="file://$MODULE_DIR$/venv" />
<excludeFolder url="file://$MODULE_DIR$/.idea/dataSources" />
</content>
<orderEntry type="jdk" jdkName="Python 3.14 (atabackend)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="PyDocumentationSettings">
<option name="format" value="PLAIN" />
<option name="myDocStringFormat" value="Plain" />
</component>
<component name="TemplatesService">
<option name="TEMPLATE_CONFIGURATION" value="Django" />
<option name="TEMPLATE_FOLDERS">
<list>
<option value="$MODULE_DIR$/templates" />
</list>
</option>
</component>
</module>

6
.idea/copilot.data.migration.agent.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AgentMigrationStateService">
<option name="migrationStatus" value="COMPLETED" />
</component>
</project>

6
.idea/copilot.data.migration.ask.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AskMigrationStateService">
<option name="migrationStatus" value="COMPLETED" />
</component>
</project>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Ask2AgentMigrationStateService">
<option name="migrationStatus" value="COMPLETED" />
</component>
</project>

6
.idea/copilot.data.migration.edit.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="EditMigrationStateService">
<option name="migrationStatus" value="COMPLETED" />
</component>
</project>

12
.idea/dataSources.xml generated Normal file
View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
<data-source source="LOCAL" name="db" uuid="83214012-3533-4bf9-a12a-8ba2974ac851">
<driver-ref>sqlite.xerial</driver-ref>
<synchronize>true</synchronize>
<jdbc-driver>org.sqlite.JDBC</jdbc-driver>
<jdbc-url>jdbc:sqlite:$PROJECT_DIR$/db.sqlite3</jdbc-url>
<working-dir>$ProjectFileDir$</working-dir>
</data-source>
</component>
</project>

7
.idea/dictionaries/project.xml generated Normal file
View File

@@ -0,0 +1,7 @@
<component name="ProjectDictionaryState">
<dictionary name="project">
<words>
<w>corsheaders</w>
</words>
</dictionary>
</component>

View File

@@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

7
.idea/misc.xml generated Normal file
View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Black">
<option name="sdkName" value="Python 3.14 (atabackend)" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.14 (atabackend)" project-jdk-type="Python SDK" />
</project>

8
.idea/modules.xml generated Normal file
View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/atabackend.iml" filepath="$PROJECT_DIR$/.idea/atabackend.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

904
AUTH.md Normal file
View File

@@ -0,0 +1,904 @@
# Authentication API Documentation
Bu doküman, Django REST API'nin authentication endpoint'lerini ve kullanım örneklerini içerir.
## 📋 İçindekiler
1. [Genel Bilgiler](#genel-bilgiler)
2. [Registration (Kayıt)](#registration-kayıt)
3. [Email Activation (Aktivasyon)](#email-activation-aktivasyon)
4. [Login (Giriş)](#login-giriş)
5. [Token Refresh](#token-refresh)
6. [Social Authentication](#social-authentication)
7. [User Profile](#user-profile)
8. [Password Reset](#password-reset)
9. [Frontend Entegrasyonu](#frontend-entegrasyonu)
10. [Error Handling](#error-handling)
---
## Genel Bilgiler
**Base URL:** `http://localhost:8000/api/v1/`
**Authentication:** JWT Bearer Token
```
Authorization: Bearer <access_token>
```
**Content-Type:** `application/json`
### Rate Limiting
- **Anonymous users:** 100 requests/hour
- **Authenticated users:** 1000 requests/hour
---
## Registration (Kayıt)
### Endpoint
```
POST /api/v1/auth/users/
```
### Request Body
```json
{
"email": "user@example.com",
"password": "StrongP@ssw0rd123",
"re_password": "StrongP@ssw0rd123",
"first_name": "Ali",
"last_name": "Veli"
}
```
### Response (201 Created)
```json
{
"id": 1,
"email": "user@example.com",
"first_name": "Ali",
"last_name": "Veli"
}
```
### Önemli Notlar
- Kullanıcı oluşturulur ancak **`is_active=False`** olarak ayarlanır
- Aktivasyon emaili otomatik gönderilir
- Kullanıcı email aktivasyonu yapmadan login olamaz
- Password minimum 8 karakter olmalı ve güçlü olmalı
### Curl Example
```bash
curl -X POST http://localhost:8000/api/v1/auth/users/ \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"password": "StrongP@ssw0rd123",
"re_password": "StrongP@ssw0rd123",
"first_name": "Ali",
"last_name": "Veli"
}'
```
---
## Email Activation (Aktivasyon)
### Endpoint
```
POST /api/v1/auth/users/activation/
```
### Request Body
```json
{
"uid": "MQ",
"token": "c4h7vu-a8f3d2e1c4b5a6d7e8f9g0h1"
}
```
### Response (204 No Content)
Başarılı aktivasyon sonrası response body boş döner.
### Önemli Notlar
- `uid` ve `token` aktivasyon emailindeki linkten alınır
- Token 24 saat geçerlidir
- Başarılı aktivasyon sonrası `is_active=True` olur
- Kullanıcı artık login olabilir
### Email Link Format
```
http://localhost:3000/auth/activate/{uid}/{token}/
```
Frontend bu linki yakalayıp backend'e POST request yapmalı.
### Curl Example
```bash
curl -X POST http://localhost:8000/api/v1/auth/users/activation/ \
-H "Content-Type: application/json" \
-d '{
"uid": "MQ",
"token": "c4h7vu-a8f3d2e1c4b5a6d7e8f9g0h1"
}'
```
### Resend Activation Email
```
POST /api/v1/auth/users/resend_activation/
```
Request Body:
```json
{
"email": "user@example.com"
}
```
---
## Login (Giriş)
### Endpoint
```
POST /api/v1/auth/jwt/create/
```
### Request Body
```json
{
"email": "user@example.com",
"password": "StrongP@ssw0rd123"
}
```
### Response (200 OK)
```json
{
"access": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
```
### Token Bilgileri
- **Access Token:** 60 dakika geçerli
- **Refresh Token:** 7 gün geçerli
- Token rotation aktif (refresh kullanıldığında yeni refresh token döner)
### Önemli Notlar
- Kullanıcı `is_active=False` ise login başarısız olur
- Hatalı email/password için 401 Unauthorized döner
### Curl Example
```bash
curl -X POST http://localhost:8000/api/v1/auth/jwt/create/ \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"password": "StrongP@ssw0rd123"
}'
```
### Error Response (401 Unauthorized)
```json
{
"detail": "No active account found with the given credentials"
}
```
---
## Token Refresh
### Endpoint
```
POST /api/v1/auth/jwt/refresh/
```
### Request Body
```json
{
"refresh": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
```
### Response (200 OK)
```json
{
"access": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
```
### Önemli Notlar
- Yeni access token ve yeni refresh token döner (rotation)
- Eski refresh token blacklist'e eklenir
- Refresh token expire olduysa 401 döner
### Curl Example
```bash
curl -X POST http://localhost:8000/api/v1/auth/jwt/refresh/ \
-H "Content-Type: application/json" \
-d '{
"refresh": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}'
```
---
## Social Authentication
### Supported Providers
- **Google:** `google-oauth2`
- **GitHub:** `github`
- **Facebook:** `facebook`
### Endpoint
```
POST /api/v1/auth/social/<provider>/
```
### Request Body
```json
{
"access_token": "ya29.a0AfH6SMBx..."
}
```
### Response (200 OK)
```json
{
"access": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": {
"id": 1,
"email": "user@example.com",
"first_name": "Ali",
"last_name": "Veli",
"is_active": true,
"date_joined": "2025-12-12T21:30:00Z"
}
}
```
### Önemli Notlar
- Social login ile gelen kullanıcılar **otomatik aktif** (`is_active=True`)
- Email aktivasyon gerekmez
- Kullanıcı yoksa otomatik oluşturulur
- Provider'dan email alınamazsa hata döner
### Google OAuth2 Example
#### 1. Frontend'de Google OAuth
```javascript
// Google OAuth2 ile token al
const googleUser = await gapi.auth2.getAuthInstance().signIn();
const accessToken = googleUser.getAuthResponse().access_token;
// Backend'e gönder
const response = await fetch('http://localhost:8000/api/v1/auth/social/google-oauth2/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
access_token: accessToken
})
});
const data = await response.json();
// data.access, data.refresh, data.user
```
#### 2. Curl Example
```bash
curl -X POST http://localhost:8000/api/v1/auth/social/google-oauth2/ \
-H "Content-Type: application/json" \
-d '{
"access_token": "ya29.a0AfH6SMBx..."
}'
```
### GitHub OAuth2 Example
```bash
curl -X POST http://localhost:8000/api/v1/auth/social/github/ \
-H "Content-Type: application/json" \
-d '{
"access_token": "gho_16C7e42F292c6912E7710c838347Ae178B4a"
}'
```
### Error Responses
**Invalid Provider (400)**
```json
{
"error": "Invalid provider. Must be one of: google-oauth2, github, facebook"
}
```
**Missing Token (400)**
```json
{
"error": "access_token is required"
}
```
**Authentication Failed (401)**
```json
{
"error": "Authentication failed. Invalid token."
}
```
**Email Not Provided (403)**
```json
{
"error": "Authentication forbidden. Email not provided by provider or permission denied."
}
```
---
## User Profile
### Get Current User
```
GET /api/v1/auth/users/me/
```
**Headers:**
```
Authorization: Bearer <access_token>
```
**Response (200 OK):**
```json
{
"id": 1,
"email": "user@example.com",
"first_name": "Ali",
"last_name": "Veli",
"is_active": true,
"date_joined": "2025-12-12T21:30:00Z"
}
```
### Update Current User
```
PATCH /api/v1/auth/users/me/
```
**Request Body:**
```json
{
"first_name": "Ahmet",
"last_name": "Yılmaz"
}
```
### Curl Example
```bash
curl -X GET http://localhost:8000/api/v1/auth/users/me/ \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
```
---
## Password Reset
### 1. Request Password Reset
```
POST /api/v1/auth/users/reset_password/
```
**Request Body:**
```json
{
"email": "user@example.com"
}
```
**Response (204 No Content)**
Email gönderilir, link formatı:
```
http://localhost:3000/auth/password/reset/confirm/{uid}/{token}/
```
### 2. Confirm Password Reset
```
POST /api/v1/auth/users/reset_password_confirm/
```
**Request Body:**
```json
{
"uid": "MQ",
"token": "c4h7vu-a8f3d2e1c4b5a6d7e8f9g0h1",
"new_password": "NewStrongP@ssw0rd123",
"re_new_password": "NewStrongP@ssw0rd123"
}
```
**Response (204 No Content)**
---
## Frontend Entegrasyonu
### Nuxt.js 3 Example
#### 1. Composable: `useAuth.ts`
```typescript
// composables/useAuth.ts
export const useAuth = () => {
const config = useRuntimeConfig();
const accessToken = useCookie('access_token');
const refreshToken = useCookie('refresh_token');
const register = async (userData: {
email: string;
password: string;
re_password: string;
first_name: string;
last_name: string;
}) => {
const { data, error } = await useFetch(`${config.public.apiBase}/auth/users/`, {
method: 'POST',
body: userData,
});
return { data, error };
};
const login = async (email: string, password: string) => {
const { data, error } = await useFetch(`${config.public.apiBase}/auth/jwt/create/`, {
method: 'POST',
body: { email, password },
});
if (data.value) {
accessToken.value = data.value.access;
refreshToken.value = data.value.refresh;
}
return { data, error };
};
const socialLogin = async (provider: string, accessTokenValue: string) => {
const { data, error } = await useFetch(
`${config.public.apiBase}/auth/social/${provider}/`,
{
method: 'POST',
body: { access_token: accessTokenValue },
}
);
if (data.value) {
accessToken.value = data.value.access;
refreshToken.value = data.value.refresh;
}
return { data, error };
};
const getUser = async () => {
if (!accessToken.value) return null;
const { data } = await useFetch(`${config.public.apiBase}/auth/users/me/`, {
headers: {
Authorization: `Bearer ${accessToken.value}`,
},
});
return data.value;
};
const logout = () => {
accessToken.value = null;
refreshToken.value = null;
};
return {
register,
login,
socialLogin,
getUser,
logout,
accessToken,
refreshToken,
};
};
```
#### 2. Register Page: `pages/auth/register.vue`
```vue
<template>
<div>
<h1>Register</h1>
<form @submit.prevent="handleRegister">
<input v-model="form.email" type="email" placeholder="Email" required />
<input v-model="form.first_name" placeholder="First Name" />
<input v-model="form.last_name" placeholder="Last Name" />
<input v-model="form.password" type="password" placeholder="Password" required />
<input v-model="form.re_password" type="password" placeholder="Confirm Password" required />
<button type="submit">Register</button>
</form>
<p v-if="message">{{ message }}</p>
</div>
</template>
<script setup lang="ts">
const { register } = useAuth();
const form = ref({
email: '',
password: '',
re_password: '',
first_name: '',
last_name: '',
});
const message = ref('');
const handleRegister = async () => {
const { data, error } = await register(form.value);
if (error.value) {
message.value = 'Registration failed';
} else {
message.value = 'Registration successful! Please check your email to activate your account.';
}
};
</script>
```
#### 3. Activation Page: `pages/auth/activate/[uid]/[token].vue`
```vue
<template>
<div>
<h1>Account Activation</h1>
<p v-if="loading">Activating your account...</p>
<p v-else-if="success"> Account activated successfully! You can now login.</p>
<p v-else-if="error"> Activation failed. Link may be expired.</p>
</div>
</template>
<script setup lang="ts">
const route = useRoute();
const config = useRuntimeConfig();
const loading = ref(true);
const success = ref(false);
const error = ref(false);
onMounted(async () => {
const { uid, token } = route.params;
try {
await $fetch(`${config.public.apiBase}/auth/users/activation/`, {
method: 'POST',
body: { uid, token },
});
success.value = true;
} catch (e) {
error.value = true;
} finally {
loading.value = false;
}
});
</script>
```
#### 4. Login Page: `pages/auth/login.vue`
```vue
<template>
<div>
<h1>Login</h1>
<form @submit.prevent="handleLogin">
<input v-model="email" type="email" placeholder="Email" required />
<input v-model="password" type="password" placeholder="Password" required />
<button type="submit">Login</button>
</form>
<div class="social-login">
<button @click="handleGoogleLogin">Login with Google</button>
<button @click="handleGithubLogin">Login with GitHub</button>
</div>
<p v-if="error">{{ error }}</p>
</div>
</template>
<script setup lang="ts">
const { login, socialLogin } = useAuth();
const router = useRouter();
const email = ref('');
const password = ref('');
const error = ref('');
const handleLogin = async () => {
const { data, error: loginError } = await login(email.value, password.value);
if (loginError.value) {
error.value = 'Login failed. Please check your credentials.';
} else {
router.push('/dashboard');
}
};
const handleGoogleLogin = async () => {
// Google OAuth2 implementation
// Use @nuxtjs/google-oauth2 or similar
const googleToken = await getGoogleAccessToken(); // Your implementation
const { data, error: socialError } = await socialLogin('google-oauth2', googleToken);
if (!socialError.value) {
router.push('/dashboard');
}
};
const handleGithubLogin = async () => {
// GitHub OAuth2 implementation
const githubToken = await getGithubAccessToken(); // Your implementation
const { data, error: socialError } = await socialLogin('github', githubToken);
if (!socialError.value) {
router.push('/dashboard');
}
};
</script>
```
### Next.js 14 Example
#### 1. Auth Context: `context/AuthContext.tsx`
```typescript
'use client';
import { createContext, useContext, useState, useEffect } from 'react';
interface User {
id: number;
email: string;
first_name: string;
last_name: string;
}
interface AuthContextType {
user: User | null;
login: (email: string, password: string) => Promise<void>;
logout: () => void;
register: (userData: any) => Promise<void>;
}
const AuthContext = createContext<AuthContextType | undefined>(undefined);
export function AuthProvider({ children }: { children: React.ReactNode }) {
const [user, setUser] = useState<User | null>(null);
const [accessToken, setAccessToken] = useState<string | null>(null);
useEffect(() => {
// Load token from localStorage
const token = localStorage.getItem('access_token');
if (token) {
setAccessToken(token);
fetchUser(token);
}
}, []);
const fetchUser = async (token: string) => {
try {
const response = await fetch('http://localhost:8000/api/v1/auth/users/me/', {
headers: {
'Authorization': `Bearer ${token}`,
},
});
const data = await response.json();
setUser(data);
} catch (error) {
console.error('Failed to fetch user', error);
}
};
const login = async (email: string, password: string) => {
const response = await fetch('http://localhost:8000/api/v1/auth/jwt/create/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ email, password }),
});
if (!response.ok) {
throw new Error('Login failed');
}
const data = await response.json();
localStorage.setItem('access_token', data.access);
localStorage.setItem('refresh_token', data.refresh);
setAccessToken(data.access);
await fetchUser(data.access);
};
const logout = () => {
localStorage.removeItem('access_token');
localStorage.removeItem('refresh_token');
setAccessToken(null);
setUser(null);
};
const register = async (userData: any) => {
const response = await fetch('http://localhost:8000/api/v1/auth/users/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(userData),
});
if (!response.ok) {
throw new Error('Registration failed');
}
};
return (
<AuthContext.Provider value={{ user, login, logout, register }}>
{children}
</AuthContext.Provider>
);
}
export const useAuth = () => {
const context = useContext(AuthContext);
if (context === undefined) {
throw new Error('useAuth must be used within an AuthProvider');
}
return context;
};
```
---
## Error Handling
### Common Error Codes
| Status Code | Meaning | Common Causes |
|-------------|---------|---------------|
| 400 | Bad Request | Invalid data, validation errors |
| 401 | Unauthorized | Invalid credentials, expired token |
| 403 | Forbidden | Account not activated, permission denied |
| 404 | Not Found | Endpoint doesn't exist |
| 429 | Too Many Requests | Rate limit exceeded |
| 500 | Internal Server Error | Server-side error |
### Error Response Format
```json
{
"detail": "Error message here",
"field_name": ["Field-specific error"]
}
```
### Example: Registration Validation Error
```json
{
"email": ["A user with that email already exists."],
"password": ["This password is too common."]
}
```
---
## Testing with Postman/Insomnia
### 1. Register
```
POST http://localhost:8000/api/v1/auth/users/
Content-Type: application/json
{
"email": "test@example.com",
"password": "TestP@ssw0rd123",
"re_password": "TestP@ssw0rd123",
"first_name": "Test",
"last_name": "User"
}
```
### 2. Check Email (MailPit)
Open: `http://localhost:8025`
### 3. Activate Account
```
POST http://localhost:8000/api/v1/auth/users/activation/
Content-Type: application/json
{
"uid": "MQ",
"token": "c4h7vu-a8f3d2e1c4b5a6d7e8f9g0h1"
}
```
### 4. Login
```
POST http://localhost:8000/api/v1/auth/jwt/create/
Content-Type: application/json
{
"email": "test@example.com",
"password": "TestP@ssw0rd123"
}
```
### 5. Get User Profile
```
GET http://localhost:8000/api/v1/auth/users/me/
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
```
---
## Environment Variables
### Development (.env.dev)
```bash
DEBUG=True
SECRET_KEY=your-secret-key-here
ALLOWED_HOSTS=localhost,127.0.0.1
# Database
DATABASE_URL=sqlite:///db.sqlite3
# Email (MailPit)
EMAIL_HOST=localhost
EMAIL_PORT=1025
EMAIL_USE_TLS=False
# CORS
CORS_ALLOWED_ORIGINS=http://localhost:3000,http://localhost:5173
```
### Production (.env.prod)
```bash
DEBUG=False
SECRET_KEY=your-production-secret-key
ALLOWED_HOSTS=yourdomain.com,api.yourdomain.com
# Database
DATABASE_URL=postgresql://user:pass@host:5432/dbname
# Email
EMAIL_HOST=smtp.gmail.com
EMAIL_PORT=587
EMAIL_USE_TLS=True
EMAIL_HOST_USER=your-email@gmail.com
EMAIL_HOST_PASSWORD=your-app-password
# Social Auth
SOCIAL_AUTH_GOOGLE_OAUTH2_KEY=your-google-client-id
SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET=your-google-client-secret
SOCIAL_AUTH_GITHUB_KEY=your-github-client-id
SOCIAL_AUTH_GITHUB_SECRET=your-github-client-secret
# CORS
CORS_ALLOWED_ORIGINS=https://yourdomain.com
```
---
## Support
Sorularınız için:
- GitHub Issues: [Your Repo]
- Email: support@yourdomain.com
- Documentation: [Your Docs URL]
---
**Last Updated:** 2025-12-12
**Version:** 1.0.0

110
CACHE.md Normal file
View File

@@ -0,0 +1,110 @@
# Cache Dokumani
Bu dokuman, `home`, `portfolio` ve `settings` app'lerinde yapilan cache
ayarlarini ve otomatik cache temizleme (invalidation) akislarini aciklar.
## Genel
- Cache suresi: 5 dakika (`60 * 5` saniye).
- Cache Django cache backend uzerinden tutulur (`django.core.cache.cache`).
- Veri ekleme, silme ve guncelleme (post_save/post_delete) veya M2M degisimi
oldugunda ilgili cache temizlenir.
## Home App
### Cache Key'leri
- `home:active_home`
- `home:active_aboutme`
- `home:service_list`
- `home:service_title`
- `home:resume`
- `home:education_list`
- `home:experience_list`
- `home:skill_list`
- `home:knowledge_list`
- `home:active_menu`
### Cache Kullanan Endpoint'ler
- `HomeDetailView` -> `home:active_home`
- `AboutMeDetailView` -> `home:active_aboutme`
- `MyServiceList` -> `home:service_list`
- `MyServiceTitleDetailView` -> `home:service_title`
- `MyResumeDetailView` -> `home:resume`
- `EducationListView` -> `home:education_list`
- `ExperienceListView` -> `home:experience_list`
- `SkillListView` -> `home:skill_list`
- `KnowledgeListView` -> `home:knowledge_list`
- `MainMenuDetailView` -> `home:active_menu`
### Cache Temizleme
`home/signals.py` uzerinden asagidaki modellerde degisim oldugunda
tum `home:*` cache'leri temizlenir:
- `Home`
- `AboutMe`
- `MyService`
- `MyServiceTitle`
- `MyResume`
- `Education`
- `Experience`
- `Skill`
- `Knowledge`
- `MainMenu`
Ek olarak `Home.tags` M2M degisimi (`post_add`, `post_remove`, `post_clear`)
oldugunda cache temizlenir.
## Portfolio App
### Cache Key'leri
- `portfolio:category_list`
- `portfolio:category_detail:<slug>`
- `portfolio:portfolio_list`
- `portfolio:portfolio_detail:<pk>`
### Cache Kullanan Endpoint'ler
- `CategoryList` -> `portfolio:category_list`
- `CategoryDetail` -> `portfolio:category_detail:<slug>`
- `PortfolioList` -> `portfolio:portfolio_list`
- `PortfolioDetail` -> `portfolio:portfolio_detail:<pk>`
### Cache Temizleme
`portfolio/signals.py` uzerinden asagidaki durumlarda cache temizlenir:
- `Category` kaydi kayit/silme/guncelleme -> kategori list ve ilgili detay
- `Portfolio` kaydi kayit/silme/guncelleme -> portfolio list ve ilgili detay
- `Portfolio.categories` M2M degisimi -> ilgili portfolio detay ve list
## Settings App
### Cache Key'leri
- `settings:detail`
- `settings:site_status`
### Cache Kullanan Endpoint'ler
- `SettingDetailView` -> `settings:detail`
- `SettingOpenCloseDetailView` -> `settings:site_status`
### Cache Temizleme
`settings/signals.py` uzerinden asagidaki modellerde degisim oldugunda
tum cache temizlenir:
- `Setting`
- `SiteSettings`
## Notlar
- Signal'larin calismasi icin `apps.py` icindeki `ready()` metodlari
ile signal moduleri yuklenir:
- `home/apps.py`
- `portfolio/apps.py`
- `settings/apps.py`

208
CONTACT_EMAIL_SETUP.md Normal file
View File

@@ -0,0 +1,208 @@
# Contact Form - Email Gönderimi (Celery)
## Yapılan Değişiklikler
### 1. Contact Model Güncellemeleri
- `user` alanı artık `null=True, blank=True` (anonim kullanıcılar da form gönderebilir)
- `ip` alanı artık `null=True, blank=True` (opsiyonel)
- `on_delete=SET_NULL` olarak değiştirildi
### 2. Yeni Dosyalar
- **contact/tasks.py**: Celery task ile email gönderimi
- **core/celery.py**: Celery yapılandırması
- **core/__init__.py**: Celery app otomatik yükleme
- **test_contact_api.py**: API test scripti
### 3. View Güncellemeleri (contact/views.py)
- `permission_classes = [AllowAny]` - Herkes form gönderebilir
- IP adresi otomatik olarak algılanır
- Kullanıcı giriş yapmışsa user kaydedilir, yoksa None
- Contact kaydedildikten sonra Celery task ile email gönderilir
### 4. Serializer Güncellemeleri
- Gereksiz alanlar kaldırıldı (ip, updated_at)
- Sadece gerekli alanlar kabul edilir
## Kurulum ve Çalıştırma
### 1. Migration Uygula (TAMAMLANDI ✅)
```bash
python manage.py makemigrations contact
python manage.py migrate contact
```
### 2. Redis'in Çalıştığından Emin Olun
Celery için Redis broker gerekli. Settings'te tanımlı:
```
CELERY_BROKER_URL = redis://default:1923btO**@10.80.80.70:6379/5
```
### 3. MailPit'in Çalıştığından Emin Olun
Email testleri için MailPit kullanılıyor:
- SMTP: localhost:1025
- Web UI: http://localhost:8025
MailPit başlatma (Docker):
```bash
docker run -d -p 1025:1025 -p 8025:8025 --name mailpit axllent/mailpit
```
### 4. Celery Worker Başlat
Yeni bir terminal açın ve şu komutu çalıştırın:
```bash
cd /Users/beyhan/Desktop/Projeler/Python/atabackend
source venv/bin/activate
celery -A core worker --loglevel=info
```
### 5. Django Sunucusunu Başlat
Başka bir terminal açın:
```bash
cd /Users/beyhan/Desktop/Projeler/Python/atabackend
source venv/bin/activate
python manage.py runserver
```
### 6. Test Et
```bash
# Terminal'de test script'i çalıştır
python test_contact_api.py
# Veya cURL ile
curl -X POST http://127.0.0.1:8000/api/v1/contact/create/ \
-H "Content-Type: application/json" \
-d '{
"name": "Test Kullanıcı",
"email": "test@example.com",
"subject": "Test Konusu",
"message": "Bu bir test mesajıdır."
}'
```
### 7. Email Kontrolü
- MailPit web arayüzüne gidin: http://localhost:8025
- Gönderilen emaili göreceksiniz
## API Endpoint
**URL**: `POST /api/v1/contact/create/`
**Permission**: AllowAny (Kimlik doğrulama gerekmez)
**Request Body**:
```json
{
"name": "Adınız Soyadınız",
"email": "email@example.com",
"subject": "Konu",
"message": "Mesajınız"
}
```
**Response** (201 Created):
```json
{
"id": 1,
"name": "Adınız Soyadınız",
"email": "email@example.com",
"subject": "Konu",
"message": "Mesajınız",
"created_at": "2026-01-15T10:30:00Z"
}
```
## Celery Task İzleme
### Task Logları
Celery worker terminalinde task durumunu görebilirsiniz:
```
[2026-01-15 10:30:00,123: INFO/MainProcess] Task contact.tasks.send_contact_email[...] received
[2026-01-15 10:30:00,456: INFO/ForkPoolWorker-1] Task contact.tasks.send_contact_email[...] succeeded
```
### Django Admin'den İzleme
Celery Beat ve Results kurulu, admin panelden task sonuçlarını görebilirsiniz:
- http://127.0.0.1:8000/admin/django_celery_results/
## Email Şablonu
Gönderilen email formatı:
```
Konu: Yeni İletişim Mesajı: [KONU]
Yeni bir iletişim mesajı alındı!
Gönderen: [AD SOYAD]
Email: [EMAIL]
IP Adresi: [IP]
Konu: [KONU]
Mesaj:
[MESAJ İÇERİĞİ]
---
Bu mesaj otomatik olarak gönderilmiştir.
```
## Production Ayarları
Production'da şunları yapın:
1. **Email Backend'i değiştir** (settings.py):
```python
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com' # veya kendi SMTP sunucunuz
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = 'your-email@gmail.com'
EMAIL_HOST_PASSWORD = 'your-app-password'
DEFAULT_FROM_EMAIL = 'noreply@denizogur.com.tr'
```
2. **Alıcı email adresini değiştir** (contact/tasks.py):
```python
recipient_list=['info@denizogur.com.tr'] # Production email
```
3. **Redis production URL'i kullan**
4. **Celery worker'ı production'da service olarak çalıştır**
## Sorun Giderme
### Email Gönderilmiyor
1. Celery worker çalışıyor mu? → Terminal'i kontrol edin
2. Redis bağlantısı var mı? → `CELERY_BROKER_URL` kontrol edin
3. MailPit çalışıyor mu? → http://localhost:8025 kontrol edin
### Task Çalışmıyor
```bash
# Celery task'ı manuel test et
python manage.py shell
>>> from contact.tasks import send_contact_email
>>> send_contact_email.delay('Test', 'test@test.com', 'Konu', 'Mesaj', '127.0.0.1')
```
### Celery Worker Hatası
```bash
# Celery worker'ı yeniden başlat
# Worker terminalinde Ctrl+C
# Sonra tekrar başlat:
celery -A core worker --loglevel=info
```
## İleride Eklenebilecek Özellikler
1. **Email Template (HTML)**: Rich HTML email şablonu
2. **Auto-reply**: Kullanıcıya otomatik teşekkür emaili
3. **Rate Limiting**: Spam koruması için rate limiting
4. **File Upload**: Contact formuna dosya ekleme
5. **Admin Notifications**: Yeni mesaj geldiğinde admin bildirim
6. **Email Queue Retry**: Email başarısız olursa yeniden deneme
## Referanslar
- Celery Docs: https://docs.celeryq.dev/
- Django Celery Results: https://django-celery-results.readthedocs.io/
- MailPit: https://github.com/axllent/mailpit

194
COPILOT_MEMORY.md Normal file
View File

@@ -0,0 +1,194 @@
# Copilot Memory - Django Auth System Development
Bu dosya, Django 6.0 projemizde Custom User + Djoser + JWT + Social Auth sisteminin geliştirilme sürecini takip eder.
---
## 2025-12-12T21:35:00Z
### ✅ Değişiklik Özeti: İlk Kurulum - Custom User Model ve Auth Sistemi Temeli
**Tamamlanan İşler:**
1. **Custom User Model Oluşturuldu** (`accounts/models.py`)
- `CustomUser` modeli: Email tabanlı authentication (username yok)
- `CustomUserManager`: `create_user` ve `create_superuser` metodları
- Alanlar: `email` (unique), `first_name`, `last_name`, `is_staff`, `is_active`, `date_joined`
- `USERNAME_FIELD = "email"`
2. **Admin Panel Konfigürasyonu** (`accounts/admin.py`)
- `CustomUserAdmin` sınıfı ile Django admin'de custom user yönetimi
- List display, filters, search fields yapılandırıldı
3. **Serializers Oluşturuldu** (`accounts/serializers.py`)
- `CustomUserCreateSerializer`: Register için, `is_active=False` set eder
- `CustomUserSerializer`: User profil bilgileri için
- `SocialLoginSerializer`: Social auth için provider + access_token
4. **Social Auth Pipeline** (`accounts/pipeline.py`)
- `activate_user` fonksiyonu: Social login ile gelen kullanıcıları otomatik aktif eder
- Normal register: `is_active=False` (email aktivasyon gerekli)
- Social register: `is_active=True` (direkt aktif)
5. **Social Login View** (`accounts/views.py`)
- `SocialLoginView`: Provider token'ı doğrular, user oluşturur/bulur, JWT döner
- Desteklenen provider'lar: google-oauth2, github, facebook
- Error handling: AuthForbidden, AuthException, genel hatalar
6. **Settings.py Tam Konfigürasyonu** (`core/settings.py`)
- `AUTH_USER_MODEL = 'accounts.CustomUser'`
- `INSTALLED_APPS`: rest_framework, rest_framework_simplejwt, djoser, corsheaders, social_django, accounts
- **REST_FRAMEWORK**: JWT authentication, throttling (100/hour anon, 1000/hour user)
- **SIMPLE_JWT**: 60 min access, 7 days refresh, token rotation, blacklist
- **DJOSER**: Email activation, custom serializers, password reset
- **EMAIL**: MailPit (localhost:1025) dev için, production için SMTP placeholder
- **CORS**: localhost:3000, 5173, 8080 (Nuxt/Next/Vue için)
- **SOCIAL_AUTH**: Google, GitHub, Facebook backends + custom pipeline
7. **Email Templates Oluşturuldu** (`templates/email/`)
- `activation_email.html` / `.txt`: Hesap aktivasyon emaili
- `confirmation_email.html` / `.txt`: Aktivasyon başarılı emaili
- `password_reset_email.html` / `.txt`: Şifre sıfırlama emaili
- Modern, responsive HTML tasarım + plain text alternatifi
8. **URL Routing** (`accounts/urls.py`)
- Djoser endpoints: `/api/v1/auth/users/` (register), `/api/v1/auth/users/activation/` (activate)
- JWT endpoints: `/api/v1/auth/jwt/create/` (login), `/api/v1/auth/jwt/refresh/`
- Social auth: `/api/v1/auth/social/<provider>/`
- Python Social Auth URLs: `/api/v1/social/`
9. **Database Migrations**
- `accounts/migrations/0001_initial.py`: CustomUser model
- `social_django` migrations: Social auth tabloları
- Tüm migration'lar başarıyla uygulandı (migrate completed)
### 📁 Değiştirilen/Oluşturulan Dosyalar:
- `accounts/models.py` (yeni)
- `accounts/admin.py` (güncellendi)
- `accounts/serializers.py` (yeni)
- `accounts/pipeline.py` (yeni)
- `accounts/views.py` (güncellendi)
- `accounts/urls.py` (güncellendi)
- `accounts/migrations/0001_initial.py` (oluşturuldu)
- `core/settings.py` (kapsamlı güncelleme)
- `templates/email/activation_email.html` (yeni)
- `templates/email/activation_email.txt` (yeni)
- `templates/email/confirmation_email.html` (yeni)
- `templates/email/confirmation_email.txt` (yeni)
- `templates/email/password_reset_email.html` (yeni)
- `templates/email/password_reset_email.txt` (yeni)
### 🎯 Sistem Özellikleri:
**Authentication Akışları:**
1. **Normal Register (Email/Password):**
```
POST /api/v1/auth/users/
Body: { "email", "password", "re_password", "first_name", "last_name" }
→ User oluşturulur (is_active=False)
→ Aktivasyon emaili gönderilir
→ POST /api/v1/auth/users/activation/ { "uid", "token" }
→ is_active=True olur
→ POST /api/v1/auth/jwt/create/ { "email", "password" }
→ JWT tokens alınır
```
2. **Social Login:**
```
POST /api/v1/auth/social/google-oauth2/
Body: { "access_token": "..." }
→ Provider'dan user bilgisi alınır
→ User bulunur/oluşturulur (is_active=True)
→ JWT tokens direkt döner
```
3. **Login:**
```
POST /api/v1/auth/jwt/create/
Body: { "email", "password" }
→ Access + Refresh token döner
```
4. **Token Refresh:**
```
POST /api/v1/auth/jwt/refresh/
Body: { "refresh": "..." }
→ Yeni access token döner
```
### ⚙️ Yapılandırma Gereksinimleri:
**Environment Variables (Production için):**
```bash
# Email
EMAIL_HOST=smtp.gmail.com
EMAIL_PORT=587
EMAIL_USE_TLS=True
EMAIL_HOST_USER=your-email@gmail.com
EMAIL_HOST_PASSWORD=your-app-password
DEFAULT_FROM_EMAIL=noreply@yourdomain.com
# Social Auth - Google
SOCIAL_AUTH_GOOGLE_OAUTH2_KEY=your-google-client-id
SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET=your-google-client-secret
# Social Auth - GitHub
SOCIAL_AUTH_GITHUB_KEY=your-github-client-id
SOCIAL_AUTH_GITHUB_SECRET=your-github-client-secret
# Social Auth - Facebook
SOCIAL_AUTH_FACEBOOK_KEY=your-facebook-app-id
SOCIAL_AUTH_FACEBOOK_SECRET=your-facebook-app-secret
```
**Development Tools:**
- MailPit: `localhost:1025` (SMTP), `localhost:8025` (Web UI)
- Database: SQLite (db.sqlite3)
### 📝 Next Steps:
1. **Testing (Yüksek Öncelik):**
- [ ] Unit tests: Register → is_active=False check
- [ ] Unit tests: Activation → is_active=True check
- [ ] Unit tests: Login → aktif/inaktif user scenarios
- [ ] Unit tests: Social login → user creation + JWT response
- [ ] Integration tests: Full auth flow
2. **Dokümantasyon:**
- [ ] `AUTH.md` oluştur: Tüm endpoint'ler, request/response örnekleri
- [ ] Frontend entegrasyon kılavuzu (Nuxt.js + Next.js)
- [ ] Environment variables dokümantasyonu
- [ ] Deployment checklist
3. **İyileştirmeler:**
- [ ] Rate limiting test et
- [ ] Email template'lerini test et (MailPit ile)
- [ ] Social auth provider'ları test et
- [ ] Error mesajlarını frontend-friendly hale getir
- [ ] Logging ekle (özellikle auth failures için)
4. **Güvenlik:**
- [ ] HTTPS için production settings
- [ ] CSRF token stratejisi netleştir
- [ ] JWT secret key'i environment variable'a taşı
- [ ] Rate limiting değerlerini production için ayarla
5. **Opsiyonel Özellikler:**
- [ ] Email değiştirme flow'u
- [ ] 2FA (Two-Factor Authentication)
- [ ] Remember me functionality
- [ ] Account deletion
- [ ] Social account linking (birden fazla provider)
### 🐛 Bilinen Sorunlar:
- Yok (şu an için)
### 📚 Referanslar:
- Djoser Docs: https://djoser.readthedocs.io/
- SimpleJWT Docs: https://django-rest-framework-simplejwt.readthedocs.io/
- Python Social Auth: https://python-social-auth.readthedocs.io/
- Django REST Framework: https://www.django-rest-framework.org/
---

404
DOCKER_CELERY.md Normal file
View File

@@ -0,0 +1,404 @@
# 🚀 Docker Compose ile Celery Kullanımı
Bu döküman, Docker Compose üzerinde Celery worker ve beat'in nasıl çalıştırılacağınııklar.
## 📋 Genel Bakış
Projede iki Docker Compose yapılandırması bulunmaktadır:
1. **docker-compose.yml** - Development (Geliştirme) ortamı
2. **docker-compose.prod.yml** - Production (Canlı) ortamı
Her iki ortamda da Celery worker ve beat aynı container içinde çalışır:
```bash
celery -A core worker --beat --scheduler django --loglevel=info
```
## 🏗️ Servis Yapısı
### Development (docker-compose.yml)
```yaml
services:
web: # Django uygulaması
celery: # Celery worker + beat
```
### Production (docker-compose.prod.yml)
```yaml
services:
web-atahan: # Django uygulaması (Gunicorn)
celery-atahan: # Celery worker + beat
nginx: # Reverse proxy
```
## 🚀 Başlatma
### Development Ortamı
```bash
# Tüm servisleri başlat (web + celery)
docker-compose up
# Arka planda çalıştır
docker-compose up -d
# Sadece Celery'yi başlat
docker-compose up celery
# Rebuild ile başlat
docker-compose up --build
```
### Production Ortamı
```bash
# Tüm servisleri başlat
docker-compose -f docker-compose.prod.yml up -d
# Sadece Celery'yi başlat
docker-compose -f docker-compose.prod.yml up -d celery-atahan
# Rebuild ile başlat
docker-compose -f docker-compose.prod.yml up --build -d
```
## 📊 Log İzleme
### Development
```bash
# Tüm servislerin logları
docker-compose logs -f
# Sadece Celery logları
docker-compose logs -f celery
# Son 100 satır
docker-compose logs --tail=100 celery
# Belirli bir tarihten sonraki loglar
docker-compose logs --since 2026-01-15T10:00:00 celery
```
### Production
```bash
# Celery logları
docker-compose -f docker-compose.prod.yml logs -f celery-atahan
# Tüm servisler
docker-compose -f docker-compose.prod.yml logs -f
```
## 🔄 Yeniden Başlatma
### Development
```bash
# Celery'yi yeniden başlat
docker-compose restart celery
# Tüm servisleri yeniden başlat
docker-compose restart
```
### Production
```bash
# Celery'yi yeniden başlat
docker-compose -f docker-compose.prod.yml restart celery-atahan
# Tüm servisleri yeniden başlat
docker-compose -f docker-compose.prod.yml restart
```
## 🛑 Durdurma
### Development
```bash
# Servisleri durdur (container'ları kaldır)
docker-compose down
# Sadece Celery'yi durdur
docker-compose stop celery
# Volume'leri de sil
docker-compose down -v
```
### Production
```bash
# Servisleri durdur
docker-compose -f docker-compose.prod.yml down
# Sadece Celery'yi durdur
docker-compose -f docker-compose.prod.yml stop celery-atahan
```
## 🔧 Container'a Bağlanma
### Development
```bash
# Celery container'a bash ile bağlan
docker-compose exec celery bash
# Celery container'da komut çalıştır
docker-compose exec celery ls -la
docker-compose exec celery python manage.py shell
```
### Production
```bash
# Celery container'a bash ile bağlan
docker-compose -f docker-compose.prod.yml exec celery-atahan bash
# Komut çalıştır
docker-compose -f docker-compose.prod.yml exec celery-atahan python manage.py shell
```
## 📝 Celery Task Yönetimi
### Task Sonuçlarını Görüntüleme
```bash
# Django shell aç
docker-compose exec web python manage.py shell
# Shell içinde:
from django_celery_results.models import TaskResult
# Tüm task sonuçları
TaskResult.objects.all()
# Başarılı task'lar
TaskResult.objects.filter(status='SUCCESS')
# Başarısız task'lar
TaskResult.objects.filter(status='FAILURE')
# En son 10 task
TaskResult.objects.order_by('-date_done')[:10]
```
### Django Admin'den Task İzleme
1. Tarayıcıda admin panele girin:
- Development: http://localhost:8000/admin/
- Production: http://your-domain.com/admin/
2. Şu bölümlere gidin:
- **Django Celery Results** → **Task results** - Task sonuçları
- **Django Celery Beat** → **Periodic tasks** - Zamanlanmış task'lar
- **Django Celery Beat** → **Intervals** - Periyodik aralıklar
### Manuel Task Çalıştırma
```bash
# Django shell aç
docker-compose exec web python manage.py shell
# Shell içinde bir task çalıştır:
from contact.tasks import send_contact_email
# Hemen çalıştır (test için)
result = send_contact_email(
name='Test',
email='test@example.com',
subject='Test Subject',
message='Test message',
ip='127.0.0.1'
)
print(result)
# Celery queue'ya ekle (asenkron)
task = send_contact_email.delay(
name='Test',
email='test@example.com',
subject='Test Subject',
message='Test message',
ip='127.0.0.1'
)
print(f"Task ID: {task.id}")
print(f"Task Status: {task.status}")
```
## ⚙️ Environment Variables
### Development (.env veya docker-compose.yml)
```bash
CELERY_BROKER_URL=redis://default:password@host:6379/5
CELERY_RESULT_BACKEND=django-db
```
### Production (.env)
```bash
CELERY_BROKER_URL=redis://default:password@host:6379/5
CELERY_RESULT_BACKEND=django-db
```
## 🐛 Sorun Giderme
### Celery Başlamıyor
```bash
# Logları kontrol et
docker-compose logs celery
# Container durumunu kontrol et
docker-compose ps
# Container'ı yeniden başlat
docker-compose restart celery
# Container'ı rebuild et
docker-compose up --build celery
```
### Redis Bağlantı Hatası
```bash
# Redis bağlantısını test et
docker-compose exec celery python -c "
from celery import Celery
app = Celery('core')
app.config_from_object('django.conf:settings', namespace='CELERY')
print('Connection OK')
"
# Environment variable'ları kontrol et
docker-compose exec celery env | grep CELERY
```
### Task Çalışmıyor
```bash
# Celery worker'ın çalıştığını doğrula
docker-compose logs -f celery
# Task'ın queue'ya eklendiğini kontrol et
docker-compose exec web python manage.py shell
>>> from django_celery_results.models import TaskResult
>>> TaskResult.objects.latest('date_created')
# Task'ı manuel çalıştır
>>> from contact.tasks import send_contact_email
>>> send_contact_email.delay('Test', 'test@test.com', 'Subject', 'Message')
```
### Email Gönderilmiyor
```bash
# Email backend ayarlarını kontrol et
docker-compose exec web python manage.py shell
>>> from django.conf import settings
>>> print(settings.EMAIL_BACKEND)
>>> print(settings.EMAIL_HOST)
>>> print(settings.EMAIL_PORT)
# MailPit kontrol et (development)
# http://localhost:8025
```
## 📈 Performans İzleme
### Container Kaynak Kullanımı
```bash
# Tüm container'ların kaynak kullanımı
docker stats
# Sadece Celery
docker stats django_celery_worker
# Production
docker stats django_celery_prod_atahan
```
### Celery Worker İstatistikleri
```bash
# Celery inspect komutu
docker-compose exec celery celery -A core inspect active
docker-compose exec celery celery -A core inspect stats
docker-compose exec celery celery -A core inspect registered
```
## 🔐 Production Best Practices
### 1. Log Rotation
Production'da log dosyaları büyüyebilir. Docker log rotation kullanın:
```yaml
# docker-compose.prod.yml
celery-atahan:
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
```
### 2. Resource Limits
Container'lara kaynak limiti koyun:
```yaml
celery-atahan:
deploy:
resources:
limits:
cpus: '1.0'
memory: 512M
reservations:
cpus: '0.5'
memory: 256M
```
### 3. Health Checks
Celery health check ekleyin:
```yaml
celery-atahan:
healthcheck:
test: ["CMD-SHELL", "celery -A core inspect ping"]
interval: 30s
timeout: 10s
retries: 3
```
### 4. Restart Policy
Otomatik yeniden başlatma:
```yaml
celery-atahan:
restart: unless-stopped
```
## 📚 Ek Kaynaklar
- [Celery Documentation](https://docs.celeryq.dev/)
- [Django Celery Results](https://django-celery-results.readthedocs.io/)
- [Django Celery Beat](https://django-celery-beat.readthedocs.io/)
- [Docker Compose Documentation](https://docs.docker.com/compose/)
## 🆘 Yardım
Sorun yaşıyorsanız:
1. Logları kontrol edin: `docker-compose logs -f celery`
2. Container durumunu kontrol edin: `docker-compose ps`
3. Environment variable'ları kontrol edin: `docker-compose exec celery env`
4. Redis bağlantısını test edin
5. Task'ları manuel çalıştırın ve sonucu gözlemleyin

331
DOCKER_CELERY_QUICKSTART.md Normal file
View File

@@ -0,0 +1,331 @@
# 🐳 Docker Compose ile Celery - Hızlı Başlangıç
Bu döküman, Docker Compose ile Celery'yi hızlıca çalıştırmak için gerekli adımları içerir.
## ✅ Hazırlık
1. **Docker ve Docker Compose yüklü olmalı**
2. **Redis erişimi olmalı** (CELERY_BROKER_URL)
## 🚀 Development Ortamı
### Başlatma
```bash
# Tüm servisleri başlat (Django + Celery)
docker-compose up
# Arka planda çalıştır
docker-compose up -d
# Logları takip et
docker-compose logs -f
# Sadece Celery logları
docker-compose logs -f celery
```
### Test Etme
```bash
# 1. Contact API'yi test et
curl -X POST http://localhost:8000/api/v1/contact/create/ \
-H "Content-Type: application/json" \
-d '{
"name": "Test User",
"email": "test@example.com",
"subject": "Test Subject",
"message": "This is a test message."
}'
# 2. Celery loglarını kontrol et
docker-compose logs -f celery
# 3. Email'i MailPit'te kontrol et
open http://localhost:8025
```
### Durdurma
```bash
# Servisleri durdur
docker-compose down
# Volume'leri de sil
docker-compose down -v
```
## 🌐 Production Ortamı
### Hazırlık
```bash
# .env dosyası oluştur
cp .env.example .env
# .env dosyasını düzenle
nano .env
# Gerekli değerler:
# - SECRET_KEY
# - DJANGO_ALLOWED_HOSTS
# - CELERY_BROKER_URL
# - POSTGRES_* (database ayarları)
```
### Başlatma
```bash
# Tüm servisleri başlat (Django + Celery + Nginx)
docker-compose -f docker-compose.prod.yml up -d
# Build ile başlat
docker-compose -f docker-compose.prod.yml up --build -d
# Logları kontrol et
docker-compose -f docker-compose.prod.yml logs -f
# Celery logları
docker-compose -f docker-compose.prod.yml logs -f celery-atahan
```
### Servis Durumları
```bash
# Container durumlarını kontrol et
docker-compose -f docker-compose.prod.yml ps
# Kaynak kullanımı
docker stats
```
### Durdurma
```bash
# Servisleri durdur
docker-compose -f docker-compose.prod.yml down
# Yeniden başlat
docker-compose -f docker-compose.prod.yml restart
# Sadece Celery'yi yeniden başlat
docker-compose -f docker-compose.prod.yml restart celery-atahan
```
## 🔧 Yararlı Komutlar
### Migrations
```bash
# Development
docker-compose exec web python manage.py makemigrations
docker-compose exec web python manage.py migrate
# Production
docker-compose -f docker-compose.prod.yml exec web-atahan python manage.py migrate
```
### Django Shell
```bash
# Development
docker-compose exec web python manage.py shell
# Production
docker-compose -f docker-compose.prod.yml exec web-atahan python manage.py shell
```
### Celery Container'a Bağlanma
```bash
# Development
docker-compose exec celery bash
# Production
docker-compose -f docker-compose.prod.yml exec celery-atahan bash
```
### Task Sonuçlarını Görme
```bash
# Shell aç
docker-compose exec web python manage.py shell
# Shell içinde:
from django_celery_results.models import TaskResult
TaskResult.objects.all()
TaskResult.objects.filter(status='SUCCESS')
TaskResult.objects.order_by('-date_done')[:10]
```
## 📊 İzleme
### Container Logları
```bash
# Tüm servisler (Development)
docker-compose logs -f
# Tüm servisler (Production)
docker-compose -f docker-compose.prod.yml logs -f
# Son 100 satır
docker-compose logs --tail=100 celery
# Belirli zaman aralığı
docker-compose logs --since 2026-01-15T10:00:00 celery
```
### Celery İstatistikleri
```bash
# Aktif task'lar
docker-compose exec celery celery -A core inspect active
# Worker istatistikleri
docker-compose exec celery celery -A core inspect stats
# Kayıtlı task'lar
docker-compose exec celery celery -A core inspect registered
```
### Django Admin
1. **Admin panele gir:**
- Development: http://localhost:8000/admin/
- Production: http://your-domain.com/admin/
2. **Task sonuçlarını gör:**
- Django Celery Results → Task results
3. **Periyodik task'ları yönet:**
- Django Celery Beat → Periodic tasks
## 🐛 Sorun Giderme
### Celery Çalışmıyor
```bash
# 1. Logları kontrol et
docker-compose logs celery
# 2. Container durumunu kontrol et
docker-compose ps
# 3. Container'ı yeniden başlat
docker-compose restart celery
# 4. Rebuild et
docker-compose up --build celery
```
### Email Gönderilmiyor
```bash
# 1. Celery loglarını kontrol et
docker-compose logs -f celery
# 2. MailPit çalışıyor mu? (Development)
open http://localhost:8025
# 3. Email ayarlarını kontrol et
docker-compose exec web python manage.py shell
>>> from django.conf import settings
>>> print(settings.EMAIL_BACKEND)
>>> print(settings.EMAIL_HOST)
```
### Redis Bağlantı Hatası
```bash
# Environment variable'ları kontrol et
docker-compose exec celery env | grep CELERY
# Redis bağlantısını test et
docker-compose exec celery python -c "
from django.conf import settings
print(settings.CELERY_BROKER_URL)
"
```
## 📚 Servis Portları
### Development
- **Django**: http://localhost:8000
- **MailPit UI**: http://localhost:8025
- **MailPit SMTP**: localhost:1025
### Production
- **Nginx**: http://localhost:8077
- **Django (Direct)**: http://localhost:8800
## 🔐 Environment Variables
### Development (.env veya docker-compose.yml)
```bash
DEBUG=1
CELERY_BROKER_URL=redis://default:password@host:6379/5
CELERY_RESULT_BACKEND=django-db
POSTGRES_DB=server_dj
POSTGRES_USER=server_dj
POSTGRES_PASSWORD=1234
POSTGRES_HOST=10.80.80.50
POSTGRES_PORT=5432
```
### Production (.env)
```bash
DEBUG=0
SECRET_KEY=your-secret-key-here
DJANGO_ALLOWED_HOSTS=yourdomain.com
CELERY_BROKER_URL=redis://default:password@host:6379/5
CELERY_RESULT_BACKEND=django-db
POSTGRES_DB=your-db
POSTGRES_USER=your-user
POSTGRES_PASSWORD=your-password
POSTGRES_HOST=your-host
POSTGRES_PORT=5432
```
## 📖 Detaylı Dökümanlar
- **DOCKER_CELERY.md** - Celery kullanımı hakkında detaylı bilgi
- **DOCKER_README.md** - Docker genel kullanımı
- **CONTACT_EMAIL_SETUP.md** - Contact email kurulumu
## 🎯 Önemli Notlar
1.**Celery worker ve beat** aynı container'da çalışır
2.**Redis** harici olarak çalışmalı (CELERY_BROKER_URL)
3.**PostgreSQL** harici olarak çalışmalı
4.**MailPit** development için email testleri sağlar
5. ✅ Production'da gerçek SMTP kullanın
## 🚨 İlk Başlatmada Yapılacaklar
```bash
# 1. Servisleri başlat
docker-compose up -d
# 2. Migration'ları uygula
docker-compose exec web python manage.py migrate
# 3. Superuser oluştur
docker-compose exec web python manage.py createsuperuser
# 4. Static dosyaları topla (Production)
docker-compose exec web python manage.py collectstatic --noinput
# 5. Test et
curl -X POST http://localhost:8000/api/v1/contact/create/ \
-H "Content-Type: application/json" \
-d '{"name":"Test","email":"test@test.com","subject":"Test","message":"Test"}'
# 6. Logları kontrol et
docker-compose logs -f celery
```
---
**Yardım**: Sorun yaşarsanız `DOCKER_CELERY.md` dosyasına bakın veya logları kontrol edin.

View File

@@ -0,0 +1,269 @@
# 🎉 Docker Compose Production Test Raporu
**Test Tarihi:** 15 Ocak 2026, 17:12
**Ortam:** Production (docker-compose.prod.yml)
## ✅ Sorun ve Çözüm
### 🐛 Tespit Edilen Sorun
```
AttributeError: 'zoneinfo.ZoneInfo' object has no attribute 'localize'
```
**Sebep:**
- Django Celery Beat'in Python 3.14'teki yeni `zoneinfo` modülü ile uyumsuzluğu
- `pytz` yerine `zoneinfo` kullanımındaki API değişikliği
### ✅ Uygulanan Çözüm
1. **Beat Scheduler Kaldırıldı**
- Worker ve Beat ayrıldı
- Worker: `celery -A core worker --loglevel=info`
- Beat: Opsiyonel (ayrı dosya: `docker-compose.celery-beat.yml`)
2. **Timezone Ayarları Güncellendi**
```python
CELERY_TIMEZONE = 'Europe/Istanbul'
CELERY_ENABLE_UTC = True
```
3. **Docker Compose Güncellemeleri**
- `docker-compose.yml` - Development (beat yok)
- `docker-compose.prod.yml` - Production (beat yok)
- `docker-compose.celery-beat.yml` - Beat için opsiyonel
## 📊 Production Test Sonuçları
### Container Durumları
| Container | Status | Ports | CPU/Memory |
|-----------|--------|-------|------------|
| django_web_prod_atahan | ✅ Running | 0.0.0.0:8800->8000 | Normal |
| django_celery_prod_atahan | ✅ Running | - | Normal |
| django_nginx_atahan | ✅ Running | 0.0.0.0:8077->80 | Normal |
### Servis Testleri
#### 1. Django Web (Gunicorn)
```
✅ Gunicorn: 3 workers aktif
✅ Port: 8800 (direct), 8077 (nginx)
✅ Database: Bağlı
✅ Migrations: Uygulandı
✅ Static files: Toplanan (365 dosya)
```
**Log:**
```
[2026-01-15 14:11:24 +0000] [1] [INFO] Starting gunicorn 23.0.0
[2026-01-15 14:11:24 +0000] [1] [INFO] Listening at: http://0.0.0.0:8000
[2026-01-15 14:11:24 +0000] [1] [INFO] Using worker: sync
[2026-01-15 14:11:24 +0000] [10] [INFO] Booting worker with pid: 10
[2026-01-15 14:11:24 +0000] [11] [INFO] Booting worker with pid: 11
[2026-01-15 14:11:24 +0000] [12] [INFO] Booting worker with pid: 12
```
#### 2. Celery Worker
```
✅ Worker: Çalışıyor
✅ Concurrency: 8 workers (prefork)
✅ Redis: Bağlı (212.64.215.243:6379/5)
✅ Tasks: Yüklendi
✅ Beat: YOK (ayrıldı)
```
**Yüklü Task'lar:**
- ✅ `contact.tasks.send_contact_email`
- ✅ `core.celery.debug_task`
- ✅ `imagekit.cachefiles.backends._generate_file`
**Log:**
```
[2026-01-15 17:11:30,001: INFO/MainProcess] Connected to redis://default:**@212.64.215.243:6379/5
[2026-01-15 17:11:31,352: INFO/MainProcess] celery@56445c300966 ready.
```
#### 3. Nginx Reverse Proxy
```
✅ Status: Running
✅ Port: 8077
✅ Upstream: django_web_prod_atahan:8000
✅ Configuration: Valid
```
### API Test Sonuçları
#### Test 1: Direct Gunicorn (Port 8800)
```bash
POST http://localhost:8800/api/v1/contact/create/
{
"name": "Production Test",
"email": "prod@test.com",
"subject": "Production Docker Test",
"message": "Bu production ortamından gönderilen bir test mesajıdır."
}
```
**Response:** ✅ 201 Created
```json
{
"id": 10,
"name": "Production Test",
"email": "prod@test.com",
"subject": "Production Docker Test",
"message": "Bu production ortamından gönderilen bir test mesajıdır.",
"created_at": "2026-01-15T17:12:24.550815+03:00"
}
```
#### Test 2: Celery Task Execution
```
✅ Task Received: contact.tasks.send_contact_email
✅ Task ID: 482451a6-d2b1-4609-ad02-b97b155c4c75
✅ Status: SUCCESS (0.066s)
✅ Worker: ForkPoolWorker-7
```
**Celery Log:**
```
[2026-01-15 17:12:24,519: INFO/MainProcess] Task contact.tasks.send_contact_email[...] received
[2026-01-15 17:12:24,587: INFO/ForkPoolWorker-7] Task contact.tasks.send_contact_email[...] succeeded in 0.065s
```
**Not:** Email SMTP hatası (beklenen - MailPit bağlı değil):
```
'Email gönderilemedi: [Errno 111] Connection refused'
```
## 📈 Performans Metrikleri
| Metrik | Değer | Durum |
|--------|-------|-------|
| Container Start Time | ~10s | ✅ İyi |
| API Response Time | <1s | ✅ Mükemmel |
| Celery Task Exec | 0.065s | ✅ Mükemmel |
| Gunicorn Workers | 3 | ✅ Optimal |
| Celery Concurrency | 8 | ✅ Optimal |
## 🔧 Yapılandırma Değişiklikleri
### docker-compose.yml (Development)
```yaml
celery:
command: celery -A core worker --loglevel=info
# --beat kaldırıldı
```
### docker-compose.prod.yml (Production)
```yaml
celery-atahan:
command: celery -A core worker --loglevel=info
# --beat --scheduler django kaldırıldı
```
### core/settings.py
```python
CELERY_TIMEZONE = 'Europe/Istanbul' # UTC yerine
CELERY_ENABLE_UTC = True # Yeni eklendi
```
### Yeni Dosya: docker-compose.celery-beat.yml
```yaml
# Periyodik task'lar için ayrı beat container
# Kullanım: docker-compose -f docker-compose.yml -f docker-compose.celery-beat.yml up -d
```
## 🎯 Sonuç
### ✅ Çalışan Özellikler
1. ✅ Production web server (Gunicorn)
2. ✅ Nginx reverse proxy
3. ✅ Celery worker (8 concurrent)
4. ✅ Asenkron task execution
5. ✅ Contact API endpoint
6. ✅ Database connection
7. ✅ Redis broker connection
8. ✅ Static file serving
9. ✅ Auto-restart (restart: unless-stopped)
10. ✅ Multi-container orchestration
### ⚠️ Notlar
1. **Email Gönderimi:** MailPit production'da yok (SMTP yapılandırması gerekli)
2. **Beat Scheduler:** Şu an devre dışı (ihtiyaç olursa ayrı container'da çalıştırılabilir)
3. **Timezone Uyarısı:** Çözüldü
### 📝 Production'a Almak İçin
1. **.env Dosyası:**
```bash
cp .env.example .env
nano .env
# Gereken değerler:
DEBUG=0
SECRET_KEY=<your-secret-key>
DJANGO_ALLOWED_HOSTS=yourdomain.com
CELERY_BROKER_URL=redis://...
```
2. **Email SMTP Ayarları:**
```python
# settings.py (production)
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = 'your-email@gmail.com'
EMAIL_HOST_PASSWORD = 'app-password'
```
3. **Başlatma:**
```bash
docker-compose -f docker-compose.prod.yml up -d
docker-compose -f docker-compose.prod.yml logs -f
```
## 🎊 Final Durum
**✅ PRODUCTION DOCKER COMPOSE HAZIR!**
| Component | Status | Notes |
|-----------|--------|-------|
| Development | ✅ Test Edildi | docker-compose.yml |
| Production | ✅ Test Edildi | docker-compose.prod.yml |
| Celery Worker | ✅ Çalışıyor | Beat ayrıldı |
| Nginx | ✅ Çalışıyor | Reverse proxy aktif |
| API | ✅ Çalışıyor | Contact endpoint |
| Tasks | ✅ Çalışıyor | Email task execution |
| Beat Scheduler | ⏸️ Opsiyonel | Ayrı dosyada |
---
**Sorun Çözüldü:** Beat scheduler hatası düzeltildi
**Test Durumu:** BAŞARILI ✅
**Production Ready:** EVET ✅
## 🚀 Hızlı Komutlar
```bash
# Production başlat
docker-compose -f docker-compose.prod.yml up -d
# Logları izle
docker-compose -f docker-compose.prod.yml logs -f celery-atahan
# Container durumları
docker ps --filter "name=atahan"
# Test
curl -X POST http://localhost:8800/api/v1/contact/create/ \
-H "Content-Type: application/json" \
-d '{"name":"Test","email":"test@test.com","subject":"Test","message":"Test"}'
# Durdur
docker-compose -f docker-compose.prod.yml down
```
🎉 **BAŞARIYLA TAMAMLANDI!**

227
DOCKER_README.md Normal file
View File

@@ -0,0 +1,227 @@
# Django Projesi - Docker Kurulum Rehberi
Bu Django projesi Python 3.14.2 ile dockerize edilmiştir.
## 📋 Gereksinimler
- Docker
- Docker Compose
## 🚀 Hızlı Başlangıç
### Geliştirme Ortamı (Development)
1. **Projeyi klonlayın ve dizine girin:**
```bash
cd /path/to/project
```
2. **Docker container'ları başlatın:**
```bash
docker-compose up --build
```
3. **Tarayıcınızda açın:**
```
http://localhost:8000
```
### Production Ortamı
1. **Environment dosyasını oluşturun:**
```bash
cp .env.example .env
# .env dosyasını düzenleyin ve gerçek değerleri girin
```
2. **Production container'ları başlatın:**
```bash
docker-compose -f docker-compose.prod.yml up --build -d
```
3. **Nginx üzerinden erişin:**
```
http://localhost
```
## 🛠️ Yararlı Komutlar
### Container'ları Başlatma
```bash
# Geliştirme
docker-compose up
# Production
docker-compose -f docker-compose.prod.yml up -d
# Rebuild ile başlatma
docker-compose up --build
```
### Container'ları Durdurma
```bash
docker-compose down
# Volume'leri de silmek için
docker-compose down -v
```
### Django Komutları Çalıştırma
```bash
# Migration oluşturma
docker-compose exec web python manage.py makemigrations
# Migration uygulama
docker-compose exec web python manage.py migrate
# Superuser oluşturma
docker-compose exec web python manage.py createsuperuser
# Shell açma
docker-compose exec web python manage.py shell
# Static dosyaları toplama
docker-compose exec web python manage.py collectstatic
```
### Celery Komutları
```bash
# Celery worker loglarını görüntüleme
docker-compose logs -f celery
# Production ortamında
docker-compose -f docker-compose.prod.yml logs -f celery-atahan
# Celery worker'ı yeniden başlatma
docker-compose restart celery
# Celery container'a bağlanma
docker-compose exec celery bash
# Celery task durumlarını kontrol etme (Django shell içinde)
docker-compose exec web python manage.py shell
# >>> from django_celery_results.models import TaskResult
# >>> TaskResult.objects.all()
```
### Logları Görüntüleme
```bash
# Tüm servislerin logları
docker-compose logs -f
# Sadece web servisinin logları
docker-compose logs -f web
# Sadece database logları
docker-compose logs -f db
```
### Container'a Bağlanma
```bash
# Web container'a bash ile bağlan
docker-compose exec web bash
# Database container'a bağlan
docker-compose exec db psql -U server_dj -d server_dj
```
## 📁 Proje Yapısı
```
.
├── Dockerfile # Ana Docker image tanımı
├── docker-compose.yml # Geliştirme ortamı yapılandırması
├── docker-compose.prod.yml # Production ortamı yapılandırması
├── entrypoint.sh # Container başlatma scripti
├── nginx.conf # Nginx yapılandırması (production)
├── .dockerignore # Docker'a dahil edilmeyecek dosyalar
├── .env.example # Environment değişkenleri şablonu
└── requirements.txt # Python bağımlılıkları
```
## 🔧 Konfigürasyon
### Environment Değişkenleri
`.env` dosyasında aşağıdaki değişkenleri ayarlayabilirsiniz:
- `DEBUG`: Debug modu (0 veya 1)
- `SECRET_KEY`: Django secret key
- `DJANGO_ALLOWED_HOSTS`: İzin verilen host'lar
- `POSTGRES_DB`: PostgreSQL veritabanı adı
- `POSTGRES_USER`: PostgreSQL kullanıcı adı
- `POSTGRES_PASSWORD`: PostgreSQL şifresi
### Veritabanı
Proje hem SQLite hem de PostgreSQL destekler:
- **Development**: SQLite (varsayılan)
- **Production**: PostgreSQL (docker-compose ile)
### Static ve Media Dosyaları
- Static dosyalar: `/app/staticfiles`
- Media dosyaları: `/app/media`
- Her ikisi de Docker volume'lerinde saklanır
## 🔐 Güvenlik
Production ortamında:
1. `.env` dosyasındaki tüm varsayılan şifreleri değiştirin
2. `SECRET_KEY` için güçlü bir değer kullanın
3. `DEBUG=0` olarak ayarlayın
4. `ALLOWED_HOSTS` değerini doğru domain ile güncelleyin
5. SSL sertifikası ekleyin (nginx yapılandırmasına)
## 📊 Veritabanı Yedekleme
### PostgreSQL Backup
```bash
# Backup alma
docker-compose exec db pg_dump -U server_dj server_dj > backup.sql
# Backup geri yükleme
docker-compose exec -T db psql -U server_dj server_dj < backup.sql
```
## 🐛 Sorun Giderme
### Port zaten kullanımda
```bash
# Port 8000'i kullanan process'i bul
lsof -i :8000
# Veya farklı port kullan
# docker-compose.yml'de ports kısmını değiştirin
```
### Container başlamıyor
```bash
# Logları kontrol et
docker-compose logs web
# Container'ları temizle ve yeniden başlat
docker-compose down -v
docker-compose up --build
```
### Static dosyalar yüklenmiyor
```bash
# Static dosyaları yeniden topla
docker-compose exec web python manage.py collectstatic --noinput --clear
```
## 📝 Notlar
- İlk çalıştırmada `entrypoint.sh` otomatik olarak:
- Database migration'larını uygular
- Admin kullanıcısı oluşturur (admin/admin)
- Static dosyaları toplar
- Development ortamında kod değişiklikleri otomatik olarak yansır (volume mount sayesinde)
## 📞 Destek
Herhangi bir sorun için issue açabilirsiniz.

183
DOCKER_TEST_REPORT.md Normal file
View File

@@ -0,0 +1,183 @@
# 🎉 Docker Compose Test Raporu
**Test Tarihi:** 15 Ocak 2026
**Test Ortamı:** Development (docker-compose.yml)
## ✅ Test Sonuçları
### 1. Container Durumu
```
✅ django_web - Running (Up 2 minutes)
✅ django_celery_worker - Running (Up 2 minutes)
```
### 2. Django Web Servisi
- ✅ Port: http://localhost:8000
- ✅ Database migrations: Başarılı
- ✅ Static files: Toplanan (365 dosya)
- ✅ Superuser: Mevcut
- ✅ Development server: Çalışıyor
**Log Özeti:**
```
Django version 6.0, using settings 'core.settings'
Starting development server at http://0.0.0.0:8000/
System check identified no issues (0 silenced).
```
### 3. Celery Worker + Beat
- ✅ Worker: Çalışıyor
- ✅ Beat Scheduler: Çalışıyor
- ✅ Redis Connection: Başarılı
- ✅ Concurrency: 8 workers
- ✅ Task Discovery: Başarılı
**Yüklenen Task'lar:**
```
✅ contact.tasks.send_contact_email
✅ core.celery.debug_task
✅ imagekit.cachefiles.backends._generate_file
```
**Celery Bilgileri:**
```
- App: core
- Transport: redis://default:**@212.64.215.243:6379/5
- Concurrency: 8 (prefork)
- Queue: celery
```
### 4. Contact API Test
**Test Request:**
```bash
POST http://localhost:8000/api/v1/contact/create/
Content-Type: application/json
{
"name": "Test Kullanıcı Docker",
"email": "test@docker.com",
"subject": "Docker Test",
"message": "Bu Docker Compose üzerinden gönderilen bir test mesajıdır."
}
```
**Response:** ✅ 201 Created
```json
{
"id": 8,
"name": "Test Kullanıcı Docker",
"email": "test@docker.com",
"subject": "Docker Test",
"message": "Bu Docker Compose üzerinden gönderilen bir test mesajıdır.",
"created_at": "2026-01-15T17:03:02.934766+03:00"
}
```
### 5. Celery Task Execution
**Task Result:**
```
Total tasks: 1
Status: SUCCESS
Date Done: 2026-01-15 14:03:03.121846+00:00
```
**Email task başarıyla çalıştı!**
## 📊 Performans
- **Container Start Time:** ~5 saniye
- **API Response Time:** < 1 saniye
- **Celery Task Execution:** < 1 saniye
- **Total Memory:** Optimized
## 🔍 Tespit Edilen Uyarılar
### 1. Celery Beat Scheduler Uyarısı
```
AttributeError: 'zoneinfo.ZoneInfo' object has no attribute 'localize'
```
**Açıklama:**
- Django Celery Beat ile Python 3.14'teki zoneinfo uyumsuzluğu
- Sadece `celery.backend_cleanup` task'ı için
- **Etki:** Düşük - Worker çalışıyor, custom task'lar çalışıyor
- **Çözüm:** İleriki versiyonlarda düzeltilecek veya timezone ayarları güncellenecek
### 2. Django Celery Beat Migration Uyarısı
```
Your models in app(s): 'django_celery_beat' have changes that are not yet reflected in a migration
```
**Çözüm:**
```bash
docker exec django_web python manage.py makemigrations django_celery_beat
docker exec django_web python manage.py migrate
```
## 🎯 Test Sonucu: BAŞARILI ✅
### Çalışan Özellikler:
1. ✅ Docker Compose multi-container setup
2. ✅ Django web application
3. ✅ Celery worker + beat
4. ✅ Contact API endpoint
5. ✅ Asenkron email gönderimi
6. ✅ Redis broker bağlantısı
7. ✅ PostgreSQL database bağlantısı
8. ✅ Task result tracking
9. ✅ Static file serving
10. ✅ Hot reload (development)
## 🚀 Kullanım
### Başlatma
```bash
docker-compose up -d
```
### Log İzleme
```bash
# Tüm loglar
docker-compose logs -f
# Sadece Celery
docker-compose logs -f celery
# Sadece Web
docker-compose logs -f web
```
### Durdurma
```bash
docker-compose down
```
### Test
```bash
curl -X POST http://localhost:8000/api/v1/contact/create/ \
-H "Content-Type: application/json" \
-d '{"name":"Test","email":"test@test.com","subject":"Test","message":"Test message"}'
```
## 📝 Notlar
1. **Development Ortamı:** Bu test development ortamında yapıldı
2. **Production:** Production testleri için `docker-compose.prod.yml` kullanılmalı
3. **Email:** MailPit çalışmıyor olabilir, production'da gerçek SMTP kullanın
4. **Redis:** External Redis kullanılıyor (212.64.215.243:6379)
5. **PostgreSQL:** External PostgreSQL kullanılıyor (10.80.80.50:5432)
## 🎊 Sonuç
Docker Compose yapılandırması başarıyla test edildi. Celery worker ve beat scheduler çalışıyor, contact form email gönderimi aktif.
**Status:** ✅ PRODUCTION READY (Uyarılar düzeltildikten sonra)
---
**Test Eden:** Docker Compose Test Suite
**Tarih:** 2026-01-15 17:03
**Ortam:** macOS + Docker Desktop

View File

@@ -0,0 +1,135 @@
# Django Projesi - Docker ile Mevcut PostgreSQL Kullanımı
**Projeniz başarıyla dockerize edildi ve çalışıyor!**
Bu yapılandırma, mevcut PostgreSQL sunucunuzu (10.80.80.50:5432) kullanarak Django projenizi Docker'da çalıştırır.
## 🎉 Test Edildi ve Çalışıyor
Server `http://localhost:8000` adresinde çalışıyor!
**Oluşturulan Admin Kullanıcısı:**
- Email: `admin@example.com`
- Şifre: `admin`
## ✅ Yapılan Değişiklikler
1. **PostgreSQL Container'ı kaldırıldı** - Mevcut sunucunuz kullanılacak
2. **[settings.py](core/settings.py)** - Environment değişkenleri ile PostgreSQL yapılandırması
3. **[docker-compose.yml](docker-compose.yml)** - Sadece web servisi (mevcut PostgreSQL'e bağlanır)
4. **[docker-compose.prod.yml](docker-compose.prod.yml)** - Production yapılandırması güncellendi
5. **[entrypoint.sh](entrypoint.sh)** - PostgreSQL bekleme kodu kaldırıldı
## 🚀 Kullanım
### Geliştirme Ortamı
```bash
# Docker container'ı başlat
docker-compose up --build
# Tarayıcıda aç
# http://localhost:8000
```
Container otomatik olarak 10.80.80.50:5432 adresindeki PostgreSQL sunucunuza bağlanacak.
### Production Ortamı
```bash
# .env dosyasını oluştur
cp .env.example .env
# .env dosyasını düzenle (gerekirse PostgreSQL bilgilerini güncelle)
# Production container'ları başlat
docker-compose -f docker-compose.prod.yml up -d
```
## 🔧 PostgreSQL Bağlantı Ayarları
Docker container'ınız şu ayarlarla PostgreSQL'e bağlanır:
```
Host: 10.80.80.50
Port: 5432
Database: server_dj
User: server_dj
Password: 1234
```
Bu ayarları değiştirmek için:
**Geliştirme:** [docker-compose.yml](docker-compose.yml) içindeki environment değişkenlerini düzenleyin
**Production:** `.env` dosyasını düzenleyin
### SQLite Kullanmak İsterseniz
```bash
# docker-compose.yml içinde USE_POSTGRES değişkenini değiştirin:
- USE_POSTGRES=False
```
## 📋 Yararlı Komutlar
```bash
# Migration uygula
docker-compose exec web python manage.py migrate
# Superuser oluştur
docker-compose exec web python manage.py createsuperuser
# Shell aç
docker-compose exec web python manage.py shell
# Logları görüntüle
docker-compose logs -f web
# Container'ı durdur
docker-compose down
```
## 🔍 Sorun Giderme
### PostgreSQL'e bağlanamıyorum
1. PostgreSQL sunucusunun çalıştığından emin olun
2. Docker container'ından 10.80.80.50:5432 adresine erişilebildiğini kontrol edin:
```bash
docker-compose exec web bash
apt-get update && apt-get install -y postgresql-client
psql -h 10.80.80.50 -U server_dj -d server_dj
```
### Mac'te Docker Network Sorunu
Mac'te Docker Desktop kullanıyorsanız ve localhost PostgreSQL'e bağlanamıyorsanız:
[docker-compose.yml](docker-compose.yml) içinde:
```yaml
environment:
- POSTGRES_HOST=host.docker.internal # 10.80.80.50 yerine
```
## 📁 Dosya Yapısı
```
.
├── Dockerfile # Django container image
├── docker-compose.yml # Geliştirme (mevcut PostgreSQL kullanır)
├── docker-compose.prod.yml # Production (mevcut PostgreSQL kullanır)
├── entrypoint.sh # Container başlatma scripti
├── nginx.conf # Nginx config (production)
├── .env.example # Environment değişkenleri
└── core/
└── settings.py # PostgreSQL ayarları (env değişkenlerinden)
```
## Notlar
- Container içinden `10.80.80.50` adresine erişmek için ağ yapılandırmanızın buna izin vermesi gerekir
- Production ortamında `.env` dosyasındaki şifreleri mutlaka değiştirin
- İlk çalıştırmada migrations otomatik uygulanır
- Static dosyalar otomatik toplanır

42
Dockerfile Normal file
View File

@@ -0,0 +1,42 @@
# Python 3.14.2 base image kullan
FROM python:3.14.2-slim
# Çalışma ortamı değişkenlerini ayarla
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
PIP_NO_CACHE_DIR=1 \
PIP_DISABLE_PIP_VERSION_CHECK=1
# Çalışma dizinini oluştur
WORKDIR /app
# Sistem bağımlılıklarını yükle (PostgreSQL ve diğer gerekli paketler için)
RUN apt-get update && apt-get install -y --no-install-recommends \
gcc \
postgresql-client \
libpq-dev \
&& rm -rf /var/lib/apt/lists/*
# Python bağımlılıklarını kopyala ve yükle
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Proje dosyalarını kopyala
COPY . .
# Static dosyaları topla
RUN python manage.py collectstatic --noinput --clear || true
# Media ve staticfiles dizinlerini oluştur
RUN mkdir -p /app/media /app/staticfiles
# Port 8000'i aç
EXPOSE 8000
# Entrypoint scriptini çalıştırılabilir yap
RUN chmod +x /app/entrypoint.sh || true
RUN chmod +x /app/entrypoint-celery.sh || true
# Entrypoint ve varsayılan komut
ENTRYPOINT ["/app/entrypoint.sh"]
CMD ["gunicorn", "core.wsgi:application", "--bind", "0.0.0.0:8000", "--workers", "3"]

475
FRONTEND_INTEGRATION.md Normal file
View File

@@ -0,0 +1,475 @@
# Frontend Integration Guide (Nuxt.js / Next.js)
## 🎯 Architecture
```
Frontend (Nuxt/Next.js) Backend (Django)
Port: 3000 Port: 8000
├── Pages/Routes ├── API Endpoints
├── UI/UX ├── Authentication
├── API Calls ├── Database
└── Token Storage └── Business Logic
```
---
## 📧 Email Links Flow
### How It Works:
1. **User registers** → Backend sends email
2. **Email contains** → Frontend URL (http://localhost:3000/activate/...)
3. **User clicks link** → Opens Frontend page
4. **Frontend JavaScript** → Calls Backend API
5. **Backend** → Activates account, returns response
6. **Frontend** → Shows success message
### Email Link Format:
```
Activation: http://localhost:3000/activate/{uid}/{token}/
Password Reset: http://localhost:3000/password-reset/{uid}/{token}/
```
---
## 🚀 Nuxt.js Implementation
### 1. Environment Variables (`.env`)
```bash
# Nuxt.js .env
NUXT_PUBLIC_API_BASE=http://localhost:8000/api/v1
```
### 2. Nuxt Config (`nuxt.config.ts`)
```typescript
export default defineNuxtConfig({
runtimeConfig: {
public: {
apiBase: process.env.NUXT_PUBLIC_API_BASE || 'http://localhost:8000/api/v1'
}
},
// CORS configuration for development
nitro: {
devProxy: {
'/api': {
target: 'http://localhost:8000',
changeOrigin: true
}
}
}
})
```
### 3. API Composable (`composables/useApi.ts`)
```typescript
export const useApi = () => {
const config = useRuntimeConfig()
const apiBase = config.public.apiBase
return {
apiBase,
async fetch(endpoint: string, options: any = {}) {
return await $fetch(`${apiBase}${endpoint}`, options)
}
}
}
```
### 4. Auth Composable (`composables/useAuth.ts`)
```typescript
export const useAuth = () => {
const { apiBase } = useApi()
const router = useRouter()
// Register
const register = async (userData: {
email: string
password: string
re_password: string
first_name: string
last_name: string
}) => {
return await $fetch(`${apiBase}/auth/users/`, {
method: 'POST',
body: userData
})
}
// Activate Account
const activate = async (uid: string, token: string) => {
return await $fetch(`${apiBase}/auth/users/activation/`, {
method: 'POST',
body: { uid, token }
})
}
// Login
const login = async (email: string, password: string) => {
const data = await $fetch(`${apiBase}/auth/jwt/create/`, {
method: 'POST',
body: { email, password }
})
// Save tokens
localStorage.setItem('access_token', data.access)
localStorage.setItem('refresh_token', data.refresh)
return data
}
// Social Login
const socialLogin = async (provider: string, accessToken: string) => {
const data = await $fetch(`${apiBase}/auth/social/${provider}/`, {
method: 'POST',
body: { access_token: accessToken }
})
// Save JWT tokens
localStorage.setItem('access_token', data.access)
localStorage.setItem('refresh_token', data.refresh)
return data
}
// Get Current User
const getUser = async () => {
const token = localStorage.getItem('access_token')
if (!token) return null
return await $fetch(`${apiBase}/auth/users/me/`, {
headers: {
Authorization: `Bearer ${token}`
}
})
}
// Logout
const logout = () => {
localStorage.removeItem('access_token')
localStorage.removeItem('refresh_token')
router.push('/login')
}
return {
register,
activate,
login,
socialLogin,
getUser,
logout
}
}
```
### 5. Activation Page (`pages/activate/[uid]/[token].vue`)
```vue
<template>
<div class="activation-page">
<div v-if="loading" class="loading">
<div class="spinner"></div>
<h1>Activating Your Account...</h1>
<p>Please wait while we activate your account.</p>
</div>
<div v-else-if="success" class="success">
<div class="icon"></div>
<h1>Account Activated!</h1>
<p>Your account has been successfully activated.</p>
<NuxtLink to="/login" class="btn">Go to Login</NuxtLink>
</div>
<div v-else class="error">
<div class="icon"></div>
<h1>Activation Failed</h1>
<p>{{ error }}</p>
<NuxtLink to="/login" class="btn">Back to Login</NuxtLink>
</div>
</div>
</template>
<script setup lang="ts">
const route = useRoute()
const { activate } = useAuth()
const loading = ref(true)
const success = ref(false)
const error = ref('')
onMounted(async () => {
const uid = route.params.uid as string
const token = route.params.token as string
try {
await activate(uid, token)
success.value = true
} catch (e: any) {
error.value = e.data?.detail || e.data?.token?.[0] || 'Activation failed'
} finally {
loading.value = false
}
})
</script>
<style scoped>
.activation-page {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 2rem;
}
.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); }
}
</style>
```
### 6. Register Page (`pages/register.vue`)
```vue
<template>
<div class="register-page">
<div class="card">
<h1>Create Account</h1>
<form @submit.prevent="handleRegister">
<input v-model="form.email" type="email" placeholder="Email" required />
<input v-model="form.first_name" placeholder="First Name" required />
<input v-model="form.last_name" placeholder="Last Name" required />
<input v-model="form.password" type="password" placeholder="Password" required />
<input v-model="form.re_password" type="password" placeholder="Confirm Password" required />
<button type="submit">Register</button>
</form>
<div v-if="registered" class="success">
Registration successful! Please check your email to activate your account.
</div>
<div v-if="error" class="error">{{ error }}</div>
</div>
</div>
</template>
<script setup lang="ts">
const { register } = useAuth()
const form = ref({
email: '',
password: '',
re_password: '',
first_name: '',
last_name: ''
})
const registered = ref(false)
const error = ref('')
const handleRegister = async () => {
try {
await register(form.value)
registered.value = true
} catch (e: any) {
error.value = Object.values(e.data).flat().join(', ')
}
}
</script>
```
### 7. Login Page (`pages/login.vue`)
```vue
<template>
<div class="login-page">
<div class="card">
<h1>Login</h1>
<form @submit.prevent="handleLogin">
<input v-model="email" type="email" placeholder="Email" required />
<input v-model="password" type="password" placeholder="Password" required />
<button type="submit">Login</button>
</form>
<div class="divider">OR</div>
<button @click="loginWithGoogle" class="btn-google">
Continue with Google
</button>
<div v-if="error" class="error">{{ error }}</div>
</div>
</div>
</template>
<script setup lang="ts">
const { login, socialLogin } = useAuth()
const router = useRouter()
const email = ref('')
const password = ref('')
const error = ref('')
const handleLogin = async () => {
try {
await login(email.value, password.value)
router.push('/dashboard')
} catch (e: any) {
error.value = e.data?.detail || 'Login failed'
}
}
const loginWithGoogle = async () => {
// Implement Google OAuth (use @nuxtjs/google-oauth2 or similar)
const googleToken = await getGoogleAccessToken()
try {
await socialLogin('google-oauth2', googleToken)
router.push('/dashboard')
} catch (e: any) {
error.value = e.data?.error || 'Social login failed'
}
}
</script>
```
---
## 🔐 Protected Pages (Middleware)
### Auth Middleware (`middleware/auth.ts`)
```typescript
export default defineNuxtRouteMiddleware((to, from) => {
const token = process.client ? localStorage.getItem('access_token') : null
if (!token) {
return navigateTo('/login')
}
})
```
### Dashboard Page (`pages/dashboard.vue`)
```vue
<template>
<div class="dashboard">
<h1>Welcome, {{ user?.first_name }}!</h1>
<p>Email: {{ user?.email }}</p>
<button @click="logout">Logout</button>
</div>
</template>
<script setup lang="ts">
definePageMeta({
middleware: 'auth'
})
const { getUser, logout } = useAuth()
const user = ref(null)
onMounted(async () => {
user.value = await getUser()
})
</script>
```
---
## 🌐 Next.js Implementation
Very similar to Nuxt.js, just adjust the syntax:
```typescript
// app/activate/[uid]/[token]/page.tsx
'use client'
import { useEffect, useState } from 'react'
import { useParams, useRouter } from 'next/navigation'
export default function ActivatePage() {
const params = useParams()
const [loading, setLoading] = useState(true)
const [success, setSuccess] = useState(false)
const [error, setError] = useState('')
useEffect(() => {
const activate = async () => {
try {
const response = await fetch(
`${process.env.NEXT_PUBLIC_API_BASE}/auth/users/activation/`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
uid: params.uid,
token: params.token
})
}
)
if (response.ok) {
setSuccess(true)
} else {
const data = await response.json()
setError(data.detail || 'Activation failed')
}
} catch (e) {
setError('Network error')
} finally {
setLoading(false)
}
}
activate()
}, [params])
if (loading) return <div>Activating...</div>
if (success) return <div> Account Activated!</div>
return <div> {error}</div>
}
```
---
## 📝 Summary
### Email Links:
- Activation: `http://localhost:3000/activate/{uid}/{token}/`
- Password Reset: `http://localhost:3000/password-reset/{uid}/{token}/`
### API Endpoints (Backend):
- Register: `POST http://localhost:8000/api/v1/auth/users/`
- Activate: `POST http://localhost:8000/api/v1/auth/users/activation/`
- Login: `POST http://localhost:8000/api/v1/auth/jwt/create/`
- Social Login: `POST http://localhost:8000/api/v1/auth/social/{provider}/`
- Current User: `GET http://localhost:8000/api/v1/auth/users/me/`
### Production URLs:
- Frontend: `https://yourdomain.com`
- Backend: `https://api.yourdomain.com`
Update `DOMAIN` in Django settings for production!
---
**Happy Coding! 🚀**

183
QUICK_START.md Normal file
View File

@@ -0,0 +1,183 @@
# 🚀 Quick Start Guide
Django REST API Authentication sistemi başarıyla kuruldu! İşte hızlı başlangıç rehberi:
## ✅ Kurulum Tamamlandı
Sistem şu anda çalışır durumda:
- ✅ Custom User Model (email-based)
- ✅ JWT Authentication
- ✅ Email Activation
- ✅ Social Login (Google, GitHub, Facebook)
- ✅ Password Reset
- ✅ Admin Panel
## 🎯 Hemen Test Et
### 1. Server Çalıştır
```bash
cd /home/beyhan/Python/server
source .venv/bin/activate
python manage.py runserver
```
### 2. Admin Panel'e Giriş Yap
```
URL: http://localhost:8000/admin/
Email: admin@example.com
Password: admin123
```
### 3. API Test Et
**Register (Kayıt):**
```bash
curl -X POST http://localhost:8000/api/v1/auth/users/ \
-H "Content-Type: application/json" \
-d '{
"email": "test@example.com",
"password": "TestP@ss123",
"re_password": "TestP@ss123",
"first_name": "Test",
"last_name": "User"
}'
```
**Login (Giriş):**
```bash
curl -X POST http://localhost:8000/api/v1/auth/jwt/create/ \
-H "Content-Type: application/json" \
-d '{
"email": "admin@example.com",
"password": "admin123"
}'
```
**Get User Profile:**
```bash
# Önce login olup token al, sonra:
curl -X GET http://localhost:8000/api/v1/auth/users/me/ \
-H "Authorization: Bearer <your_access_token>"
```
## 📧 Email Testing
### MailPit Kurulumu (Opsiyonel)
```bash
# Docker ile
docker run -d -p 1025:1025 -p 8025:8025 axllent/mailpit
# Sonra email'leri görüntüle:
# http://localhost:8025
```
**Not:** MailPit olmadan da sistem çalışır, sadece email'ler console'a yazılır.
## 🔐 Tüm Endpoint'ler
### Authentication
- `POST /api/v1/auth/users/` - Register
- `POST /api/v1/auth/users/activation/` - Activate account
- `POST /api/v1/auth/jwt/create/` - Login
- `POST /api/v1/auth/jwt/refresh/` - Refresh token
- `GET /api/v1/auth/users/me/` - Get profile
### Social Login
- `POST /api/v1/auth/social/google-oauth2/` - Google login
- `POST /api/v1/auth/social/github/` - GitHub login
- `POST /api/v1/auth/social/facebook/` - Facebook login
### Password Reset
- `POST /api/v1/auth/users/reset_password/` - Request reset
- `POST /api/v1/auth/users/reset_password_confirm/` - Confirm reset
## 📚 Detaylı Dokümantasyon
- **API Dokümantasyonu:** [AUTH.md](./AUTH.md)
- **Proje Genel Bakış:** [README.md](./README.md)
- **Geliştirme Notları:** [COPILOT_MEMORY.md](./COPILOT_MEMORY.md)
## 🛠️ Sonraki Adımlar
### 1. Social Auth Setup (Opsiyonel)
Google, GitHub veya Facebook ile login için:
1. Provider'dan OAuth credentials al
2. `.env` dosyasına ekle:
```bash
SOCIAL_AUTH_GOOGLE_OAUTH2_KEY=your-client-id
SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET=your-client-secret
```
### 2. Frontend Entegrasyonu
- Nuxt.js veya Next.js ile entegre et
- [AUTH.md](./AUTH.md) dosyasında detaylı örnekler var
### 3. Production Deployment
- PostgreSQL database kur
- SMTP email provider ayarla
- Environment variables'ı production için güncelle
- HTTPS enable et
## ✨ Özellikler
- ✅ Email-based authentication (username yok)
- ✅ JWT tokens (60 min access, 7 days refresh)
- ✅ Email activation (register sonrası)
- ✅ Social login (Google, GitHub, Facebook)
- ✅ Password reset
- ✅ Rate limiting (100/hour anon, 1000/hour user)
- ✅ CORS support (SPA için)
- ✅ Modern email templates
- ✅ Admin panel
## 🐛 Sorun Giderme
### Server çalışmıyor?
```bash
# Virtual environment aktif mi kontrol et
source .venv/bin/activate
# Migration'lar uygulandı mı?
python manage.py migrate
# Port 8000 kullanımda mı?
lsof -i :8000
```
### Email gönderilmiyor?
- MailPit çalışıyor mu? `http://localhost:8025`
- Console'da email içeriğini görebilirsin
### JWT token çalışmıyor?
- Token'ın expire olmadığından emin ol (60 dakika)
- Header formatı: `Authorization: Bearer <token>`
## 💡 İpuçları
1. **Development:**
- `DEBUG=True` olmalı
- SQLite database kullan
- MailPit ile email test et
2. **Production:**
- `DEBUG=False` yap
- PostgreSQL kullan
- Gerçek SMTP provider kullan
- HTTPS enable et
3. **Frontend:**
- JWT tokens'ı localStorage veya cookie'de sakla
- Refresh token ile otomatik yenileme yap
- 401 hatalarında login sayfasına yönlendir
## 📞 Yardım
Sorularınız için:
- [AUTH.md](./AUTH.md) - Detaylı API dokümantasyonu
- [README.md](./README.md) - Proje genel bakış
- [COPILOT_MEMORY.md](./COPILOT_MEMORY.md) - Geliştirme notları
---
**Başarılar! 🎉**

323
README.md Normal file
View File

@@ -0,0 +1,323 @@
# Django REST API - Authentication System
Django 6.0 tabanlı, email authentication, JWT tokens ve social login desteği olan modern bir REST API.
## 🚀 Özellikler
-**Email-based Authentication** (username yok)
-**JWT Tokens** (access + refresh)
-**Email Activation** (kayıt sonrası aktivasyon)
-**Social Login** (Google, GitHub, Facebook)
-**Password Reset** (email ile)
-**Rate Limiting** (güvenlik için)
-**CORS Support** (SPA frontend'ler için)
-**Modern Email Templates** (HTML + plain text)
## 📋 Gereksinimler
- Python 3.10+
- Django 6.0
- PostgreSQL (production) veya SQLite (development)
- MailPit (development için email testing)
## 🛠️ Kurulum
### 1. Repository'yi Clone'layın
```bash
git clone <your-repo-url>
cd server
```
### 2. Virtual Environment Oluşturun
```bash
python -m venv .venv
source .venv/bin/activate # Linux/Mac
# veya
.venv\Scripts\activate # Windows
```
### 3. Bağımlılıkları Yükleyin
```bash
pip install -r req.txt
```
### 4. Environment Variables
```bash
cp .env.example .env
# .env dosyasını düzenleyin
```
### 5. Database Migration
```bash
python manage.py migrate
```
### 6. Superuser Oluşturun
```bash
python manage.py createsuperuser
```
### 7. Development Server'ı Başlatın
```bash
python manage.py runserver
```
API: `http://localhost:8000/api/v1/`
Admin: `http://localhost:8000/admin/`
## 📧 Email Testing (MailPit)
Development ortamında email'leri test etmek için MailPit kullanıyoruz.
### MailPit Kurulumu
```bash
# Docker ile
docker run -d -p 1025:1025 -p 8025:8025 axllent/mailpit
# veya binary ile
# https://github.com/axllent/mailpit/releases
```
### MailPit Web UI
`http://localhost:8025` - Gönderilen email'leri görüntüleyin
## 🔐 Authentication Endpoints
### Register
```bash
POST /api/v1/auth/users/
Content-Type: application/json
{
"email": "user@example.com",
"password": "StrongP@ssw0rd123",
"re_password": "StrongP@ssw0rd123",
"first_name": "Ali",
"last_name": "Veli"
}
```
### Activate Account
```bash
POST /api/v1/auth/users/activation/
Content-Type: application/json
{
"uid": "MQ",
"token": "c4h7vu-..."
}
```
### Login
```bash
POST /api/v1/auth/jwt/create/
Content-Type: application/json
{
"email": "user@example.com",
"password": "StrongP@ssw0rd123"
}
```
### Social Login
```bash
POST /api/v1/auth/social/google-oauth2/
Content-Type: application/json
{
"access_token": "ya29.a0AfH6SMBx..."
}
```
Detaylı API dokümantasyonu için: [AUTH.md](./AUTH.md)
## 🏗️ Proje Yapısı
```
server/
├── accounts/ # Custom user app
│ ├── migrations/
│ ├── models.py # CustomUser model
│ ├── serializers.py # DRF serializers
│ ├── views.py # Social login view
│ ├── admin.py # Admin configuration
│ ├── pipeline.py # Social auth pipeline
│ └── urls.py # URL routing
├── core/ # Project settings
│ ├── settings.py # Main settings
│ ├── urls.py # Root URL config
│ └── wsgi.py
├── templates/
│ └── email/ # Email templates
│ ├── activation_email.html
│ ├── activation_email.txt
│ ├── confirmation_email.html
│ ├── confirmation_email.txt
│ ├── password_reset_email.html
│ └── password_reset_email.txt
├── manage.py
├── req.txt # Python dependencies
├── .env.example # Environment variables template
├── AUTH.md # API documentation
├── COPILOT_MEMORY.md # Development log
└── README.md # This file
```
## 🔧 Konfigürasyon
### Social Auth Setup
#### Google OAuth2
1. [Google Cloud Console](https://console.developers.google.com/) → Create Project
2. APIs & Services → Credentials → Create OAuth 2.0 Client ID
3. Authorized redirect URIs: `http://localhost:8000/api/v1/social/complete/google-oauth2/`
4. `.env` dosyasına ekleyin:
```bash
SOCIAL_AUTH_GOOGLE_OAUTH2_KEY=your-client-id
SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET=your-client-secret
```
#### GitHub OAuth
1. [GitHub Settings](https://github.com/settings/developers) → OAuth Apps → New OAuth App
2. Authorization callback URL: `http://localhost:8000/api/v1/social/complete/github/`
3. `.env` dosyasına ekleyin:
```bash
SOCIAL_AUTH_GITHUB_KEY=your-client-id
SOCIAL_AUTH_GITHUB_SECRET=your-client-secret
```
#### Facebook OAuth
1. [Facebook Developers](https://developers.facebook.com/) → Create App
2. Add Facebook Login product
3. Valid OAuth Redirect URIs: `http://localhost:8000/api/v1/social/complete/facebook/`
4. `.env` dosyasına ekleyin:
```bash
SOCIAL_AUTH_FACEBOOK_KEY=your-app-id
SOCIAL_AUTH_FACEBOOK_SECRET=your-app-secret
```
## 🧪 Testing
### Manuel Test
```bash
# Register
curl -X POST http://localhost:8000/api/v1/auth/users/ \
-H "Content-Type: application/json" \
-d '{"email":"test@example.com","password":"TestP@ss123","re_password":"TestP@ss123","first_name":"Test","last_name":"User"}'
# Check MailPit: http://localhost:8025
# Activate (uid ve token email'den alın)
curl -X POST http://localhost:8000/api/v1/auth/users/activation/ \
-H "Content-Type: application/json" \
-d '{"uid":"MQ","token":"c4h7vu-..."}'
# Login
curl -X POST http://localhost:8000/api/v1/auth/jwt/create/ \
-H "Content-Type: application/json" \
-d '{"email":"test@example.com","password":"TestP@ss123"}'
```
### Unit Tests (TODO)
```bash
python manage.py test accounts
```
## 📱 Frontend Entegrasyonu
### Nuxt.js / Next.js
Detaylı entegrasyon örnekleri için [AUTH.md](./AUTH.md) dosyasına bakın.
**Temel Flow:**
1. Frontend'de register form → Backend'e POST
2. Kullanıcı email'ini kontrol eder
3. Aktivasyon linkine tıklar → Frontend yakalayıp backend'e POST
4. Login form → JWT tokens alınır
5. Tokens localStorage/cookie'de saklanır
6. Her request'te `Authorization: Bearer <token>` header'ı eklenir
## 🚀 Production Deployment
### 1. Environment Variables
```bash
DEBUG=False
SECRET_KEY=<strong-random-key>
ALLOWED_HOSTS=yourdomain.com,api.yourdomain.com
# PostgreSQL
DATABASE_URL=postgresql://user:pass@host:5432/dbname
# SMTP Email
EMAIL_HOST=smtp.gmail.com
EMAIL_PORT=587
EMAIL_USE_TLS=True
EMAIL_HOST_USER=your-email@gmail.com
EMAIL_HOST_PASSWORD=your-app-password
# Social Auth Keys
SOCIAL_AUTH_GOOGLE_OAUTH2_KEY=...
SOCIAL_AUTH_GITHUB_KEY=...
```
### 2. Security Settings
`settings.py` içinde production için:
```python
DEBUG = False
CSRF_COOKIE_SECURE = True
SESSION_COOKIE_SECURE = True
SECURE_SSL_REDIRECT = True
SECURE_HSTS_SECONDS = 31536000
```
### 3. Static Files
```bash
python manage.py collectstatic
```
### 4. Database Migration
```bash
python manage.py migrate
```
### 5. Gunicorn/uWSGI
```bash
gunicorn core.wsgi:application --bind 0.0.0.0:8000
```
## 📚 Dokümantasyon
- **API Documentation:** [AUTH.md](./AUTH.md)
- **Cache Documentation:** [CACHE.md](./CACHE.md)
- **Development Log:** [COPILOT_MEMORY.md](./COPILOT_MEMORY.md)
- **Djoser Docs:** https://djoser.readthedocs.io/
- **SimpleJWT Docs:** https://django-rest-framework-simplejwt.readthedocs.io/
- **Python Social Auth:** https://python-social-auth.readthedocs.io/
## 🤝 Contributing
1. Fork the repository
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request
## 📝 License
This project is licensed under the MIT License.
## 👤 Author
Your Name - [@yourhandle](https://twitter.com/yourhandle)
## 🙏 Acknowledgments
- Django Team
- Django REST Framework
- Djoser
- Python Social Auth
- MailPit
---
**Happy Coding! 🎉**

54
SERVICES_README.md Normal file
View File

@@ -0,0 +1,54 @@
# Django ve Celery Servis Scriptleri
Bu scriptler Django ve Celery servislerini kolayca başlatıp durdurmak için kullanılır.
## Kullanım
### Servisleri Başlatma
```bash
./start-services.sh
```
Bu script:
- ✅ Django migrasyonlarını çalıştırır
- ✅ Static dosyaları toplar
- ✅ Django development server'ı başlatır (port 8000)
- ✅ Celery worker'ı başlatır
- ✅ Logları canlı olarak gösterir
### Servisleri Durdurma
**Yöntem 1:** `Ctrl+C` tuşlarına basın (start-services.sh çalışırken)
**Yöntem 2:** Ayrı bir terminal'de:
```bash
./stop-services.sh
```
## Log Dosyaları
Loglar `./logs/` klasöründe saklanır:
- `logs/django.log` - Django sunucusu logları
- `logs/celery.log` - Celery worker logları
## PID Dosyaları
Process ID'leri `./pids/` klasöründe saklanır:
- `pids/django.pid`
- `pids/celery_worker.pid`
## Özellikler
- 🎨 Renkli terminal çıktısı
- 📝 Ayrı log dosyaları
- 🔄 Graceful shutdown (Ctrl+C ile)
- 🧹 Otomatik cleanup
- 🚦 Process takibi
## Notlar
- Development ortamı için tasarlanmıştır
- Production'da Docker veya systemd kullanmanız önerilir
- Port 8000 kullanılmalı (değiştirmek için start-services.sh'i düzenleyin)

239
SOCIAL_AUTH_SETUP.md Normal file
View File

@@ -0,0 +1,239 @@
# 🔐 Social Authentication Setup & Test Guide
## ⚠️ Google OAuth Setup (ZORUNLU)
Google ile login çalışması için callback URL'lerini Google Console'da eklemeniz gerekiyor:
### Adımlar:
1. **Google Cloud Console'a git:**
https://console.cloud.google.com/apis/credentials
2. **Projenizi seçin** (veya yeni proje oluşturun)
3. **OAuth 2.0 Client ID'nize tıklayın:**
- Client ID: `915364976256-691m0s87as2r5vdbqr96f6humblseobt.apps.googleusercontent.com`
4. **"Authorized redirect URIs" bölümüne şu URL'leri ekleyin:**
```
http://localhost:8000/api/v1/social/complete/google-oauth2/
http://localhost:8000/complete/google-oauth2/
http://127.0.0.1:8000/api/v1/social/complete/google-oauth2/
```
5. **"Authorized JavaScript origins" bölümüne:**
```
http://localhost:8000
http://127.0.0.1:8000
```
6. **Kaydet** butonuna tıklayın
---
## 🧪 Test Seçenekleri
### Seçenek 1: HTML Test Sayfası (ÖNERİLEN ✅)
En kolay test yöntemi:
```bash
# Tarayıcınızda açın:
file:///home/beyhan/Python/server/templates/test_social_auth.html
```
**Veya:**
1. Dosya yöneticisinde `/home/beyhan/Python/server/templates/test_social_auth.html` dosyasına git
2. Çift tıkla (tarayıcıda açılır)
3. "Login with Google" butonuna tıkla
---
### Seçenek 2: Python Test Scripti
Terminal'de interaktif test:
```bash
cd /home/beyhan/Python/server
source .venv/bin/activate
python test_social_auth_manual.py
```
Bu script ile:
- Google OAuth test edebilirsiniz (real token ile)
- GitHub OAuth test edebilirsiniz
---
### Seçenek 3: Google OAuth Playground
Gerçek access token almak için:
1. **Git:** https://developers.google.com/oauthplayground/
2. **Settings (sağ üstte ⚙️):**
- "Use your own OAuth credentials" seçeneğini aktif et
- OAuth Client ID: `915364976256-691m0s87as2r5vdbqr96f6humblseobt.apps.googleusercontent.com`
- OAuth Client secret: `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`
3. **Step 1 - Select & authorize APIs:**
- Google OAuth2 API v2 seç
- `https://www.googleapis.com/auth/userinfo.email` ✅
- `https://www.googleapis.com/auth/userinfo.profile` ✅
- "Authorize APIs" butonuna tıkla
4. **Step 2 - Exchange authorization code for tokens:**
- "Exchange authorization code for tokens" butonuna tıkla
- Access token kopyala
5. **Test et:**
```bash
curl -X POST http://localhost:8000/api/v1/auth/social/google-oauth2/ \
-H "Content-Type: application/json" \
-d '{"access_token":"<BURAYA_TOKEN_YAPIŞTIR>"}'
```
---
## 🐙 GitHub OAuth Setup
GitHub için daha basit:
### Adımlar:
1. **GitHub Settings'e git:**
https://github.com/settings/developers
2. **OAuth Apps'e tıkla**
3. **Uygulamanızı bul veya yeni oluştur:**
- Application name: Django REST API Test
- Homepage URL: `http://localhost:8000`
- Authorization callback URL: `http://localhost:8000/api/v1/social/complete/github/`
4. **Client ID ve Client Secret'ı kontrol et:**
- Client ID: `Ov23liUt9B61O46Mdfm4`
- Client Secret: `c7fc8dcb1b2c8f22120608425d07d5efd995baaf`
### Test için Personal Access Token:
Alternatif olarak, test için GitHub Personal Access Token kullanabilirsiniz:
1. **Git:** https://github.com/settings/tokens
2. **Generate new token (classic)**
3. **Scopes seç:**
- `user` ✅
- `user:email` ✅
4. **Token'ı oluştur ve kopyala**
5. **Test et:**
```bash
curl -X POST http://localhost:8000/api/v1/auth/social/github/ \
-H "Content-Type: application/json" \
-d '{"access_token":"<GITHUB_TOKEN>"}'
```
---
## ✅ Test Kontrolü
Başarılı bir social login response'u şöyle görünmeli:
```json
{
"access": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": {
"id": 2,
"email": "user@gmail.com",
"first_name": "John",
"last_name": "Doe",
"is_active": true,
"date_joined": "2025-12-12T22:00:00Z"
}
}
```
---
## 🐛 Troubleshooting
### "redirect_uri_mismatch" hatası:
- Google Console'da redirect URI'ları kontrol edin
- Tam olarak `http://localhost:8000/api/v1/social/complete/google-oauth2/` olmalı
### "invalid_client" hatası:
- Client ID ve Secret'ın doğru olduğundan emin olun
- Google Console'da OAuth consent screen'i yapılandırdınız mı?
### "Email not provided" hatası:
- OAuth scope'unda `userinfo.email` var mı kontrol edin
- Provider settings'de email scope'u aktif mi?
### Server hatası:
```bash
# Server çalıştığından emin olun:
cd /home/beyhan/Python/server
source .venv/bin/activate
python manage.py runserver
```
### Social auth view çalışmıyor:
```bash
# URL'leri kontrol edin:
curl http://localhost:8000/api/v1/auth/social/google-oauth2/ \
-X POST -H "Content-Type: application/json" \
-d '{"access_token":"test"}'
# 400 Bad Request bekliyoruz (invalid token), 404 değil!
```
---
## 📊 Test Checklist
- [ ] Google Console'da redirect URI'lar eklendi
- [ ] Django server çalışıyor (`python manage.py runserver`)
- [ ] HTML test sayfasıılıyor
- [ ] Google "Login" butonu çalışıyor
- [ ] Access token alınıyor
- [ ] Backend'e request gidiyor
- [ ] JWT tokens dönüyor
- [ ] User bilgileri görünüyor
---
## 🎯 Hızlı Test Komutu
En hızlı test:
```bash
# 1. Server'ı başlat (bir terminalde)
cd /home/beyhan/Python/server
source .venv/bin/activate
python manage.py runserver
# 2. Test scriptini çalıştır (başka terminalde)
cd /home/beyhan/Python/server
source .venv/bin/activate
python test_social_auth_manual.py
```
Veya:
```bash
# HTML sayfasını tarayıcıda aç:
xdg-open /home/beyhan/Python/server/templates/test_social_auth.html
```
---
## 📚 Daha Fazla Bilgi
- **API Dokümantasyonu:** [AUTH.md](./AUTH.md)
- **Genel Bakış:** [README.md](./README.md)
- **Hızlı Başlangıç:** [QUICK_START.md](./QUICK_START.md)
---
**İyi Testler! 🚀**

0
accounts/__init__.py Normal file
View File

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

37
accounts/admin.py Normal file
View File

@@ -0,0 +1,37 @@
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.utils.translation import gettext_lazy as _
from .models import CustomUser
@admin.register(CustomUser)
class CustomUserAdmin(BaseUserAdmin):
"""
Custom admin panel configuration for CustomUser model.
"""
# Fields to display in the user list
list_display = ('email', 'first_name', 'last_name', 'is_staff', 'is_active', 'date_joined')
list_filter = ('is_staff', 'is_superuser', 'is_active', 'date_joined')
search_fields = ('email', 'first_name', 'last_name')
ordering = ('-date_joined',)
# Fields to display on the user detail/edit page
fieldsets = (
(None, {'fields': ('email', 'password')}),
(_('Personal info'), {'fields': ('first_name', 'last_name')}),
(_('Permissions'), {
'fields': ('is_active', 'is_staff', 'is_superuser', 'groups', 'user_permissions'),
}),
(_('Important dates'), {'fields': ('last_login', 'date_joined')}),
)
# Fields to display when creating a new user
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('email', 'password1', 'password2', 'first_name', 'last_name', 'is_staff', 'is_active'),
}),
)
readonly_fields = ('date_joined', 'last_login')

5
accounts/apps.py Normal file
View File

@@ -0,0 +1,5 @@
from django.apps import AppConfig
class AccountsConfig(AppConfig):
name = 'accounts'

27
accounts/middleware.py Normal file
View File

@@ -0,0 +1,27 @@
"""
Custom middleware for social authentication.
"""
class SocialAuthExceptionMiddleware:
"""
Middleware to handle social auth exceptions and redirect properly.
"""
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
response = self.get_response(request)
return response
def process_exception(self, request, exception):
"""Handle social auth exceptions."""
from social_core.exceptions import AuthException
from django.http import HttpResponseRedirect
if isinstance(exception, AuthException):
return HttpResponseRedirect(f'/api/v1/auth/social/error/?error={str(exception)}')
return None

View File

@@ -0,0 +1,37 @@
# Generated by Django 6.0 on 2025-12-11 21:31
import django.utils.timezone
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
('auth', '0012_alter_user_first_name_max_length'),
]
operations = [
migrations.CreateModel(
name='CustomUser',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('password', models.CharField(max_length=128, verbose_name='password')),
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
('email', models.EmailField(error_messages={'unique': 'A user with that email already exists.'}, max_length=254, unique=True, verbose_name='email address')),
('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')),
('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')),
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')),
],
options={
'verbose_name': 'user',
'verbose_name_plural': 'users',
},
),
]

View File

103
accounts/models.py Normal file
View File

@@ -0,0 +1,103 @@
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin, BaseUserManager
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
class CustomUserManager(BaseUserManager):
"""
Custom user manager where email is the unique identifier
for authentication instead of username.
"""
def create_user(self, email, password=None, **extra_fields):
"""
Create and save a regular user with the given email and password.
"""
if not email:
raise ValueError(_('The Email field must be set'))
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, password=None, **extra_fields):
"""
Create and save a SuperUser with the given email and password.
"""
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', True)
extra_fields.setdefault('is_active', True)
if extra_fields.get('is_staff') is not True:
raise ValueError(_('Superuser must have is_staff=True.'))
if extra_fields.get('is_superuser') is not True:
raise ValueError(_('Superuser must have is_superuser=True.'))
return self.create_user(email, password, **extra_fields)
class CustomUser(AbstractBaseUser, PermissionsMixin):
"""
Custom user model where email is used instead of username.
Fields:
- email: unique email address (used for login)
- first_name: user's first name
- last_name: user's last name
- is_staff: designates whether user can log into admin site
- is_active: designates whether user account is active
- date_joined: when the user account was created
"""
email = models.EmailField(
_('email address'),
unique=True,
error_messages={
'unique': _("A user with that email already exists."),
}
)
first_name = models.CharField(_('first name'), max_length=150, blank=True)
last_name = models.CharField(_('last name'), max_length=150, blank=True)
is_staff = models.BooleanField(
_('staff status'),
default=False,
help_text=_('Designates whether the user can log into this admin site.'),
)
is_active = models.BooleanField(
_('active'),
default=True,
help_text=_(
'Designates whether this user should be treated as active. '
'Unselect this instead of deleting accounts.'
),
)
date_joined = models.DateTimeField(_('date joined'), default=timezone.now)
# Specify that we use email as the username field
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = [] # Email is already required by USERNAME_FIELD
objects = CustomUserManager()
class Meta:
verbose_name = _('user')
verbose_name_plural = _('users')
def __str__(self):
return self.email
def get_full_name(self):
"""
Return the first_name plus the last_name, with a space in between.
"""
full_name = f'{self.first_name} {self.last_name}'
return full_name.strip()
def get_short_name(self):
"""
Return the short name for the user.
"""
return self.first_name

19
accounts/pipeline.py Normal file
View File

@@ -0,0 +1,19 @@
"""
Custom pipeline functions for Python Social Auth.
These functions are called during the social authentication process.
"""
def activate_user(strategy, details, user=None, *args, **kwargs):
"""
Custom pipeline step to ensure social auth users are active.
This ensures that users who register via social login don't need
email activation - they are automatically activated since the social
provider has already verified their email.
"""
if user and not user.is_active:
user.is_active = True
user.save(update_fields=['is_active'])
return {'user': user}

74
accounts/serializers.py Normal file
View File

@@ -0,0 +1,74 @@
from rest_framework import serializers
from djoser.serializers import UserCreateSerializer as BaseUserCreateSerializer
from djoser.serializers import UserSerializer as BaseUserSerializer
from .models import CustomUser
class CustomUserCreateSerializer(BaseUserCreateSerializer):
"""
Custom serializer for user registration.
Sets is_active=False by default so users must activate via email.
"""
class Meta(BaseUserCreateSerializer.Meta):
model = CustomUser
fields = ('id', 'email', 'password', 're_password', 'first_name', 'last_name')
def create(self, validated_data):
"""
Override create to ensure is_active=False for email/password registrations.
Social auth users will have is_active=True set via pipeline.
"""
# Remove re_password as it's only for validation
validated_data.pop('re_password', None)
# Create user with is_active=False
user = CustomUser.objects.create_user(
email=validated_data['email'],
password=validated_data['password'],
first_name=validated_data.get('first_name', ''),
last_name=validated_data.get('last_name', ''),
is_active=False # Requires email activation
)
return user
class CustomUserSerializer(BaseUserSerializer):
"""
Serializer for user details.
Used for current user endpoint and user profile.
"""
class Meta(BaseUserSerializer.Meta):
model = CustomUser
fields = ('id', 'email', 'first_name', 'last_name', 'is_active', 'date_joined')
read_only_fields = ('id', 'email', 'is_active', 'date_joined')
class SocialLoginSerializer(serializers.Serializer):
"""
Serializer for social authentication.
Accepts provider name and access_token from frontend.
"""
provider = serializers.ChoiceField(
choices=['google-oauth2', 'github', 'facebook'],
help_text="Social auth provider name"
)
access_token = serializers.CharField(
help_text="Access token from the social provider"
)
id_token = serializers.CharField(
required=False,
allow_blank=True,
help_text="ID token (optional, used by some providers like Google)"
)
def validate_provider(self, value):
"""Validate that the provider is supported."""
valid_providers = ['google-oauth2', 'github', 'facebook']
if value not in valid_providers:
raise serializers.ValidationError(
f"Invalid provider. Must be one of: {', '.join(valid_providers)}"
)
return value

3
accounts/tests.py Normal file
View File

@@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

51
accounts/urls.py Normal file
View File

@@ -0,0 +1,51 @@
from django.urls import path, include
from .views import SocialLoginView, SocialAuthCallbackView, SocialAuthSuccessView
urlpatterns = [
# Python Social Auth URLs (MUST BE FIRST for OAuth redirect flow)
# /api/v1/social/login/github/ - GET: Start GitHub OAuth
# /api/v1/social/login/google-oauth2/ - GET: Start Google OAuth
# /api/v1/social/complete/github/ - GET: GitHub callback (handled by social-auth)
# /api/v1/social/complete/google-oauth2/ - GET: Google callback (handled by social-auth)
path('social/', include('social_django.urls', namespace='social')),
# SPA Test Page (Main app)
path('spa/', lambda request:
__import__('django.shortcuts').shortcuts.render(
request, 'spa_test/index.html'
), name='spa-test'),
# SPA Activation Page (Frontend route for email links)
path('spa/activate/<str:uid>/<str:token>/', lambda request, uid, token:
__import__('django.shortcuts').shortcuts.render(
request, 'spa_test/activate.html', {'uid': uid, 'token': token}
), name='spa-activate'),
# Django REST Framework browsable API auth
path('api-auth/', include('rest_framework.urls')),
# Djoser endpoints (registration, activation, etc.)
# /api/v1/auth/users/ - POST: Register new user
# /api/v1/auth/users/activation/ - POST: Activate account with uid/token
# /api/v1/auth/users/me/ - GET: Get current user info
# /api/v1/auth/users/resend_activation/ - POST: Resend activation email
path('auth/', include('djoser.urls')),
# Djoser JWT endpoints
# /api/v1/auth/jwt/create/ - POST: Login (get JWT tokens)
# /api/v1/auth/jwt/refresh/ - POST: Refresh access token
# /api/v1/auth/jwt/verify/ - POST: Verify token
path('auth/', include('djoser.urls.jwt')),
# Social authentication endpoints (Token-based - for mobile/SPA)
# /api/v1/auth/social/google-oauth2/ - POST: Login with Google (requires access_token)
# /api/v1/auth/social/github/ - POST: Login with GitHub (requires access_token)
# /api/v1/auth/social/facebook/ - POST: Login with Facebook (requires access_token)
path('auth/social/<str:provider>/', SocialLoginView.as_view(), name='social-login'),
# OAuth callback handler (after social-auth completes)
path('auth/social/callback/', SocialAuthCallbackView.as_view(), name='social-callback'),
# Success/Error pages
path('auth/social/success/', SocialAuthSuccessView.as_view(), name='social-success'),
]

271
accounts/views.py Normal file
View File

@@ -0,0 +1,271 @@
from django.shortcuts import redirect
from django.views import View
from rest_framework import status
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import AllowAny
from rest_framework_simplejwt.tokens import RefreshToken
from social_django.utils import load_strategy, load_backend
from social_core.backends.oauth import BaseOAuth2
from social_core.exceptions import AuthException, AuthForbidden
from .serializers import SocialLoginSerializer, CustomUserSerializer
import json
class SocialLoginView(APIView):
"""
Social authentication endpoint.
Accepts access_token from social provider and returns JWT tokens.
POST /api/v1/auth/social/<provider>/
Body: { "access_token": "..." }
Supported providers: google-oauth2, github, facebook
"""
permission_classes = [AllowAny]
serializer_class = SocialLoginSerializer
def post(self, request, provider):
"""
Authenticate user with social provider token.
"""
# Validate provider
valid_providers = ['google-oauth2', 'github', 'facebook']
if provider not in valid_providers:
return Response(
{'error': f'Invalid provider. Must be one of: {", ".join(valid_providers)}'},
status=status.HTTP_400_BAD_REQUEST
)
# Get access_token from request
access_token = request.data.get('access_token')
id_token = request.data.get('id_token', None)
if not access_token:
return Response(
{'error': 'access_token is required'},
status=status.HTTP_400_BAD_REQUEST
)
try:
# Load social auth strategy and backend
strategy = load_strategy(request)
backend = load_backend(
strategy=strategy,
name=provider,
redirect_uri=None
)
# Verify token and get user
if isinstance(backend, BaseOAuth2):
# For OAuth2 providers, use access_token to get user info
user = backend.do_auth(access_token)
else:
return Response(
{'error': 'Unsupported authentication backend'},
status=status.HTTP_400_BAD_REQUEST
)
if not user:
return Response(
{'error': 'Authentication failed. Invalid token.'},
status=status.HTTP_401_UNAUTHORIZED
)
# Check if user is active
if not user.is_active:
# This shouldn't happen for social auth users, but just in case
user.is_active = True
user.save(update_fields=['is_active'])
# Generate JWT tokens
refresh = RefreshToken.for_user(user)
# Serialize user data
user_serializer = CustomUserSerializer(user)
return Response({
'access': str(refresh.access_token),
'refresh': str(refresh),
'user': user_serializer.data
}, status=status.HTTP_200_OK)
except AuthForbidden:
return Response(
{'error': 'Authentication forbidden. Email not provided by provider or permission denied.'},
status=status.HTTP_403_FORBIDDEN
)
except AuthException as e:
return Response(
{'error': f'Authentication error: {str(e)}'},
status=status.HTTP_400_BAD_REQUEST
)
except Exception as e:
return Response(
{'error': f'An error occurred during authentication: {str(e)}'},
status=status.HTTP_500_INTERNAL_SERVER_ERROR
)
class SocialAuthCallbackView(View):
"""
Callback view for OAuth flow completion.
After successful authentication, redirects to frontend with tokens.
"""
permission_classes = [AllowAny]
authentication_classes = [] # No authentication required for callback
def get(self, request):
"""Handle OAuth callback and redirect to frontend with JWT tokens."""
from django.http import HttpResponseRedirect
# Get the authenticated user from the session
user = request.user
if user and user.is_authenticated:
# Generate JWT tokens
refresh = RefreshToken.for_user(user)
# Redirect to SPA with tokens (for testing)
redirect_url = f"/api/v1/spa/?access={str(refresh.access_token)}&refresh={str(refresh)}"
print(f"[OAuth Callback] Redirecting to: {redirect_url}")
return HttpResponseRedirect(redirect_url)
else:
# Authentication failed
return HttpResponseRedirect("/api/v1/auth/social/error/?error=authentication_failed")
class SocialAuthSuccessView(APIView):
"""
Success page after social authentication.
Displays tokens for testing purposes.
"""
permission_classes = [AllowAny]
authentication_classes = [] # No authentication required
def get(self, request):
"""Display success page with tokens."""
access_token = request.GET.get('access', '')
refresh_token = request.GET.get('refresh', '')
# Also check if user is in session
if not access_token and request.user.is_authenticated:
refresh = RefreshToken.for_user(request.user)
access_token = str(refresh.access_token)
refresh_token = str(refresh)
html_content = f"""
<!DOCTYPE html>
<html>
<head>
<title>Authentication Successful</title>
<style>
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: #28a745;
text-align: center;
margin-bottom: 20px;
}}
.success-icon {{
text-align: center;
font-size: 64px;
margin-bottom: 20px;
}}
.token-box {{
background: #f8f9fa;
border: 2px solid #e1e4e8;
border-radius: 8px;
padding: 15px;
margin: 15px 0;
word-break: break-all;
}}
.token-label {{
font-weight: bold;
color: #333;
margin-bottom: 5px;
}}
.token-value {{
font-family: 'Courier New', monospace;
font-size: 12px;
color: #666;
background: white;
padding: 10px;
border-radius: 4px;
overflow-x: auto;
}}
.btn {{
display: block;
width: 100%;
padding: 12px;
margin-top: 20px;
background: #667eea;
color: white;
border: none;
border-radius: 8px;
font-size: 16px;
cursor: pointer;
transition: background 0.3s;
}}
.btn:hover {{
background: #5568d3;
}}
</style>
</head>
<body>
<div class="container">
<div class="success-icon">✅</div>
<h1>Authentication Successful!</h1>
<p style="text-align: center; color: #666; margin-bottom: 30px;">
You have successfully authenticated with your social account.
</p>
<div class="token-box">
<div class="token-label">Access Token:</div>
<div class="token-value" id="accessToken">{access_token}</div>
</div>
<div class="token-box">
<div class="token-label">Refresh Token:</div>
<div class="token-value" id="refreshToken">{refresh_token}</div>
</div>
<button class="btn" onclick="copyTokens()">Copy Tokens to Clipboard</button>
<button class="btn" onclick="window.close()" style="background: #6c757d;">Close Window</button>
</div>
<script>
function copyTokens() {{
const tokens = {{
access: "{access_token}",
refresh: "{refresh_token}"
}};
navigator.clipboard.writeText(JSON.stringify(tokens, null, 2))
.then(() => alert('Tokens copied to clipboard!'))
.catch(err => alert('Failed to copy: ' + err));
}}
</script>
</body>
</html>
"""
from django.http import HttpResponse
return HttpResponse(html_content)

0
backup/__init__.py Normal file
View File

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

162
backup/admin.py Normal file
View File

@@ -0,0 +1,162 @@
from django.contrib import admin
from django.utils.html import format_html
from django.contrib import messages
from django.utils import timezone
from .models import DatabaseBackup
from .views import BackupManager
@admin.register(DatabaseBackup)
class DatabaseBackupAdmin(admin.ModelAdmin):
list_display = ['name', 'status_badge', 'backup_type', 'file_size_display', 'created_by', 'created_at', 'completed_at']
list_filter = ['status', 'backup_type', 'created_at']
search_fields = ['name', 'notes', 'error_message']
readonly_fields = ['file_path', 'file_size', 'status', 'created_by', 'created_at', 'completed_at', 'error_message', 'file_size_display_field']
fieldsets = (
('Temel Bilgiler', {
'fields': ('name', 'backup_type', 'status', 'notes')
}),
('Yedek Dosya Bilgileri', {
'fields': ('file_path', 'file_size_display_field')
}),
('Zaman Bilgileri', {
'fields': ('created_by', 'created_at', 'completed_at')
}),
('Hata Bilgileri', {
'fields': ('error_message',),
'classes': ('collapse',)
}),
)
actions = ['create_new_backup', 'restore_selected_backup', 'delete_backup_files']
def status_badge(self, obj):
"""Durum için renkli badge gösterir"""
colors = {
'pending': '#FFA500',
'in_progress': '#2196F3',
'completed': '#4CAF50',
'failed': '#F44336',
}
color = colors.get(obj.status, '#999')
return format_html(
'<span style="background-color: {}; color: white; padding: 3px 10px; border-radius: 3px; font-weight: bold;">{}</span>',
color,
obj.get_status_display()
)
status_badge.short_description = 'Durum'
def file_size_display(self, obj):
"""Dosya boyutunu gösterir"""
return obj.get_file_size_display()
file_size_display.short_description = 'Dosya Boyutu'
def file_size_display_field(self, obj):
"""Read-only field için dosya boyutu"""
return obj.get_file_size_display()
file_size_display_field.short_description = 'Dosya Boyutu'
def save_model(self, request, obj, form, change):
"""Model kaydedilirken created_by alanını otomatik doldur"""
if not change: # Yeni kayıt
obj.created_by = request.user
super().save_model(request, obj, form, change)
def create_new_backup(self, request, queryset):
"""Yeni bir yedek oluşturur"""
# Yeni bir backup objesi oluştur
timestamp = timezone.now().strftime('%Y-%m-%d %H:%M:%S')
backup = DatabaseBackup.objects.create(
name=f"Manuel Yedek - {timestamp}",
backup_type='manual',
created_by=request.user,
status='pending'
)
# Yedekleme işlemini başlat
manager = BackupManager()
success, message = manager.create_backup(backup)
if success:
self.message_user(request, message, messages.SUCCESS)
else:
self.message_user(request, message, messages.ERROR)
create_new_backup.short_description = "Yeni Yedek Oluştur"
def restore_selected_backup(self, request, queryset):
"""Seçili yedeği geri yükler"""
if queryset.count() != 1:
self.message_user(
request,
"Lütfen geri yüklemek için sadece bir yedek seçin",
messages.WARNING
)
return
backup = queryset.first()
if backup.status != 'completed':
self.message_user(
request,
"Sadece tamamlanmış yedekler geri yüklenebilir",
messages.WARNING
)
return
if not backup.file_path:
self.message_user(
request,
"Yedek dosya yolu bulunamadı",
messages.ERROR
)
return
manager = BackupManager()
success, message = manager.restore_backup(backup.file_path)
if success:
self.message_user(request, message, messages.SUCCESS)
else:
self.message_user(request, message, messages.ERROR)
restore_selected_backup.short_description = "Seçili Yedeği Geri Yükle"
def delete_backup_files(self, request, queryset):
"""Seçili yedeklerin dosyalarını siler"""
deleted_count = 0
error_count = 0
manager = BackupManager()
for backup in queryset:
if backup.file_path:
success, message = manager.delete_backup_file(backup.file_path)
if success:
backup.file_path = None
backup.file_size = None
backup.save()
deleted_count += 1
else:
error_count += 1
if deleted_count > 0:
self.message_user(
request,
f"{deleted_count} yedek dosyası silindi",
messages.SUCCESS
)
if error_count > 0:
self.message_user(
request,
f"{error_count} yedek dosyası silinemedi",
messages.WARNING
)
delete_backup_files.short_description = "Yedek Dosyalarını Sil"
def has_delete_permission(self, request, obj=None):
"""Silme iznini kontrol et - Tüm admin kullanıcıları silebilir"""
return request.user.is_staff

5
backup/apps.py Normal file
View File

@@ -0,0 +1,5 @@
from django.apps import AppConfig
class BackupConfig(AppConfig):
name = 'backup'

View File

@@ -0,0 +1,38 @@
# Generated by Django 6.0 on 2025-12-22 16:52
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='DatabaseBackup',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=255, verbose_name='Yedek Adı')),
('file_path', models.CharField(blank=True, max_length=500, null=True, verbose_name='Dosya Yolu')),
('file_size', models.BigIntegerField(blank=True, null=True, verbose_name='Dosya Boyutu (bytes)')),
('status', models.CharField(choices=[('pending', 'Bekliyor'), ('in_progress', 'İşleniyor'), ('completed', 'Tamamlandı'), ('failed', 'Başarısız')], default='pending', max_length=20, verbose_name='Durum')),
('backup_type', models.CharField(choices=[('manual', 'Manuel'), ('automatic', 'Otomatik')], default='manual', max_length=20, verbose_name='Yedek Tipi')),
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Oluşturulma Tarihi')),
('completed_at', models.DateTimeField(blank=True, null=True, verbose_name='Tamamlanma Tarihi')),
('error_message', models.TextField(blank=True, null=True, verbose_name='Hata Mesajı')),
('notes', models.TextField(blank=True, null=True, verbose_name='Notlar')),
('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='Oluşturan')),
],
options={
'verbose_name': 'Veritabanı Yedeği',
'verbose_name_plural': 'Veritabanı Yedekleri',
'ordering': ['-created_at'],
},
),
]

View File

Binary file not shown.

51
backup/models.py Normal file
View File

@@ -0,0 +1,51 @@
from django.db import models
from django.contrib.auth import get_user_model
User = get_user_model()
class DatabaseBackup(models.Model):
"""Veritabanı yedekleme kayıtlarını tutar"""
STATUS_CHOICES = [
('pending', 'Bekliyor'),
('in_progress', 'İşleniyor'),
('completed', 'Tamamlandı'),
('failed', 'Başarısız'),
]
BACKUP_TYPE_CHOICES = [
('manual', 'Manuel'),
('automatic', 'Otomatik'),
]
name = models.CharField(max_length=255, verbose_name='Yedek Adı')
file_path = models.CharField(max_length=500, verbose_name='Dosya Yolu', blank=True, null=True)
file_size = models.BigIntegerField(verbose_name='Dosya Boyutu (bytes)', null=True, blank=True)
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='pending', verbose_name='Durum')
backup_type = models.CharField(max_length=20, choices=BACKUP_TYPE_CHOICES, default='manual', verbose_name='Yedek Tipi')
created_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, verbose_name='Oluşturan')
created_at = models.DateTimeField(auto_now_add=True, verbose_name='Oluşturulma Tarihi')
completed_at = models.DateTimeField(null=True, blank=True, verbose_name='Tamamlanma Tarihi')
error_message = models.TextField(blank=True, null=True, verbose_name='Hata Mesajı')
notes = models.TextField(blank=True, null=True, verbose_name='Notlar')
class Meta:
verbose_name = 'Veritabanı Yedeği'
verbose_name_plural = 'Veritabanı Yedekleri'
ordering = ['-created_at']
def __str__(self):
return f"{self.name} - {self.get_status_display()}"
def get_file_size_display(self):
"""Dosya boyutunu okunabilir formatta döndürür"""
if not self.file_size:
return "N/A"
size = self.file_size
for unit in ['B', 'KB', 'MB', 'GB']:
if size < 1024.0:
return f"{size:.2f} {unit}"
size /= 1024.0
return f"{size:.2f} TB"

3
backup/tests.py Normal file
View File

@@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

259
backup/views.py Normal file
View File

@@ -0,0 +1,259 @@
import os
from datetime import datetime
from django.conf import settings
from django.utils import timezone
from .models import DatabaseBackup
from django.tasks import task
try:
import psycopg2
from psycopg2 import sql
PSYCOPG2_AVAILABLE = True
except ImportError:
PSYCOPG2_AVAILABLE = False
class BackupManager:
"""PostgreSQL veritabanı yedekleme işlemlerini yönetir - Sadece psycopg2 kullanarak"""
def __init__(self):
self.backup_dir = os.path.join(settings.BASE_DIR, 'backups')
if not os.path.exists(self.backup_dir):
os.makedirs(self.backup_dir)
def get_db_config(self):
"""Veritabanı yapılandırmasını alır"""
db_config = settings.DATABASES['default']
return {
'dbname': db_config.get('NAME'),
'user': db_config.get('USER'),
'password': db_config.get('PASSWORD'),
'host': db_config.get('HOST', 'localhost'),
'port': db_config.get('PORT', '5432'),
}
def get_connection(self):
"""PostgreSQL bağlantısı oluşturur"""
if not PSYCOPG2_AVAILABLE:
raise Exception("psycopg2 kütüphanesi yüklü değil")
db_config = self.get_db_config()
return psycopg2.connect(
dbname=db_config['dbname'],
user=db_config['user'],
password=db_config['password'],
host=db_config['host'],
port=db_config['port']
)
#@task
def create_backup(self, backup_obj):
"""
PostgreSQL veritabanının yedeğini oluşturur
Sadece psycopg2 kullanarak SQL dump oluşturur
"""
try:
backup_obj.status = 'in_progress'
backup_obj.save()
db_config = self.get_db_config()
# Yedek dosyası adını oluştur
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
backup_filename = f"backup_{db_config['dbname']}_{timestamp}.sql"
backup_path = os.path.join(self.backup_dir, backup_filename)
# Veritabanına bağlan
conn = self.get_connection()
cursor = conn.cursor()
with open(backup_path, 'w', encoding='utf-8') as f:
# Header
f.write("-- PostgreSQL Database Backup\n")
f.write(f"-- Database: {db_config['dbname']}\n")
f.write(f"-- Date: {datetime.now()}\n")
f.write("-- Created by Django Backup System using psycopg2\n\n")
f.write("SET client_encoding = 'UTF8';\n")
f.write("SET standard_conforming_strings = on;\n")
f.write("SET check_function_bodies = false;\n")
f.write("SET client_min_messages = warning;\n\n")
# Tüm tabloları al
cursor.execute("""
SELECT tablename FROM pg_tables
WHERE schemaname = 'public'
ORDER BY tablename;
""")
tables = cursor.fetchall()
for (table_name,) in tables:
f.write(f"\n-- Table: {table_name}\n")
# Tablo yapısını al - kolon bilgilerini çek
cursor.execute("""
SELECT
column_name,
data_type,
character_maximum_length,
is_nullable,
column_default
FROM information_schema.columns
WHERE table_schema = 'public' AND table_name = %s
ORDER BY ordinal_position;
""", [table_name])
columns_info = cursor.fetchall()
if columns_info:
f.write(f"DROP TABLE IF EXISTS {table_name} CASCADE;\n")
f.write(f"CREATE TABLE {table_name} (\n")
col_defs = []
for col_name, data_type, max_length, is_nullable, col_default in columns_info:
col_def = f" {col_name} "
# Veri tipini ekle
if max_length and data_type == 'character varying':
col_def += f"VARCHAR({max_length})"
elif max_length and data_type == 'character':
col_def += f"CHAR({max_length})"
else:
col_def += data_type.upper()
# NOT NULL
if is_nullable == 'NO':
col_def += " NOT NULL"
# DEFAULT değer
if col_default:
col_def += f" DEFAULT {col_default}"
col_defs.append(col_def)
f.write(",\n".join(col_defs))
f.write("\n);\n\n")
# Veriyi al ve INSERT komutları oluştur
cursor.execute(sql.SQL("SELECT * FROM {}").format(sql.Identifier(table_name)))
rows = cursor.fetchall()
if rows:
# Kolon isimlerini al
cursor.execute(sql.SQL("""
SELECT column_name
FROM information_schema.columns
WHERE table_name = %s
ORDER BY ordinal_position;
"""), [table_name])
columns = [row[0] for row in cursor.fetchall()]
f.write(f"-- Data for table: {table_name}\n")
for row in rows:
values = []
for val in row:
if val is None:
values.append('NULL')
elif isinstance(val, str):
# SQL injection'a karşı koruma
escaped = val.replace("'", "''")
values.append(f"'{escaped}'")
elif isinstance(val, (int, float)):
values.append(str(val))
elif isinstance(val, bool):
values.append('TRUE' if val else 'FALSE')
else:
# Diğer tipler için string'e çevir
escaped = str(val).replace("'", "''")
values.append(f"'{escaped}'")
cols_str = ', '.join(columns)
vals_str = ', '.join(values)
f.write(f"INSERT INTO {table_name} ({cols_str}) VALUES ({vals_str});\n")
f.write("\n")
# Sequence'leri sıfırla
f.write("\n-- Reset sequences\n")
cursor.execute("""
SELECT
c.relname as sequence_name,
t.relname as table_name,
a.attname as column_name
FROM pg_class c
JOIN pg_depend d ON d.objid = c.oid
JOIN pg_class t ON d.refobjid = t.oid
JOIN pg_attribute a ON a.attrelid = t.oid AND a.attnum = d.refobjsubid
WHERE c.relkind = 'S'
AND t.relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'public');
""")
sequences = cursor.fetchall()
for seq_name, tbl_name, col_name in sequences:
f.write(f"SELECT setval('{seq_name}', (SELECT COALESCE(MAX({col_name}), 1) FROM {tbl_name}));\n")
cursor.close()
conn.close()
# Başarılı
file_size = os.path.getsize(backup_path)
backup_obj.file_path = backup_path
backup_obj.file_size = file_size
backup_obj.status = 'completed'
backup_obj.completed_at = timezone.now()
backup_obj.save()
return True, f"Yedekleme başarıyla tamamlandı: {backup_filename}"
except Exception as e:
backup_obj.status = 'failed'
backup_obj.error_message = str(e)
backup_obj.save()
return False, f"Yedekleme hatası: {str(e)}"
def restore_backup(self, backup_path):
"""
Bir yedek dosyasından veritabanını geri yükler
SQL dosyasını okuyup komutları çalıştırır
"""
try:
if not os.path.exists(backup_path):
return False, "Yedek dosyası bulunamadı"
# SQL dosyasını oku
with open(backup_path, 'r', encoding='utf-8') as f:
sql_content = f.read()
# Veritabanına bağlan
conn = self.get_connection()
conn.autocommit = True
cursor = conn.cursor()
# SQL komutlarını çalıştır
# Basit bir şekilde satır satır çalıştır
statements = sql_content.split(';')
for statement in statements:
statement = statement.strip()
if statement and not statement.startswith('--'):
try:
cursor.execute(statement)
except Exception as e:
# Bazı hatalar göz ardı edilebilir (örn: tablo zaten var)
if 'does not exist' not in str(e):
print(f"Warning: {e}")
cursor.close()
conn.close()
return True, "Veritabanı başarıyla geri yüklendi"
except Exception as e:
return False, f"Geri yükleme hatası: {str(e)}"
def delete_backup_file(self, backup_path):
"""Yedek dosyasını fiziksel olarak siler"""
try:
if os.path.exists(backup_path):
os.remove(backup_path)
return True, "Yedek dosyası silindi"
else:
return False, "Yedek dosyası bulunamadı"
except Exception as e:
return False, f"Dosya silme hatası: {str(e)}"

View File

@@ -0,0 +1,535 @@
-- PostgreSQL Database Backup
-- Database: server_dj
-- Date: 2025-12-22 17:09:20.281699
-- Created by Django Backup System using psycopg2
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SET check_function_bodies = false;
SET client_min_messages = warning;
-- Table: accounts_customuser
DROP TABLE IF EXISTS accounts_customuser CASCADE;
CREATE TABLE accounts_customuser (
id BIGINT NOT NULL,
password VARCHAR(128) NOT NULL,
last_login TIMESTAMP WITH TIME ZONE,
is_superuser BOOLEAN NOT NULL,
email VARCHAR(254) NOT NULL,
first_name VARCHAR(150) NOT NULL,
last_name VARCHAR(150) NOT NULL,
is_staff BOOLEAN NOT NULL,
is_active BOOLEAN NOT NULL,
date_joined TIMESTAMP WITH TIME ZONE NOT NULL
);
-- Data for table: accounts_customuser
INSERT INTO accounts_customuser (id, password, last_login, is_superuser, email, first_name, last_name, is_staff, is_active, date_joined) VALUES (1, 'pbkdf2_sha256$1200000$93xPBCOPbW1XXQzUIvHCOc$gO1/rPxbbMoz0kHfYfhBibSEaW4OvXTw/Mf+QEcCCrY=', '2025-12-22 17:00:30.489489+00:00', True, 'beyhan@beyhan.dev', '', '', True, True, '2025-12-22 17:00:19.382231+00:00');
-- Table: accounts_customuser_groups
DROP TABLE IF EXISTS accounts_customuser_groups CASCADE;
CREATE TABLE accounts_customuser_groups (
id BIGINT NOT NULL,
customuser_id BIGINT NOT NULL,
group_id INTEGER NOT NULL
);
-- Table: accounts_customuser_user_permissions
DROP TABLE IF EXISTS accounts_customuser_user_permissions CASCADE;
CREATE TABLE accounts_customuser_user_permissions (
id BIGINT NOT NULL,
customuser_id BIGINT NOT NULL,
permission_id INTEGER NOT NULL
);
-- Table: auth_group
DROP TABLE IF EXISTS auth_group CASCADE;
CREATE TABLE auth_group (
id INTEGER NOT NULL,
name VARCHAR(150) NOT NULL
);
-- Table: auth_group_permissions
DROP TABLE IF EXISTS auth_group_permissions CASCADE;
CREATE TABLE auth_group_permissions (
id BIGINT NOT NULL,
group_id INTEGER NOT NULL,
permission_id INTEGER NOT NULL
);
-- Table: auth_permission
DROP TABLE IF EXISTS auth_permission CASCADE;
CREATE TABLE auth_permission (
id INTEGER NOT NULL,
name VARCHAR(255) NOT NULL,
content_type_id INTEGER NOT NULL,
codename VARCHAR(100) NOT NULL
);
-- Data for table: auth_permission
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (1, 'Can add log entry', 1, 'add_logentry');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (2, 'Can change log entry', 1, 'change_logentry');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (3, 'Can delete log entry', 1, 'delete_logentry');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (4, 'Can view log entry', 1, 'view_logentry');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (5, 'Can add permission', 3, 'add_permission');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (6, 'Can change permission', 3, 'change_permission');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (7, 'Can delete permission', 3, 'delete_permission');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (8, 'Can view permission', 3, 'view_permission');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (9, 'Can add group', 2, 'add_group');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (10, 'Can change group', 2, 'change_group');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (11, 'Can delete group', 2, 'delete_group');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (12, 'Can view group', 2, 'view_group');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (13, 'Can add content type', 4, 'add_contenttype');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (14, 'Can change content type', 4, 'change_contenttype');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (15, 'Can delete content type', 4, 'delete_contenttype');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (16, 'Can view content type', 4, 'view_contenttype');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (17, 'Can add session', 5, 'add_session');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (18, 'Can change session', 5, 'change_session');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (19, 'Can delete session', 5, 'delete_session');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (20, 'Can view session', 5, 'view_session');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (21, 'Can add association', 6, 'add_association');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (22, 'Can change association', 6, 'change_association');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (23, 'Can delete association', 6, 'delete_association');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (24, 'Can view association', 6, 'view_association');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (25, 'Can add code', 7, 'add_code');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (26, 'Can change code', 7, 'change_code');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (27, 'Can delete code', 7, 'delete_code');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (28, 'Can view code', 7, 'view_code');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (29, 'Can add nonce', 8, 'add_nonce');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (30, 'Can change nonce', 8, 'change_nonce');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (31, 'Can delete nonce', 8, 'delete_nonce');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (32, 'Can view nonce', 8, 'view_nonce');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (33, 'Can add user social auth', 10, 'add_usersocialauth');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (34, 'Can change user social auth', 10, 'change_usersocialauth');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (35, 'Can delete user social auth', 10, 'delete_usersocialauth');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (36, 'Can view user social auth', 10, 'view_usersocialauth');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (37, 'Can add partial', 9, 'add_partial');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (38, 'Can change partial', 9, 'change_partial');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (39, 'Can delete partial', 9, 'delete_partial');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (40, 'Can view partial', 9, 'view_partial');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (41, 'Can add site', 11, 'add_site');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (42, 'Can change site', 11, 'change_site');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (43, 'Can delete site', 11, 'delete_site');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (44, 'Can view site', 11, 'view_site');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (45, 'Can add user', 12, 'add_customuser');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (46, 'Can change user', 12, 'change_customuser');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (47, 'Can delete user', 12, 'delete_customuser');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (48, 'Can view user', 12, 'view_customuser');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (49, 'Can add Banner', 13, 'add_banner');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (50, 'Can change Banner', 13, 'change_banner');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (51, 'Can delete Banner', 13, 'delete_banner');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (52, 'Can view Banner', 13, 'view_banner');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (53, 'Can add Site Ayarı', 14, 'add_setting');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (54, 'Can change Site Ayarı', 14, 'change_setting');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (55, 'Can delete Site Ayarı', 14, 'delete_setting');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (56, 'Can view Site Ayarı', 14, 'view_setting');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (57, 'Can add Post Tagı', 19, 'add_tags');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (58, 'Can change Post Tagı', 19, 'change_tags');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (59, 'Can delete Post Tagı', 19, 'delete_tags');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (60, 'Can view Post Tagı', 19, 'view_tags');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (61, 'Can add Post Kategori', 15, 'add_category');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (62, 'Can change Post Kategori', 15, 'change_category');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (63, 'Can delete Post Kategori', 15, 'delete_category');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (64, 'Can view Post Kategori', 15, 'view_category');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (65, 'Can add Post', 18, 'add_post');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (66, 'Can change Post', 18, 'change_post');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (67, 'Can delete Post', 18, 'delete_post');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (68, 'Can view Post', 18, 'view_post');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (69, 'Can add Kategori Ziyareti', 16, 'add_categoryview');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (70, 'Can change Kategori Ziyareti', 16, 'change_categoryview');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (71, 'Can delete Kategori Ziyareti', 16, 'delete_categoryview');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (72, 'Can view Kategori Ziyareti', 16, 'view_categoryview');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (73, 'Can add Post Yorum', 17, 'add_comment');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (74, 'Can change Post Yorum', 17, 'change_comment');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (75, 'Can delete Post Yorum', 17, 'delete_comment');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (76, 'Can view Post Yorum', 17, 'view_comment');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (77, 'Can add Veritabanı Yedeği', 20, 'add_databasebackup');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (78, 'Can change Veritabanı Yedeği', 20, 'change_databasebackup');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (79, 'Can delete Veritabanı Yedeği', 20, 'delete_databasebackup');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (80, 'Can view Veritabanı Yedeği', 20, 'view_databasebackup');
-- Table: backup_databasebackup
DROP TABLE IF EXISTS backup_databasebackup CASCADE;
CREATE TABLE backup_databasebackup (
id BIGINT NOT NULL,
name VARCHAR(255) NOT NULL,
file_path VARCHAR(500),
file_size BIGINT,
status VARCHAR(20) NOT NULL,
backup_type VARCHAR(20) NOT NULL,
created_at TIMESTAMP WITH TIME ZONE NOT NULL,
completed_at TIMESTAMP WITH TIME ZONE,
error_message TEXT,
notes TEXT,
created_by_id BIGINT
);
-- Data for table: backup_databasebackup
INSERT INTO backup_databasebackup (id, name, file_path, file_size, status, backup_type, created_at, completed_at, error_message, notes, created_by_id) VALUES (1, 'Yedek 1', NULL, NULL, 'pending', 'manual', '2025-12-22 17:00:54.955082+00:00', NULL, NULL, '', 1);
INSERT INTO backup_databasebackup (id, name, file_path, file_size, status, backup_type, created_at, completed_at, error_message, notes, created_by_id) VALUES (6, 'Manuel Yedek - 2025-12-22 17:09:20', NULL, NULL, 'in_progress', 'manual', '2025-12-22 17:09:20.245933+00:00', NULL, NULL, NULL, 1);
-- Table: banners
DROP TABLE IF EXISTS banners CASCADE;
CREATE TABLE banners (
id BIGINT NOT NULL,
color VARCHAR(25) NOT NULL,
title VARCHAR(254),
text1 VARCHAR(254),
text2 VARCHAR(254),
text4 VARCHAR(254),
text5 VARCHAR(254),
image VARCHAR(100) NOT NULL,
image_k VARCHAR(100),
image_k_txt VARCHAR(254),
is_active BOOLEAN NOT NULL,
created_at TIMESTAMP WITH TIME ZONE NOT NULL,
updated_at TIMESTAMP WITH TIME ZONE NOT NULL
);
-- Table: categories
DROP TABLE IF EXISTS categories CASCADE;
CREATE TABLE categories (
id BIGINT NOT NULL,
title VARCHAR(254) NOT NULL,
keywords VARCHAR(254) NOT NULL,
description VARCHAR(254) NOT NULL,
created_at TIMESTAMP WITH TIME ZONE NOT NULL,
updated_at TIMESTAMP WITH TIME ZONE NOT NULL,
is_active BOOLEAN NOT NULL,
order INTEGER NOT NULL,
slug VARCHAR(250) NOT NULL,
image VARCHAR(100),
parent_id BIGINT
);
-- Table: category_views
DROP TABLE IF EXISTS category_views CASCADE;
CREATE TABLE category_views (
id BIGINT NOT NULL,
ip_address INET NOT NULL,
user_agent TEXT,
created_at TIMESTAMP WITH TIME ZONE NOT NULL,
category_id BIGINT NOT NULL
);
-- Table: comments
DROP TABLE IF EXISTS comments CASCADE;
CREATE TABLE comments (
id BIGINT NOT NULL,
title VARCHAR(254) NOT NULL,
body TEXT NOT NULL,
created_at TIMESTAMP WITH TIME ZONE NOT NULL,
updated_at TIMESTAMP WITH TIME ZONE NOT NULL,
is_active BOOLEAN NOT NULL,
slug VARCHAR(50) NOT NULL,
parent_id BIGINT,
user_id BIGINT NOT NULL,
product_id BIGINT NOT NULL
);
-- Table: django_admin_log
DROP TABLE IF EXISTS django_admin_log CASCADE;
CREATE TABLE django_admin_log (
id INTEGER NOT NULL,
action_time TIMESTAMP WITH TIME ZONE NOT NULL,
object_id TEXT,
object_repr VARCHAR(200) NOT NULL,
action_flag SMALLINT NOT NULL,
change_message TEXT NOT NULL,
content_type_id INTEGER,
user_id BIGINT NOT NULL
);
-- Data for table: django_admin_log
INSERT INTO django_admin_log (id, action_time, object_id, object_repr, action_flag, change_message, content_type_id, user_id) VALUES (1, '2025-12-22 17:00:54.961166+00:00', '1', 'Yedek 1 - Bekliyor', 1, '[{"added": {}}]', 20, 1);
INSERT INTO django_admin_log (id, action_time, object_id, object_repr, action_flag, change_message, content_type_id, user_id) VALUES (2, '2025-12-22 17:01:10.019183+00:00', '1', 'Yedek 1 - Bekliyor', 2, '[]', 20, 1);
INSERT INTO django_admin_log (id, action_time, object_id, object_repr, action_flag, change_message, content_type_id, user_id) VALUES (3, '2025-12-22 17:08:18.352881+00:00', '2', 'Manuel Yedek - 2025-12-22 17:01:15 - Başarısız', 3, '', 20, 1);
INSERT INTO django_admin_log (id, action_time, object_id, object_repr, action_flag, change_message, content_type_id, user_id) VALUES (4, '2025-12-22 17:08:25.284922+00:00', '4', 'Manuel Yedek - 2025-12-22 17:05:18 - Başarısız', 3, '', 20, 1);
INSERT INTO django_admin_log (id, action_time, object_id, object_repr, action_flag, change_message, content_type_id, user_id) VALUES (5, '2025-12-22 17:08:30.992298+00:00', '3', 'Manuel Yedek - 2025-12-22 17:03:41 - Başarısız', 3, '', 20, 1);
INSERT INTO django_admin_log (id, action_time, object_id, object_repr, action_flag, change_message, content_type_id, user_id) VALUES (6, '2025-12-22 17:08:56.836202+00:00', '5', 'Manuel Yedek - 2025-12-22 17:06:15 - Tamamlandı', 3, '', 20, 1);
-- Table: django_content_type
DROP TABLE IF EXISTS django_content_type CASCADE;
CREATE TABLE django_content_type (
id INTEGER NOT NULL,
app_label VARCHAR(100) NOT NULL,
model VARCHAR(100) NOT NULL
);
-- Data for table: django_content_type
INSERT INTO django_content_type (id, app_label, model) VALUES (1, 'admin', 'logentry');
INSERT INTO django_content_type (id, app_label, model) VALUES (2, 'auth', 'group');
INSERT INTO django_content_type (id, app_label, model) VALUES (3, 'auth', 'permission');
INSERT INTO django_content_type (id, app_label, model) VALUES (4, 'contenttypes', 'contenttype');
INSERT INTO django_content_type (id, app_label, model) VALUES (5, 'sessions', 'session');
INSERT INTO django_content_type (id, app_label, model) VALUES (6, 'social_django', 'association');
INSERT INTO django_content_type (id, app_label, model) VALUES (7, 'social_django', 'code');
INSERT INTO django_content_type (id, app_label, model) VALUES (8, 'social_django', 'nonce');
INSERT INTO django_content_type (id, app_label, model) VALUES (9, 'social_django', 'partial');
INSERT INTO django_content_type (id, app_label, model) VALUES (10, 'social_django', 'usersocialauth');
INSERT INTO django_content_type (id, app_label, model) VALUES (11, 'sites', 'site');
INSERT INTO django_content_type (id, app_label, model) VALUES (12, 'accounts', 'customuser');
INSERT INTO django_content_type (id, app_label, model) VALUES (13, 'settings', 'banner');
INSERT INTO django_content_type (id, app_label, model) VALUES (14, 'settings', 'setting');
INSERT INTO django_content_type (id, app_label, model) VALUES (15, 'blog', 'category');
INSERT INTO django_content_type (id, app_label, model) VALUES (16, 'blog', 'categoryview');
INSERT INTO django_content_type (id, app_label, model) VALUES (17, 'blog', 'comment');
INSERT INTO django_content_type (id, app_label, model) VALUES (18, 'blog', 'post');
INSERT INTO django_content_type (id, app_label, model) VALUES (19, 'blog', 'tags');
INSERT INTO django_content_type (id, app_label, model) VALUES (20, 'backup', 'databasebackup');
-- Table: django_migrations
DROP TABLE IF EXISTS django_migrations CASCADE;
CREATE TABLE django_migrations (
id BIGINT NOT NULL,
app VARCHAR(255) NOT NULL,
name VARCHAR(255) NOT NULL,
applied TIMESTAMP WITH TIME ZONE NOT NULL
);
-- Data for table: django_migrations
INSERT INTO django_migrations (id, app, name, applied) VALUES (1, 'contenttypes', '0001_initial', '2025-12-22 16:57:19.217932+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (2, 'contenttypes', '0002_remove_content_type_name', '2025-12-22 16:57:19.234555+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (3, 'auth', '0001_initial', '2025-12-22 16:57:19.434147+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (4, 'auth', '0002_alter_permission_name_max_length', '2025-12-22 16:57:19.446206+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (5, 'auth', '0003_alter_user_email_max_length', '2025-12-22 16:57:19.455809+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (6, 'auth', '0004_alter_user_username_opts', '2025-12-22 16:57:19.465593+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (7, 'auth', '0005_alter_user_last_login_null', '2025-12-22 16:57:19.475691+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (8, 'auth', '0006_require_contenttypes_0002', '2025-12-22 16:57:19.481434+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (9, 'auth', '0007_alter_validators_add_error_messages', '2025-12-22 16:57:19.565856+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (10, 'auth', '0008_alter_user_username_max_length', '2025-12-22 16:57:19.592172+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (11, 'auth', '0009_alter_user_last_name_max_length', '2025-12-22 16:57:19.603096+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (12, 'auth', '0010_alter_group_name_max_length', '2025-12-22 16:57:19.625591+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (13, 'auth', '0011_update_proxy_permissions', '2025-12-22 16:57:19.634914+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (14, 'auth', '0012_alter_user_first_name_max_length', '2025-12-22 16:57:19.645268+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (15, 'accounts', '0001_initial', '2025-12-22 16:57:19.898703+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (16, 'admin', '0001_initial', '2025-12-22 16:57:19.967758+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (17, 'admin', '0002_logentry_remove_auto_add', '2025-12-22 16:57:19.980668+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (18, 'admin', '0003_logentry_add_action_flag_choices', '2025-12-22 16:57:19.994932+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (19, 'backup', '0001_initial', '2025-12-22 16:57:20.047172+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (20, 'blog', '0001_initial', '2025-12-22 16:57:20.451373+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (21, 'sessions', '0001_initial', '2025-12-22 16:57:20.596961+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (22, 'settings', '0001_initial', '2025-12-22 16:57:20.623314+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (23, 'sites', '0001_initial', '2025-12-22 16:57:20.634939+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (24, 'sites', '0002_alter_domain_unique', '2025-12-22 16:57:20.648215+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (25, 'default', '0001_initial', '2025-12-22 16:57:20.743912+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (26, 'social_auth', '0001_initial', '2025-12-22 16:57:20.747238+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (27, 'social_django', '0001_initial', '2025-12-22 16:57:20.750337+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (28, 'default', '0002_add_related_name', '2025-12-22 16:57:20.772416+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (29, 'social_auth', '0002_add_related_name', '2025-12-22 16:57:20.776564+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (30, 'social_django', '0002_add_related_name', '2025-12-22 16:57:20.778681+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (31, 'default', '0003_alter_email_max_length', '2025-12-22 16:57:20.797950+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (32, 'social_auth', '0003_alter_email_max_length', '2025-12-22 16:57:20.800526+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (33, 'social_django', '0003_alter_email_max_length', '2025-12-22 16:57:20.802697+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (34, 'default', '0004_auto_20160423_0400', '2025-12-22 16:57:20.818189+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (35, 'social_auth', '0004_auto_20160423_0400', '2025-12-22 16:57:20.821978+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (36, 'social_django', '0004_auto_20160423_0400', '2025-12-22 16:57:20.824686+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (37, 'social_auth', '0005_auto_20160727_2333', '2025-12-22 16:57:20.838781+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (38, 'social_django', '0005_auto_20160727_2333', '2025-12-22 16:57:20.842005+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (39, 'social_django', '0006_partial', '2025-12-22 16:57:20.882162+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (40, 'social_django', '0007_code_timestamp', '2025-12-22 16:57:21.016558+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (41, 'social_django', '0008_partial_timestamp', '2025-12-22 16:57:21.036847+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (42, 'social_django', '0009_auto_20191118_0520', '2025-12-22 16:57:21.078912+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (43, 'social_django', '0010_uid_db_index', '2025-12-22 16:57:21.103380+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (44, 'social_django', '0011_alter_id_fields', '2025-12-22 16:57:21.271476+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (45, 'social_django', '0012_usersocialauth_extra_data_new', '2025-12-22 16:57:21.315237+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (46, 'social_django', '0013_migrate_extra_data', '2025-12-22 16:57:21.359048+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (47, 'social_django', '0014_remove_usersocialauth_extra_data', '2025-12-22 16:57:21.387186+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (48, 'social_django', '0015_rename_extra_data_new_usersocialauth_extra_data', '2025-12-22 16:57:21.411254+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (49, 'social_django', '0016_alter_usersocialauth_extra_data', '2025-12-22 16:57:21.425493+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (50, 'social_django', '0017_usersocialauth_user_social_auth_uid_required', '2025-12-22 16:57:21.447520+00:00');
-- Table: django_session
DROP TABLE IF EXISTS django_session CASCADE;
CREATE TABLE django_session (
session_key VARCHAR(40) NOT NULL,
session_data TEXT NOT NULL,
expire_date TIMESTAMP WITH TIME ZONE NOT NULL
);
-- Data for table: django_session
INSERT INTO django_session (session_key, session_data, expire_date) VALUES ('e7jyr13wedmqdkjukqb35t2pyylkbvwz', '.eJxVjEEOwiAQRe_C2hBgpKBL9z0DmWFGqRpISrsy3l2bdKHb_977L5VwXUpau8xpYnVWVh1-N8L8kLoBvmO9NZ1bXeaJ9KbonXY9NpbnZXf_Dgr28q0F0bKTEGNG70Uie8vgLbGBYxQbwBHlwQ0szoILOQsDwMmZeKVgvHp_APiKN_E:1vXjGo:c9NPOwqzmQXV6RsDHkclP-w4ogI8VDPbV0KQilsiW6Y', '2026-01-05 17:00:30.494599+00:00');
-- Table: django_site
DROP TABLE IF EXISTS django_site CASCADE;
CREATE TABLE django_site (
id INTEGER NOT NULL,
domain VARCHAR(100) NOT NULL,
name VARCHAR(50) NOT NULL
);
-- Data for table: django_site
INSERT INTO django_site (id, domain, name) VALUES (1, 'example.com', 'example.com');
-- Table: posts
DROP TABLE IF EXISTS posts CASCADE;
CREATE TABLE posts (
id BIGINT NOT NULL,
title VARCHAR(254) NOT NULL,
content TEXT,
keywords VARCHAR(254) NOT NULL,
image VARCHAR(100),
video VARCHAR(254),
slug VARCHAR(250) NOT NULL,
created_at TIMESTAMP WITH TIME ZONE NOT NULL,
updated_at TIMESTAMP WITH TIME ZONE NOT NULL,
is_active BOOLEAN NOT NULL,
is_front BOOLEAN NOT NULL,
parent_id BIGINT
);
-- Table: posts_categories
DROP TABLE IF EXISTS posts_categories CASCADE;
CREATE TABLE posts_categories (
id BIGINT NOT NULL,
post_id BIGINT NOT NULL,
category_id BIGINT NOT NULL
);
-- Table: posts_tags
DROP TABLE IF EXISTS posts_tags CASCADE;
CREATE TABLE posts_tags (
id BIGINT NOT NULL,
post_id BIGINT NOT NULL,
tags_id BIGINT NOT NULL
);
-- Table: settings
DROP TABLE IF EXISTS settings CASCADE;
CREATE TABLE settings (
id BIGINT NOT NULL,
title VARCHAR(254) NOT NULL,
meta_title VARCHAR(254) NOT NULL,
meta_description VARCHAR(254) NOT NULL,
phone VARCHAR(254) NOT NULL,
url VARCHAR(254),
email VARCHAR(254) NOT NULL,
facebook VARCHAR(254),
x VARCHAR(254),
instagram VARCHAR(254),
whatsapp VARCHAR(254),
slogan VARCHAR(254),
w_logo VARCHAR(100),
b_logo VARCHAR(100),
created_at TIMESTAMP WITH TIME ZONE NOT NULL,
updated_at TIMESTAMP WITH TIME ZONE NOT NULL,
is_active BOOLEAN NOT NULL
);
-- Table: social_auth_association
DROP TABLE IF EXISTS social_auth_association CASCADE;
CREATE TABLE social_auth_association (
id BIGINT NOT NULL,
server_url VARCHAR(255) NOT NULL,
handle VARCHAR(255) NOT NULL,
secret VARCHAR(255) NOT NULL,
issued INTEGER NOT NULL,
lifetime INTEGER NOT NULL,
assoc_type VARCHAR(64) NOT NULL
);
-- Table: social_auth_code
DROP TABLE IF EXISTS social_auth_code CASCADE;
CREATE TABLE social_auth_code (
id BIGINT NOT NULL,
email VARCHAR(254) NOT NULL,
code VARCHAR(32) NOT NULL,
verified BOOLEAN NOT NULL,
timestamp TIMESTAMP WITH TIME ZONE NOT NULL
);
-- Table: social_auth_nonce
DROP TABLE IF EXISTS social_auth_nonce CASCADE;
CREATE TABLE social_auth_nonce (
id BIGINT NOT NULL,
server_url VARCHAR(255) NOT NULL,
timestamp INTEGER NOT NULL,
salt VARCHAR(65) NOT NULL
);
-- Table: social_auth_partial
DROP TABLE IF EXISTS social_auth_partial CASCADE;
CREATE TABLE social_auth_partial (
id BIGINT NOT NULL,
token VARCHAR(32) NOT NULL,
next_step SMALLINT NOT NULL,
backend VARCHAR(32) NOT NULL,
timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
data JSONB NOT NULL
);
-- Table: social_auth_usersocialauth
DROP TABLE IF EXISTS social_auth_usersocialauth CASCADE;
CREATE TABLE social_auth_usersocialauth (
id BIGINT NOT NULL,
provider VARCHAR(32) NOT NULL,
uid VARCHAR(255) NOT NULL,
user_id BIGINT NOT NULL,
created TIMESTAMP WITH TIME ZONE NOT NULL,
modified TIMESTAMP WITH TIME ZONE NOT NULL,
extra_data JSONB NOT NULL
);
-- Table: tags
DROP TABLE IF EXISTS tags CASCADE;
CREATE TABLE tags (
id BIGINT NOT NULL,
tag VARCHAR(254) NOT NULL,
created_at TIMESTAMP WITH TIME ZONE NOT NULL,
updated_at TIMESTAMP WITH TIME ZONE NOT NULL,
is_active BOOLEAN NOT NULL
);
-- Reset sequences
SELECT setval('django_migrations_id_seq', (SELECT COALESCE(MAX(id), 1) FROM django_migrations));
SELECT setval('django_content_type_id_seq', (SELECT COALESCE(MAX(id), 1) FROM django_content_type));
SELECT setval('auth_permission_id_seq', (SELECT COALESCE(MAX(id), 1) FROM auth_permission));
SELECT setval('auth_group_id_seq', (SELECT COALESCE(MAX(id), 1) FROM auth_group));
SELECT setval('auth_group_permissions_id_seq', (SELECT COALESCE(MAX(id), 1) FROM auth_group_permissions));
SELECT setval('accounts_customuser_id_seq', (SELECT COALESCE(MAX(id), 1) FROM accounts_customuser));
SELECT setval('accounts_customuser_groups_id_seq', (SELECT COALESCE(MAX(id), 1) FROM accounts_customuser_groups));
SELECT setval('accounts_customuser_user_permissions_id_seq', (SELECT COALESCE(MAX(id), 1) FROM accounts_customuser_user_permissions));
SELECT setval('django_admin_log_id_seq', (SELECT COALESCE(MAX(id), 1) FROM django_admin_log));
SELECT setval('backup_databasebackup_id_seq', (SELECT COALESCE(MAX(id), 1) FROM backup_databasebackup));
SELECT setval('tags_id_seq', (SELECT COALESCE(MAX(id), 1) FROM tags));
SELECT setval('categories_id_seq', (SELECT COALESCE(MAX(id), 1) FROM categories));
SELECT setval('posts_id_seq', (SELECT COALESCE(MAX(id), 1) FROM posts));
SELECT setval('posts_categories_id_seq', (SELECT COALESCE(MAX(id), 1) FROM posts_categories));
SELECT setval('posts_tags_id_seq', (SELECT COALESCE(MAX(id), 1) FROM posts_tags));
SELECT setval('category_views_id_seq', (SELECT COALESCE(MAX(id), 1) FROM category_views));
SELECT setval('comments_id_seq', (SELECT COALESCE(MAX(id), 1) FROM comments));
SELECT setval('banners_id_seq', (SELECT COALESCE(MAX(id), 1) FROM banners));
SELECT setval('settings_id_seq', (SELECT COALESCE(MAX(id), 1) FROM settings));
SELECT setval('django_site_id_seq', (SELECT COALESCE(MAX(id), 1) FROM django_site));
SELECT setval('social_auth_association_id_seq', (SELECT COALESCE(MAX(id), 1) FROM social_auth_association));
SELECT setval('social_auth_code_id_seq', (SELECT COALESCE(MAX(id), 1) FROM social_auth_code));
SELECT setval('social_auth_nonce_id_seq', (SELECT COALESCE(MAX(id), 1) FROM social_auth_nonce));
SELECT setval('social_auth_usersocialauth_id_seq', (SELECT COALESCE(MAX(id), 1) FROM social_auth_usersocialauth));
SELECT setval('social_auth_partial_id_seq', (SELECT COALESCE(MAX(id), 1) FROM social_auth_partial));

View File

@@ -0,0 +1,676 @@
-- PostgreSQL Database Backup
-- Database: server_dj
-- Date: 2025-12-22 18:09:22.149348
-- Created by Django Backup System using psycopg2
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SET check_function_bodies = false;
SET client_min_messages = warning;
-- Table: accounts_customuser
DROP TABLE IF EXISTS accounts_customuser CASCADE;
CREATE TABLE accounts_customuser (
id BIGINT NOT NULL,
password VARCHAR(128) NOT NULL,
last_login TIMESTAMP WITH TIME ZONE,
is_superuser BOOLEAN NOT NULL,
email VARCHAR(254) NOT NULL,
first_name VARCHAR(150) NOT NULL,
last_name VARCHAR(150) NOT NULL,
is_staff BOOLEAN NOT NULL,
is_active BOOLEAN NOT NULL,
date_joined TIMESTAMP WITH TIME ZONE NOT NULL
);
-- Data for table: accounts_customuser
INSERT INTO accounts_customuser (id, password, last_login, is_superuser, email, first_name, last_name, is_staff, is_active, date_joined) VALUES (1, 'pbkdf2_sha256$1200000$93xPBCOPbW1XXQzUIvHCOc$gO1/rPxbbMoz0kHfYfhBibSEaW4OvXTw/Mf+QEcCCrY=', '2025-12-22 17:00:30.489489+00:00', True, 'beyhan@beyhan.dev', '', '', True, True, '2025-12-22 17:00:19.382231+00:00');
-- Table: accounts_customuser_groups
DROP TABLE IF EXISTS accounts_customuser_groups CASCADE;
CREATE TABLE accounts_customuser_groups (
id BIGINT NOT NULL,
customuser_id BIGINT NOT NULL,
group_id INTEGER NOT NULL
);
-- Table: accounts_customuser_user_permissions
DROP TABLE IF EXISTS accounts_customuser_user_permissions CASCADE;
CREATE TABLE accounts_customuser_user_permissions (
id BIGINT NOT NULL,
customuser_id BIGINT NOT NULL,
permission_id INTEGER NOT NULL
);
-- Table: auth_group
DROP TABLE IF EXISTS auth_group CASCADE;
CREATE TABLE auth_group (
id INTEGER NOT NULL,
name VARCHAR(150) NOT NULL
);
-- Table: auth_group_permissions
DROP TABLE IF EXISTS auth_group_permissions CASCADE;
CREATE TABLE auth_group_permissions (
id BIGINT NOT NULL,
group_id INTEGER NOT NULL,
permission_id INTEGER NOT NULL
);
-- Table: auth_permission
DROP TABLE IF EXISTS auth_permission CASCADE;
CREATE TABLE auth_permission (
id INTEGER NOT NULL,
name VARCHAR(255) NOT NULL,
content_type_id INTEGER NOT NULL,
codename VARCHAR(100) NOT NULL
);
-- Data for table: auth_permission
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (1, 'Can add log entry', 1, 'add_logentry');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (2, 'Can change log entry', 1, 'change_logentry');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (3, 'Can delete log entry', 1, 'delete_logentry');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (4, 'Can view log entry', 1, 'view_logentry');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (5, 'Can add permission', 3, 'add_permission');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (6, 'Can change permission', 3, 'change_permission');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (7, 'Can delete permission', 3, 'delete_permission');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (8, 'Can view permission', 3, 'view_permission');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (9, 'Can add group', 2, 'add_group');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (10, 'Can change group', 2, 'change_group');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (11, 'Can delete group', 2, 'delete_group');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (12, 'Can view group', 2, 'view_group');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (13, 'Can add content type', 4, 'add_contenttype');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (14, 'Can change content type', 4, 'change_contenttype');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (15, 'Can delete content type', 4, 'delete_contenttype');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (16, 'Can view content type', 4, 'view_contenttype');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (17, 'Can add session', 5, 'add_session');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (18, 'Can change session', 5, 'change_session');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (19, 'Can delete session', 5, 'delete_session');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (20, 'Can view session', 5, 'view_session');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (21, 'Can add association', 6, 'add_association');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (22, 'Can change association', 6, 'change_association');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (23, 'Can delete association', 6, 'delete_association');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (24, 'Can view association', 6, 'view_association');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (25, 'Can add code', 7, 'add_code');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (26, 'Can change code', 7, 'change_code');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (27, 'Can delete code', 7, 'delete_code');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (28, 'Can view code', 7, 'view_code');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (29, 'Can add nonce', 8, 'add_nonce');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (30, 'Can change nonce', 8, 'change_nonce');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (31, 'Can delete nonce', 8, 'delete_nonce');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (32, 'Can view nonce', 8, 'view_nonce');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (33, 'Can add user social auth', 10, 'add_usersocialauth');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (34, 'Can change user social auth', 10, 'change_usersocialauth');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (35, 'Can delete user social auth', 10, 'delete_usersocialauth');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (36, 'Can view user social auth', 10, 'view_usersocialauth');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (37, 'Can add partial', 9, 'add_partial');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (38, 'Can change partial', 9, 'change_partial');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (39, 'Can delete partial', 9, 'delete_partial');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (40, 'Can view partial', 9, 'view_partial');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (41, 'Can add site', 11, 'add_site');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (42, 'Can change site', 11, 'change_site');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (43, 'Can delete site', 11, 'delete_site');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (44, 'Can view site', 11, 'view_site');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (45, 'Can add user', 12, 'add_customuser');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (46, 'Can change user', 12, 'change_customuser');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (47, 'Can delete user', 12, 'delete_customuser');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (48, 'Can view user', 12, 'view_customuser');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (49, 'Can add Banner', 13, 'add_banner');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (50, 'Can change Banner', 13, 'change_banner');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (51, 'Can delete Banner', 13, 'delete_banner');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (52, 'Can view Banner', 13, 'view_banner');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (53, 'Can add Site Ayarı', 14, 'add_setting');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (54, 'Can change Site Ayarı', 14, 'change_setting');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (55, 'Can delete Site Ayarı', 14, 'delete_setting');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (56, 'Can view Site Ayarı', 14, 'view_setting');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (57, 'Can add Post Tagı', 19, 'add_tags');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (58, 'Can change Post Tagı', 19, 'change_tags');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (59, 'Can delete Post Tagı', 19, 'delete_tags');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (60, 'Can view Post Tagı', 19, 'view_tags');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (61, 'Can add Post Kategori', 15, 'add_category');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (62, 'Can change Post Kategori', 15, 'change_category');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (63, 'Can delete Post Kategori', 15, 'delete_category');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (64, 'Can view Post Kategori', 15, 'view_category');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (65, 'Can add Post', 18, 'add_post');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (66, 'Can change Post', 18, 'change_post');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (67, 'Can delete Post', 18, 'delete_post');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (68, 'Can view Post', 18, 'view_post');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (69, 'Can add Kategori Ziyareti', 16, 'add_categoryview');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (70, 'Can change Kategori Ziyareti', 16, 'change_categoryview');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (71, 'Can delete Kategori Ziyareti', 16, 'delete_categoryview');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (72, 'Can view Kategori Ziyareti', 16, 'view_categoryview');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (73, 'Can add Post Yorum', 17, 'add_comment');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (74, 'Can change Post Yorum', 17, 'change_comment');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (75, 'Can delete Post Yorum', 17, 'delete_comment');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (76, 'Can view Post Yorum', 17, 'view_comment');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (77, 'Can add Veritabanı Yedeği', 20, 'add_databasebackup');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (78, 'Can change Veritabanı Yedeği', 20, 'change_databasebackup');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (79, 'Can delete Veritabanı Yedeği', 20, 'delete_databasebackup');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (80, 'Can view Veritabanı Yedeği', 20, 'view_databasebackup');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (81, 'Can add crontab', 21, 'add_crontabschedule');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (82, 'Can change crontab', 21, 'change_crontabschedule');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (83, 'Can delete crontab', 21, 'delete_crontabschedule');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (84, 'Can view crontab', 21, 'view_crontabschedule');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (85, 'Can add interval', 22, 'add_intervalschedule');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (86, 'Can change interval', 22, 'change_intervalschedule');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (87, 'Can delete interval', 22, 'delete_intervalschedule');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (88, 'Can view interval', 22, 'view_intervalschedule');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (89, 'Can add periodic task', 23, 'add_periodictask');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (90, 'Can change periodic task', 23, 'change_periodictask');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (91, 'Can delete periodic task', 23, 'delete_periodictask');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (92, 'Can view periodic task', 23, 'view_periodictask');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (93, 'Can add periodic task track', 24, 'add_periodictasks');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (94, 'Can change periodic task track', 24, 'change_periodictasks');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (95, 'Can delete periodic task track', 24, 'delete_periodictasks');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (96, 'Can view periodic task track', 24, 'view_periodictasks');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (97, 'Can add solar event', 25, 'add_solarschedule');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (98, 'Can change solar event', 25, 'change_solarschedule');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (99, 'Can delete solar event', 25, 'delete_solarschedule');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (100, 'Can view solar event', 25, 'view_solarschedule');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (101, 'Can add clocked', 26, 'add_clockedschedule');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (102, 'Can change clocked', 26, 'change_clockedschedule');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (103, 'Can delete clocked', 26, 'delete_clockedschedule');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (104, 'Can view clocked', 26, 'view_clockedschedule');
-- Table: backup_databasebackup
DROP TABLE IF EXISTS backup_databasebackup CASCADE;
CREATE TABLE backup_databasebackup (
id BIGINT NOT NULL,
name VARCHAR(255) NOT NULL,
file_path VARCHAR(500),
file_size BIGINT,
status VARCHAR(20) NOT NULL,
backup_type VARCHAR(20) NOT NULL,
created_at TIMESTAMP WITH TIME ZONE NOT NULL,
completed_at TIMESTAMP WITH TIME ZONE,
error_message TEXT,
notes TEXT,
created_by_id BIGINT
);
-- Data for table: backup_databasebackup
INSERT INTO backup_databasebackup (id, name, file_path, file_size, status, backup_type, created_at, completed_at, error_message, notes, created_by_id) VALUES (15, 'Manuel Yedek - 2025-12-22 18:09:22', NULL, NULL, 'in_progress', 'manual', '2025-12-22 18:09:22.113009+00:00', NULL, NULL, NULL, 1);
INSERT INTO backup_databasebackup (id, name, file_path, file_size, status, backup_type, created_at, completed_at, error_message, notes, created_by_id) VALUES (13, 'Manuel Yedek - 2025-12-22 17:50:15', '/Users/beyhan/Projeler/Python/server/backups/backup_server_dj_20251222_175016.sql', 44445, 'completed', 'manual', '2025-12-22 17:50:15.880005+00:00', '2025-12-22 17:50:16.493592+00:00', NULL, '', 1);
-- Table: banners
DROP TABLE IF EXISTS banners CASCADE;
CREATE TABLE banners (
id BIGINT NOT NULL,
color VARCHAR(25) NOT NULL,
title VARCHAR(254),
text1 VARCHAR(254),
text2 VARCHAR(254),
text4 VARCHAR(254),
text5 VARCHAR(254),
image VARCHAR(100) NOT NULL,
image_k VARCHAR(100),
image_k_txt VARCHAR(254),
is_active BOOLEAN NOT NULL,
created_at TIMESTAMP WITH TIME ZONE NOT NULL,
updated_at TIMESTAMP WITH TIME ZONE NOT NULL
);
-- Table: categories
DROP TABLE IF EXISTS categories CASCADE;
CREATE TABLE categories (
id BIGINT NOT NULL,
title VARCHAR(254) NOT NULL,
keywords VARCHAR(254) NOT NULL,
description VARCHAR(254) NOT NULL,
created_at TIMESTAMP WITH TIME ZONE NOT NULL,
updated_at TIMESTAMP WITH TIME ZONE NOT NULL,
is_active BOOLEAN NOT NULL,
order INTEGER NOT NULL,
slug VARCHAR(250) NOT NULL,
image VARCHAR(100),
parent_id BIGINT
);
-- Table: category_views
DROP TABLE IF EXISTS category_views CASCADE;
CREATE TABLE category_views (
id BIGINT NOT NULL,
ip_address INET NOT NULL,
user_agent TEXT,
created_at TIMESTAMP WITH TIME ZONE NOT NULL,
category_id BIGINT NOT NULL
);
-- Table: comments
DROP TABLE IF EXISTS comments CASCADE;
CREATE TABLE comments (
id BIGINT NOT NULL,
title VARCHAR(254) NOT NULL,
body TEXT NOT NULL,
created_at TIMESTAMP WITH TIME ZONE NOT NULL,
updated_at TIMESTAMP WITH TIME ZONE NOT NULL,
is_active BOOLEAN NOT NULL,
slug VARCHAR(50) NOT NULL,
parent_id BIGINT,
user_id BIGINT NOT NULL,
product_id BIGINT NOT NULL
);
-- Table: django_admin_log
DROP TABLE IF EXISTS django_admin_log CASCADE;
CREATE TABLE django_admin_log (
id INTEGER NOT NULL,
action_time TIMESTAMP WITH TIME ZONE NOT NULL,
object_id TEXT,
object_repr VARCHAR(200) NOT NULL,
action_flag SMALLINT NOT NULL,
change_message TEXT NOT NULL,
content_type_id INTEGER,
user_id BIGINT NOT NULL
);
-- Data for table: django_admin_log
INSERT INTO django_admin_log (id, action_time, object_id, object_repr, action_flag, change_message, content_type_id, user_id) VALUES (1, '2025-12-22 17:00:54.961166+00:00', '1', 'Yedek 1 - Bekliyor', 1, '[{"added": {}}]', 20, 1);
INSERT INTO django_admin_log (id, action_time, object_id, object_repr, action_flag, change_message, content_type_id, user_id) VALUES (2, '2025-12-22 17:01:10.019183+00:00', '1', 'Yedek 1 - Bekliyor', 2, '[]', 20, 1);
INSERT INTO django_admin_log (id, action_time, object_id, object_repr, action_flag, change_message, content_type_id, user_id) VALUES (3, '2025-12-22 17:08:18.352881+00:00', '2', 'Manuel Yedek - 2025-12-22 17:01:15 - Başarısız', 3, '', 20, 1);
INSERT INTO django_admin_log (id, action_time, object_id, object_repr, action_flag, change_message, content_type_id, user_id) VALUES (4, '2025-12-22 17:08:25.284922+00:00', '4', 'Manuel Yedek - 2025-12-22 17:05:18 - Başarısız', 3, '', 20, 1);
INSERT INTO django_admin_log (id, action_time, object_id, object_repr, action_flag, change_message, content_type_id, user_id) VALUES (5, '2025-12-22 17:08:30.992298+00:00', '3', 'Manuel Yedek - 2025-12-22 17:03:41 - Başarısız', 3, '', 20, 1);
INSERT INTO django_admin_log (id, action_time, object_id, object_repr, action_flag, change_message, content_type_id, user_id) VALUES (6, '2025-12-22 17:08:56.836202+00:00', '5', 'Manuel Yedek - 2025-12-22 17:06:15 - Tamamlandı', 3, '', 20, 1);
INSERT INTO django_admin_log (id, action_time, object_id, object_repr, action_flag, change_message, content_type_id, user_id) VALUES (7, '2025-12-22 17:32:09.624013+00:00', '7', 'Manuel Yedek - 2025-12-22 17:30:14 - Tamamlandı', 3, '', 20, 1);
INSERT INTO django_admin_log (id, action_time, object_id, object_repr, action_flag, change_message, content_type_id, user_id) VALUES (8, '2025-12-22 17:32:15.437591+00:00', '6', 'Manuel Yedek - 2025-12-22 17:09:20 - Tamamlandı', 3, '', 20, 1);
INSERT INTO django_admin_log (id, action_time, object_id, object_repr, action_flag, change_message, content_type_id, user_id) VALUES (9, '2025-12-22 17:35:52.413394+00:00', '8', 'Manuel Yedek - 2025-12-22 17:32:27 - Tamamlandı', 3, '', 20, 1);
INSERT INTO django_admin_log (id, action_time, object_id, object_repr, action_flag, change_message, content_type_id, user_id) VALUES (10, '2025-12-22 18:03:49.897584+00:00', '13', 'Manuel Yedek - 2025-12-22 17:50:15 - Tamamlandı', 2, '[{"changed": {"fields": ["Yedek Tipi"]}}]', 20, 1);
INSERT INTO django_admin_log (id, action_time, object_id, object_repr, action_flag, change_message, content_type_id, user_id) VALUES (11, '2025-12-22 18:08:37.961862+00:00', '11', 'Manuel Yedek - 2025-12-22 17:38:03 - Tamamlandı', 3, '', 20, 1);
INSERT INTO django_admin_log (id, action_time, object_id, object_repr, action_flag, change_message, content_type_id, user_id) VALUES (12, '2025-12-22 18:08:57.986969+00:00', '14', 'Manuel Yedek - 2025-12-22 18:07:38 - Tamamlandı', 3, '', 20, 1);
INSERT INTO django_admin_log (id, action_time, object_id, object_repr, action_flag, change_message, content_type_id, user_id) VALUES (13, '2025-12-22 18:09:03.531449+00:00', '12', 'Manuel Yedek - 2025-12-22 17:43:28 - Tamamlandı', 3, '', 20, 1);
INSERT INTO django_admin_log (id, action_time, object_id, object_repr, action_flag, change_message, content_type_id, user_id) VALUES (14, '2025-12-22 18:09:17.538540+00:00', '13', 'Manuel Yedek - 2025-12-22 17:50:15 - Tamamlandı', 2, '[{"changed": {"fields": ["Yedek Tipi"]}}]', 20, 1);
-- Table: django_celery_beat_clockedschedule
DROP TABLE IF EXISTS django_celery_beat_clockedschedule CASCADE;
CREATE TABLE django_celery_beat_clockedschedule (
id INTEGER NOT NULL,
clocked_time TIMESTAMP WITH TIME ZONE NOT NULL
);
-- Table: django_celery_beat_crontabschedule
DROP TABLE IF EXISTS django_celery_beat_crontabschedule CASCADE;
CREATE TABLE django_celery_beat_crontabschedule (
id INTEGER NOT NULL,
minute VARCHAR(240) NOT NULL,
hour VARCHAR(96) NOT NULL,
day_of_week VARCHAR(64) NOT NULL,
day_of_month VARCHAR(124) NOT NULL,
month_of_year VARCHAR(64) NOT NULL,
timezone VARCHAR(63) NOT NULL
);
-- Table: django_celery_beat_intervalschedule
DROP TABLE IF EXISTS django_celery_beat_intervalschedule CASCADE;
CREATE TABLE django_celery_beat_intervalschedule (
id INTEGER NOT NULL,
every INTEGER NOT NULL,
period VARCHAR(24) NOT NULL
);
-- Table: django_celery_beat_periodictask
DROP TABLE IF EXISTS django_celery_beat_periodictask CASCADE;
CREATE TABLE django_celery_beat_periodictask (
id INTEGER NOT NULL,
name VARCHAR(200) NOT NULL,
task VARCHAR(200) NOT NULL,
args TEXT NOT NULL,
kwargs TEXT NOT NULL,
queue VARCHAR(200),
exchange VARCHAR(200),
routing_key VARCHAR(200),
expires TIMESTAMP WITH TIME ZONE,
enabled BOOLEAN NOT NULL,
last_run_at TIMESTAMP WITH TIME ZONE,
total_run_count INTEGER NOT NULL,
date_changed TIMESTAMP WITH TIME ZONE NOT NULL,
description TEXT NOT NULL,
crontab_id INTEGER,
interval_id INTEGER,
solar_id INTEGER,
one_off BOOLEAN NOT NULL,
start_time TIMESTAMP WITH TIME ZONE,
priority INTEGER,
headers TEXT NOT NULL,
clocked_id INTEGER,
expire_seconds INTEGER
);
-- Table: django_celery_beat_periodictasks
DROP TABLE IF EXISTS django_celery_beat_periodictasks CASCADE;
CREATE TABLE django_celery_beat_periodictasks (
ident SMALLINT NOT NULL,
last_update TIMESTAMP WITH TIME ZONE NOT NULL
);
-- Table: django_celery_beat_solarschedule
DROP TABLE IF EXISTS django_celery_beat_solarschedule CASCADE;
CREATE TABLE django_celery_beat_solarschedule (
id INTEGER NOT NULL,
event VARCHAR(24) NOT NULL,
latitude NUMERIC NOT NULL,
longitude NUMERIC NOT NULL
);
-- Table: django_content_type
DROP TABLE IF EXISTS django_content_type CASCADE;
CREATE TABLE django_content_type (
id INTEGER NOT NULL,
app_label VARCHAR(100) NOT NULL,
model VARCHAR(100) NOT NULL
);
-- Data for table: django_content_type
INSERT INTO django_content_type (id, app_label, model) VALUES (1, 'admin', 'logentry');
INSERT INTO django_content_type (id, app_label, model) VALUES (2, 'auth', 'group');
INSERT INTO django_content_type (id, app_label, model) VALUES (3, 'auth', 'permission');
INSERT INTO django_content_type (id, app_label, model) VALUES (4, 'contenttypes', 'contenttype');
INSERT INTO django_content_type (id, app_label, model) VALUES (5, 'sessions', 'session');
INSERT INTO django_content_type (id, app_label, model) VALUES (6, 'social_django', 'association');
INSERT INTO django_content_type (id, app_label, model) VALUES (7, 'social_django', 'code');
INSERT INTO django_content_type (id, app_label, model) VALUES (8, 'social_django', 'nonce');
INSERT INTO django_content_type (id, app_label, model) VALUES (9, 'social_django', 'partial');
INSERT INTO django_content_type (id, app_label, model) VALUES (10, 'social_django', 'usersocialauth');
INSERT INTO django_content_type (id, app_label, model) VALUES (11, 'sites', 'site');
INSERT INTO django_content_type (id, app_label, model) VALUES (12, 'accounts', 'customuser');
INSERT INTO django_content_type (id, app_label, model) VALUES (13, 'settings', 'banner');
INSERT INTO django_content_type (id, app_label, model) VALUES (14, 'settings', 'setting');
INSERT INTO django_content_type (id, app_label, model) VALUES (15, 'blog', 'category');
INSERT INTO django_content_type (id, app_label, model) VALUES (16, 'blog', 'categoryview');
INSERT INTO django_content_type (id, app_label, model) VALUES (17, 'blog', 'comment');
INSERT INTO django_content_type (id, app_label, model) VALUES (18, 'blog', 'post');
INSERT INTO django_content_type (id, app_label, model) VALUES (19, 'blog', 'tags');
INSERT INTO django_content_type (id, app_label, model) VALUES (20, 'backup', 'databasebackup');
INSERT INTO django_content_type (id, app_label, model) VALUES (21, 'django_celery_beat', 'crontabschedule');
INSERT INTO django_content_type (id, app_label, model) VALUES (22, 'django_celery_beat', 'intervalschedule');
INSERT INTO django_content_type (id, app_label, model) VALUES (23, 'django_celery_beat', 'periodictask');
INSERT INTO django_content_type (id, app_label, model) VALUES (24, 'django_celery_beat', 'periodictasks');
INSERT INTO django_content_type (id, app_label, model) VALUES (25, 'django_celery_beat', 'solarschedule');
INSERT INTO django_content_type (id, app_label, model) VALUES (26, 'django_celery_beat', 'clockedschedule');
-- Table: django_migrations
DROP TABLE IF EXISTS django_migrations CASCADE;
CREATE TABLE django_migrations (
id BIGINT NOT NULL,
app VARCHAR(255) NOT NULL,
name VARCHAR(255) NOT NULL,
applied TIMESTAMP WITH TIME ZONE NOT NULL
);
-- Data for table: django_migrations
INSERT INTO django_migrations (id, app, name, applied) VALUES (1, 'contenttypes', '0001_initial', '2025-12-22 16:57:19.217932+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (2, 'contenttypes', '0002_remove_content_type_name', '2025-12-22 16:57:19.234555+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (3, 'auth', '0001_initial', '2025-12-22 16:57:19.434147+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (4, 'auth', '0002_alter_permission_name_max_length', '2025-12-22 16:57:19.446206+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (5, 'auth', '0003_alter_user_email_max_length', '2025-12-22 16:57:19.455809+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (6, 'auth', '0004_alter_user_username_opts', '2025-12-22 16:57:19.465593+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (7, 'auth', '0005_alter_user_last_login_null', '2025-12-22 16:57:19.475691+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (8, 'auth', '0006_require_contenttypes_0002', '2025-12-22 16:57:19.481434+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (9, 'auth', '0007_alter_validators_add_error_messages', '2025-12-22 16:57:19.565856+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (10, 'auth', '0008_alter_user_username_max_length', '2025-12-22 16:57:19.592172+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (11, 'auth', '0009_alter_user_last_name_max_length', '2025-12-22 16:57:19.603096+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (12, 'auth', '0010_alter_group_name_max_length', '2025-12-22 16:57:19.625591+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (13, 'auth', '0011_update_proxy_permissions', '2025-12-22 16:57:19.634914+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (14, 'auth', '0012_alter_user_first_name_max_length', '2025-12-22 16:57:19.645268+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (15, 'accounts', '0001_initial', '2025-12-22 16:57:19.898703+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (16, 'admin', '0001_initial', '2025-12-22 16:57:19.967758+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (17, 'admin', '0002_logentry_remove_auto_add', '2025-12-22 16:57:19.980668+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (18, 'admin', '0003_logentry_add_action_flag_choices', '2025-12-22 16:57:19.994932+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (19, 'backup', '0001_initial', '2025-12-22 16:57:20.047172+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (20, 'blog', '0001_initial', '2025-12-22 16:57:20.451373+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (21, 'sessions', '0001_initial', '2025-12-22 16:57:20.596961+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (22, 'settings', '0001_initial', '2025-12-22 16:57:20.623314+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (23, 'sites', '0001_initial', '2025-12-22 16:57:20.634939+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (24, 'sites', '0002_alter_domain_unique', '2025-12-22 16:57:20.648215+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (25, 'default', '0001_initial', '2025-12-22 16:57:20.743912+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (26, 'social_auth', '0001_initial', '2025-12-22 16:57:20.747238+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (27, 'social_django', '0001_initial', '2025-12-22 16:57:20.750337+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (28, 'default', '0002_add_related_name', '2025-12-22 16:57:20.772416+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (29, 'social_auth', '0002_add_related_name', '2025-12-22 16:57:20.776564+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (30, 'social_django', '0002_add_related_name', '2025-12-22 16:57:20.778681+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (31, 'default', '0003_alter_email_max_length', '2025-12-22 16:57:20.797950+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (32, 'social_auth', '0003_alter_email_max_length', '2025-12-22 16:57:20.800526+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (33, 'social_django', '0003_alter_email_max_length', '2025-12-22 16:57:20.802697+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (34, 'default', '0004_auto_20160423_0400', '2025-12-22 16:57:20.818189+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (35, 'social_auth', '0004_auto_20160423_0400', '2025-12-22 16:57:20.821978+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (36, 'social_django', '0004_auto_20160423_0400', '2025-12-22 16:57:20.824686+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (37, 'social_auth', '0005_auto_20160727_2333', '2025-12-22 16:57:20.838781+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (38, 'social_django', '0005_auto_20160727_2333', '2025-12-22 16:57:20.842005+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (39, 'social_django', '0006_partial', '2025-12-22 16:57:20.882162+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (40, 'social_django', '0007_code_timestamp', '2025-12-22 16:57:21.016558+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (41, 'social_django', '0008_partial_timestamp', '2025-12-22 16:57:21.036847+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (42, 'social_django', '0009_auto_20191118_0520', '2025-12-22 16:57:21.078912+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (43, 'social_django', '0010_uid_db_index', '2025-12-22 16:57:21.103380+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (44, 'social_django', '0011_alter_id_fields', '2025-12-22 16:57:21.271476+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (45, 'social_django', '0012_usersocialauth_extra_data_new', '2025-12-22 16:57:21.315237+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (46, 'social_django', '0013_migrate_extra_data', '2025-12-22 16:57:21.359048+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (47, 'social_django', '0014_remove_usersocialauth_extra_data', '2025-12-22 16:57:21.387186+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (48, 'social_django', '0015_rename_extra_data_new_usersocialauth_extra_data', '2025-12-22 16:57:21.411254+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (49, 'social_django', '0016_alter_usersocialauth_extra_data', '2025-12-22 16:57:21.425493+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (50, 'social_django', '0017_usersocialauth_user_social_auth_uid_required', '2025-12-22 16:57:21.447520+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (51, 'django_celery_beat', '0001_initial', '2025-12-22 17:29:12.618773+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (52, 'django_celery_beat', '0002_auto_20161118_0346', '2025-12-22 17:29:12.644272+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (53, 'django_celery_beat', '0003_auto_20161209_0049', '2025-12-22 17:29:12.661945+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (54, 'django_celery_beat', '0004_auto_20170221_0000', '2025-12-22 17:29:12.669274+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (55, 'django_celery_beat', '0005_add_solarschedule_events_choices', '2025-12-22 17:29:12.678019+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (56, 'django_celery_beat', '0006_auto_20180322_0932', '2025-12-22 17:29:12.752211+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (57, 'django_celery_beat', '0007_auto_20180521_0826', '2025-12-22 17:29:12.793017+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (58, 'django_celery_beat', '0008_auto_20180914_1922', '2025-12-22 17:29:12.831420+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (59, 'django_celery_beat', '0006_auto_20180210_1226', '2025-12-22 17:29:12.856887+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (60, 'django_celery_beat', '0006_periodictask_priority', '2025-12-22 17:29:12.877901+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (61, 'django_celery_beat', '0009_periodictask_headers', '2025-12-22 17:29:12.902729+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (62, 'django_celery_beat', '0010_auto_20190429_0326', '2025-12-22 17:29:13.109071+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (63, 'django_celery_beat', '0011_auto_20190508_0153', '2025-12-22 17:29:13.153527+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (64, 'django_celery_beat', '0012_periodictask_expire_seconds', '2025-12-22 17:29:13.170247+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (65, 'django_celery_beat', '0013_auto_20200609_0727', '2025-12-22 17:29:13.182913+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (66, 'django_celery_beat', '0014_remove_clockedschedule_enabled', '2025-12-22 17:29:13.197676+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (67, 'django_celery_beat', '0015_edit_solarschedule_events_choices', '2025-12-22 17:29:13.207482+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (68, 'django_celery_beat', '0016_alter_crontabschedule_timezone', '2025-12-22 17:29:13.224397+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (69, 'django_celery_beat', '0017_alter_crontabschedule_month_of_year', '2025-12-22 17:29:13.238625+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (70, 'django_celery_beat', '0018_improve_crontab_helptext', '2025-12-22 17:29:13.252445+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (71, 'django_celery_beat', '0019_alter_periodictasks_options', '2025-12-22 17:29:13.259425+00:00');
-- Table: django_session
DROP TABLE IF EXISTS django_session CASCADE;
CREATE TABLE django_session (
session_key VARCHAR(40) NOT NULL,
session_data TEXT NOT NULL,
expire_date TIMESTAMP WITH TIME ZONE NOT NULL
);
-- Data for table: django_session
INSERT INTO django_session (session_key, session_data, expire_date) VALUES ('e7jyr13wedmqdkjukqb35t2pyylkbvwz', '.eJxVjEEOwiAQRe_C2hBgpKBL9z0DmWFGqRpISrsy3l2bdKHb_977L5VwXUpau8xpYnVWVh1-N8L8kLoBvmO9NZ1bXeaJ9KbonXY9NpbnZXf_Dgr28q0F0bKTEGNG70Uie8vgLbGBYxQbwBHlwQ0szoILOQsDwMmZeKVgvHp_APiKN_E:1vXjGo:c9NPOwqzmQXV6RsDHkclP-w4ogI8VDPbV0KQilsiW6Y', '2026-01-05 17:00:30.494599+00:00');
-- Table: django_site
DROP TABLE IF EXISTS django_site CASCADE;
CREATE TABLE django_site (
id INTEGER NOT NULL,
domain VARCHAR(100) NOT NULL,
name VARCHAR(50) NOT NULL
);
-- Data for table: django_site
INSERT INTO django_site (id, domain, name) VALUES (1, 'example.com', 'example.com');
-- Table: posts
DROP TABLE IF EXISTS posts CASCADE;
CREATE TABLE posts (
id BIGINT NOT NULL,
title VARCHAR(254) NOT NULL,
content TEXT,
keywords VARCHAR(254) NOT NULL,
image VARCHAR(100),
video VARCHAR(254),
slug VARCHAR(250) NOT NULL,
created_at TIMESTAMP WITH TIME ZONE NOT NULL,
updated_at TIMESTAMP WITH TIME ZONE NOT NULL,
is_active BOOLEAN NOT NULL,
is_front BOOLEAN NOT NULL,
parent_id BIGINT
);
-- Table: posts_categories
DROP TABLE IF EXISTS posts_categories CASCADE;
CREATE TABLE posts_categories (
id BIGINT NOT NULL,
post_id BIGINT NOT NULL,
category_id BIGINT NOT NULL
);
-- Table: posts_tags
DROP TABLE IF EXISTS posts_tags CASCADE;
CREATE TABLE posts_tags (
id BIGINT NOT NULL,
post_id BIGINT NOT NULL,
tags_id BIGINT NOT NULL
);
-- Table: settings
DROP TABLE IF EXISTS settings CASCADE;
CREATE TABLE settings (
id BIGINT NOT NULL,
title VARCHAR(254) NOT NULL,
meta_title VARCHAR(254) NOT NULL,
meta_description VARCHAR(254) NOT NULL,
phone VARCHAR(254) NOT NULL,
url VARCHAR(254),
email VARCHAR(254) NOT NULL,
facebook VARCHAR(254),
x VARCHAR(254),
instagram VARCHAR(254),
whatsapp VARCHAR(254),
slogan VARCHAR(254),
w_logo VARCHAR(100),
b_logo VARCHAR(100),
created_at TIMESTAMP WITH TIME ZONE NOT NULL,
updated_at TIMESTAMP WITH TIME ZONE NOT NULL,
is_active BOOLEAN NOT NULL
);
-- Table: social_auth_association
DROP TABLE IF EXISTS social_auth_association CASCADE;
CREATE TABLE social_auth_association (
id BIGINT NOT NULL,
server_url VARCHAR(255) NOT NULL,
handle VARCHAR(255) NOT NULL,
secret VARCHAR(255) NOT NULL,
issued INTEGER NOT NULL,
lifetime INTEGER NOT NULL,
assoc_type VARCHAR(64) NOT NULL
);
-- Table: social_auth_code
DROP TABLE IF EXISTS social_auth_code CASCADE;
CREATE TABLE social_auth_code (
id BIGINT NOT NULL,
email VARCHAR(254) NOT NULL,
code VARCHAR(32) NOT NULL,
verified BOOLEAN NOT NULL,
timestamp TIMESTAMP WITH TIME ZONE NOT NULL
);
-- Table: social_auth_nonce
DROP TABLE IF EXISTS social_auth_nonce CASCADE;
CREATE TABLE social_auth_nonce (
id BIGINT NOT NULL,
server_url VARCHAR(255) NOT NULL,
timestamp INTEGER NOT NULL,
salt VARCHAR(65) NOT NULL
);
-- Table: social_auth_partial
DROP TABLE IF EXISTS social_auth_partial CASCADE;
CREATE TABLE social_auth_partial (
id BIGINT NOT NULL,
token VARCHAR(32) NOT NULL,
next_step SMALLINT NOT NULL,
backend VARCHAR(32) NOT NULL,
timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
data JSONB NOT NULL
);
-- Table: social_auth_usersocialauth
DROP TABLE IF EXISTS social_auth_usersocialauth CASCADE;
CREATE TABLE social_auth_usersocialauth (
id BIGINT NOT NULL,
provider VARCHAR(32) NOT NULL,
uid VARCHAR(255) NOT NULL,
user_id BIGINT NOT NULL,
created TIMESTAMP WITH TIME ZONE NOT NULL,
modified TIMESTAMP WITH TIME ZONE NOT NULL,
extra_data JSONB NOT NULL
);
-- Table: tags
DROP TABLE IF EXISTS tags CASCADE;
CREATE TABLE tags (
id BIGINT NOT NULL,
tag VARCHAR(254) NOT NULL,
created_at TIMESTAMP WITH TIME ZONE NOT NULL,
updated_at TIMESTAMP WITH TIME ZONE NOT NULL,
is_active BOOLEAN NOT NULL
);
-- Reset sequences
SELECT setval('django_migrations_id_seq', (SELECT COALESCE(MAX(id), 1) FROM django_migrations));
SELECT setval('django_content_type_id_seq', (SELECT COALESCE(MAX(id), 1) FROM django_content_type));
SELECT setval('auth_permission_id_seq', (SELECT COALESCE(MAX(id), 1) FROM auth_permission));
SELECT setval('auth_group_id_seq', (SELECT COALESCE(MAX(id), 1) FROM auth_group));
SELECT setval('auth_group_permissions_id_seq', (SELECT COALESCE(MAX(id), 1) FROM auth_group_permissions));
SELECT setval('accounts_customuser_id_seq', (SELECT COALESCE(MAX(id), 1) FROM accounts_customuser));
SELECT setval('accounts_customuser_groups_id_seq', (SELECT COALESCE(MAX(id), 1) FROM accounts_customuser_groups));
SELECT setval('accounts_customuser_user_permissions_id_seq', (SELECT COALESCE(MAX(id), 1) FROM accounts_customuser_user_permissions));
SELECT setval('django_admin_log_id_seq', (SELECT COALESCE(MAX(id), 1) FROM django_admin_log));
SELECT setval('backup_databasebackup_id_seq', (SELECT COALESCE(MAX(id), 1) FROM backup_databasebackup));
SELECT setval('tags_id_seq', (SELECT COALESCE(MAX(id), 1) FROM tags));
SELECT setval('categories_id_seq', (SELECT COALESCE(MAX(id), 1) FROM categories));
SELECT setval('posts_id_seq', (SELECT COALESCE(MAX(id), 1) FROM posts));
SELECT setval('posts_categories_id_seq', (SELECT COALESCE(MAX(id), 1) FROM posts_categories));
SELECT setval('posts_tags_id_seq', (SELECT COALESCE(MAX(id), 1) FROM posts_tags));
SELECT setval('category_views_id_seq', (SELECT COALESCE(MAX(id), 1) FROM category_views));
SELECT setval('comments_id_seq', (SELECT COALESCE(MAX(id), 1) FROM comments));
SELECT setval('banners_id_seq', (SELECT COALESCE(MAX(id), 1) FROM banners));
SELECT setval('settings_id_seq', (SELECT COALESCE(MAX(id), 1) FROM settings));
SELECT setval('django_site_id_seq', (SELECT COALESCE(MAX(id), 1) FROM django_site));
SELECT setval('social_auth_association_id_seq', (SELECT COALESCE(MAX(id), 1) FROM social_auth_association));
SELECT setval('social_auth_code_id_seq', (SELECT COALESCE(MAX(id), 1) FROM social_auth_code));
SELECT setval('social_auth_nonce_id_seq', (SELECT COALESCE(MAX(id), 1) FROM social_auth_nonce));
SELECT setval('social_auth_usersocialauth_id_seq', (SELECT COALESCE(MAX(id), 1) FROM social_auth_usersocialauth));
SELECT setval('social_auth_partial_id_seq', (SELECT COALESCE(MAX(id), 1) FROM social_auth_partial));
SELECT setval('django_celery_beat_crontabschedule_id_seq', (SELECT COALESCE(MAX(id), 1) FROM django_celery_beat_crontabschedule));
SELECT setval('django_celery_beat_intervalschedule_id_seq', (SELECT COALESCE(MAX(id), 1) FROM django_celery_beat_intervalschedule));
SELECT setval('django_celery_beat_periodictask_id_seq', (SELECT COALESCE(MAX(id), 1) FROM django_celery_beat_periodictask));
SELECT setval('django_celery_beat_solarschedule_id_seq', (SELECT COALESCE(MAX(id), 1) FROM django_celery_beat_solarschedule));
SELECT setval('django_celery_beat_clockedschedule_id_seq', (SELECT COALESCE(MAX(id), 1) FROM django_celery_beat_clockedschedule));

View File

@@ -0,0 +1,678 @@
-- PostgreSQL Database Backup
-- Database: server_dj
-- Date: 2025-12-22 18:34:13.266916
-- Created by Django Backup System using psycopg2
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SET check_function_bodies = false;
SET client_min_messages = warning;
-- Table: accounts_customuser
DROP TABLE IF EXISTS accounts_customuser CASCADE;
CREATE TABLE accounts_customuser (
id BIGINT NOT NULL,
password VARCHAR(128) NOT NULL,
last_login TIMESTAMP WITH TIME ZONE,
is_superuser BOOLEAN NOT NULL,
email VARCHAR(254) NOT NULL,
first_name VARCHAR(150) NOT NULL,
last_name VARCHAR(150) NOT NULL,
is_staff BOOLEAN NOT NULL,
is_active BOOLEAN NOT NULL,
date_joined TIMESTAMP WITH TIME ZONE NOT NULL
);
-- Data for table: accounts_customuser
INSERT INTO accounts_customuser (id, password, last_login, is_superuser, email, first_name, last_name, is_staff, is_active, date_joined) VALUES (1, 'pbkdf2_sha256$1200000$93xPBCOPbW1XXQzUIvHCOc$gO1/rPxbbMoz0kHfYfhBibSEaW4OvXTw/Mf+QEcCCrY=', '2025-12-22 17:00:30.489489+00:00', True, 'beyhan@beyhan.dev', '', '', True, True, '2025-12-22 17:00:19.382231+00:00');
-- Table: accounts_customuser_groups
DROP TABLE IF EXISTS accounts_customuser_groups CASCADE;
CREATE TABLE accounts_customuser_groups (
id BIGINT NOT NULL,
customuser_id BIGINT NOT NULL,
group_id INTEGER NOT NULL
);
-- Table: accounts_customuser_user_permissions
DROP TABLE IF EXISTS accounts_customuser_user_permissions CASCADE;
CREATE TABLE accounts_customuser_user_permissions (
id BIGINT NOT NULL,
customuser_id BIGINT NOT NULL,
permission_id INTEGER NOT NULL
);
-- Table: auth_group
DROP TABLE IF EXISTS auth_group CASCADE;
CREATE TABLE auth_group (
id INTEGER NOT NULL,
name VARCHAR(150) NOT NULL
);
-- Table: auth_group_permissions
DROP TABLE IF EXISTS auth_group_permissions CASCADE;
CREATE TABLE auth_group_permissions (
id BIGINT NOT NULL,
group_id INTEGER NOT NULL,
permission_id INTEGER NOT NULL
);
-- Table: auth_permission
DROP TABLE IF EXISTS auth_permission CASCADE;
CREATE TABLE auth_permission (
id INTEGER NOT NULL,
name VARCHAR(255) NOT NULL,
content_type_id INTEGER NOT NULL,
codename VARCHAR(100) NOT NULL
);
-- Data for table: auth_permission
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (1, 'Can add log entry', 1, 'add_logentry');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (2, 'Can change log entry', 1, 'change_logentry');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (3, 'Can delete log entry', 1, 'delete_logentry');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (4, 'Can view log entry', 1, 'view_logentry');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (5, 'Can add permission', 3, 'add_permission');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (6, 'Can change permission', 3, 'change_permission');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (7, 'Can delete permission', 3, 'delete_permission');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (8, 'Can view permission', 3, 'view_permission');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (9, 'Can add group', 2, 'add_group');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (10, 'Can change group', 2, 'change_group');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (11, 'Can delete group', 2, 'delete_group');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (12, 'Can view group', 2, 'view_group');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (13, 'Can add content type', 4, 'add_contenttype');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (14, 'Can change content type', 4, 'change_contenttype');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (15, 'Can delete content type', 4, 'delete_contenttype');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (16, 'Can view content type', 4, 'view_contenttype');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (17, 'Can add session', 5, 'add_session');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (18, 'Can change session', 5, 'change_session');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (19, 'Can delete session', 5, 'delete_session');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (20, 'Can view session', 5, 'view_session');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (21, 'Can add association', 6, 'add_association');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (22, 'Can change association', 6, 'change_association');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (23, 'Can delete association', 6, 'delete_association');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (24, 'Can view association', 6, 'view_association');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (25, 'Can add code', 7, 'add_code');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (26, 'Can change code', 7, 'change_code');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (27, 'Can delete code', 7, 'delete_code');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (28, 'Can view code', 7, 'view_code');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (29, 'Can add nonce', 8, 'add_nonce');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (30, 'Can change nonce', 8, 'change_nonce');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (31, 'Can delete nonce', 8, 'delete_nonce');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (32, 'Can view nonce', 8, 'view_nonce');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (33, 'Can add user social auth', 10, 'add_usersocialauth');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (34, 'Can change user social auth', 10, 'change_usersocialauth');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (35, 'Can delete user social auth', 10, 'delete_usersocialauth');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (36, 'Can view user social auth', 10, 'view_usersocialauth');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (37, 'Can add partial', 9, 'add_partial');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (38, 'Can change partial', 9, 'change_partial');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (39, 'Can delete partial', 9, 'delete_partial');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (40, 'Can view partial', 9, 'view_partial');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (41, 'Can add site', 11, 'add_site');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (42, 'Can change site', 11, 'change_site');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (43, 'Can delete site', 11, 'delete_site');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (44, 'Can view site', 11, 'view_site');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (45, 'Can add user', 12, 'add_customuser');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (46, 'Can change user', 12, 'change_customuser');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (47, 'Can delete user', 12, 'delete_customuser');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (48, 'Can view user', 12, 'view_customuser');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (49, 'Can add Banner', 13, 'add_banner');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (50, 'Can change Banner', 13, 'change_banner');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (51, 'Can delete Banner', 13, 'delete_banner');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (52, 'Can view Banner', 13, 'view_banner');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (53, 'Can add Site Ayarı', 14, 'add_setting');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (54, 'Can change Site Ayarı', 14, 'change_setting');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (55, 'Can delete Site Ayarı', 14, 'delete_setting');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (56, 'Can view Site Ayarı', 14, 'view_setting');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (57, 'Can add Post Tagı', 19, 'add_tags');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (58, 'Can change Post Tagı', 19, 'change_tags');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (59, 'Can delete Post Tagı', 19, 'delete_tags');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (60, 'Can view Post Tagı', 19, 'view_tags');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (61, 'Can add Post Kategori', 15, 'add_category');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (62, 'Can change Post Kategori', 15, 'change_category');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (63, 'Can delete Post Kategori', 15, 'delete_category');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (64, 'Can view Post Kategori', 15, 'view_category');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (65, 'Can add Post', 18, 'add_post');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (66, 'Can change Post', 18, 'change_post');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (67, 'Can delete Post', 18, 'delete_post');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (68, 'Can view Post', 18, 'view_post');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (69, 'Can add Kategori Ziyareti', 16, 'add_categoryview');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (70, 'Can change Kategori Ziyareti', 16, 'change_categoryview');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (71, 'Can delete Kategori Ziyareti', 16, 'delete_categoryview');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (72, 'Can view Kategori Ziyareti', 16, 'view_categoryview');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (73, 'Can add Post Yorum', 17, 'add_comment');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (74, 'Can change Post Yorum', 17, 'change_comment');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (75, 'Can delete Post Yorum', 17, 'delete_comment');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (76, 'Can view Post Yorum', 17, 'view_comment');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (77, 'Can add Veritabanı Yedeği', 20, 'add_databasebackup');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (78, 'Can change Veritabanı Yedeği', 20, 'change_databasebackup');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (79, 'Can delete Veritabanı Yedeği', 20, 'delete_databasebackup');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (80, 'Can view Veritabanı Yedeği', 20, 'view_databasebackup');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (81, 'Can add crontab', 21, 'add_crontabschedule');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (82, 'Can change crontab', 21, 'change_crontabschedule');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (83, 'Can delete crontab', 21, 'delete_crontabschedule');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (84, 'Can view crontab', 21, 'view_crontabschedule');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (85, 'Can add interval', 22, 'add_intervalschedule');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (86, 'Can change interval', 22, 'change_intervalschedule');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (87, 'Can delete interval', 22, 'delete_intervalschedule');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (88, 'Can view interval', 22, 'view_intervalschedule');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (89, 'Can add periodic task', 23, 'add_periodictask');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (90, 'Can change periodic task', 23, 'change_periodictask');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (91, 'Can delete periodic task', 23, 'delete_periodictask');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (92, 'Can view periodic task', 23, 'view_periodictask');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (93, 'Can add periodic task track', 24, 'add_periodictasks');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (94, 'Can change periodic task track', 24, 'change_periodictasks');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (95, 'Can delete periodic task track', 24, 'delete_periodictasks');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (96, 'Can view periodic task track', 24, 'view_periodictasks');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (97, 'Can add solar event', 25, 'add_solarschedule');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (98, 'Can change solar event', 25, 'change_solarschedule');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (99, 'Can delete solar event', 25, 'delete_solarschedule');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (100, 'Can view solar event', 25, 'view_solarschedule');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (101, 'Can add clocked', 26, 'add_clockedschedule');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (102, 'Can change clocked', 26, 'change_clockedschedule');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (103, 'Can delete clocked', 26, 'delete_clockedschedule');
INSERT INTO auth_permission (id, name, content_type_id, codename) VALUES (104, 'Can view clocked', 26, 'view_clockedschedule');
-- Table: backup_databasebackup
DROP TABLE IF EXISTS backup_databasebackup CASCADE;
CREATE TABLE backup_databasebackup (
id BIGINT NOT NULL,
name VARCHAR(255) NOT NULL,
file_path VARCHAR(500),
file_size BIGINT,
status VARCHAR(20) NOT NULL,
backup_type VARCHAR(20) NOT NULL,
created_at TIMESTAMP WITH TIME ZONE NOT NULL,
completed_at TIMESTAMP WITH TIME ZONE,
error_message TEXT,
notes TEXT,
created_by_id BIGINT
);
-- Data for table: backup_databasebackup
INSERT INTO backup_databasebackup (id, name, file_path, file_size, status, backup_type, created_at, completed_at, error_message, notes, created_by_id) VALUES (15, 'Manuel Yedek - 2025-12-22 18:09:22', '/Users/beyhan/Projeler/Python/server/backups/backup_server_dj_20251222_180922.sql', 45094, 'completed', 'manual', '2025-12-22 18:09:22.113009+00:00', '2025-12-22 18:09:22.825989+00:00', NULL, NULL, 1);
INSERT INTO backup_databasebackup (id, name, file_path, file_size, status, backup_type, created_at, completed_at, error_message, notes, created_by_id) VALUES (16, 'Manuel Yedek - 2025-12-22 18:33:20', NULL, NULL, 'pending', 'manual', '2025-12-22 18:33:20.612696+00:00', NULL, NULL, NULL, 1);
INSERT INTO backup_databasebackup (id, name, file_path, file_size, status, backup_type, created_at, completed_at, error_message, notes, created_by_id) VALUES (17, 'Manuel Yedek - 2025-12-22 18:34:13', NULL, NULL, 'in_progress', 'manual', '2025-12-22 18:34:13.234428+00:00', NULL, NULL, NULL, 1);
INSERT INTO backup_databasebackup (id, name, file_path, file_size, status, backup_type, created_at, completed_at, error_message, notes, created_by_id) VALUES (13, 'Manuel Yedek - 2025-12-22 17:50:15', '/Users/beyhan/Projeler/Python/server/backups/backup_server_dj_20251222_175016.sql', 44445, 'completed', 'manual', '2025-12-22 17:50:15.880005+00:00', '2025-12-22 17:50:16.493592+00:00', NULL, '', 1);
-- Table: banners
DROP TABLE IF EXISTS banners CASCADE;
CREATE TABLE banners (
id BIGINT NOT NULL,
color VARCHAR(25) NOT NULL,
title VARCHAR(254),
text1 VARCHAR(254),
text2 VARCHAR(254),
text4 VARCHAR(254),
text5 VARCHAR(254),
image VARCHAR(100) NOT NULL,
image_k VARCHAR(100),
image_k_txt VARCHAR(254),
is_active BOOLEAN NOT NULL,
created_at TIMESTAMP WITH TIME ZONE NOT NULL,
updated_at TIMESTAMP WITH TIME ZONE NOT NULL
);
-- Table: categories
DROP TABLE IF EXISTS categories CASCADE;
CREATE TABLE categories (
id BIGINT NOT NULL,
title VARCHAR(254) NOT NULL,
keywords VARCHAR(254) NOT NULL,
description VARCHAR(254) NOT NULL,
created_at TIMESTAMP WITH TIME ZONE NOT NULL,
updated_at TIMESTAMP WITH TIME ZONE NOT NULL,
is_active BOOLEAN NOT NULL,
order INTEGER NOT NULL,
slug VARCHAR(250) NOT NULL,
image VARCHAR(100),
parent_id BIGINT
);
-- Table: category_views
DROP TABLE IF EXISTS category_views CASCADE;
CREATE TABLE category_views (
id BIGINT NOT NULL,
ip_address INET NOT NULL,
user_agent TEXT,
created_at TIMESTAMP WITH TIME ZONE NOT NULL,
category_id BIGINT NOT NULL
);
-- Table: comments
DROP TABLE IF EXISTS comments CASCADE;
CREATE TABLE comments (
id BIGINT NOT NULL,
title VARCHAR(254) NOT NULL,
body TEXT NOT NULL,
created_at TIMESTAMP WITH TIME ZONE NOT NULL,
updated_at TIMESTAMP WITH TIME ZONE NOT NULL,
is_active BOOLEAN NOT NULL,
slug VARCHAR(50) NOT NULL,
parent_id BIGINT,
user_id BIGINT NOT NULL,
product_id BIGINT NOT NULL
);
-- Table: django_admin_log
DROP TABLE IF EXISTS django_admin_log CASCADE;
CREATE TABLE django_admin_log (
id INTEGER NOT NULL,
action_time TIMESTAMP WITH TIME ZONE NOT NULL,
object_id TEXT,
object_repr VARCHAR(200) NOT NULL,
action_flag SMALLINT NOT NULL,
change_message TEXT NOT NULL,
content_type_id INTEGER,
user_id BIGINT NOT NULL
);
-- Data for table: django_admin_log
INSERT INTO django_admin_log (id, action_time, object_id, object_repr, action_flag, change_message, content_type_id, user_id) VALUES (1, '2025-12-22 17:00:54.961166+00:00', '1', 'Yedek 1 - Bekliyor', 1, '[{"added": {}}]', 20, 1);
INSERT INTO django_admin_log (id, action_time, object_id, object_repr, action_flag, change_message, content_type_id, user_id) VALUES (2, '2025-12-22 17:01:10.019183+00:00', '1', 'Yedek 1 - Bekliyor', 2, '[]', 20, 1);
INSERT INTO django_admin_log (id, action_time, object_id, object_repr, action_flag, change_message, content_type_id, user_id) VALUES (3, '2025-12-22 17:08:18.352881+00:00', '2', 'Manuel Yedek - 2025-12-22 17:01:15 - Başarısız', 3, '', 20, 1);
INSERT INTO django_admin_log (id, action_time, object_id, object_repr, action_flag, change_message, content_type_id, user_id) VALUES (4, '2025-12-22 17:08:25.284922+00:00', '4', 'Manuel Yedek - 2025-12-22 17:05:18 - Başarısız', 3, '', 20, 1);
INSERT INTO django_admin_log (id, action_time, object_id, object_repr, action_flag, change_message, content_type_id, user_id) VALUES (5, '2025-12-22 17:08:30.992298+00:00', '3', 'Manuel Yedek - 2025-12-22 17:03:41 - Başarısız', 3, '', 20, 1);
INSERT INTO django_admin_log (id, action_time, object_id, object_repr, action_flag, change_message, content_type_id, user_id) VALUES (6, '2025-12-22 17:08:56.836202+00:00', '5', 'Manuel Yedek - 2025-12-22 17:06:15 - Tamamlandı', 3, '', 20, 1);
INSERT INTO django_admin_log (id, action_time, object_id, object_repr, action_flag, change_message, content_type_id, user_id) VALUES (7, '2025-12-22 17:32:09.624013+00:00', '7', 'Manuel Yedek - 2025-12-22 17:30:14 - Tamamlandı', 3, '', 20, 1);
INSERT INTO django_admin_log (id, action_time, object_id, object_repr, action_flag, change_message, content_type_id, user_id) VALUES (8, '2025-12-22 17:32:15.437591+00:00', '6', 'Manuel Yedek - 2025-12-22 17:09:20 - Tamamlandı', 3, '', 20, 1);
INSERT INTO django_admin_log (id, action_time, object_id, object_repr, action_flag, change_message, content_type_id, user_id) VALUES (9, '2025-12-22 17:35:52.413394+00:00', '8', 'Manuel Yedek - 2025-12-22 17:32:27 - Tamamlandı', 3, '', 20, 1);
INSERT INTO django_admin_log (id, action_time, object_id, object_repr, action_flag, change_message, content_type_id, user_id) VALUES (10, '2025-12-22 18:03:49.897584+00:00', '13', 'Manuel Yedek - 2025-12-22 17:50:15 - Tamamlandı', 2, '[{"changed": {"fields": ["Yedek Tipi"]}}]', 20, 1);
INSERT INTO django_admin_log (id, action_time, object_id, object_repr, action_flag, change_message, content_type_id, user_id) VALUES (11, '2025-12-22 18:08:37.961862+00:00', '11', 'Manuel Yedek - 2025-12-22 17:38:03 - Tamamlandı', 3, '', 20, 1);
INSERT INTO django_admin_log (id, action_time, object_id, object_repr, action_flag, change_message, content_type_id, user_id) VALUES (12, '2025-12-22 18:08:57.986969+00:00', '14', 'Manuel Yedek - 2025-12-22 18:07:38 - Tamamlandı', 3, '', 20, 1);
INSERT INTO django_admin_log (id, action_time, object_id, object_repr, action_flag, change_message, content_type_id, user_id) VALUES (13, '2025-12-22 18:09:03.531449+00:00', '12', 'Manuel Yedek - 2025-12-22 17:43:28 - Tamamlandı', 3, '', 20, 1);
INSERT INTO django_admin_log (id, action_time, object_id, object_repr, action_flag, change_message, content_type_id, user_id) VALUES (14, '2025-12-22 18:09:17.538540+00:00', '13', 'Manuel Yedek - 2025-12-22 17:50:15 - Tamamlandı', 2, '[{"changed": {"fields": ["Yedek Tipi"]}}]', 20, 1);
-- Table: django_celery_beat_clockedschedule
DROP TABLE IF EXISTS django_celery_beat_clockedschedule CASCADE;
CREATE TABLE django_celery_beat_clockedschedule (
id INTEGER NOT NULL,
clocked_time TIMESTAMP WITH TIME ZONE NOT NULL
);
-- Table: django_celery_beat_crontabschedule
DROP TABLE IF EXISTS django_celery_beat_crontabschedule CASCADE;
CREATE TABLE django_celery_beat_crontabschedule (
id INTEGER NOT NULL,
minute VARCHAR(240) NOT NULL,
hour VARCHAR(96) NOT NULL,
day_of_week VARCHAR(64) NOT NULL,
day_of_month VARCHAR(124) NOT NULL,
month_of_year VARCHAR(64) NOT NULL,
timezone VARCHAR(63) NOT NULL
);
-- Table: django_celery_beat_intervalschedule
DROP TABLE IF EXISTS django_celery_beat_intervalschedule CASCADE;
CREATE TABLE django_celery_beat_intervalschedule (
id INTEGER NOT NULL,
every INTEGER NOT NULL,
period VARCHAR(24) NOT NULL
);
-- Table: django_celery_beat_periodictask
DROP TABLE IF EXISTS django_celery_beat_periodictask CASCADE;
CREATE TABLE django_celery_beat_periodictask (
id INTEGER NOT NULL,
name VARCHAR(200) NOT NULL,
task VARCHAR(200) NOT NULL,
args TEXT NOT NULL,
kwargs TEXT NOT NULL,
queue VARCHAR(200),
exchange VARCHAR(200),
routing_key VARCHAR(200),
expires TIMESTAMP WITH TIME ZONE,
enabled BOOLEAN NOT NULL,
last_run_at TIMESTAMP WITH TIME ZONE,
total_run_count INTEGER NOT NULL,
date_changed TIMESTAMP WITH TIME ZONE NOT NULL,
description TEXT NOT NULL,
crontab_id INTEGER,
interval_id INTEGER,
solar_id INTEGER,
one_off BOOLEAN NOT NULL,
start_time TIMESTAMP WITH TIME ZONE,
priority INTEGER,
headers TEXT NOT NULL,
clocked_id INTEGER,
expire_seconds INTEGER
);
-- Table: django_celery_beat_periodictasks
DROP TABLE IF EXISTS django_celery_beat_periodictasks CASCADE;
CREATE TABLE django_celery_beat_periodictasks (
ident SMALLINT NOT NULL,
last_update TIMESTAMP WITH TIME ZONE NOT NULL
);
-- Table: django_celery_beat_solarschedule
DROP TABLE IF EXISTS django_celery_beat_solarschedule CASCADE;
CREATE TABLE django_celery_beat_solarschedule (
id INTEGER NOT NULL,
event VARCHAR(24) NOT NULL,
latitude NUMERIC NOT NULL,
longitude NUMERIC NOT NULL
);
-- Table: django_content_type
DROP TABLE IF EXISTS django_content_type CASCADE;
CREATE TABLE django_content_type (
id INTEGER NOT NULL,
app_label VARCHAR(100) NOT NULL,
model VARCHAR(100) NOT NULL
);
-- Data for table: django_content_type
INSERT INTO django_content_type (id, app_label, model) VALUES (1, 'admin', 'logentry');
INSERT INTO django_content_type (id, app_label, model) VALUES (2, 'auth', 'group');
INSERT INTO django_content_type (id, app_label, model) VALUES (3, 'auth', 'permission');
INSERT INTO django_content_type (id, app_label, model) VALUES (4, 'contenttypes', 'contenttype');
INSERT INTO django_content_type (id, app_label, model) VALUES (5, 'sessions', 'session');
INSERT INTO django_content_type (id, app_label, model) VALUES (6, 'social_django', 'association');
INSERT INTO django_content_type (id, app_label, model) VALUES (7, 'social_django', 'code');
INSERT INTO django_content_type (id, app_label, model) VALUES (8, 'social_django', 'nonce');
INSERT INTO django_content_type (id, app_label, model) VALUES (9, 'social_django', 'partial');
INSERT INTO django_content_type (id, app_label, model) VALUES (10, 'social_django', 'usersocialauth');
INSERT INTO django_content_type (id, app_label, model) VALUES (11, 'sites', 'site');
INSERT INTO django_content_type (id, app_label, model) VALUES (12, 'accounts', 'customuser');
INSERT INTO django_content_type (id, app_label, model) VALUES (13, 'settings', 'banner');
INSERT INTO django_content_type (id, app_label, model) VALUES (14, 'settings', 'setting');
INSERT INTO django_content_type (id, app_label, model) VALUES (15, 'blog', 'category');
INSERT INTO django_content_type (id, app_label, model) VALUES (16, 'blog', 'categoryview');
INSERT INTO django_content_type (id, app_label, model) VALUES (17, 'blog', 'comment');
INSERT INTO django_content_type (id, app_label, model) VALUES (18, 'blog', 'post');
INSERT INTO django_content_type (id, app_label, model) VALUES (19, 'blog', 'tags');
INSERT INTO django_content_type (id, app_label, model) VALUES (20, 'backup', 'databasebackup');
INSERT INTO django_content_type (id, app_label, model) VALUES (21, 'django_celery_beat', 'crontabschedule');
INSERT INTO django_content_type (id, app_label, model) VALUES (22, 'django_celery_beat', 'intervalschedule');
INSERT INTO django_content_type (id, app_label, model) VALUES (23, 'django_celery_beat', 'periodictask');
INSERT INTO django_content_type (id, app_label, model) VALUES (24, 'django_celery_beat', 'periodictasks');
INSERT INTO django_content_type (id, app_label, model) VALUES (25, 'django_celery_beat', 'solarschedule');
INSERT INTO django_content_type (id, app_label, model) VALUES (26, 'django_celery_beat', 'clockedschedule');
-- Table: django_migrations
DROP TABLE IF EXISTS django_migrations CASCADE;
CREATE TABLE django_migrations (
id BIGINT NOT NULL,
app VARCHAR(255) NOT NULL,
name VARCHAR(255) NOT NULL,
applied TIMESTAMP WITH TIME ZONE NOT NULL
);
-- Data for table: django_migrations
INSERT INTO django_migrations (id, app, name, applied) VALUES (1, 'contenttypes', '0001_initial', '2025-12-22 16:57:19.217932+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (2, 'contenttypes', '0002_remove_content_type_name', '2025-12-22 16:57:19.234555+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (3, 'auth', '0001_initial', '2025-12-22 16:57:19.434147+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (4, 'auth', '0002_alter_permission_name_max_length', '2025-12-22 16:57:19.446206+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (5, 'auth', '0003_alter_user_email_max_length', '2025-12-22 16:57:19.455809+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (6, 'auth', '0004_alter_user_username_opts', '2025-12-22 16:57:19.465593+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (7, 'auth', '0005_alter_user_last_login_null', '2025-12-22 16:57:19.475691+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (8, 'auth', '0006_require_contenttypes_0002', '2025-12-22 16:57:19.481434+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (9, 'auth', '0007_alter_validators_add_error_messages', '2025-12-22 16:57:19.565856+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (10, 'auth', '0008_alter_user_username_max_length', '2025-12-22 16:57:19.592172+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (11, 'auth', '0009_alter_user_last_name_max_length', '2025-12-22 16:57:19.603096+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (12, 'auth', '0010_alter_group_name_max_length', '2025-12-22 16:57:19.625591+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (13, 'auth', '0011_update_proxy_permissions', '2025-12-22 16:57:19.634914+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (14, 'auth', '0012_alter_user_first_name_max_length', '2025-12-22 16:57:19.645268+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (15, 'accounts', '0001_initial', '2025-12-22 16:57:19.898703+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (16, 'admin', '0001_initial', '2025-12-22 16:57:19.967758+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (17, 'admin', '0002_logentry_remove_auto_add', '2025-12-22 16:57:19.980668+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (18, 'admin', '0003_logentry_add_action_flag_choices', '2025-12-22 16:57:19.994932+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (19, 'backup', '0001_initial', '2025-12-22 16:57:20.047172+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (20, 'blog', '0001_initial', '2025-12-22 16:57:20.451373+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (21, 'sessions', '0001_initial', '2025-12-22 16:57:20.596961+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (22, 'settings', '0001_initial', '2025-12-22 16:57:20.623314+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (23, 'sites', '0001_initial', '2025-12-22 16:57:20.634939+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (24, 'sites', '0002_alter_domain_unique', '2025-12-22 16:57:20.648215+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (25, 'default', '0001_initial', '2025-12-22 16:57:20.743912+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (26, 'social_auth', '0001_initial', '2025-12-22 16:57:20.747238+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (27, 'social_django', '0001_initial', '2025-12-22 16:57:20.750337+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (28, 'default', '0002_add_related_name', '2025-12-22 16:57:20.772416+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (29, 'social_auth', '0002_add_related_name', '2025-12-22 16:57:20.776564+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (30, 'social_django', '0002_add_related_name', '2025-12-22 16:57:20.778681+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (31, 'default', '0003_alter_email_max_length', '2025-12-22 16:57:20.797950+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (32, 'social_auth', '0003_alter_email_max_length', '2025-12-22 16:57:20.800526+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (33, 'social_django', '0003_alter_email_max_length', '2025-12-22 16:57:20.802697+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (34, 'default', '0004_auto_20160423_0400', '2025-12-22 16:57:20.818189+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (35, 'social_auth', '0004_auto_20160423_0400', '2025-12-22 16:57:20.821978+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (36, 'social_django', '0004_auto_20160423_0400', '2025-12-22 16:57:20.824686+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (37, 'social_auth', '0005_auto_20160727_2333', '2025-12-22 16:57:20.838781+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (38, 'social_django', '0005_auto_20160727_2333', '2025-12-22 16:57:20.842005+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (39, 'social_django', '0006_partial', '2025-12-22 16:57:20.882162+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (40, 'social_django', '0007_code_timestamp', '2025-12-22 16:57:21.016558+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (41, 'social_django', '0008_partial_timestamp', '2025-12-22 16:57:21.036847+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (42, 'social_django', '0009_auto_20191118_0520', '2025-12-22 16:57:21.078912+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (43, 'social_django', '0010_uid_db_index', '2025-12-22 16:57:21.103380+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (44, 'social_django', '0011_alter_id_fields', '2025-12-22 16:57:21.271476+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (45, 'social_django', '0012_usersocialauth_extra_data_new', '2025-12-22 16:57:21.315237+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (46, 'social_django', '0013_migrate_extra_data', '2025-12-22 16:57:21.359048+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (47, 'social_django', '0014_remove_usersocialauth_extra_data', '2025-12-22 16:57:21.387186+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (48, 'social_django', '0015_rename_extra_data_new_usersocialauth_extra_data', '2025-12-22 16:57:21.411254+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (49, 'social_django', '0016_alter_usersocialauth_extra_data', '2025-12-22 16:57:21.425493+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (50, 'social_django', '0017_usersocialauth_user_social_auth_uid_required', '2025-12-22 16:57:21.447520+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (51, 'django_celery_beat', '0001_initial', '2025-12-22 17:29:12.618773+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (52, 'django_celery_beat', '0002_auto_20161118_0346', '2025-12-22 17:29:12.644272+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (53, 'django_celery_beat', '0003_auto_20161209_0049', '2025-12-22 17:29:12.661945+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (54, 'django_celery_beat', '0004_auto_20170221_0000', '2025-12-22 17:29:12.669274+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (55, 'django_celery_beat', '0005_add_solarschedule_events_choices', '2025-12-22 17:29:12.678019+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (56, 'django_celery_beat', '0006_auto_20180322_0932', '2025-12-22 17:29:12.752211+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (57, 'django_celery_beat', '0007_auto_20180521_0826', '2025-12-22 17:29:12.793017+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (58, 'django_celery_beat', '0008_auto_20180914_1922', '2025-12-22 17:29:12.831420+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (59, 'django_celery_beat', '0006_auto_20180210_1226', '2025-12-22 17:29:12.856887+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (60, 'django_celery_beat', '0006_periodictask_priority', '2025-12-22 17:29:12.877901+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (61, 'django_celery_beat', '0009_periodictask_headers', '2025-12-22 17:29:12.902729+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (62, 'django_celery_beat', '0010_auto_20190429_0326', '2025-12-22 17:29:13.109071+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (63, 'django_celery_beat', '0011_auto_20190508_0153', '2025-12-22 17:29:13.153527+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (64, 'django_celery_beat', '0012_periodictask_expire_seconds', '2025-12-22 17:29:13.170247+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (65, 'django_celery_beat', '0013_auto_20200609_0727', '2025-12-22 17:29:13.182913+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (66, 'django_celery_beat', '0014_remove_clockedschedule_enabled', '2025-12-22 17:29:13.197676+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (67, 'django_celery_beat', '0015_edit_solarschedule_events_choices', '2025-12-22 17:29:13.207482+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (68, 'django_celery_beat', '0016_alter_crontabschedule_timezone', '2025-12-22 17:29:13.224397+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (69, 'django_celery_beat', '0017_alter_crontabschedule_month_of_year', '2025-12-22 17:29:13.238625+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (70, 'django_celery_beat', '0018_improve_crontab_helptext', '2025-12-22 17:29:13.252445+00:00');
INSERT INTO django_migrations (id, app, name, applied) VALUES (71, 'django_celery_beat', '0019_alter_periodictasks_options', '2025-12-22 17:29:13.259425+00:00');
-- Table: django_session
DROP TABLE IF EXISTS django_session CASCADE;
CREATE TABLE django_session (
session_key VARCHAR(40) NOT NULL,
session_data TEXT NOT NULL,
expire_date TIMESTAMP WITH TIME ZONE NOT NULL
);
-- Data for table: django_session
INSERT INTO django_session (session_key, session_data, expire_date) VALUES ('e7jyr13wedmqdkjukqb35t2pyylkbvwz', '.eJxVjEEOwiAQRe_C2hBgpKBL9z0DmWFGqRpISrsy3l2bdKHb_977L5VwXUpau8xpYnVWVh1-N8L8kLoBvmO9NZ1bXeaJ9KbonXY9NpbnZXf_Dgr28q0F0bKTEGNG70Uie8vgLbGBYxQbwBHlwQ0szoILOQsDwMmZeKVgvHp_APiKN_E:1vXjGo:c9NPOwqzmQXV6RsDHkclP-w4ogI8VDPbV0KQilsiW6Y', '2026-01-05 17:00:30.494599+00:00');
-- Table: django_site
DROP TABLE IF EXISTS django_site CASCADE;
CREATE TABLE django_site (
id INTEGER NOT NULL,
domain VARCHAR(100) NOT NULL,
name VARCHAR(50) NOT NULL
);
-- Data for table: django_site
INSERT INTO django_site (id, domain, name) VALUES (1, 'example.com', 'example.com');
-- Table: posts
DROP TABLE IF EXISTS posts CASCADE;
CREATE TABLE posts (
id BIGINT NOT NULL,
title VARCHAR(254) NOT NULL,
content TEXT,
keywords VARCHAR(254) NOT NULL,
image VARCHAR(100),
video VARCHAR(254),
slug VARCHAR(250) NOT NULL,
created_at TIMESTAMP WITH TIME ZONE NOT NULL,
updated_at TIMESTAMP WITH TIME ZONE NOT NULL,
is_active BOOLEAN NOT NULL,
is_front BOOLEAN NOT NULL,
parent_id BIGINT
);
-- Table: posts_categories
DROP TABLE IF EXISTS posts_categories CASCADE;
CREATE TABLE posts_categories (
id BIGINT NOT NULL,
post_id BIGINT NOT NULL,
category_id BIGINT NOT NULL
);
-- Table: posts_tags
DROP TABLE IF EXISTS posts_tags CASCADE;
CREATE TABLE posts_tags (
id BIGINT NOT NULL,
post_id BIGINT NOT NULL,
tags_id BIGINT NOT NULL
);
-- Table: settings
DROP TABLE IF EXISTS settings CASCADE;
CREATE TABLE settings (
id BIGINT NOT NULL,
title VARCHAR(254) NOT NULL,
meta_title VARCHAR(254) NOT NULL,
meta_description VARCHAR(254) NOT NULL,
phone VARCHAR(254) NOT NULL,
url VARCHAR(254),
email VARCHAR(254) NOT NULL,
facebook VARCHAR(254),
x VARCHAR(254),
instagram VARCHAR(254),
whatsapp VARCHAR(254),
slogan VARCHAR(254),
w_logo VARCHAR(100),
b_logo VARCHAR(100),
created_at TIMESTAMP WITH TIME ZONE NOT NULL,
updated_at TIMESTAMP WITH TIME ZONE NOT NULL,
is_active BOOLEAN NOT NULL
);
-- Table: social_auth_association
DROP TABLE IF EXISTS social_auth_association CASCADE;
CREATE TABLE social_auth_association (
id BIGINT NOT NULL,
server_url VARCHAR(255) NOT NULL,
handle VARCHAR(255) NOT NULL,
secret VARCHAR(255) NOT NULL,
issued INTEGER NOT NULL,
lifetime INTEGER NOT NULL,
assoc_type VARCHAR(64) NOT NULL
);
-- Table: social_auth_code
DROP TABLE IF EXISTS social_auth_code CASCADE;
CREATE TABLE social_auth_code (
id BIGINT NOT NULL,
email VARCHAR(254) NOT NULL,
code VARCHAR(32) NOT NULL,
verified BOOLEAN NOT NULL,
timestamp TIMESTAMP WITH TIME ZONE NOT NULL
);
-- Table: social_auth_nonce
DROP TABLE IF EXISTS social_auth_nonce CASCADE;
CREATE TABLE social_auth_nonce (
id BIGINT NOT NULL,
server_url VARCHAR(255) NOT NULL,
timestamp INTEGER NOT NULL,
salt VARCHAR(65) NOT NULL
);
-- Table: social_auth_partial
DROP TABLE IF EXISTS social_auth_partial CASCADE;
CREATE TABLE social_auth_partial (
id BIGINT NOT NULL,
token VARCHAR(32) NOT NULL,
next_step SMALLINT NOT NULL,
backend VARCHAR(32) NOT NULL,
timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
data JSONB NOT NULL
);
-- Table: social_auth_usersocialauth
DROP TABLE IF EXISTS social_auth_usersocialauth CASCADE;
CREATE TABLE social_auth_usersocialauth (
id BIGINT NOT NULL,
provider VARCHAR(32) NOT NULL,
uid VARCHAR(255) NOT NULL,
user_id BIGINT NOT NULL,
created TIMESTAMP WITH TIME ZONE NOT NULL,
modified TIMESTAMP WITH TIME ZONE NOT NULL,
extra_data JSONB NOT NULL
);
-- Table: tags
DROP TABLE IF EXISTS tags CASCADE;
CREATE TABLE tags (
id BIGINT NOT NULL,
tag VARCHAR(254) NOT NULL,
created_at TIMESTAMP WITH TIME ZONE NOT NULL,
updated_at TIMESTAMP WITH TIME ZONE NOT NULL,
is_active BOOLEAN NOT NULL
);
-- Reset sequences
SELECT setval('django_migrations_id_seq', (SELECT COALESCE(MAX(id), 1) FROM django_migrations));
SELECT setval('django_content_type_id_seq', (SELECT COALESCE(MAX(id), 1) FROM django_content_type));
SELECT setval('auth_permission_id_seq', (SELECT COALESCE(MAX(id), 1) FROM auth_permission));
SELECT setval('auth_group_id_seq', (SELECT COALESCE(MAX(id), 1) FROM auth_group));
SELECT setval('auth_group_permissions_id_seq', (SELECT COALESCE(MAX(id), 1) FROM auth_group_permissions));
SELECT setval('accounts_customuser_id_seq', (SELECT COALESCE(MAX(id), 1) FROM accounts_customuser));
SELECT setval('accounts_customuser_groups_id_seq', (SELECT COALESCE(MAX(id), 1) FROM accounts_customuser_groups));
SELECT setval('accounts_customuser_user_permissions_id_seq', (SELECT COALESCE(MAX(id), 1) FROM accounts_customuser_user_permissions));
SELECT setval('django_admin_log_id_seq', (SELECT COALESCE(MAX(id), 1) FROM django_admin_log));
SELECT setval('backup_databasebackup_id_seq', (SELECT COALESCE(MAX(id), 1) FROM backup_databasebackup));
SELECT setval('tags_id_seq', (SELECT COALESCE(MAX(id), 1) FROM tags));
SELECT setval('categories_id_seq', (SELECT COALESCE(MAX(id), 1) FROM categories));
SELECT setval('posts_id_seq', (SELECT COALESCE(MAX(id), 1) FROM posts));
SELECT setval('posts_categories_id_seq', (SELECT COALESCE(MAX(id), 1) FROM posts_categories));
SELECT setval('posts_tags_id_seq', (SELECT COALESCE(MAX(id), 1) FROM posts_tags));
SELECT setval('category_views_id_seq', (SELECT COALESCE(MAX(id), 1) FROM category_views));
SELECT setval('comments_id_seq', (SELECT COALESCE(MAX(id), 1) FROM comments));
SELECT setval('banners_id_seq', (SELECT COALESCE(MAX(id), 1) FROM banners));
SELECT setval('settings_id_seq', (SELECT COALESCE(MAX(id), 1) FROM settings));
SELECT setval('django_site_id_seq', (SELECT COALESCE(MAX(id), 1) FROM django_site));
SELECT setval('social_auth_association_id_seq', (SELECT COALESCE(MAX(id), 1) FROM social_auth_association));
SELECT setval('social_auth_code_id_seq', (SELECT COALESCE(MAX(id), 1) FROM social_auth_code));
SELECT setval('social_auth_nonce_id_seq', (SELECT COALESCE(MAX(id), 1) FROM social_auth_nonce));
SELECT setval('social_auth_usersocialauth_id_seq', (SELECT COALESCE(MAX(id), 1) FROM social_auth_usersocialauth));
SELECT setval('social_auth_partial_id_seq', (SELECT COALESCE(MAX(id), 1) FROM social_auth_partial));
SELECT setval('django_celery_beat_crontabschedule_id_seq', (SELECT COALESCE(MAX(id), 1) FROM django_celery_beat_crontabschedule));
SELECT setval('django_celery_beat_intervalschedule_id_seq', (SELECT COALESCE(MAX(id), 1) FROM django_celery_beat_intervalschedule));
SELECT setval('django_celery_beat_periodictask_id_seq', (SELECT COALESCE(MAX(id), 1) FROM django_celery_beat_periodictask));
SELECT setval('django_celery_beat_solarschedule_id_seq', (SELECT COALESCE(MAX(id), 1) FROM django_celery_beat_solarschedule));
SELECT setval('django_celery_beat_clockedschedule_id_seq', (SELECT COALESCE(MAX(id), 1) FROM django_celery_beat_clockedschedule));

0
blog/__init__.py Normal file
View File

95
blog/admin.py Normal file
View File

@@ -0,0 +1,95 @@
from django.contrib import admin
from django.utils.safestring import mark_safe
from blog.models import Category, Tags, Post, Comment, CategoryView
# Register your models here.
class PostAdmin(admin.ModelAdmin):
list_display = ('title', 'post_resim', 'is_active', 'post_kategorileri', 'slug')
list_filter = ('is_active', 'categories')
search_fields = ('title', 'is_active', 'slug', 'content')
list_editable = ('is_active', 'slug',) # Removed 'price' as it is not a field
class Meta:
model = Post
def formatted_hit_count(self, obj):
return obj.current_hit_count if obj.current_hit_count > 0 else '-'
formatted_hit_count.admin_order_field = 'hit_count'
formatted_hit_count.short_description = 'Hits'
def post_tags(self, obj):
tags = '<ul>'
for tag in obj.tags.all():
tags += '<li>' + tag.tag + '</li>'
tags += '</ul>'
return mark_safe(tags)
def post_kategorileri(self, obj):
html = '<ul>'
for category in obj.categories.all():
html += '<li>' + category.title + '</li>'
html += '</ul>'
return mark_safe(html)
def post_resim(self, obj):
if obj.image:
return mark_safe(
'<a href="/admin/post/post/{}/change/#id_images" onclick="window.location.href=\'/admin/post/post/{}/change/#id_images\'; return false;"><img src="{}" width="50" height="50" style="object-fit: cover; cursor: pointer;" title="Resmi değiştirmek için tıklayın" /></a>'.format(
obj.id, obj.id, obj.image.url))
return mark_safe(
'<a href="/admin/post/post/{}/change/#id_images" onclick="window.location.href=\'/admin/post/post/{}/change/#id_images\'; return false;">Resim Yok</a>'.format(
obj.id, obj.id))
post_resim.short_description = 'Kurs Resmi'
admin.site.register(Post, PostAdmin)
class CategoryAdmin(admin.ModelAdmin):
list_display = ('title', 'parent_category', 'is_active', 'created_at', 'order') # Removed 'view_count' and 'unique_view_count'
list_filter = ('title', 'is_active', 'created_at', 'parent')
search_fields = ('title', 'is_active', 'slug')
list_editable = ('is_active', 'order')
class Meta:
model = Category
def parent_category(self, obj):
if obj.parent:
return obj.parent.title
return "Ana Kategori"
parent_category.short_description = 'Üst Kategori'
admin.site.register(Category, CategoryAdmin)
class TagsAdmin(admin.ModelAdmin):
list_display = ('tag', 'created_at',)
list_filter = ('tag',)
search_fields = ('tag',)
class Meta:
model = Tags
admin.site.register(Tags, TagsAdmin)
class CategoryViewAdmin(admin.ModelAdmin):
list_display = ('category', 'ip_address', 'created_at')
list_filter = ('created_at', 'category')
search_fields = ('ip_address', 'category__title')
readonly_fields = ('category', 'ip_address', 'user_agent', 'created_at')
class Meta:
model = CategoryView
admin.site.register(CategoryView, CategoryViewAdmin)
admin.site.register(Comment)

5
blog/apps.py Normal file
View File

@@ -0,0 +1,5 @@
from django.apps import AppConfig
class BlogConfig(AppConfig):
name = 'blog'

View File

@@ -0,0 +1,123 @@
# Generated by Django 6.0 on 2025-12-19 12:36
import autoslug.fields
import core.utils
import django.db.models.deletion
import imagekit.models.fields
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='Tags',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('tag', models.CharField(max_length=254, verbose_name='Post Tagları')),
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Oluşturulma Tarihi')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Güncelleme Tarihi')),
('is_active', models.BooleanField(choices=[(True, 'Evet'), (False, 'Hayır')], default=True, verbose_name='Yayındamı')),
],
options={
'verbose_name': 'Post Tagı',
'verbose_name_plural': 'Post Tagları',
'db_table': 'tags',
'ordering': ['-created_at'],
},
),
migrations.CreateModel(
name='Category',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=254, verbose_name='Kategori')),
('keywords', models.CharField(max_length=254, verbose_name='Seo Kelimeleri Aralarına Virgül Koyunuz')),
('description', models.CharField(max_length=254, verbose_name='ıklama')),
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Oluşturulma Tarihi')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Güncelleme Tarihi')),
('is_active', models.BooleanField(choices=[(True, 'Evet'), (False, 'Hayır')], default=True, verbose_name='Yayındamı')),
('order', models.IntegerField(db_index=True, default=1, verbose_name='Görüntülenme Sırası')),
('slug', autoslug.fields.AutoSlugField(blank=True, editable=True, max_length=250, populate_from='title', unique=True)),
('image', imagekit.models.fields.ProcessedImageField(blank=True, null=True, upload_to=core.utils.UniquePathAndRename('uploads/category'), verbose_name='Resim 630 x 653 Olmali ve Transparan PNG Olmali')),
('parent', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='child', to='blog.category', verbose_name='Üst Kategorisi')),
],
options={
'verbose_name': 'Post Kategori',
'verbose_name_plural': 'Post Kategorilerileri',
'db_table': 'categories',
'ordering': ['order'],
'unique_together': {('slug', 'parent')},
},
),
migrations.CreateModel(
name='Post',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=254, verbose_name='Post Başlığı')),
('content', models.TextField(blank=True, null=True, verbose_name='Post İçeriği')),
('keywords', models.CharField(max_length=254, verbose_name='Seo Kelimeleri Aralarına Virgül Koyunuz')),
('image', imagekit.models.fields.ProcessedImageField(blank=True, null=True, upload_to=core.utils.UniquePathAndRename('uploads/post'))),
('video', models.CharField(blank=True, default='none', max_length=254, null=True, verbose_name='Video')),
('slug', autoslug.fields.AutoSlugField(blank=True, editable=True, max_length=250, populate_from='title', unique=True)),
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Oluşturulma Tarihi')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Güncelleme Tarihi')),
('is_active', models.BooleanField(choices=[(True, 'Evet'), (False, 'Hayır')], default=True, verbose_name='Yayındamı ?')),
('is_front', models.BooleanField(choices=[(True, 'Evet'), (False, 'Hayır')], default=True, verbose_name='Önde Görünsünmü ?')),
('categories', models.ManyToManyField(related_name='c_categories', to='blog.category', verbose_name='Post Kategorisi')),
('parent', models.ForeignKey(blank=True, editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='child', to='blog.post', verbose_name='Konular')),
('tags', models.ManyToManyField(related_name='tags', to='blog.tags', verbose_name='Post Tagları')),
],
options={
'verbose_name': 'Post',
'verbose_name_plural': 'Posts',
'db_table': 'posts',
'ordering': ['created_at'],
'unique_together': {('slug',)},
},
),
migrations.CreateModel(
name='CategoryView',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('ip_address', models.GenericIPAddressField(verbose_name='IP Adresi')),
('user_agent', models.TextField(blank=True, null=True, verbose_name='User Agent')),
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Ziyaret Tarihi')),
('category', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='category_views', to='blog.category')),
],
options={
'verbose_name': 'Kategori Ziyareti',
'verbose_name_plural': 'Kategori Ziyaretleri',
'db_table': 'category_views',
'indexes': [models.Index(fields=['category', 'ip_address', 'created_at'], name='category_vi_categor_234334_idx')],
},
),
migrations.CreateModel(
name='Comment',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=254, verbose_name='Yorum Başlığı')),
('body', models.TextField(verbose_name='Yorum')),
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Oluşturulma Tarihi')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Güncelleme Tarihi')),
('is_active', models.BooleanField(choices=[(True, 'Evet'), (False, 'Hayır')], default=True, verbose_name='Yayındamı')),
('slug', autoslug.fields.AutoSlugField(editable=False, populate_from='title', unique=True)),
('parent', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='child', to='blog.comment')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='cuser', to=settings.AUTH_USER_MODEL)),
('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='_product', to='blog.post')),
],
options={
'verbose_name': 'Post Yorum',
'verbose_name_plural': 'Post Yorumları',
'db_table': 'comments',
'ordering': ['-created_at'],
'unique_together': {('slug', 'parent')},
},
),
]

View File

187
blog/models.py Normal file
View File

@@ -0,0 +1,187 @@
from autoslug import AutoSlugField
from django.conf import settings
from django.db import models
from imagekit.models import ProcessedImageField
from pilkit.processors import ResizeToFill
from core.utils import image_optimizer
# Create your models here.
class PCategory(models.Model):
aktif = (
(True, 'Evet'),
(False, 'Hayır'),
)
title = models.CharField(max_length=254, verbose_name="Kategori")
keywords = models.CharField(max_length=254, verbose_name="Seo Kelimeleri Aralarına Virgül Koyunuz")
description = models.CharField(max_length=254, verbose_name="ıklama")
created_at = models.DateTimeField(auto_now_add=True, editable=False, verbose_name="Oluşturulma Tarihi")
updated_at = models.DateTimeField(auto_now=True, editable=False, verbose_name="Güncelleme Tarihi")
is_active = models.BooleanField(default=True, verbose_name='Yayındamı', choices=aktif)
order = models.IntegerField(verbose_name='Görüntülenme Sırası', default=1, db_index=True)
slug = AutoSlugField(populate_from='title', null=False, unique=True, editable=True, db_index=True, max_length=250,
blank=True)
parent = models.ForeignKey('self', related_name='child', on_delete=models.CASCADE, blank=True, null=True,
verbose_name='Üst Kategorisi')
image = ProcessedImageField(**image_optimizer('uploads/category', 300, 300, 85, 'PNG'),
verbose_name='Resim 630 x 653 Olmali ve Transparan PNG Olmali', blank=True, null=True)
class Meta:
ordering = ["order"]
db_table = 'p_categories'
verbose_name_plural = "Post Kategorilerileri"
verbose_name = "Post Kategori"
unique_together = ('slug', 'parent',)
def get_slug(self):
slug = self.title.replace('ı', "i").replace('İ', 'i')
number = 1
while Category.objects.filter(slug=slug).exists():
slug = '{}-{}'.format(slug, number)
number += 1
return slug
def save(self, *args, **kwargs):
if not self.slug:
self.slug = self.get_slug()
super().save(*args, **kwargs)
def __str__(self):
full_path = [self.title]
k = self.parent
while k is not None:
full_path.append(k.title)
k = k.parent
return ' -> '.join(full_path[::-1])
class PTags(models.Model):
aktif = (
(True, 'Evet'),
(False, 'Hayır'),
)
tag = models.CharField(max_length=254, verbose_name="Post Tagları")
created_at = models.DateTimeField(auto_now_add=True, editable=False, verbose_name="Oluşturulma Tarihi")
updated_at = models.DateTimeField(auto_now=True, editable=False, verbose_name="Güncelleme Tarihi")
is_active = models.BooleanField(default=True, verbose_name='Yayındamı', choices=aktif)
class Meta:
ordering = ["-created_at"]
db_table = 'p_tags'
verbose_name_plural = "Post Tagları"
verbose_name = "Post Tagı"
def __str__(self):
return self.tag
class PPost(models.Model):
aktif = (
(True, 'Evet'),
(False, 'Hayır'),
)
title = models.CharField(max_length=254, verbose_name="Post Başlığı")
content = models.TextField(blank=True, null=True, verbose_name='Post İçeriği')
categories = models.ManyToManyField(Category, verbose_name="Post Kategorisi", related_name='c_categories')
keywords = models.CharField(max_length=254, verbose_name="Seo Kelimeleri Aralarına Virgül Koyunuz")
tags = models.ManyToManyField(Tags, verbose_name="Post Tagları", related_name='tags')
image = ProcessedImageField(**image_optimizer('uploads/post', 700, 450, 90, 'avif'), null=True, blank=True)
video = models.CharField(verbose_name="Video", null=True, blank=True, max_length=254, default='none')
slug = AutoSlugField(populate_from='title', null=False, unique=True, editable=True, db_index=True, max_length=250,
blank=True)
created_at = models.DateTimeField(auto_now_add=True, editable=False, verbose_name="Oluşturulma Tarihi")
updated_at = models.DateTimeField(auto_now=True, editable=False, verbose_name="Güncelleme Tarihi")
is_active = models.BooleanField(default=True, verbose_name='Yayındamı ?', choices=aktif)
is_front = models.BooleanField(default=True, verbose_name='Önde Görünsünmü ?', choices=aktif)
parent = models.ForeignKey('self', related_name='child', on_delete=models.CASCADE, blank=True, null=True,
editable=False,
verbose_name='Konular')
class Meta:
ordering = ["created_at"]
db_table = 'p_posts'
verbose_name_plural = "Posts"
verbose_name = "Post"
unique_together = ('slug',)
def get_slug(self):
slug = self.title.replace('ı', "i").replace('İ', 'i')
number = 1
while Post.objects.filter(slug=slug).exists():
slug = '{}-{}'.format(slug, number)
number += 1
return slug
def save(self, *args, **kwargs):
if not self.slug:
self.slug = self.get_slug()
super().save(*args, **kwargs)
def __str__(self):
return f"Postlar: {self.title}"
class PCategoryView(models.Model):
"""Kategori ziyaretlerini takip etmek için model"""
category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name='category_views')
ip_address = models.GenericIPAddressField(verbose_name='IP Adresi')
user_agent = models.TextField(blank=True, null=True, verbose_name='User Agent')
created_at = models.DateTimeField(auto_now_add=True, verbose_name='Ziyaret Tarihi')
class Meta:
db_table = 'p_category_views'
verbose_name = 'Kategori Ziyareti'
verbose_name_plural = 'Kategori Ziyaretleri'
# unique_together kısıtlamasını kaldırdık - artık günlük bazda kontrol edeceğiz
indexes = [
models.Index(fields=['category', 'ip_address', 'created_at']),
]
def __str__(self):
return f"{self.category.title} - {self.ip_address} - {self.created_at.strftime('%Y-%m-%d %H:%M')}"
class PComment(models.Model):
aktif = (
(True, 'Evet'),
(False, 'Hayır'),
)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='cuser')
product = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='_product')
title = models.CharField(max_length=254, verbose_name="Yorum Başlığı")
body = models.TextField(verbose_name='Yorum')
created_at = models.DateTimeField(auto_now_add=True, editable=False, verbose_name="Oluşturulma Tarihi")
updated_at = models.DateTimeField(auto_now=True, editable=False, verbose_name="Güncelleme Tarihi")
is_active = models.BooleanField(default=True, verbose_name='Yayındamı', choices=aktif)
slug = AutoSlugField(populate_from='title', null=False, unique=True, editable=False, db_index=True)
parent = models.ForeignKey('self', related_name='child', on_delete=models.CASCADE, blank=True, null=True)
class Meta:
ordering = ["-created_at"]
db_table = 'p_comments'
verbose_name_plural = "Post Yorumları"
verbose_name = "Post Yorum"
unique_together = ('slug', 'parent',)
def get_slug(self):
slug = self.title.replace('ı', "i").replace('İ', 'i')
number = 1
while Comment.objects.filter(slug=slug).exists():
slug = '{}-{}'.format(slug, number)
number += 1
return slug
def save(self, *args, **kwargs):
if not self.slug:
self.slug = self.get_slug()
super().save(*args, **kwargs)
def __str__(self):
full_path = [self.title]
k = self.parent
while k is not None:
full_path.append(k.title)
k = k.parent
return ' -> '.join(full_path[::-1])

3
blog/tests.py Normal file
View File

@@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

0
blog/urls.py Normal file
View File

3
blog/views.py Normal file
View File

@@ -0,0 +1,3 @@
from django.shortcuts import render
# Create your views here.

41
build/Dockerfile Normal file
View File

@@ -0,0 +1,41 @@
# Python 3.14.2 base image kullan
FROM python:3.14.2-slim
# Çalışma ortamı değişkenlerini ayarla
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
PIP_NO_CACHE_DIR=1 \
PIP_DISABLE_PIP_VERSION_CHECK=1
# Çalışma dizinini oluştur
WORKDIR /app
# Sistem bağımlılıklarını yükle (PostgreSQL ve diğer gerekli paketler için)
RUN apt-get update && apt-get install -y --no-install-recommends \
gcc \
postgresql-client \
libpq-dev \
&& rm -rf /var/lib/apt/lists/*
# Python bağımlılıklarını kopyala ve yükle
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Proje dosyalarını kopyala
COPY . .
# Static dosyaları topla
RUN python manage.py collectstatic --noinput --clear || true
# Media ve staticfiles dizinlerini oluştur
RUN mkdir -p /app/media /app/staticfiles
# Port 8000'i aç
EXPOSE 8000
# Entrypoint scriptini çalıştırılabilir yap
RUN chmod +x /app/entrypoint.sh || true
# Entrypoint ve varsayılan komut
ENTRYPOINT ["/app/entrypoint.sh"]
CMD ["gunicorn", "core.wsgi:application", "--bind", "0.0.0.0:8000", "--workers", "3"]

75
build/requirements.txt Normal file
View File

@@ -0,0 +1,75 @@
amqp==5.3.1
asgiref==3.11.0
billiard==4.2.4
celery==5.6.2
celery-types==0.24.0
certifi==2025.11.12
cffi==2.0.0
charset-normalizer==3.4.4
click==8.3.1
click-didyoumean==0.3.1
click-plugins==1.1.1.2
click-repl==0.3.0
cryptography==46.0.3
defusedxml==0.7.1
Django==6.0
django-appconf==1.2.0
django-autoslug==1.9.9
django-celery-beat==2.1.0
django-ckeditor-5==0.2.18
django-cleanup==9.0.0
django-colorfield==0.14.0
django-cors-headers==4.9.0
django-cropper-image==1.0.5
django-environ==0.12.0
django-filter==25.2
django-imagekit==6.0.0
django-redis==6.0.0
django-stubs==5.2.8
django-stubs-ext==5.2.8
django-timezone-field==4.2.3
django-tinymce==5.0.0
django_celery_results==2.6.0
djangorestframework==3.16.1
djangorestframework-stubs==3.16.6
djangorestframework_simplejwt==5.5.1
djoser==2.3.3
Faker==26.0.0
flower==2.0.1
gunicorn==23.0.0
hiredis==3.3.0
humanize==4.15.0
idna==3.11
kombu==5.6.2
Markdown==3.10
oauthlib==3.3.1
packaging==25.0
pilkit==3.0
pillow==12.0.0
prometheus_client==0.24.1
prompt_toolkit==3.0.52
psycopg2-binary==2.9.11
pycparser==2.23
PyJWT==2.10.1
python-crontab==3.3.0
python-dateutil==2.9.0.post0
python-dotenv==1.0.0
python3-openid==3.2.0
pytz==2025.2
redis==7.1.0
requests==2.32.5
requests-oauthlib==2.0.0
six==1.17.0
social-auth-app-django==5.6.0
social-auth-core==4.8.1
sqlparse==0.5.4
tornado==6.5.4
types-PyYAML==6.0.12.20250915
types-requests==2.32.4.20260107
typing_extensions==4.15.0
tzdata==2025.2
tzlocal==5.3.1
urllib3==2.6.2
vine==5.1.0
wcwidth==0.2.14
whitenoise==6.11.0

28
caddy/Caddyfile Normal file
View File

@@ -0,0 +1,28 @@
:80 {
# Büyük upload limiti (Nginx'teki client_max_body_size 100M eşdeğeri)
request_body {
max_size 100MB
}
# Static dosyalar
handle_path /static/* {
root * /app/staticfiles
header Cache-Control "public, immutable"
file_server
}
# Media dosyalar
handle_path /media/* {
root * /app/media
header Cache-Control "public"
file_server
}
# Diğer tüm istekler Django'ya
reverse_proxy web-ata:8000 {
header_up Host {host}
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
header_up X-Forwarded-Proto {scheme}
}
}

4
caddy/Dockerfile Normal file
View File

@@ -0,0 +1,4 @@
FROM caddy:2
# Build context repo root'u (.) olduğu için caddy/Caddyfile yolu kullanıyoruz
COPY caddy/Caddyfile /etc/caddy/Caddyfile

View File

@@ -0,0 +1 @@
{"web":{"client_id":"915364976256-691m0s87as2r5vdbqr96f6humblseobt.apps.googleusercontent.com","project_id":"django-471018","auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://oauth2.googleapis.com/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","client_secret":"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","redirect_uris":["http://localhost:3000/api/auth/callback/google","http://localhost:8000/api/auth/callback/google","http://127.0.0.1:8000/api/auth/callback/google","http://127.0.0.1:3000/api/auth/callback/google","http://127.0.0.1:8000/accounts/auth/google/login/callback/","http://127.0.0.1:8000/auth/google/callback/","http://localhost:8000/auth/google/callback/","http://localhost:3000/auth/google","http://localhost:8000/auth/google"],"javascript_origins":["http://localhost:3000","http://localhost:8000","http://127.0.0.1:8000","http://127.0.0.1:3000"]}}

0
contact/__init__.py Normal file
View File

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

11
contact/admin.py Normal file
View File

@@ -0,0 +1,11 @@
from django.contrib import admin
from .models import Contact
# Register your models here.
class ContactAdmin(admin.ModelAdmin):
list_display = ('name', 'email', 'subject', 'created_at')
list_filter = ('created_at',)
search_fields = ('name', 'email', 'subject', 'message')
readonly_fields = ('created_at', 'updated_at')
admin.site.register(Contact, ContactAdmin)

5
contact/apps.py Normal file
View File

@@ -0,0 +1,5 @@
from django.apps import AppConfig
class ContactConfig(AppConfig):
name = 'contact'

View File

@@ -0,0 +1,32 @@
# Generated by Django 6.0 on 2026-01-15 11:59
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Contact',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=254, verbose_name='Ad Soyad ')),
('email', models.CharField(max_length=254, verbose_name='Eposta Adresi ')),
('subject', models.CharField(max_length=254, verbose_name='Konu ')),
('message', models.CharField(max_length=254, verbose_name='Mesaj ')),
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Oluşturulma Tarihi')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Güncelleme Tarihi')),
],
options={
'verbose_name': 'Contact',
'verbose_name_plural': 'Contact',
'db_table': 'contacts',
'ordering': ['created_at'],
},
),
]

View File

@@ -0,0 +1,22 @@
# Generated by Django 6.0 on 2026-01-15 12:39
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('contact', '0001_initial'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.AddField(
model_name='contact',
name='user',
field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Kullanıcı'),
preserve_default=False,
),
]

View File

@@ -0,0 +1,18 @@
# Generated by Django 6.0 on 2026-01-15 12:43
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('contact', '0002_contact_user'),
]
operations = [
migrations.AlterField(
model_name='contact',
name='message',
field=models.TextField(verbose_name='Mesaj '),
),
]

Some files were not shown because too many files have changed in this diff Show More