231 lines
10 KiB
Python
231 lines
10 KiB
Python
import json
|
|
from flask import Blueprint, render_template, request, redirect, url_for, flash, Response
|
|
from app.models import Client, Domain, ClientPassword, PasswordCategory
|
|
from app import db
|
|
|
|
tools_bp = Blueprint('tools', __name__)
|
|
|
|
@tools_bp.route('/tools', methods=['GET'])
|
|
def tools():
|
|
return render_template('tools.html')
|
|
|
|
|
|
@tools_bp.route('/tools/password_categories', methods=['GET', 'POST'])
|
|
def password_categories():
|
|
if request.method == 'POST':
|
|
category_name = request.form.get('category_name')
|
|
if category_name:
|
|
existing = PasswordCategory.query.filter_by(name=category_name.strip()).first()
|
|
if not existing:
|
|
new_cat = PasswordCategory(name=category_name.strip())
|
|
db.session.add(new_cat)
|
|
db.session.commit()
|
|
categories = PasswordCategory.query.all()
|
|
return render_template('password_categories.html', categories=categories)
|
|
|
|
@tools_bp.route('/tools/password_categories/delete/<int:category_id>', methods=['POST'])
|
|
def delete_password_category(category_id):
|
|
from app.models import ClientPassword, PasswordCategory
|
|
# Retrieve the category to be deleted
|
|
cat = PasswordCategory.query.get_or_404(category_id)
|
|
# Do not allow deletion of the default "General" category
|
|
if cat.name == "General":
|
|
flash("Cannot delete the default category.", "warning")
|
|
return redirect(url_for('tools.password_categories'))
|
|
# Find the default "General" category or create it if it doesn't exist
|
|
default_cat = PasswordCategory.query.filter_by(name="General").first()
|
|
if not default_cat:
|
|
default_cat = PasswordCategory(name="General")
|
|
db.session.add(default_cat)
|
|
db.session.commit()
|
|
# Reassign all passwords using the category to be deleted to "General"
|
|
ClientPassword.query.filter_by(category_id=cat.id).update({"category_id": default_cat.id})
|
|
# Delete the category
|
|
db.session.delete(cat)
|
|
db.session.commit()
|
|
flash("Category deleted and associated passwords reassigned to General.", "success")
|
|
return redirect(url_for('tools.password_categories'))
|
|
|
|
@tools_bp.route('/tools/export_clients', methods=['GET'])
|
|
def export_clients():
|
|
clients = Client.query.all()
|
|
data = []
|
|
for c in clients:
|
|
client_dict = {
|
|
'name': c.name,
|
|
'phone': c.phone,
|
|
'address': c.address,
|
|
'passwords': [],
|
|
'domains': [],
|
|
'ssl_domains': []
|
|
}
|
|
for p in c.passwords:
|
|
client_dict['passwords'].append({
|
|
'item': p.item,
|
|
'username': p.username,
|
|
'password': p.password,
|
|
'category': p.category.name if p.category else None
|
|
})
|
|
for d in c.domains:
|
|
client_dict['domains'].append({
|
|
'domain': d.domain,
|
|
'expiration_date': d.expiration_date,
|
|
'ssl_expiration_date': d.ssl_expiration_date,
|
|
'ssl_only': d.ssl_only
|
|
})
|
|
for d in c.ssl_domains:
|
|
client_dict['ssl_domains'].append({
|
|
'domain': d.domain,
|
|
'expiration_date': d.expiration_date,
|
|
'ssl_expiration_date': d.ssl_expiration_date,
|
|
'ssl_only': d.ssl_only
|
|
})
|
|
data.append(client_dict)
|
|
json_data = json.dumps(data)
|
|
response = Response(json_data, mimetype='application/json')
|
|
response.headers['Content-Disposition'] = 'attachment; filename=clients_data.json'
|
|
return response
|
|
|
|
@tools_bp.route('/tools/import_clients', methods=['GET', 'POST'])
|
|
def import_clients():
|
|
if request.method == 'POST':
|
|
file = request.files.get('file')
|
|
if file:
|
|
try:
|
|
data = json.load(file)
|
|
for client_data in data:
|
|
new_client = Client(
|
|
name = client_data.get('name'),
|
|
phone = client_data.get('phone'),
|
|
address = client_data.get('address')
|
|
)
|
|
db.session.add(new_client)
|
|
db.session.flush() # assign new_client.id
|
|
# Import passwords
|
|
for p in client_data.get('passwords', []):
|
|
category_name = p.get('category')
|
|
category = None
|
|
if category_name:
|
|
category = PasswordCategory.query.filter_by(name=category_name).first()
|
|
if not category:
|
|
category = PasswordCategory(name=category_name)
|
|
db.session.add(category)
|
|
db.session.flush()
|
|
new_password = ClientPassword(
|
|
item = p.get('item'),
|
|
username = p.get('username'),
|
|
password = p.get('password'),
|
|
client_id = new_client.id,
|
|
category = category
|
|
)
|
|
db.session.add(new_password)
|
|
# Import domain associations
|
|
for d in client_data.get('domains', []):
|
|
domain_name = d.get('domain')
|
|
if domain_name:
|
|
domain_obj = Domain.query.filter_by(domain=domain_name).first()
|
|
if not domain_obj:
|
|
domain_obj = Domain(
|
|
domain = domain_name,
|
|
expiration_date = d.get('expiration_date'),
|
|
ssl_expiration_date = d.get('ssl_expiration_date'),
|
|
ssl_only = d.get('ssl_only', False)
|
|
)
|
|
db.session.add(domain_obj)
|
|
db.session.flush()
|
|
new_client.domains.append(domain_obj)
|
|
# Import SSL domain associations
|
|
for d in client_data.get('ssl_domains', []):
|
|
domain_name = d.get('domain')
|
|
if domain_name:
|
|
domain_obj = Domain.query.filter_by(domain=domain_name).first()
|
|
if not domain_obj:
|
|
domain_obj = Domain(
|
|
domain = domain_name,
|
|
expiration_date = d.get('expiration_date'),
|
|
ssl_expiration_date = d.get('ssl_expiration_date'),
|
|
ssl_only = d.get('ssl_only', True)
|
|
)
|
|
db.session.add(domain_obj)
|
|
db.session.flush()
|
|
new_client.ssl_domains.append(domain_obj)
|
|
db.session.commit()
|
|
flash("Clients imported successfully", "success")
|
|
except Exception as e:
|
|
flash(f"Error importing clients: {str(e)}", "danger")
|
|
else:
|
|
flash("No file uploaded", "warning")
|
|
return redirect(url_for('tools.tools'))
|
|
return render_template('import_clients.html')
|
|
|
|
|
|
@tools_bp.route('/tools/export_domains', methods=['GET'])
|
|
def export_domains():
|
|
domains = Domain.query.all()
|
|
data = []
|
|
for d in domains:
|
|
data.append({
|
|
'domain': d.domain,
|
|
'expiration_date': d.expiration_date,
|
|
'ssl_expiration_date': d.ssl_expiration_date,
|
|
'ssl_only': d.ssl_only
|
|
})
|
|
json_data = json.dumps(data)
|
|
response = Response(json_data, mimetype='application/json')
|
|
response.headers['Content-Disposition'] = 'attachment; filename=domains_data.json'
|
|
return response
|
|
|
|
@tools_bp.route('/tools/import_domains', methods=['GET', 'POST'])
|
|
def import_domains():
|
|
if request.method == 'POST':
|
|
file = request.files.get('file')
|
|
if file:
|
|
try:
|
|
data = json.load(file)
|
|
for record in data:
|
|
domain_name = record.get('domain')
|
|
if domain_name:
|
|
existing = Domain.query.filter_by(domain=domain_name).first()
|
|
if not existing:
|
|
new_domain = Domain(
|
|
domain = domain_name,
|
|
expiration_date = record.get('expiration_date'),
|
|
ssl_expiration_date = record.get('ssl_expiration_date'),
|
|
ssl_only = record.get('ssl_only', False)
|
|
)
|
|
db.session.add(new_domain)
|
|
db.session.commit()
|
|
flash("Domains imported successfully", "success")
|
|
except Exception as e:
|
|
flash(f"Error importing domains: {str(e)}", "danger")
|
|
else:
|
|
flash("No file uploaded", "warning")
|
|
return redirect(url_for('tools.tools'))
|
|
return render_template('import_domains.html')
|
|
|
|
|
|
@tools_bp.route('/tools/remote_categories', methods=['GET', 'POST'])
|
|
def remote_categories():
|
|
from app.models import RemoteCategory
|
|
if request.method == 'POST':
|
|
category_name = request.form.get('category_name')
|
|
if category_name:
|
|
# Check if it exists
|
|
if not RemoteCategory.query.filter_by(name=category_name.strip()).first():
|
|
new_cat = RemoteCategory(name=category_name.strip())
|
|
db.session.add(new_cat)
|
|
db.session.commit()
|
|
categories = RemoteCategory.query.all()
|
|
return render_template('remote_categories.html', categories=categories)
|
|
|
|
@tools_bp.route('/tools/remote_categories/delete/<int:cat_id>', methods=['POST'])
|
|
def delete_remote_category(cat_id):
|
|
from app.models import RemoteCategory, ClientRemote
|
|
cat = RemoteCategory.query.get_or_404(cat_id)
|
|
# Optional: you might want to prevent deletion of defaults.
|
|
db.session.query(ClientRemote).filter_by(remote_category_id=cat.id).update({"remote_category_id": None}, synchronize_session=False)
|
|
db.session.delete(cat)
|
|
db.session.commit()
|
|
flash("Remote category deleted.", "success")
|
|
return redirect(url_for('tools.remote_categories'))
|