diff --git a/app/routes/tools.py b/app/routes/tools.py index cfacc25..721d8d5 100644 --- a/app/routes/tools.py +++ b/app/routes/tools.py @@ -1,6 +1,6 @@ import json from flask import Blueprint, render_template, request, redirect, url_for, flash, Response -from app.models import Domain, PasswordCategory +from app.models import Client, Domain, ClientPassword, PasswordCategory from app import db tools_bp = Blueprint('tools', __name__) @@ -9,48 +9,6 @@ tools_bp = Blueprint('tools', __name__) def tools(): return render_template('tools.html') -@tools_bp.route('/tools/export', methods=['GET']) -def export_data(): - domains = Domain.query.all() - data = [] - for d in domains: - data.append({ - 'id': d.id, - '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', methods=['GET', 'POST']) -def import_data(): - if request.method == 'POST': - file = request.files.get('file') - if file: - try: - data = json.load(file) - for record in data: - existing = Domain.query.filter_by(domain=record.get('domain')).first() - if not existing: - new_domain = Domain( - domain=record.get('domain'), - 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("Data imported successfully", "success") - except Exception as e: - flash(f"Error importing data: {str(e)}", "danger") - else: - flash("No file uploaded", "warning") - return redirect(url_for('tools.tools')) - return render_template('tools.html') @tools_bp.route('/tools/password_categories', methods=['GET', 'POST']) def password_categories(): @@ -87,3 +45,160 @@ def delete_password_category(category_id): 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') \ No newline at end of file diff --git a/app/templates/client_detail.html b/app/templates/client_detail.html index d0e7af0..3779f33 100644 --- a/app/templates/client_detail.html +++ b/app/templates/client_detail.html @@ -113,89 +113,99 @@
-

Domains

- - - - - - - - - - {% for d in client.domains %} - - - - - - {% endfor %} - -
DomainWHOIS ExpirationAction
{{ d.domain }}{{ d.expiration_date }} -
- -
-
-
-
- - -
- -
-
+

Domains

+ {% if client.domains|length > 0 %} + + + + + + + + + + {% for d in client.domains %} + + + + + + {% endfor %} + +
DomainWHOIS ExpirationAction
{{ d.domain }}{{ d.expiration_date }} +
+ +
+
+ {% else %} +

No domain associations.

+ {% endif %} +
+
+ + +
+ +
+ +
-

SSL

- - - - - - - - - - {% for d in client.ssl_domains %} - - - - - - {% endfor %} - -
DomainSSL ExpirationAction
{{ d.domain }}{{ d.ssl_expiration_date }} -
- -
-
-
-
- - -
- -
-
+

SSL

+ {% if client.ssl_domains|length > 0 %} + + + + + + + + + + {% for d in client.ssl_domains %} + + + + + + {% endfor %} + +
DomainSSL ExpirationAction
{{ d.domain }}{{ d.ssl_expiration_date }} +
+ +
+
+ {% else %} +

No SSL associations.

+ {% endif %} +
+
+ + +
+ +
+ +
diff --git a/app/templates/import_clients.html b/app/templates/import_clients.html new file mode 100644 index 0000000..5b3cb83 --- /dev/null +++ b/app/templates/import_clients.html @@ -0,0 +1,16 @@ +{% extends "base.html" %} +{% block title %}Import Clients{% endblock %} +{% block content %} +
+

Import Clients

+
+
+ + +
+ +
+
+ Back to Tools +
+{% endblock %} diff --git a/app/templates/import_domains.html b/app/templates/import_domains.html new file mode 100644 index 0000000..e3b1cd5 --- /dev/null +++ b/app/templates/import_domains.html @@ -0,0 +1,16 @@ +{% extends "base.html" %} +{% block title %}Import Domains{% endblock %} +{% block content %} +
+

Import Domains

+
+
+ + +
+ +
+
+ Back to Tools +
+{% endblock %} diff --git a/app/templates/tools.html b/app/templates/tools.html index c6208e8..4d2d897 100644 --- a/app/templates/tools.html +++ b/app/templates/tools.html @@ -3,28 +3,32 @@ {% block content %}

Tools

+ + +
-
Import / Export Data
-
-
-
-
- - -
- -
-
-
- Export Data -
-
-
-
Password Categories
+ + +
+
Client Import / Export
+ +
+ + +
+
Domain Import / Export
+ +
{% endblock %}