test
This commit is contained in:
parent
f69de9a8df
commit
27c1d69ae8
@ -1,32 +0,0 @@
|
|||||||
from django.core.management.base import BaseCommand
|
|
||||||
from django.contrib.auth.models import User
|
|
||||||
from decouple import config
|
|
||||||
from django.db import transaction
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
|
||||||
help = 'Check if any users exist and create admin if none exist'
|
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
|
||||||
# Check if any users exist
|
|
||||||
if User.objects.exists():
|
|
||||||
self.stdout.write(
|
|
||||||
self.style.WARNING('Users already exist, skipping admin creation')
|
|
||||||
)
|
|
||||||
return
|
|
||||||
|
|
||||||
# Get credentials from environment variables or use defaults
|
|
||||||
username = config('ADMIN_USERNAME', default='admin')
|
|
||||||
password = config('ADMIN_PASSWORD', default='admin123')
|
|
||||||
email = config('ADMIN_EMAIL', default='admin@boulangerie.fr')
|
|
||||||
|
|
||||||
# Create the admin user
|
|
||||||
with transaction.atomic():
|
|
||||||
user = User.objects.create_superuser(
|
|
||||||
username=username,
|
|
||||||
email=email,
|
|
||||||
password=password
|
|
||||||
)
|
|
||||||
|
|
||||||
self.stdout.write(
|
|
||||||
self.style.SUCCESS(f'Successfully created admin user "{username}"')
|
|
||||||
)
|
|
||||||
@ -5,8 +5,8 @@ urlpatterns = [
|
|||||||
path('register/', RegisterView.as_view(), name='register'),
|
path('register/', RegisterView.as_view(), name='register'),
|
||||||
path('me/', UserMeView.as_view(), name='me'),
|
path('me/', UserMeView.as_view(), name='me'),
|
||||||
path('', UserListView.as_view(), name='user-list'),
|
path('', UserListView.as_view(), name='user-list'),
|
||||||
path('<int:user_id>/', UserDetailView.as_view(), name='user-detail'),
|
path('<int:user>/', UserDetailView.as_view(), name='user-detail'),
|
||||||
path('<int:user_id>/promote/', UserPromoteView.as_view(), name='user-promote'),
|
path('<int:user>/promote/', UserPromoteView.as_view(), name='user-promote'),
|
||||||
path('<int:user_id>/delete/', UserDeleteView.as_view(), name='user-delete'),
|
path('<int:user>/delete/', UserDeleteView.as_view(), name='user-delete'),
|
||||||
path('invitations/', InvitationCreateView.as_view(), name='invitation-create'),
|
path('invitations/', InvitationCreateView.as_view(), name='invitation-create'),
|
||||||
]
|
]
|
||||||
|
|||||||
@ -35,6 +35,8 @@ class UserListView(generics.ListAPIView):
|
|||||||
class UserDetailView(generics.RetrieveUpdateDestroyAPIView):
|
class UserDetailView(generics.RetrieveUpdateDestroyAPIView):
|
||||||
permission_classes = (IsAuthenticated,)
|
permission_classes = (IsAuthenticated,)
|
||||||
serializer_class = UserSerializer
|
serializer_class = UserSerializer
|
||||||
|
lookup_field = 'id'
|
||||||
|
lookup_url_kwarg = 'user'
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
if not (self.request.user.is_staff or self.request.user.is_superuser):
|
if not (self.request.user.is_staff or self.request.user.is_superuser):
|
||||||
@ -61,14 +63,14 @@ class UserDetailView(generics.RetrieveUpdateDestroyAPIView):
|
|||||||
class UserPromoteView(APIView):
|
class UserPromoteView(APIView):
|
||||||
permission_classes = (IsAuthenticated,)
|
permission_classes = (IsAuthenticated,)
|
||||||
|
|
||||||
def post(self, request, user_id):
|
def post(self, request, user):
|
||||||
if not (request.user.is_staff or request.user.is_superuser):
|
if not (request.user.is_staff or request.user.is_superuser):
|
||||||
raise PermissionDenied('Seuls les administrateurs peuvent promouvoir des utilisateurs.')
|
raise PermissionDenied('Seuls les administrateurs peuvent promouvoir des utilisateurs.')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
user = User.objects.get(id=user_id)
|
user_obj = User.objects.get(id=user)
|
||||||
user.is_staff = True
|
user_obj.is_staff = True
|
||||||
user.save()
|
user_obj.save()
|
||||||
return Response({'message': 'Utilisateur promu avec succès'}, status=200)
|
return Response({'message': 'Utilisateur promu avec succès'}, status=200)
|
||||||
except User.DoesNotExist:
|
except User.DoesNotExist:
|
||||||
return Response({'error': 'Utilisateur non trouvé'}, status=404)
|
return Response({'error': 'Utilisateur non trouvé'}, status=404)
|
||||||
@ -77,17 +79,17 @@ class UserPromoteView(APIView):
|
|||||||
class UserDeleteView(APIView):
|
class UserDeleteView(APIView):
|
||||||
permission_classes = (IsAuthenticated,)
|
permission_classes = (IsAuthenticated,)
|
||||||
|
|
||||||
def delete(self, request, user_id):
|
def delete(self, request, user):
|
||||||
if not (request.user.is_staff or request.user.is_superuser):
|
if not (request.user.is_staff or request.user.is_superuser):
|
||||||
raise PermissionDenied('Seuls les administrateurs peuvent supprimer des utilisateurs.')
|
raise PermissionDenied('Seuls les administrateurs peuvent supprimer des utilisateurs.')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
user = User.objects.get(id=user_id)
|
user_obj = User.objects.get(id=user)
|
||||||
# Ne pas permettre de supprimer l'utilisateur courant
|
# Ne pas permettre de supprimer l'utilisateur courant
|
||||||
if user == request.user:
|
if user_obj == request.user:
|
||||||
return Response({'error': 'Vous ne pouvez pas supprimer votre propre compte'}, status=400)
|
return Response({'error': 'Vous ne pouvez pas supprimer votre propre compte'}, status=400)
|
||||||
|
|
||||||
user.delete()
|
user_obj.delete()
|
||||||
return Response({'message': 'Utilisateur supprimé avec succès'}, status=200)
|
return Response({'message': 'Utilisateur supprimé avec succès'}, status=200)
|
||||||
except User.DoesNotExist:
|
except User.DoesNotExist:
|
||||||
return Response({'error': 'Utilisateur non trouvé'}, status=404)
|
return Response({'error': 'Utilisateur non trouvé'}, status=404)
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { Routes, Route, Navigate } from 'react-router-dom';
|
import { Routes, Route, Navigate } from 'react-router-dom';
|
||||||
import LoginPage from './pages/LoginPage';
|
import LoginPage from './pages/LoginPage';
|
||||||
import HomePage from './pages/HomePage';
|
import HomePage from './pages/HomePage';
|
||||||
import ProtectedRoute from './components/ProtectedRoute';
|
import AdminRoute from './components/AdminRoute';
|
||||||
import Header from './components/Header';
|
import Header from './components/Header';
|
||||||
import AdminUsersPage from './pages/AdminUsersPage';
|
import AdminUsersPage from './pages/AdminUsersPage';
|
||||||
import AdminInvitePage from './pages/AdminInvitePage';
|
import AdminInvitePage from './pages/AdminInvitePage';
|
||||||
@ -31,14 +31,14 @@ function App() {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<Route path="/users" element={
|
<Route path="/users" element={
|
||||||
<ProtectedRoute>
|
<AdminRoute>
|
||||||
<AdminUsersPage />
|
<AdminUsersPage />
|
||||||
</ProtectedRoute>
|
</AdminRoute>
|
||||||
} />
|
} />
|
||||||
<Route path="/invite" element={
|
<Route path="/invite" element={
|
||||||
<ProtectedRoute>
|
<AdminRoute>
|
||||||
<AdminInvitePage />
|
<AdminInvitePage />
|
||||||
</ProtectedRoute>
|
</AdminRoute>
|
||||||
} />
|
} />
|
||||||
<Route path="*" element={<Navigate to="/" replace />} />
|
<Route path="*" element={<Navigate to="/" replace />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
|
|||||||
26
frontend/src/components/AdminRoute.jsx
Normal file
26
frontend/src/components/AdminRoute.jsx
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Navigate, useLocation } from 'react-router-dom';
|
||||||
|
import { useAuth } from '../context/AuthContext';
|
||||||
|
|
||||||
|
const AdminRoute = ({ children }) => {
|
||||||
|
const { user, loading, isAdmin } = useAuth();
|
||||||
|
const location = useLocation();
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
|
return <div>Loading...</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
// Redirect them to the /login page, but save the current location they were trying to go to.
|
||||||
|
return <Navigate to="/login" state={{ from: location }} replace />;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If user is not admin, redirect to profile page
|
||||||
|
if (!isAdmin) {
|
||||||
|
return <Navigate to="/profile" state={{ from: location }} replace />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return children;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AdminRoute;
|
||||||
@ -41,10 +41,14 @@ const AdminUsersPage = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleMakeAdmin = async (userId) => {
|
const handleMakeAdmin = async (userId) => {
|
||||||
|
if (!window.confirm('Êtes-vous sûr de vouloir promouvoir cet utilisateur ?')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await userApi.promoteUser(userId);
|
await userApi.promoteUser(userId);
|
||||||
setUsers(users.map(user =>
|
setUsers(users.map(user =>
|
||||||
user.id === userId ? { ...user, is_staff: true } : user
|
user.id === userId ? { ...user, is_admin: true } : user
|
||||||
));
|
));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setError('Erreur lors de la promotion de l\'utilisateur');
|
setError('Erreur lors de la promotion de l\'utilisateur');
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user