Доработана работа с пользователями (ввод пароля и отмена автозаполнения) Добавлен логотип блога.
This commit is contained in:
parent
e4d5029e72
commit
9ba64a453c
107
.import/mysql_json_convert.py
Normal file
107
.import/mysql_json_convert.py
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
import json
|
||||||
|
import io
|
||||||
|
from datetime import datetime
|
||||||
|
from bs4 import BeautifulSoup
|
||||||
|
|
||||||
|
# Файл дампа
|
||||||
|
input_directory = "D:/__TEMP/____4/__convert"
|
||||||
|
json_file = "1-2025"
|
||||||
|
output_file = "2-2025-convert.json"
|
||||||
|
|
||||||
|
def main():
|
||||||
|
try:
|
||||||
|
f = io.open(input_directory + '/' + json_file + '.json', encoding='utf-8')
|
||||||
|
records = json.loads(f.read())
|
||||||
|
except FileNotFoundError:
|
||||||
|
print("Ошибка: Входной JSON файл не найден.")
|
||||||
|
return
|
||||||
|
except json.JSONDecodeError as e:
|
||||||
|
print(f"Ошибка декодирования JSON: {e}")
|
||||||
|
return
|
||||||
|
|
||||||
|
articles = list()
|
||||||
|
|
||||||
|
for item in records:
|
||||||
|
try:
|
||||||
|
article = dict()
|
||||||
|
|
||||||
|
pre = item['pre']
|
||||||
|
full = item['full']
|
||||||
|
|
||||||
|
article['id'] = item['id']
|
||||||
|
article['title'] = item['title']
|
||||||
|
article['content'] = full
|
||||||
|
article['categoryId'] = item['cat_id']
|
||||||
|
article['cityId'] = item['city_id']
|
||||||
|
|
||||||
|
soup = BeautifulSoup(pre, "html.parser")
|
||||||
|
|
||||||
|
# Извлекаем URL изображения
|
||||||
|
img_tag = soup.find("img")
|
||||||
|
img_url = img_tag["src"] if img_tag else None
|
||||||
|
|
||||||
|
# Удаляем тег <img> из HTML
|
||||||
|
if img_tag:
|
||||||
|
img_tag.decompose()
|
||||||
|
|
||||||
|
# Удаляем пустые <p> (с пробелами или полностью пустые)
|
||||||
|
for p in soup.find_all("p"):
|
||||||
|
if not p.get_text(strip=True): # strip=True убирает пробелы и невидимые символы
|
||||||
|
p.decompose()
|
||||||
|
|
||||||
|
# Извлекаем текст из оставшихся <p>
|
||||||
|
text_content = " ".join(p.get_text(strip=True) for p in soup.find_all("p"))
|
||||||
|
|
||||||
|
if not text_content:
|
||||||
|
# Находим первый тег <p> и извлекаем текст
|
||||||
|
soup = BeautifulSoup(full, "html.parser")
|
||||||
|
first_p = soup.find("p")
|
||||||
|
text_content = first_p.get_text(strip=True) if first_p else ""
|
||||||
|
|
||||||
|
article['excerpt'] = text_content
|
||||||
|
article['coverImage'] = img_url
|
||||||
|
|
||||||
|
article['readTime'] = 2
|
||||||
|
article['likes'] = 0
|
||||||
|
article['dislikes'] = 0
|
||||||
|
|
||||||
|
article['gallery'] = []
|
||||||
|
|
||||||
|
# Разбираем строку в объект datetime
|
||||||
|
date_obj = datetime.strptime(item['date'], "%d.%m.%Y")
|
||||||
|
|
||||||
|
# Преобразуем в нужный формат
|
||||||
|
formatted_date = date_obj.strftime("%Y-%m-%dT00:00:00Z")
|
||||||
|
|
||||||
|
article['publishedAt'] = formatted_date
|
||||||
|
|
||||||
|
author = dict()
|
||||||
|
author['id'] = '41e09d9a-f9c1-44a7-97f4-0be694371e7e'
|
||||||
|
|
||||||
|
article['author'] = author
|
||||||
|
|
||||||
|
articles.append(article)
|
||||||
|
|
||||||
|
except KeyError as e:
|
||||||
|
print(f"Потерян ключ в записи: {e}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
save_to_json_file(output_file, articles, 'w')
|
||||||
|
|
||||||
|
|
||||||
|
def save_to_file(path, data, mode):
|
||||||
|
f = open(input_directory + '/' + path, mode)
|
||||||
|
f.write(data)
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
def save_to_json_file(path, data, mode):
|
||||||
|
f = io.open(input_directory + '/' + path, encoding='utf-8', mode=mode)
|
||||||
|
json.dump(data, f, ensure_ascii=False, indent=2)
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
|
||||||
|
#def create_article:
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
BIN
public/images/Logo-3.png
Normal file
BIN
public/images/Logo-3.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 903 KiB |
BIN
public/images/Logo-4.png
Normal file
BIN
public/images/Logo-4.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 951 KiB |
@ -91,7 +91,7 @@ export function Header() {
|
|||||||
to={`/?category=${category}${currentCity ? `&city=${currentCity}` : ''}`}
|
to={`/?category=${category}${currentCity ? `&city=${currentCity}` : ''}`}
|
||||||
className={`px-3 py-2 font-medium transition-colors whitespace-nowrap ${
|
className={`px-3 py-2 font-medium transition-colors whitespace-nowrap ${
|
||||||
Number(currentCategory) === category
|
Number(currentCategory) === category
|
||||||
? 'text-base md:text-lg lg:text-xl font-semibold text-blue-600 hover:text-blue-800 underline'
|
? 'text-base md:text-lg lg:text-xl font-semibold text-blue-600 hover:text-blue-800 bg-gray-200'
|
||||||
: 'text-sm md:text-base lg:text-lg font-medium text-gray-600 hover:text-gray-900'
|
: 'text-sm md:text-base lg:text-lg font-medium text-gray-600 hover:text-gray-900'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
|
@ -16,7 +16,7 @@ const initialFormData: UserFormData = {
|
|||||||
password: '',
|
password: '',
|
||||||
displayName: '',
|
displayName: '',
|
||||||
bio: '',
|
bio: '',
|
||||||
avatarUrl: ''
|
avatarUrl: '/images/avatar.jpg'
|
||||||
};
|
};
|
||||||
|
|
||||||
export function UserManagementPage() {
|
export function UserManagementPage() {
|
||||||
@ -253,7 +253,7 @@ export function UserManagementPage() {
|
|||||||
<div className="bg-white rounded-lg max-w-md w-full p-6">
|
<div className="bg-white rounded-lg max-w-md w-full p-6">
|
||||||
<div className="flex justify-between items-center mb-4">
|
<div className="flex justify-between items-center mb-4">
|
||||||
<h3 className="text-lg font-medium text-gray-900">
|
<h3 className="text-lg font-medium text-gray-900">
|
||||||
{showCreateModal ? 'Создание нового' : 'Редактирование'}
|
{showCreateModal ? 'Создание нового пользователя' : 'Редактирование'}
|
||||||
</h3>
|
</h3>
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@ -274,7 +274,7 @@ export function UserManagementPage() {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<form onSubmit={handleSubmit} className="space-y-4">
|
<form onSubmit={handleSubmit} className="space-y-4" autoComplete="off">
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700">
|
<label className="block text-sm font-medium text-gray-700">
|
||||||
Аватар
|
Аватар
|
||||||
@ -306,6 +306,7 @@ export function UserManagementPage() {
|
|||||||
type="text"
|
type="text"
|
||||||
value={formData.displayName}
|
value={formData.displayName}
|
||||||
onChange={(e) => setFormData(prev => ({ ...prev, displayName: e.target.value }))}
|
onChange={(e) => setFormData(prev => ({ ...prev, displayName: e.target.value }))}
|
||||||
|
autoComplete="off"
|
||||||
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500"
|
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500"
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
@ -319,6 +320,7 @@ export function UserManagementPage() {
|
|||||||
type="email"
|
type="email"
|
||||||
value={formData.email}
|
value={formData.email}
|
||||||
onChange={(e) => setFormData(prev => ({ ...prev, email: e.target.value }))}
|
onChange={(e) => setFormData(prev => ({ ...prev, email: e.target.value }))}
|
||||||
|
autoComplete="off"
|
||||||
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500"
|
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500"
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
@ -326,12 +328,13 @@ export function UserManagementPage() {
|
|||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700">
|
<label className="block text-sm font-medium text-gray-700">
|
||||||
Пароль {showEditModal}
|
Пароль
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="password"
|
type="password"
|
||||||
value={''}
|
value={formData.password}
|
||||||
onChange={(e) => setFormData(prev => ({ ...prev, password: e.target.value }))}
|
onChange={(e) => setFormData(prev => ({ ...prev, password: e.target.value }))}
|
||||||
|
autoComplete="new-password"
|
||||||
placeholder={showEditModal ? 'Оставьте пустым, чтобы не менять' : ''}
|
placeholder={showEditModal ? 'Оставьте пустым, чтобы не менять' : ''}
|
||||||
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500"
|
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500"
|
||||||
required={!showEditModal}
|
required={!showEditModal}
|
||||||
|
@ -8,7 +8,7 @@ export const userService = {
|
|||||||
return response.data;
|
return response.data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Ошибка получения списка пользователей:', error);
|
console.error('Ошибка получения списка пользователей:', error);
|
||||||
throw new Error('Ошибка получения списка пользователей');
|
throw new Error('Сбой при получении списка пользователей');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -17,8 +17,8 @@ export const userService = {
|
|||||||
const response = await axios.post('/users', userData);
|
const response = await axios.post('/users', userData);
|
||||||
return response.data;
|
return response.data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error creating user:', error);
|
console.error('Ошибка создания пользователя:', error);
|
||||||
throw new Error('Failed to create user');
|
throw new Error('Сбой при создании пользователя');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -27,8 +27,8 @@ export const userService = {
|
|||||||
const response = await axios.put(`/users/${userId}`, userData);
|
const response = await axios.put(`/users/${userId}`, userData);
|
||||||
return response.data;
|
return response.data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error updating user:', error);
|
console.error('Ошибка редактирования пользователя:', error);
|
||||||
throw new Error('Failed to update user');
|
throw new Error('Сбой при редактировании пользователя');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -37,8 +37,8 @@ export const userService = {
|
|||||||
const response = await axios.put(`/users/${userId}/permissions`, { permissions });
|
const response = await axios.put(`/users/${userId}/permissions`, { permissions });
|
||||||
return response.data;
|
return response.data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error updating user permissions:', error);
|
console.error('Ошибка редактирования прав пользователя:', error);
|
||||||
throw new Error('Failed to update user permissions');
|
throw new Error('Сбой при редактировании прав пользователя');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -46,8 +46,8 @@ export const userService = {
|
|||||||
try {
|
try {
|
||||||
await axios.delete(`/users/${userId}`);
|
await axios.delete(`/users/${userId}`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error deleting user:', error);
|
console.error('Ошибка удаления пользователя:', error);
|
||||||
throw new Error('Failed to delete user');
|
throw new Error('Сбой при удалении пользователя');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
Loading…
x
Reference in New Issue
Block a user