Details for instances

This commit is contained in:
2025-06-10 09:47:54 +02:00
parent 580289d3a1
commit 5bb0667060
4 changed files with 263 additions and 223 deletions

View File

@@ -503,6 +503,93 @@ def init_routes(main_bp):
db.session.rollback()
return jsonify({'error': str(e)}), 400
@main_bp.route('/instances/<int:instance_id>/detail')
@login_required
@require_password_change
def instance_detail(instance_id):
if not os.environ.get('MASTER', 'false').lower() == 'true':
flash('This page is only available in master instances.', 'error')
return redirect(url_for('main.dashboard'))
instance = Instance.query.get_or_404(instance_id)
# Check instance status
status_info = check_instance_status(instance)
instance.status = status_info['status']
instance.status_details = status_info['details']
# Fetch company name from instance settings
try:
if instance.connection_token:
# First get JWT token
jwt_response = requests.post(
f"{instance.main_url.rstrip('/')}/api/admin/management-token",
headers={
'X-API-Key': instance.connection_token,
'Accept': 'application/json'
},
timeout=5
)
if jwt_response.status_code == 200:
jwt_data = jwt_response.json()
jwt_token = jwt_data.get('token')
if jwt_token:
# Then fetch settings with JWT token
response = requests.get(
f"{instance.main_url.rstrip('/')}/api/admin/settings",
headers={
'Authorization': f'Bearer {jwt_token}',
'Accept': 'application/json'
},
timeout=5
)
if response.status_code == 200:
data = response.json()
if 'company_name' in data:
instance.company = data['company_name']
db.session.commit()
except Exception as e:
current_app.logger.error(f"Error fetching instance settings: {str(e)}")
return render_template('main/instance_detail.html', instance=instance)
@main_bp.route('/instances/<int:instance_id>/auth-status')
@login_required
@require_password_change
def instance_auth_status(instance_id):
if not os.environ.get('MASTER', 'false').lower() == 'true':
return jsonify({'error': 'Unauthorized'}), 403
instance = Instance.query.get_or_404(instance_id)
# Check if instance has a connection token
has_token = bool(instance.connection_token)
# If there's a token, verify it's still valid
is_valid = False
if has_token:
try:
# Try to get a JWT token using the connection token
response = requests.post(
f"{instance.main_url.rstrip('/')}/api/admin/management-token",
headers={
'X-API-Key': instance.connection_token,
'Accept': 'application/json'
},
timeout=5
)
is_valid = response.status_code == 200
except Exception as e:
current_app.logger.error(f"Error verifying token: {str(e)}")
is_valid = False
return jsonify({
'authenticated': has_token and is_valid,
'has_token': has_token,
'is_valid': is_valid
})
UPLOAD_FOLDER = '/app/uploads/profile_pics'
if not os.path.exists(UPLOAD_FOLDER):
os.makedirs(UPLOAD_FOLDER)
@@ -1401,227 +1488,4 @@ def init_routes(main_bp):
headers={
'Content-Disposition': f'attachment; filename=event_log_{datetime.utcnow().strftime("%Y%m%d_%H%M%S")}.csv'
}
)
@main_bp.route('/settings/email-templates/<int:template_id>', methods=['PUT'])
@login_required
def update_email_template(template_id):
if not current_user.is_admin:
return jsonify({'error': 'Unauthorized'}), 403
template = EmailTemplate.query.get_or_404(template_id)
data = request.get_json()
if not data:
return jsonify({'error': 'No data provided'}), 400
template.subject = data.get('subject', template.subject)
template.body = data.get('body', template.body)
try:
db.session.commit()
# Log the template update
log_event(
event_type='settings_update',
details={
'user_id': current_user.id,
'user_name': f"{current_user.username} {current_user.last_name}",
'update_type': 'email_template',
'template_id': template.id,
'template_name': template.name,
'changes': {
'subject': template.subject,
'body': template.body
}
}
)
db.session.commit()
return jsonify({
'message': 'Template updated successfully',
'template': {
'id': template.id,
'name': template.name,
'subject': template.subject,
'body': template.body
}
})
except Exception as e:
db.session.rollback()
return jsonify({'error': str(e)}), 500
@main_bp.route('/settings/mails')
@login_required
def mails():
if not current_user.is_admin:
flash('You do not have permission to access settings.', 'error')
return redirect(url_for('main.index'))
# Get filter parameters
status = request.args.get('status', '')
date_range = request.args.get('date_range', '7d')
user_id = request.args.get('user_id', '')
template_id = request.args.get('template_id', '')
page = request.args.get('page', 1, type=int)
per_page = 10
# Build query
query = Mail.query
# Apply filters
if status:
query = query.filter_by(status=status)
if user_id:
query = query.filter_by(recipient=user_id)
if template_id:
query = query.filter_by(template_id=template_id)
if date_range:
if date_range == '24h':
cutoff = datetime.utcnow() - timedelta(hours=24)
elif date_range == '7d':
cutoff = datetime.utcnow() - timedelta(days=7)
elif date_range == '30d':
cutoff = datetime.utcnow() - timedelta(days=30)
else:
cutoff = None
if cutoff:
query = query.filter(Mail.created_at >= cutoff)
# Get paginated results
mails = query.order_by(Mail.created_at.desc()).paginate(page=page, per_page=per_page)
total_pages = mails.pages
current_page = mails.page
# Get all users for the filter dropdown
users = User.query.order_by(User.username).all()
# Get all email templates
email_templates = EmailTemplate.query.filter_by(is_active=True).all()
# Check if this is an AJAX request
if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
return render_template('settings/tabs/mails.html',
mails=mails,
total_pages=total_pages,
current_page=page,
status=status,
date_range=date_range,
user_id=user_id,
template_id=template_id,
users=users,
email_templates=email_templates,
csrf_token=generate_csrf())
# For full page requests, render the full settings page
site_settings = SiteSettings.get_settings()
company_form = CompanySettingsForm()
return render_template('settings/settings.html',
primary_color=site_settings.primary_color,
secondary_color=site_settings.secondary_color,
active_tab='mails',
site_settings=site_settings,
mails=mails,
total_pages=total_pages,
current_page=page,
status=status,
date_range=date_range,
user_id=user_id,
template_id=template_id,
users=users,
email_templates=email_templates,
form=company_form,
csrf_token=generate_csrf())
@main_bp.route('/settings/mails/<int:mail_id>')
@login_required
def get_mail_details(mail_id):
if not current_user.is_admin:
return jsonify({'error': 'Unauthorized'}), 403
mail = Mail.query.get_or_404(mail_id)
return jsonify({
'id': mail.id,
'recipient': mail.recipient,
'subject': mail.subject,
'body': mail.body,
'status': mail.status,
'created_at': mail.created_at.isoformat(),
'sent_at': mail.sent_at.isoformat() if mail.sent_at else None,
'template': {
'id': mail.template.id,
'name': mail.template.name
} if mail.template else None
})
@main_bp.route('/settings/mails/download')
@login_required
def download_mails():
if not current_user.is_admin:
flash('Only administrators can download mail logs.', 'error')
return redirect(url_for('main.dashboard'))
# Get filter parameters
status = request.args.get('status')
date_range = request.args.get('date_range', '7d')
user_id = request.args.get('user_id')
# Calculate date range
end_date = datetime.utcnow()
if date_range == '24h':
start_date = end_date - timedelta(days=1)
elif date_range == '7d':
start_date = end_date - timedelta(days=7)
elif date_range == '30d':
start_date = end_date - timedelta(days=30)
else:
start_date = None
# Build query
query = Mail.query
if status:
query = query.filter_by(status=status)
if start_date:
query = query.filter(Mail.created_at >= start_date)
if user_id:
query = query.filter(Mail.recipient == User.query.get(user_id).email)
# Get all mails
mails = query.order_by(Mail.created_at.desc()).all()
# Create CSV
output = StringIO()
writer = csv.writer(output)
# Write header
writer.writerow([
'Created At',
'Recipient',
'Subject',
'Status',
'Template',
'Sent At'
])
# Write data
for mail in mails:
writer.writerow([
mail.created_at.strftime('%Y-%m-%d %H:%M:%S'),
mail.recipient,
mail.subject,
mail.status,
mail.template.name if mail.template else '-',
mail.sent_at.strftime('%Y-%m-%d %H:%M:%S') if mail.sent_at else '-'
])
output.seek(0)
return Response(
output,
mimetype='text/csv',
headers={
'Content-Disposition': f'attachment; filename=mail_log_{datetime.utcnow().strftime("%Y%m%d_%H%M%S")}.csv'
}
)