Skip to content

Commit 3cbcda0

Browse files
committed
Добавлена поддержка переименования папок и файлов.
Исправлена ошибка при скачивании папок на русском.
1 parent 6828540 commit 3cbcda0

3 files changed

Lines changed: 73 additions & 12 deletions

File tree

backend/server.js

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,14 @@ function isPathInsideRoot(fullPath) {
2222

2323
const accept = resolvedTarget.startsWith(resolvedRoot);
2424

25-
console.log(`[Защита каталога] [${accept}] Проверка пути: ${resolvedTarget} в ${resolvedRoot}`);
25+
// console.log(`[Защита каталога] [${accept}] Проверка пути: ${resolvedTarget} в ${resolvedRoot}`);
2626

2727
return accept;
2828
}
2929

3030
// Получение списка файлов и папок
3131
app.get('/api/files', (req, res) => {
3232
const dirPath = path.join(DIR_PATH, req.query.path || '/');
33-
console.log(`[Чтение каталога] Попытка получить файлы: ${req.query.path || '/'}`);
3433
if (!isPathInsideRoot(dirPath)) {
3534
res.status(400).json({ error: 'Неверный путь' });
3635
return;
@@ -42,13 +41,13 @@ app.get('/api/files', (req, res) => {
4241
isDirectory: file.isDirectory()
4342
}));
4443
res.json(result);
44+
console.log(`Файлы получены: ${req.query.path || '/'}`);
4545
});
4646
});
4747

4848
// Удаление файла или папки
4949
app.delete('/api/files', (req, res) => {
5050
const targetPath = path.join(DIR_PATH, req.query.path || '');
51-
console.log(`[Удаление файла/каталога] Попытка удалить файл/каталог: ${req.query.path || ''}`);
5251
if (!isPathInsideRoot(targetPath)) {
5352
res.status(400).json({ error: 'Неверный путь' });
5453
return;
@@ -59,24 +58,44 @@ app.delete('/api/files', (req, res) => {
5958
fs.rm(targetPath, { recursive: true, force: true }, err => {
6059
if (err) return res.status(500).json({ error: 'Ошибка удаления папки' });
6160
res.json({ message: 'Папка удалена' });
61+
console.log(`Папка удалена: ${req.query.path || ''}`);
6262
});
6363
} else {
6464
fs.unlink(targetPath, err => {
6565
if (err) return res.status(500).json({ error: 'Ошибка удаления файла' });
6666
res.json({ message: 'Файл удален' });
67+
console.log(`Файл удален: ${req.query.path || ''}`);
6768
});
6869
}
6970
});
7071
});
7172

73+
// Переименование файла или папки
74+
app.post('/api/rename', (req, res) => {
75+
const { path: targetPath, name } = req.body;
76+
77+
const oldPath = path.join(DIR_PATH, targetPath);
78+
const newPath = path.join(path.dirname(oldPath), name);
79+
80+
if (!isPathInsideRoot(oldPath) || !isPathInsideRoot(newPath)) {
81+
res.status(400).json({ error: 'Неверный путь' });
82+
return;
83+
}
84+
85+
fs.rename(oldPath, newPath, err => {
86+
if (err) return res.status(500).json({ error: 'Ошибка переименования' });
87+
res.json({ message: 'Переименование успешно' });
88+
89+
console.log(`Переименовано ${oldPath} на ${newPath}`);
90+
});
91+
})
92+
7293
// Создание файла или папки
7394
app.post('/api/files', (req, res) => {
7495
const { path: targetPath, type } = req.body;
7596

7697
const fullPath = path.join(DIR_PATH, targetPath);
7798

78-
console.log(`[Создание файла/каталога] Попытка создать файл/каталог: ${targetPath}`);
79-
8099
if (!isPathInsideRoot(fullPath)) {
81100
res.status(400).json({ error: 'Неверный путь' });
82101
return;
@@ -86,11 +105,13 @@ app.post('/api/files', (req, res) => {
86105
fs.mkdir(fullPath, { recursive: false }, err => {
87106
if (err) return res.status(500).json({ error: 'Ошибка создания папки' });
88107
res.json({ message: 'Папка создана' });
108+
console.log(`Папка создана: ${targetPath}`);
89109
});
90110
} else if (type === 'file') {
91111
fs.writeFile(fullPath, '', err => {
92112
if (err) return res.status(500).json({ error: 'Ошибка создания файла' });
93113
res.json({ message: 'Файл создан' });
114+
console.log(`Файл создан: ${targetPath}`);
94115
});
95116
} else {
96117
res.status(400).json({ error: 'Неверный тип. Используйте "file" или "folder".' });
@@ -105,8 +126,6 @@ app.post('/api/upload', (req, res) => {
105126
const { filename } = info;
106127
const saveTo = path.join(DIR_PATH, req.query.destination || '/', filename);
107128

108-
console.log(`[Получение файла] Попытка сохранить файл: ${req.query.destination || '/'}`);
109-
110129
if (!isPathInsideRoot(saveTo)) {
111130
return res.status(400).json({ error: 'Неверный путь' });
112131
}
@@ -145,7 +164,6 @@ app.post('/api/upload', (req, res) => {
145164

146165
app.get('/api/notes', (req, res) => {
147166
const filePath = path.join(DIR_PATH, (req.query.path || '') + "notes.txt");
148-
console.log(`[Получение заметок каталога] Попытка получить заметки: ${(req.query.path || '') + "notes.txt"}`);
149167
if (!isPathInsideRoot(filePath)) {
150168
res.status(400).json({ error: 'Неверный путь' });
151169
return;
@@ -154,6 +172,7 @@ app.get('/api/notes', (req, res) => {
154172
let notes = "";
155173
if (fs.existsSync(filePath)) {
156174
notes = fs.readFileSync(filePath, 'utf-8');
175+
console.log(`Заметки получены: ${filePath}`);
157176
}
158177

159178
res.json({ message: notes });
@@ -162,7 +181,6 @@ app.get('/api/notes', (req, res) => {
162181
// Скачивание файла или папки (как zip)
163182
app.get('/api/download', (req, res) => {
164183
const filePath = path.join(DIR_PATH, req.query.path || '');
165-
console.log(`[Скачивание файла] Попытка скачать файл: ${req.query.path || ''}`);
166184
if (!isPathInsideRoot(filePath)) {
167185
res.status(400).json({ error: 'Неверный путь' });
168186
return;
@@ -177,12 +195,15 @@ app.get('/api/download', (req, res) => {
177195
// Скачиваем файл
178196
res.download(filePath, err => {
179197
if (err) res.status(500).json({ error: 'Ошибка скачивания файла' });
198+
console.log(`Файл скачан: ${filePath}`);
180199
});
181200
} else if (stats.isDirectory()) {
182201
// Скачиваем папку как zip
183202
const folderName = path.basename(filePath);
184203
res.setHeader('Content-Type', 'application/zip');
185-
res.setHeader('Content-Disposition', `attachment; filename=${folderName}.zip`);
204+
205+
const encodedName = encodeURIComponent(folderName + '.zip');
206+
res.setHeader('Content-Disposition', `attachment; filename="${encodedName}.zip"; filename*=UTF-8''${encodedName}`);
186207

187208
const archive = archiver('zip', { zlib: { level: 9 } });
188209
archive.directory(filePath, false);
@@ -191,6 +212,8 @@ app.get('/api/download', (req, res) => {
191212
archive.finalize().catch(err => {
192213
console.error(err);
193214
res.status(500).json({ error: 'Ошибка архивации' });
215+
}).finally(() => {
216+
console.log(`Папка скачана: ${filePath}`);
194217
});
195218
} else {
196219
res.status(400).json({ error: 'Недопустимый тип' });

frontend/app.js

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,17 @@ async function loadFiles(path = '/') {
142142

143143
const actions = document.createElement('div');
144144

145+
const renameBtn = document.createElement('button');
146+
147+
renameBtn.textContent = '✏️ Переименовать';
148+
renameBtn.classList.add('rename');
149+
renameBtn.onclick = (e) => {
150+
e.stopPropagation();
151+
renameFile(file.name, `${path}${file.name}`);
152+
};
153+
154+
actions.appendChild(renameBtn);
155+
145156
const downloadBtn = document.createElement('button');
146157

147158
// Переход внутрь папки
@@ -225,9 +236,28 @@ async function deleteFile(filePath) {
225236
}
226237
}
227238

239+
// Переименование каталога
240+
async function renameFile(oldName, filePath) {
241+
const newName = prompt('Введите новое название:', oldName);
242+
if (newName) {
243+
const response = await fetch(`${API_URL}/rename`, {
244+
method: 'POST',
245+
headers: { 'Content-Type': 'application/json' },
246+
body: JSON.stringify({ path: filePath, name: newName })
247+
});
248+
249+
const result = await response.json();
250+
if (result.error) {
251+
alert(`Ошибка: ${result.error}`);
252+
}
253+
254+
refreshCurrentFolder();
255+
}
256+
}
257+
228258
// Создание каталога
229259
async function createFolder() {
230-
const folderName = prompt('Введите имя новой папки:');
260+
const folderName = prompt('Введите название новой папки:');
231261
if (folderName) {
232262
const response = await fetch(`${API_URL}/files`, {
233263
method: 'POST',
@@ -246,7 +276,7 @@ async function createFolder() {
246276

247277
// Создание файла
248278
async function createFile() {
249-
const fileName = prompt('Введите имя нового файла:');
279+
const fileName = prompt('Введите название нового файла:');
250280
if (fileName) {
251281
const response = await fetch(`${API_URL}/files`, {
252282
method: 'POST',

frontend/style.css

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ h1 {
2727
background-color: hsl(0, 70%, 60%);
2828
}
2929

30+
.file button.rename {
31+
background-color: hsl(133, 70%, 60%);
32+
}
33+
3034
.file button:hover {
3135
background-color: hsl(216, 70%, 70%);
3236
}
@@ -35,6 +39,10 @@ h1 {
3539
background-color: hsl(0, 70%, 70%);
3640
}
3741

42+
.file button.rename:hover {
43+
background-color: hsl(133, 70%, 70%);
44+
}
45+
3846
#nav {
3947
margin: 10px 0;
4048
}

0 commit comments

Comments
 (0)