diff --git a/backend/imk-backend/src/admin/admin.controller.ts b/backend/imk-backend/src/admin/admin.controller.ts
index aa163e3..7bce7ad 100644
--- a/backend/imk-backend/src/admin/admin.controller.ts
+++ b/backend/imk-backend/src/admin/admin.controller.ts
@@ -11,7 +11,6 @@ import {
ParseIntPipe,
UseGuards,
Request,
- Req,
} from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { AdminService } from './admin.service';
@@ -96,12 +95,25 @@ export class AdminController {
return this.adminService.updateDocumentStatus(+id, status);
}
+ // async uploadDocument(
+ // @UploadedFile() file: Express.Multer.File,
+ // @Body('title') title: string,
+ // @Request() req,
+ // ) {
+ // return this.adminService.uploadDocument(file, title, req.user.userId);
+ // }
async uploadDocument(
@UploadedFile() file: Express.Multer.File,
@Body('title') title: string,
+ @Body('description') description: number[],
@Request() req,
) {
- return this.adminService.uploadDocument(file, title, req.user.userId);
+ return this.adminService.uploadDocument(
+ file,
+ title,
+ req.user.userId,
+ description,
+ );
}
@Get('test-s3-connection')
async testS3Connection() {
diff --git a/backend/imk-backend/src/admin/admin.service.ts b/backend/imk-backend/src/admin/admin.service.ts
index b33a3bd..3b93e6d 100644
--- a/backend/imk-backend/src/admin/admin.service.ts
+++ b/backend/imk-backend/src/admin/admin.service.ts
@@ -85,8 +85,41 @@ export class AdminService {
});
}
+ // async getAllDocuments() {
+ // return this.prisma.document.findMany({
+ // include: {
+ // sharedWith: {
+ // select: {
+ // id: true,
+ // name: true,
+ // email: true,
+ // },
+ // },
+ // },
+ // });
+ // }
async getAllDocuments() {
- return this.prisma.document.findMany();
+ return this.prisma.document.findMany({
+ include: {
+ author: {
+ select: {
+ id: true,
+ name: true,
+ email: true,
+ },
+ },
+ sharedWith: {
+ select: {
+ id: true,
+ name: true,
+ email: true,
+ },
+ },
+ },
+ orderBy: {
+ createdAt: 'desc',
+ },
+ });
}
async updateDocument(
@@ -116,6 +149,41 @@ export class AdminService {
},
});
}
+ async uploadDocument(
+ file: Express.Multer.File,
+ title: string,
+ userId: number,
+ sharedWith: number[],
+ ) {
+ let s3Key;
+ try {
+ s3Key = await this.s3Service.uploadFile(file, 'documents');
+
+ // Log the sharedWith array to verify the data
+ console.log('Sharing document with users:', sharedWith);
+
+ const document = await this.prisma.document.create({
+ data: {
+ title,
+ authorId: userId,
+ s3Key,
+ status: 'completed',
+ sharedWith: {
+ connect: sharedWith.map((id) => ({ id })),
+ },
+ },
+ include: {
+ sharedWith: true, // Include this to verify the relation was created
+ },
+ });
+
+ console.log('Created document:', document);
+ return document;
+ } catch (error) {
+ console.error('Error in uploadDocument:', error);
+ throw error;
+ }
+ }
async deleteDocument(id: number) {
const document = await this.prisma.document.findUnique({
@@ -221,42 +289,49 @@ export class AdminService {
// problem whith upload status writing to db, i will fix it later
- async uploadDocument(
- file: Express.Multer.File,
- title: string,
- userId: number,
- ) {
- let s3Key;
- try {
- // First upload to S3
- s3Key = await this.s3Service.uploadFile(file, 'documents');
+ // async uploadDocument(
+ // file: Express.Multer.File,
+ // title: string,
+ // userId: number,
+ // sharedWith: number[],
+ // ) {
+ // let s3Key;
+ // try {
+ // // First upload to S3
+ // s3Key = await this.s3Service.uploadFile(file, 'documents');
- // Then create document with completed status and s3Key
- const document = await this.prisma.document.create({
- data: {
- title,
- authorId: userId,
- s3Key,
- status: 'completed', // Set status to completed immediately after successful upload
- },
- });
+ // // Then create document with completed status and s3Key
+ // const document = await this.prisma.document.create({
+ // data: {
+ // title,
+ // authorId: userId,
+ // s3Key,
+ // status: 'completed', // Set status to completed immediately after successful upload
+ // sharedWith: {
+ // connect: sharedWith.map((id: number) => ({ id })),
+ // },
+ // },
+ // });
- return document;
- } catch (error) {
- // Create document with failed status if upload fails
- if (title && userId) {
- await this.prisma.document.create({
- data: {
- title,
- authorId: userId,
- s3Key: s3Key || '',
- status: 'failed',
- },
- });
- }
- throw error;
- }
- }
+ // return document;
+ // } catch (error) {
+ // // Create document with failed status if upload fails
+ // if (title && userId) {
+ // await this.prisma.document.create({
+ // data: {
+ // title,
+ // authorId: userId,
+ // s3Key: s3Key || '',
+ // status: 'failed',
+ // sharedWith: {
+ // connect: sharedWith.map((id: number) => ({ id })),
+ // },
+ // },
+ // });
+ // }
+ // throw error;
+ // }
+ // }
async getDocumentUrl(documentId: number) {
const document = await this.prisma.document.findUnique({
diff --git a/frontend/imk/src/components/UserCreate.jsx b/frontend/imk/src/components/UserCreate.jsx
new file mode 100644
index 0000000..e3633ee
--- /dev/null
+++ b/frontend/imk/src/components/UserCreate.jsx
@@ -0,0 +1,84 @@
+import { useState } from 'react';
+import { createUser } from '../services/api';
+
+// eslint-disable-next-line react/prop-types
+function UserCreate({ onUserCreated }) {
+ const [formData, setFormData] = useState({
+ name: '',
+ email: '',
+ password: '',
+ });
+ const [error, setError] = useState('');
+ const [loading, setLoading] = useState(false);
+
+ const handleSubmit = async (e) => {
+ e.preventDefault();
+ setLoading(true);
+ setError('');
+
+ try {
+ await createUser(formData);
+ setFormData({ name: '', email: '', password: '' });
+ if (onUserCreated) onUserCreated();
+ } catch (err) {
+ setError(err.response?.data?.message || 'Failed to create user');
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ return (
+
+ );
+}
+
+export default UserCreate;
\ No newline at end of file
diff --git a/frontend/imk/src/components/adminPanel/AdminPanel.jsx b/frontend/imk/src/components/adminPanel/AdminPanel.jsx
index 2a29ab5..e53c6ab 100644
--- a/frontend/imk/src/components/adminPanel/AdminPanel.jsx
+++ b/frontend/imk/src/components/adminPanel/AdminPanel.jsx
@@ -1,86 +1,42 @@
-// import { useState, useEffect } from 'react';
-// import { getAllUsers, uploadDocument } from '../../services/api';
-// import DocumentUpload from '../documentUpload/DocumentUpload';
-// function AdminPanel() {
-// const [users, setUsers] = useState([]);
-// const [file, setFile] = useState(null);
-// const [title, setTitle] = useState('');
-
-// useEffect(() => {
-// fetchUsers();
-// }, []);
-
-// const fetchUsers = async () => {
-// try {
-// const response = await getAllUsers();
-// setUsers(response.data);
-// } catch (error) {
-// console.error('Failed to fetch users:', error);
-// }
-// };
-
-// const handleFileUpload = async (e) => {
-// e.preventDefault();
-// if (!file) return;
-
-// const formData = new FormData();
-// formData.append('file', file);
-// formData.append('title', title);
-
-// try {
-// await uploadDocument(formData);
-// alert('Document uploaded successfully');
-// } catch (error) {
-// console.error('Failed to upload document:', error);
-// }
-// };
-
-// return (
-//
-//
Users
-//
-// {users.map(user => (
-// - {user.name} ({user.email})
-// ))}
-//
-
-//
Upload Document
-//
-//
-//
-// );
-// }
-
-// export default AdminPanel;
-
import { useState, useEffect } from 'react';
-import { getAllUsers, getAllDocuments } from '../../services/api';
+import { getAllUsers, getAllDocuments, getUserInfo } from '../../services/api';
import DocumentUpload from '../documentUpload/DocumentUpload';
+import UserCreate from '../UserCreate';
+import { useNavigate } from 'react-router-dom';
function AdminPanel() {
+ const navigate = useNavigate();
const [activeTab, setActiveTab] = useState('documents');
const [users, setUsers] = useState([]);
const [documents, setDocuments] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState('');
+ const [isAdmin, setIsAdmin] = useState(false);
useEffect(() => {
- fetchData();
- }, [activeTab]);
+ checkAdminStatus();
+ }, []);
+
+ const checkAdminStatus = async () => {
+ try {
+ const response = await getUserInfo();
+ if (!response?.data?.isAdmin) {
+ navigate('/');
+ } else {
+ setIsAdmin(true);
+ await fetchData();
+ }
+ } catch (error) {
+ console.error('Admin check failed:', error);
+ navigate('/');
+ }
+ };
+
+ useEffect(() => {
+ if (isAdmin) {
+ fetchData();
+ }
+ }, [activeTab, isAdmin]);
const fetchData = async () => {
setLoading(true);
@@ -110,6 +66,10 @@ function AdminPanel() {
return colors[status] || 'bg-gray-100 text-gray-800';
};
+ if (!isAdmin) {
+ return null;
+ }
+
return (
@@ -175,7 +135,7 @@ function AdminPanel() {
| Title |
Status |
- Author |
+ Shared With |
Created At |
@@ -188,7 +148,9 @@ function AdminPanel() {
{doc.status}
-
{doc.authorId} |
+
+ {doc.sharedWith?.map((user) => user.name).join(', ') || 'None'}
+ |
{new Date(doc.createdAt).toLocaleDateString()}
|
@@ -200,29 +162,36 @@ function AdminPanel() {
)}
{activeTab === 'users' && (
-
-
-
-
- | Name |
- Email |
- Role |
-
-
-
- {users.map((user) => (
-
- | {user.name} |
- {user.email} |
-
-
- {user.isAdmin ? 'Admin' : 'User'}
-
- |
-
- ))}
-
-
+
+
+
+
+
+
+ | Name |
+ Email |
+ Role |
+
+
+
+ {users.map((user) => (
+
+ | {user.name} |
+ {user.email} |
+
+
+ {user.isAdmin ? 'Admin' : 'User'}
+
+ |
+
+ ))}
+
+
+
+
+
+
+
)}
diff --git a/frontend/imk/src/components/documentUpload/DocumentUpload.jsx b/frontend/imk/src/components/documentUpload/DocumentUpload.jsx
index 8b50777..dd3c8d3 100644
--- a/frontend/imk/src/components/documentUpload/DocumentUpload.jsx
+++ b/frontend/imk/src/components/documentUpload/DocumentUpload.jsx
@@ -1,12 +1,27 @@
-import { useState } from 'react';
-import { uploadDocument } from '../../services/api';
+import { useState, useEffect } from 'react';
+import { uploadDocument, getAllUsers } from '../../services/api';
function DocumentUpload() {
const [file, setFile] = useState(null);
const [title, setTitle] = useState('');
+ const [selectedUsers, setSelectedUsers] = useState([]);
+ const [availableUsers, setAvailableUsers] = useState([]);
const [status, setStatus] = useState('idle'); // idle, uploading, completed, failed
const [errorMessage, setErrorMessage] = useState('');
+ useEffect(() => {
+ fetchUsers();
+ }, []);
+
+ const fetchUsers = async () => {
+ try {
+ const response = await getAllUsers();
+ setAvailableUsers(response.data.filter(user => !user.isAdmin));
+ } catch (error) {
+ setErrorMessage('Failed to load users');
+ }
+ };
+
const handleFileChange = (event) => {
const selectedFile = event.target.files[0];
setFile(selectedFile);
@@ -14,8 +29,8 @@ function DocumentUpload() {
const handleSubmit = async (event) => {
event.preventDefault();
- if (!file || !title) {
- setErrorMessage('Please provide both a title and a file');
+ if (!file || !title || selectedUsers.length === 0) {
+ setErrorMessage('Please provide a title, file, and select at least one user');
return;
}
@@ -25,17 +40,18 @@ function DocumentUpload() {
const formData = new FormData();
formData.append('file', file);
formData.append('title', title);
+ formData.append('sharedWith', JSON.stringify(selectedUsers));
try {
await uploadDocument(formData);
setStatus('completed');
setTitle('');
setFile(null);
- // Reset form
+ setSelectedUsers([]);
event.target.reset();
} catch (error) {
setStatus('failed');
- setErrorMessage(error.response?.data?.message || 'Upload failed. Please try again.');
+ setErrorMessage(error.response?.data?.message || 'Upload failed');
}
};
@@ -69,6 +85,25 @@ function DocumentUpload() {
/>
+
+
+
+
+
{errorMessage && (
{errorMessage}