clients page
This commit is contained in:
parent
3d2b0a5d6d
commit
1a7f2afd79
@ -71,6 +71,10 @@
|
|||||||
"tsconfig-paths": "^4.2.0",
|
"tsconfig-paths": "^4.2.0",
|
||||||
"typescript": "^5.1.3"
|
"typescript": "^5.1.3"
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"prisma": {
|
||||||
|
"seed": "ts-node prisma/seed.ts"
|
||||||
|
},
|
||||||
"jest": {
|
"jest": {
|
||||||
"moduleFileExtensions": [
|
"moduleFileExtensions": [
|
||||||
"js",
|
"js",
|
||||||
|
|||||||
@ -1,27 +0,0 @@
|
|||||||
-- CreateTable
|
|
||||||
CREATE TABLE "User" (
|
|
||||||
"id" SERIAL NOT NULL,
|
|
||||||
"email" TEXT NOT NULL,
|
|
||||||
"name" TEXT,
|
|
||||||
"password" TEXT NOT NULL,
|
|
||||||
"isAdmin" BOOLEAN NOT NULL DEFAULT false,
|
|
||||||
|
|
||||||
CONSTRAINT "User_pkey" PRIMARY KEY ("id")
|
|
||||||
);
|
|
||||||
|
|
||||||
-- CreateTable
|
|
||||||
CREATE TABLE "Document" (
|
|
||||||
"id" SERIAL NOT NULL,
|
|
||||||
"title" TEXT NOT NULL,
|
|
||||||
"content" TEXT,
|
|
||||||
"published" BOOLEAN NOT NULL DEFAULT false,
|
|
||||||
"authorId" INTEGER NOT NULL,
|
|
||||||
|
|
||||||
CONSTRAINT "Document_pkey" PRIMARY KEY ("id")
|
|
||||||
);
|
|
||||||
|
|
||||||
-- CreateIndex
|
|
||||||
CREATE UNIQUE INDEX "User_email_key" ON "User"("email");
|
|
||||||
|
|
||||||
-- AddForeignKey
|
|
||||||
ALTER TABLE "Document" ADD CONSTRAINT "Document_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
-- AlterTable
|
|
||||||
ALTER TABLE "Document" ADD COLUMN "s3Key" TEXT;
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
/*
|
|
||||||
Warnings:
|
|
||||||
|
|
||||||
- Made the column `s3Key` on table `Document` required. This step will fail if there are existing NULL values in that column.
|
|
||||||
|
|
||||||
*/
|
|
||||||
-- AlterTable
|
|
||||||
ALTER TABLE "Document" ALTER COLUMN "s3Key" SET NOT NULL;
|
|
||||||
@ -1,13 +1,28 @@
|
|||||||
/*
|
-- CreateTable
|
||||||
Warnings:
|
CREATE TABLE "Document" (
|
||||||
|
"id" SERIAL NOT NULL,
|
||||||
|
"title" TEXT NOT NULL,
|
||||||
|
"content" TEXT,
|
||||||
|
"published" BOOLEAN NOT NULL DEFAULT false,
|
||||||
|
"authorId" INTEGER NOT NULL,
|
||||||
|
"s3Key" TEXT NOT NULL,
|
||||||
|
"status" TEXT NOT NULL DEFAULT 'pending',
|
||||||
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||||
|
|
||||||
- Added the required column `updatedAt` to the `Document` table without a default value. This is not possible if the table is not empty.
|
CONSTRAINT "Document_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
*/
|
-- CreateTable
|
||||||
-- AlterTable
|
CREATE TABLE "User" (
|
||||||
ALTER TABLE "Document" ADD COLUMN "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
"id" SERIAL NOT NULL,
|
||||||
ADD COLUMN "status" TEXT NOT NULL DEFAULT 'pending',
|
"email" TEXT NOT NULL,
|
||||||
ADD COLUMN "updatedAt" TIMESTAMP(3) NOT NULL;
|
"name" TEXT,
|
||||||
|
"password" TEXT NOT NULL,
|
||||||
|
"isAdmin" BOOLEAN NOT NULL DEFAULT false,
|
||||||
|
|
||||||
|
CONSTRAINT "User_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
-- CreateTable
|
-- CreateTable
|
||||||
CREATE TABLE "Notification" (
|
CREATE TABLE "Notification" (
|
||||||
@ -26,12 +41,18 @@ CREATE TABLE "_SharedDocuments" (
|
|||||||
"B" INTEGER NOT NULL
|
"B" INTEGER NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "User_email_key" ON "User"("email");
|
||||||
|
|
||||||
-- CreateIndex
|
-- CreateIndex
|
||||||
CREATE UNIQUE INDEX "_SharedDocuments_AB_unique" ON "_SharedDocuments"("A", "B");
|
CREATE UNIQUE INDEX "_SharedDocuments_AB_unique" ON "_SharedDocuments"("A", "B");
|
||||||
|
|
||||||
-- CreateIndex
|
-- CreateIndex
|
||||||
CREATE INDEX "_SharedDocuments_B_index" ON "_SharedDocuments"("B");
|
CREATE INDEX "_SharedDocuments_B_index" ON "_SharedDocuments"("B");
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "Document" ADD CONSTRAINT "Document_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
-- AddForeignKey
|
-- AddForeignKey
|
||||||
ALTER TABLE "Notification" ADD CONSTRAINT "Notification_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
ALTER TABLE "Notification" ADD CONSTRAINT "Notification_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
Warnings:
|
||||||
|
|
||||||
|
- You are about to drop the column `authorId` on the `Document` table. All the data in the column will be lost.
|
||||||
|
- You are about to drop the column `published` on the `Document` table. All the data in the column will be lost.
|
||||||
|
- You are about to drop the `_SharedDocuments` table. If the table is not empty, all the data it contains will be lost.
|
||||||
|
- Added the required column `sharedWithId` to the `Document` table without a default value. This is not possible if the table is not empty.
|
||||||
|
|
||||||
|
*/
|
||||||
|
-- DropForeignKey
|
||||||
|
ALTER TABLE "Document" DROP CONSTRAINT "Document_authorId_fkey";
|
||||||
|
|
||||||
|
-- DropForeignKey
|
||||||
|
ALTER TABLE "_SharedDocuments" DROP CONSTRAINT "_SharedDocuments_A_fkey";
|
||||||
|
|
||||||
|
-- DropForeignKey
|
||||||
|
ALTER TABLE "_SharedDocuments" DROP CONSTRAINT "_SharedDocuments_B_fkey";
|
||||||
|
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "Document" DROP COLUMN "authorId",
|
||||||
|
DROP COLUMN "published",
|
||||||
|
ADD COLUMN "sharedWithId" INTEGER NOT NULL;
|
||||||
|
|
||||||
|
-- DropTable
|
||||||
|
DROP TABLE "_SharedDocuments";
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "Document" ADD CONSTRAINT "Document_sharedWithId_fkey" FOREIGN KEY ("sharedWithId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
@ -1,9 +1,3 @@
|
|||||||
// This is your Prisma schema file,
|
|
||||||
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
|
||||||
|
|
||||||
// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
|
|
||||||
// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init
|
|
||||||
|
|
||||||
generator client {
|
generator client {
|
||||||
provider = "prisma-client-js"
|
provider = "prisma-client-js"
|
||||||
}
|
}
|
||||||
@ -13,19 +7,16 @@ datasource db {
|
|||||||
url = env("DATABASE_URL")
|
url = env("DATABASE_URL")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
model Document {
|
model Document {
|
||||||
id Int @id @default(autoincrement())
|
id Int @id @default(autoincrement())
|
||||||
title String
|
title String
|
||||||
content String?
|
content String?
|
||||||
published Boolean @default(false)
|
|
||||||
authorId Int
|
|
||||||
author User @relation(fields: [authorId], references: [id])
|
|
||||||
s3Key String
|
s3Key String
|
||||||
status String @default("pending") // pending, uploading, completed, failed
|
status String @default("pending")
|
||||||
sharedWith User[] @relation("SharedDocuments")
|
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
|
sharedWithId Int
|
||||||
|
sharedWith User @relation("SharedDocuments", fields: [sharedWithId], references: [id])
|
||||||
}
|
}
|
||||||
|
|
||||||
model User {
|
model User {
|
||||||
@ -34,7 +25,6 @@ model User {
|
|||||||
name String?
|
name String?
|
||||||
password String
|
password String
|
||||||
isAdmin Boolean @default(false)
|
isAdmin Boolean @default(false)
|
||||||
authoredDocuments Document[] @relation("AuthoredDocuments")
|
|
||||||
sharedDocuments Document[] @relation("SharedDocuments")
|
sharedDocuments Document[] @relation("SharedDocuments")
|
||||||
notifications Notification[]
|
notifications Notification[]
|
||||||
}
|
}
|
||||||
@ -44,8 +34,6 @@ model Notification {
|
|||||||
message String
|
message String
|
||||||
read Boolean @default(false)
|
read Boolean @default(false)
|
||||||
userId Int
|
userId Int
|
||||||
user User @relation(fields: [userId], references: [id])
|
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
|
user User @relation(fields: [userId], references: [id])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
30
backend/imk-backend/prisma/seed.ts
Normal file
30
backend/imk-backend/prisma/seed.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import { PrismaClient } from '@prisma/client';
|
||||||
|
import * as bcrypt from 'bcrypt';
|
||||||
|
|
||||||
|
const prisma = new PrismaClient();
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const hashedPassword = await bcrypt.hash('admin123', 10);
|
||||||
|
|
||||||
|
const admin = await prisma.user.upsert({
|
||||||
|
where: { email: 'admin@example.com' },
|
||||||
|
update: {},
|
||||||
|
create: {
|
||||||
|
email: 'admin@example.com',
|
||||||
|
name: 'Admin User',
|
||||||
|
password: hashedPassword,
|
||||||
|
isAdmin: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log({ admin });
|
||||||
|
}
|
||||||
|
|
||||||
|
main()
|
||||||
|
.catch((e) => {
|
||||||
|
console.error(e);
|
||||||
|
process.exit(1);
|
||||||
|
})
|
||||||
|
.finally(async () => {
|
||||||
|
await prisma.$disconnect();
|
||||||
|
});
|
||||||
@ -4,22 +4,21 @@ import {
|
|||||||
Post,
|
Post,
|
||||||
Body,
|
Body,
|
||||||
Param,
|
Param,
|
||||||
Delete,
|
|
||||||
Put,
|
Put,
|
||||||
UseInterceptors,
|
UseInterceptors,
|
||||||
UploadedFile,
|
UploadedFile,
|
||||||
ParseIntPipe,
|
ParseIntPipe,
|
||||||
UseGuards,
|
UseGuards,
|
||||||
Request,
|
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { FileInterceptor } from '@nestjs/platform-express';
|
import { FileInterceptor } from '@nestjs/platform-express';
|
||||||
import { AdminService } from './admin.service';
|
import { AdminService } from './admin.service';
|
||||||
import { CreateDocumentDto } from '../dto/create-document.dto';
|
//import { CreateDocumentDto } from '../dto/create-document.dto';
|
||||||
import { UpdateDocumentDto } from '../dto/update-document.dto';
|
import { UpdateDocumentDto } from '../dto/update-document.dto';
|
||||||
import { AdminGuard } from '../auth/admin.guard';
|
import { AdminGuard } from '../auth/admin.guard';
|
||||||
import { JwtAuthGuard } from '../auth/jwt-auth.guard';
|
import { JwtAuthGuard } from '../auth/jwt-auth.guard';
|
||||||
import { CreateUserDto } from '../dto/create-user.dto';
|
import { CreateUserDto } from '../dto/create-user.dto';
|
||||||
import { S3Service } from 'src/s3/s3.service';
|
import { S3Service } from 'src/s3/s3.service';
|
||||||
|
import { PrismaService } from 'src/prisma/prisma.service';
|
||||||
|
|
||||||
@Controller('admin')
|
@Controller('admin')
|
||||||
@UseGuards(JwtAuthGuard, AdminGuard)
|
@UseGuards(JwtAuthGuard, AdminGuard)
|
||||||
@ -27,27 +26,9 @@ export class AdminController {
|
|||||||
constructor(
|
constructor(
|
||||||
private readonly adminService: AdminService,
|
private readonly adminService: AdminService,
|
||||||
private readonly s3Service: S3Service,
|
private readonly s3Service: S3Service,
|
||||||
|
private readonly prisma: PrismaService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@Post('documents')
|
|
||||||
@UseInterceptors(FileInterceptor('file'))
|
|
||||||
createDocument(
|
|
||||||
@Body() createDocumentDto: CreateDocumentDto,
|
|
||||||
@UploadedFile() file: Express.Multer.File,
|
|
||||||
) {
|
|
||||||
return this.adminService.createDocument(createDocumentDto, file);
|
|
||||||
}
|
|
||||||
|
|
||||||
// @Post('document')
|
|
||||||
// @UseInterceptors(FileInterceptor('file'))
|
|
||||||
// async createDocument(
|
|
||||||
// @Body() createDocumentDto: CreateDocumentDto,
|
|
||||||
// @UploadedFile() file: Express.Multer.File,
|
|
||||||
// ) {
|
|
||||||
// // The actual file upload is handled by the FileInterceptor
|
|
||||||
// // We just need to pass the file to the service
|
|
||||||
// return this.adminService.createDocument(createDocumentDto, file);
|
|
||||||
// }
|
|
||||||
@Get('documents')
|
@Get('documents')
|
||||||
getAllDocuments() {
|
getAllDocuments() {
|
||||||
return this.adminService.getAllDocuments();
|
return this.adminService.getAllDocuments();
|
||||||
@ -63,16 +44,27 @@ export class AdminController {
|
|||||||
return this.adminService.updateDocument(id, updateDocumentDto, file);
|
return this.adminService.updateDocument(id, updateDocumentDto, file);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Delete('documents/:id')
|
|
||||||
async deleteDocument(@Param('id') id: string) {
|
|
||||||
await this.adminService.deleteDocument(+id);
|
|
||||||
return { message: 'Document deleted successfully' };
|
|
||||||
}
|
|
||||||
|
|
||||||
@Get('users')
|
@Get('users')
|
||||||
getAllUsers() {
|
getAllUsers() {
|
||||||
return this.adminService.getAllUsers();
|
return this.adminService.getAllUsers();
|
||||||
}
|
}
|
||||||
|
@Post('test-document')
|
||||||
|
async testDocumentCreation() {
|
||||||
|
try {
|
||||||
|
const document = await this.prisma.document.create({
|
||||||
|
data: {
|
||||||
|
title: 'Test Document',
|
||||||
|
s3Key: 'test-key',
|
||||||
|
status: 'completed',
|
||||||
|
sharedWithId: 2, // ID of 'pero' user
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return document;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Test document creation error:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Post('users')
|
@Post('users')
|
||||||
async createUser(@Body() createUserDto: CreateUserDto) {
|
async createUser(@Body() createUserDto: CreateUserDto) {
|
||||||
@ -82,9 +74,9 @@ export class AdminController {
|
|||||||
@Post('documents/:id/share')
|
@Post('documents/:id/share')
|
||||||
async shareDocument(
|
async shareDocument(
|
||||||
@Param('id') id: string,
|
@Param('id') id: string,
|
||||||
@Body() { userIds }: { userIds: number[] },
|
@Body() { userId }: { userId: number },
|
||||||
) {
|
) {
|
||||||
return this.adminService.shareDocument(+id, userIds);
|
return this.adminService.shareDocument(+id, userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Put('documents/:id/status')
|
@Put('documents/:id/status')
|
||||||
@ -95,25 +87,33 @@ export class AdminController {
|
|||||||
return this.adminService.updateDocumentStatus(+id, status);
|
return this.adminService.updateDocumentStatus(+id, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
// async uploadDocument(
|
@Post('documents')
|
||||||
// @UploadedFile() file: Express.Multer.File,
|
@UseInterceptors(FileInterceptor('file'))
|
||||||
// @Body('title') title: string,
|
|
||||||
// @Request() req,
|
|
||||||
// ) {
|
|
||||||
// return this.adminService.uploadDocument(file, title, req.user.userId);
|
|
||||||
// }
|
|
||||||
async uploadDocument(
|
async uploadDocument(
|
||||||
@UploadedFile() file: Express.Multer.File,
|
@UploadedFile() file: Express.Multer.File,
|
||||||
@Body('title') title: string,
|
@Body('title') title: string,
|
||||||
@Body('description') description: number[],
|
@Body('sharedWith') sharedWithId: string,
|
||||||
@Request() req,
|
|
||||||
) {
|
) {
|
||||||
return this.adminService.uploadDocument(
|
console.log('Received upload request:', {
|
||||||
|
fileExists: !!file,
|
||||||
|
fileSize: file?.size,
|
||||||
|
title,
|
||||||
|
sharedWithId,
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const document = await this.adminService.uploadDocument(
|
||||||
file,
|
file,
|
||||||
title,
|
title,
|
||||||
req.user.userId,
|
Number(sharedWithId),
|
||||||
description,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
console.log('Document created:', document);
|
||||||
|
return document;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Upload error:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@Get('test-s3-connection')
|
@Get('test-s3-connection')
|
||||||
async testS3Connection() {
|
async testS3Connection() {
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { Injectable, NotFoundException } from '@nestjs/common';
|
import { Injectable, NotFoundException } from '@nestjs/common';
|
||||||
import { PrismaService } from '../prisma/prisma.service';
|
import { PrismaService } from '../prisma/prisma.service';
|
||||||
import { S3Service } from '../s3/s3.service';
|
import { S3Service } from '../s3/s3.service';
|
||||||
import { CreateDocumentDto } from '../dto/create-document.dto';
|
//import { CreateDocumentDto } from '../dto/create-document.dto';
|
||||||
import { UpdateDocumentDto } from '../dto/update-document.dto';
|
import { UpdateDocumentDto } from '../dto/update-document.dto';
|
||||||
import { CreateUserDto } from '../dto/create-user.dto';
|
import { CreateUserDto } from '../dto/create-user.dto';
|
||||||
import * as bcrypt from 'bcrypt';
|
import * as bcrypt from 'bcrypt';
|
||||||
@ -13,101 +13,70 @@ export class AdminService {
|
|||||||
private s3Service: S3Service,
|
private s3Service: S3Service,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
// async createDocument(
|
async uploadDocument(
|
||||||
// createDocumentDto: CreateDocumentDto,
|
|
||||||
// file: Express.Multer.File,
|
|
||||||
// ) {
|
|
||||||
// const { title, content, clientEmail } = createDocumentDto;
|
|
||||||
|
|
||||||
// console.log('Received createDocumentDto:', createDocumentDto);
|
|
||||||
|
|
||||||
// let author;
|
|
||||||
// if (clientEmail) {
|
|
||||||
// author = await this.prisma.user.findUnique({
|
|
||||||
// where: { email: clientEmail },
|
|
||||||
// });
|
|
||||||
|
|
||||||
// if (!author) {
|
|
||||||
// throw new NotFoundException(`User with email ${clientEmail} not found`);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const s3Key = await this.s3Service.uploadFile(file, 'documents');
|
|
||||||
|
|
||||||
// return this.prisma.document.create({
|
|
||||||
// data: {
|
|
||||||
// title,
|
|
||||||
// content,
|
|
||||||
// s3Key,
|
|
||||||
// ...(author && { author: { connect: { id: author.id } } }),
|
|
||||||
// },
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
async createDocument(
|
|
||||||
createDocumentDto: CreateDocumentDto,
|
|
||||||
file: Express.Multer.File,
|
file: Express.Multer.File,
|
||||||
|
title: string,
|
||||||
|
sharedWithId: number,
|
||||||
) {
|
) {
|
||||||
const { title, content, clientEmail } = createDocumentDto;
|
try {
|
||||||
|
// First verify the user exists
|
||||||
console.log('Received createDocumentDto:', createDocumentDto);
|
console.log('Verifying user:', sharedWithId);
|
||||||
|
const user = await this.prisma.user.findUnique({
|
||||||
let authorId: number;
|
where: { id: sharedWithId },
|
||||||
if (clientEmail) {
|
|
||||||
const author = await this.prisma.user.findUnique({
|
|
||||||
where: { email: clientEmail },
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!author) {
|
if (!user) {
|
||||||
throw new NotFoundException(`User with email ${clientEmail} not found`);
|
throw new NotFoundException(`User with ID ${sharedWithId} not found`);
|
||||||
}
|
|
||||||
authorId = author.id;
|
|
||||||
} else {
|
|
||||||
// If no clientEmail is provided, we'll use a default admin user
|
|
||||||
// You should replace this with an appropriate default user ID
|
|
||||||
const defaultAdmin = await this.prisma.user.findFirst({
|
|
||||||
where: { isAdmin: true },
|
|
||||||
});
|
|
||||||
if (!defaultAdmin) {
|
|
||||||
throw new NotFoundException('No default admin user found');
|
|
||||||
}
|
|
||||||
authorId = defaultAdmin.id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log('Found user:', user);
|
||||||
|
|
||||||
|
// Upload file to S3
|
||||||
|
console.log('Uploading file to S3...');
|
||||||
const s3Key = await this.s3Service.uploadFile(file, 'documents');
|
const s3Key = await this.s3Service.uploadFile(file, 'documents');
|
||||||
|
console.log('File uploaded to S3:', s3Key);
|
||||||
|
|
||||||
return this.prisma.document.create({
|
console.log('Creating document record with data:', {
|
||||||
|
title,
|
||||||
|
s3Key,
|
||||||
|
sharedWithId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const document = await this.prisma.document.create({
|
||||||
data: {
|
data: {
|
||||||
title,
|
title,
|
||||||
content,
|
|
||||||
s3Key,
|
s3Key,
|
||||||
author: { connect: { id: authorId } },
|
status: 'completed',
|
||||||
|
sharedWithId,
|
||||||
},
|
},
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// async getAllDocuments() {
|
|
||||||
// return this.prisma.document.findMany({
|
|
||||||
// include: {
|
|
||||||
// sharedWith: {
|
|
||||||
// select: {
|
|
||||||
// id: true,
|
|
||||||
// name: true,
|
|
||||||
// email: true,
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
async getAllDocuments() {
|
|
||||||
return this.prisma.document.findMany({
|
|
||||||
include: {
|
include: {
|
||||||
author: {
|
sharedWith: {
|
||||||
select: {
|
select: {
|
||||||
id: true,
|
id: true,
|
||||||
name: true,
|
name: true,
|
||||||
email: true,
|
email: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('Created document:', document);
|
||||||
|
return document;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error in uploadDocument:', error);
|
||||||
|
if (error.code === 'P2002') {
|
||||||
|
console.error('Unique constraint violation');
|
||||||
|
}
|
||||||
|
if (error.code === 'P2003') {
|
||||||
|
console.error('Foreign key constraint violation');
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async getAllDocuments() {
|
||||||
|
try {
|
||||||
|
const documents = await this.prisma.document.findMany({
|
||||||
|
include: {
|
||||||
sharedWith: {
|
sharedWith: {
|
||||||
select: {
|
select: {
|
||||||
id: true,
|
id: true,
|
||||||
@ -120,6 +89,13 @@ export class AdminService {
|
|||||||
createdAt: 'desc',
|
createdAt: 'desc',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
console.log('Retrieved documents with shared users:', documents);
|
||||||
|
return documents;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching documents:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateDocument(
|
async updateDocument(
|
||||||
@ -149,57 +125,6 @@ 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({
|
|
||||||
where: { id },
|
|
||||||
select: { s3Key: true },
|
|
||||||
});
|
|
||||||
if (document?.s3Key) {
|
|
||||||
await this.s3Service.deleteFile(document.s3Key);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.prisma.document.delete({ where: { id } });
|
|
||||||
}
|
|
||||||
|
|
||||||
async getAllUsers() {
|
|
||||||
return this.prisma.user.findMany();
|
|
||||||
}
|
|
||||||
|
|
||||||
async createUser(createUserDto: CreateUserDto) {
|
async createUser(createUserDto: CreateUserDto) {
|
||||||
const hashedPassword = await bcrypt.hash(createUserDto.password, 10);
|
const hashedPassword = await bcrypt.hash(createUserDto.password, 10);
|
||||||
@ -211,25 +136,22 @@ export class AdminService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async shareDocument(documentId: number, userIds: number[]) {
|
async shareDocument(documentId: number, userId: number) {
|
||||||
const document = await this.prisma.document.update({
|
return this.prisma.document.update({
|
||||||
where: { id: documentId },
|
where: { id: documentId },
|
||||||
data: {
|
data: {
|
||||||
|
sharedWithId: userId,
|
||||||
|
},
|
||||||
|
include: {
|
||||||
sharedWith: {
|
sharedWith: {
|
||||||
connect: userIds.map((id: number) => ({ id })),
|
select: {
|
||||||
|
id: true,
|
||||||
|
name: true,
|
||||||
|
email: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create notifications for shared users
|
|
||||||
await this.prisma.notification.createMany({
|
|
||||||
data: userIds.map((userId: number) => ({
|
|
||||||
userId,
|
|
||||||
message: `A new document "${document.title}" has been shared with you.`,
|
|
||||||
})),
|
|
||||||
});
|
|
||||||
|
|
||||||
return document;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateDocumentStatus(documentId: number, status: string) {
|
async updateDocumentStatus(documentId: number, status: string) {
|
||||||
@ -239,100 +161,6 @@ export class AdminService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// async uploadDocument(
|
|
||||||
// file: Express.Multer.File,
|
|
||||||
// title: string,
|
|
||||||
// userId: number,
|
|
||||||
// ) {
|
|
||||||
// try {
|
|
||||||
// // First create document with pending status
|
|
||||||
// const document = await this.prisma.document.create({
|
|
||||||
// data: {
|
|
||||||
// title,
|
|
||||||
// authorId: userId,
|
|
||||||
// status: 'pending',
|
|
||||||
// s3Key: '', // Temporary empty key
|
|
||||||
// },
|
|
||||||
// });
|
|
||||||
|
|
||||||
// // Update status to uploading
|
|
||||||
// await this.prisma.document.update({
|
|
||||||
// where: { id: document.id },
|
|
||||||
// data: { status: 'uploading' },
|
|
||||||
// });
|
|
||||||
|
|
||||||
// // Upload to S3
|
|
||||||
// const s3Key = await this.s3Service.uploadFile(file, 'documents');
|
|
||||||
|
|
||||||
// // Update document with s3Key and completed status
|
|
||||||
// return this.prisma.document.update({
|
|
||||||
// where: { id: document.id },
|
|
||||||
// data: {
|
|
||||||
// s3Key,
|
|
||||||
// status: 'completed',
|
|
||||||
// },
|
|
||||||
// });
|
|
||||||
// } catch (error) {
|
|
||||||
// // If anything fails, update status to failed
|
|
||||||
// const document = await this.prisma.document.findFirst({
|
|
||||||
// where: { title, authorId: userId },
|
|
||||||
// });
|
|
||||||
// if (document) {
|
|
||||||
// await this.prisma.document.update({
|
|
||||||
// where: { id: document.id },
|
|
||||||
// data: { status: 'failed' },
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// throw error;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// problem whith upload status writing to db, i will fix it later
|
|
||||||
|
|
||||||
// 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
|
|
||||||
// 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',
|
|
||||||
// sharedWith: {
|
|
||||||
// connect: sharedWith.map((id: number) => ({ id })),
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// throw error;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
async getDocumentUrl(documentId: number) {
|
async getDocumentUrl(documentId: number) {
|
||||||
const document = await this.prisma.document.findUnique({
|
const document = await this.prisma.document.findUnique({
|
||||||
where: { id: documentId },
|
where: { id: documentId },
|
||||||
@ -342,4 +170,34 @@ export class AdminService {
|
|||||||
}
|
}
|
||||||
return this.s3Service.getFileUrl(document.s3Key);
|
return this.s3Service.getFileUrl(document.s3Key);
|
||||||
}
|
}
|
||||||
|
async getUserWithDocuments(userId: number) {
|
||||||
|
return this.prisma.user.findUnique({
|
||||||
|
where: { id: userId },
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
name: true,
|
||||||
|
email: true,
|
||||||
|
sharedDocuments: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async getAllUsers() {
|
||||||
|
try {
|
||||||
|
const users = await this.prisma.user.findMany({
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
name: true,
|
||||||
|
email: true,
|
||||||
|
isAdmin: true,
|
||||||
|
sharedDocuments: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
console.log('All users:', users);
|
||||||
|
return users;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching users:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import { PrismaService } from './prisma/prisma.service';
|
|||||||
import { PrismaModule } from './prisma/prisma.module';
|
import { PrismaModule } from './prisma/prisma.module';
|
||||||
import { ConfigModule } from '@nestjs/config';
|
import { ConfigModule } from '@nestjs/config';
|
||||||
import { AuthController } from './auth/auth.controller';
|
import { AuthController } from './auth/auth.controller';
|
||||||
|
import { DocumentsController } from './documents/documents.controller';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
@ -32,7 +33,7 @@ import { AuthController } from './auth/auth.controller';
|
|||||||
S3Module,
|
S3Module,
|
||||||
PrismaModule,
|
PrismaModule,
|
||||||
],
|
],
|
||||||
controllers: [AppController, AuthController],
|
controllers: [AppController, AuthController, DocumentsController],
|
||||||
providers: [
|
providers: [
|
||||||
AppService,
|
AppService,
|
||||||
UploadService,
|
UploadService,
|
||||||
|
|||||||
@ -10,6 +10,6 @@ export class ClientController {
|
|||||||
|
|
||||||
@Get('documents')
|
@Get('documents')
|
||||||
async getClientDocuments(@User() user) {
|
async getClientDocuments(@User() user) {
|
||||||
return this.clientService.getClientDocuments(user.id);
|
return this.clientService.getDocuments(user.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,10 +5,26 @@ import { PrismaService } from '../prisma/prisma.service';
|
|||||||
export class ClientService {
|
export class ClientService {
|
||||||
constructor(private prisma: PrismaService) {}
|
constructor(private prisma: PrismaService) {}
|
||||||
|
|
||||||
async getClientDocuments(userId: string) {
|
// async getClientDocuments(userId: string) {
|
||||||
|
// return this.prisma.document.findMany({
|
||||||
|
// where: {
|
||||||
|
// authorId: Number(userId),
|
||||||
|
// },
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
async getDocuments(userId: string) {
|
||||||
return this.prisma.document.findMany({
|
return this.prisma.document.findMany({
|
||||||
where: {
|
where: {
|
||||||
authorId: Number(userId),
|
sharedWithId: Number(userId),
|
||||||
|
},
|
||||||
|
include: {
|
||||||
|
sharedWith: {
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
name: true,
|
||||||
|
email: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,18 @@
|
|||||||
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
|
import { DocumentsController } from './documents.controller';
|
||||||
|
|
||||||
|
describe('DocumentsController', () => {
|
||||||
|
let controller: DocumentsController;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
|
controllers: [DocumentsController],
|
||||||
|
}).compile();
|
||||||
|
|
||||||
|
controller = module.get<DocumentsController>(DocumentsController);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be defined', () => {
|
||||||
|
expect(controller).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
12
backend/imk-backend/src/documents/documents.controller.ts
Normal file
12
backend/imk-backend/src/documents/documents.controller.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { Controller, Get, Param } from '@nestjs/common';
|
||||||
|
import { DocumentsService } from './documents.service';
|
||||||
|
|
||||||
|
@Controller('documents')
|
||||||
|
export class DocumentsController {
|
||||||
|
constructor(private readonly documentsService: DocumentsService) {}
|
||||||
|
@Get('shared/:userId')
|
||||||
|
async getSharedDocuments(@Param('userId') userId: string) {
|
||||||
|
console.log('userId', userId);
|
||||||
|
return this.documentsService.getClientDocuments(parseInt(userId));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,14 +1,33 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { PrismaService } from '../prisma/prisma.service';
|
import { PrismaService } from '../prisma/prisma.service';
|
||||||
import { Document } from '@prisma/client';
|
//import { Document } from '@prisma/client';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class DocumentsService {
|
export class DocumentsService {
|
||||||
constructor(private readonly prisma: PrismaService) {}
|
constructor(private readonly prisma: PrismaService) {}
|
||||||
|
|
||||||
async findAllForClient(clientId: number): Promise<Document[]> {
|
async getClientDocuments(clientId: number) {
|
||||||
|
// return this.prisma.document.findMany({
|
||||||
|
// where: {
|
||||||
|
// sharedWithId: clientId,
|
||||||
|
// },
|
||||||
|
// include: {
|
||||||
|
// sharedWith: {
|
||||||
|
// select: {
|
||||||
|
// id: true,
|
||||||
|
// name: true,
|
||||||
|
// email: true,
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// });
|
||||||
return this.prisma.document.findMany({
|
return this.prisma.document.findMany({
|
||||||
where: { authorId: clientId },
|
where: {
|
||||||
|
sharedWithId: clientId,
|
||||||
|
},
|
||||||
|
orderBy: {
|
||||||
|
createdAt: 'desc',
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -148,8 +148,11 @@ function AdminPanel() {
|
|||||||
{doc.status}
|
{doc.status}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
{/* <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
||||||
{doc.sharedWith?.map((user) => user.name).join(', ') || 'None'}
|
{doc.sharedWith?.map((user) => user.name).join(', ') || 'None'}
|
||||||
|
</td> */}
|
||||||
|
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
||||||
|
{doc.sharedWith ? `${doc.sharedWith.name} (${doc.sharedWith.email})` : 'None'}
|
||||||
</td>
|
</td>
|
||||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
||||||
{new Date(doc.createdAt).toLocaleDateString()}
|
{new Date(doc.createdAt).toLocaleDateString()}
|
||||||
|
|||||||
@ -1,11 +1,93 @@
|
|||||||
import React from 'react'
|
import { useState, useEffect } from 'react'
|
||||||
|
import { useAuth } from '../../hooks/useAuth';
|
||||||
|
import { getSharedDocuments } from '../../services/api';
|
||||||
|
|
||||||
function Clients() {
|
function Clients() {
|
||||||
return (
|
const [documents, setDocuments] = useState([]);
|
||||||
<div>
|
const [loading, setLoading] = useState(true);
|
||||||
|
const [error, setError] = useState('');
|
||||||
|
const { user } = useAuth();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchDocuments = async () => {
|
||||||
|
try {
|
||||||
|
const response = await getSharedDocuments(user.id);
|
||||||
|
setDocuments(response.data);
|
||||||
|
} catch (err) {
|
||||||
|
setError('Failed to fetch documents');
|
||||||
|
console.error('Error fetching documents:', err);
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (user) {
|
||||||
|
fetchDocuments();
|
||||||
|
}
|
||||||
|
}, [user]);
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
|
return (
|
||||||
|
<div className="flex justify-center items-center min-h-screen">
|
||||||
|
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-gray-900"></div>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return (
|
||||||
|
<div className="text-center text-red-600 p-4">
|
||||||
|
{error}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="container mx-auto px-4 py-8">
|
||||||
|
<h1 className="text-2xl font-bold mb-6">Your Documents</h1>
|
||||||
|
|
||||||
|
{documents.length === 0 ? (
|
||||||
|
<p className="text-gray-600">No documents have been shared with you yet.</p>
|
||||||
|
) : (
|
||||||
|
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
|
||||||
|
{documents.map((doc) => (
|
||||||
|
<div
|
||||||
|
key={doc.id}
|
||||||
|
className="bg-white p-6 rounded-lg shadow-md hover:shadow-lg transition-shadow"
|
||||||
|
>
|
||||||
|
<div className="flex justify-between items-start mb-4">
|
||||||
|
<h2 className="text-xl font-semibold">{doc.title}</h2>
|
||||||
|
<span className={`px-2 py-1 text-xs rounded-full ${
|
||||||
|
doc.status === 'completed'
|
||||||
|
? 'bg-green-100 text-green-800'
|
||||||
|
: 'bg-yellow-100 text-yellow-800'
|
||||||
|
}`}>
|
||||||
|
{doc.status}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="text-sm text-gray-600">
|
||||||
|
<p>Created: {new Date(doc.createdAt).toLocaleDateString()}</p>
|
||||||
|
{doc.content && (
|
||||||
|
<p className="mt-2">{doc.content}</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-4 flex justify-end">
|
||||||
|
<button
|
||||||
|
onClick={() => window.open(`/api/documents/download/${doc.s3Key}`, '_blank')}
|
||||||
|
className="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600 transition-colors"
|
||||||
|
>
|
||||||
|
Download
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Clients
|
export default Clients;
|
||||||
|
|
||||||
|
|||||||
@ -27,8 +27,11 @@ function DocumentUpload() {
|
|||||||
setFile(selectedFile);
|
setFile(selectedFile);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSubmit = async (event) => {
|
const handleSubmit = async (event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
|
console.log('Form submission:', { file, title, selectedUsers });
|
||||||
|
|
||||||
if (!file || !title || selectedUsers.length === 0) {
|
if (!file || !title || selectedUsers.length === 0) {
|
||||||
setErrorMessage('Please provide a title, file, and select at least one user');
|
setErrorMessage('Please provide a title, file, and select at least one user');
|
||||||
return;
|
return;
|
||||||
@ -40,21 +43,29 @@ function DocumentUpload() {
|
|||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append('file', file);
|
formData.append('file', file);
|
||||||
formData.append('title', title);
|
formData.append('title', title);
|
||||||
formData.append('sharedWith', JSON.stringify(selectedUsers));
|
formData.append('sharedWith', selectedUsers[0]);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await uploadDocument(formData);
|
console.log('Sending request with:', {
|
||||||
|
title,
|
||||||
|
sharedWith: selectedUsers[0],
|
||||||
|
fileSize: file.size
|
||||||
|
});
|
||||||
|
|
||||||
|
const response = await uploadDocument(formData);
|
||||||
|
console.log('Upload response:', response);
|
||||||
|
|
||||||
setStatus('completed');
|
setStatus('completed');
|
||||||
setTitle('');
|
setTitle('');
|
||||||
setFile(null);
|
setFile(null);
|
||||||
setSelectedUsers([]);
|
setSelectedUsers([]);
|
||||||
event.target.reset();
|
event.target.reset();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
console.error('Upload error:', error);
|
||||||
setStatus('failed');
|
setStatus('failed');
|
||||||
setErrorMessage(error.response?.data?.message || 'Upload failed');
|
setErrorMessage(error.response?.data?.message || 'Upload failed');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="max-w-md mx-auto mt-8 p-6 bg-white rounded-lg shadow-md">
|
<div className="max-w-md mx-auto mt-8 p-6 bg-white rounded-lg shadow-md">
|
||||||
<h2 className="text-2xl font-bold mb-6">Upload Document</h2>
|
<h2 className="text-2xl font-bold mb-6">Upload Document</h2>
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import axios from 'axios';
|
|||||||
const API_URL = 'http://localhost:3000';
|
const API_URL = 'http://localhost:3000';
|
||||||
|
|
||||||
const api = axios.create({
|
const api = axios.create({
|
||||||
baseURL: API_URL,
|
baseURL: API_URL
|
||||||
});
|
});
|
||||||
|
|
||||||
api.interceptors.request.use((config) => {
|
api.interceptors.request.use((config) => {
|
||||||
@ -16,26 +16,28 @@ api.interceptors.request.use((config) => {
|
|||||||
});
|
});
|
||||||
export const createUser = (userData) => api.post('/admin/users', userData);
|
export const createUser = (userData) => api.post('/admin/users', userData);
|
||||||
export const login = (username, password) => api.post('/auth/login', { username, password });
|
export const login = (username, password) => api.post('/auth/login', { username, password });
|
||||||
// export const getAllUsers = () => api.get('/admin/users');
|
|
||||||
export const shareDocument = (documentId, userIds) => api.post(`/admin/documents/${documentId}/share`, { userIds });
|
export const shareDocument = (documentId, userIds) => api.post(`/admin/documents/${documentId}/share`, { userIds });
|
||||||
export const updateDocumentStatus = (documentId, status) => api.put(`/admin/documents/${documentId}/status`, { status });
|
export const updateDocumentStatus = (documentId, status) => api.put(`/admin/documents/${documentId}/status`, { status });
|
||||||
// export const uploadDocument = (formData) => api.post('/admin/documents', formData, {
|
|
||||||
// headers: { 'Content-Type': 'multipart/form-data' },
|
|
||||||
// });
|
|
||||||
|
|
||||||
|
|
||||||
export const uploadDocument = async (formData) => {
|
export const uploadDocument = async (formData) => {
|
||||||
|
try {
|
||||||
const response = await api.post('/admin/documents', formData, {
|
const response = await api.post('/admin/documents', formData, {
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'multipart/form-data',
|
'Content-Type': 'multipart/form-data',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
console.log('Upload API response:', response.data);
|
||||||
return response.data;
|
return response.data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Upload API error:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
export const getUserInfo = () => api.get('/auth/user-info');
|
export const getUserInfo = () => api.get('/auth/user-info');
|
||||||
// ... existing code ...
|
|
||||||
|
|
||||||
export const getAllDocuments = () => api.get('/admin/documents');
|
export const getAllDocuments = () => api.get('/admin/documents');
|
||||||
|
export const getSharedDocuments = (userId) => api.get(`/documents/shared/${userId}`);
|
||||||
export const getAllUsers = () => api.get('/admin/users');
|
export const getAllUsers = () => api.get('/admin/users');
|
||||||
|
|
||||||
export default api;
|
export default api;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user