mirror of https://github.com/Aidaho12/haproxy-wi
				
				
				
			
							parent
							
								
									ef91b0a831
								
							
						
					
					
						commit
						69ad8101bc
					
				|  | @ -12,7 +12,8 @@ Web interface(user-friendly web GUI, alerting, monitoring and secure) for managi | |||
|  | ||||
| 
 | ||||
| # Features: | ||||
| 1. Installation and updating HAProxy, Nginx and Keepalived with Roxy-WI | ||||
| 1. Installation and updating HAProxy, Nginx and Keepalived with Roxy-WI as system service | ||||
| 1. Installation and updating HAProxy and Nginx with Roxy-WI as Docker service | ||||
| 2. Installation and updating Grafana, Prometheus servers with Roxy-WI | ||||
| 3. Installation and updating HAProxy and Nginx exporters with Roxy-WI | ||||
| 4. Server provisioning on AWS, DigitalOcean and G-Core Labs | ||||
|  | @ -125,4 +126,4 @@ and check executeble py files | |||
| 
 | ||||
| If you see plain text, check section "Directory" in httpd conf | ||||
| 
 | ||||
| [Read more] (https://roxy-wi.org/troubleshooting.py) | ||||
| [Read more](https://roxy-wi.org/troubleshooting.py) | ||||
|  |  | |||
|  | @ -805,7 +805,6 @@ def update_db_v_5_3_0(**kwargs): | |||
| 					print("An error occurred:", e) | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| def update_db_v_5_3_1(**kwargs): | ||||
| 	cursor = conn.cursor() | ||||
| 	sql = """ | ||||
|  | @ -823,8 +822,46 @@ def update_db_v_5_3_1(**kwargs): | |||
| 		print("Updating... DB has been updated to version 5.3.1") | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| def update_db_v_5_3_2(**kwargs): | ||||
| 	try: | ||||
| 		Setting.insert(param='checker_maxconn_threshold', value=90, section='monitoring', | ||||
| 					   desc='Threshold value for alerting, in %').execute() | ||||
| 	except Exception as e: | ||||
| 		if kwargs.get('silent') != 1: | ||||
| 			if ( | ||||
| 					str(e) == 'columns param, group are not unique' or | ||||
| 					str(e) == '(1062, "Duplicate entry \'checker_maxconn_threshold-1\' for key \'param\'")' or | ||||
| 					str(e) == 'UNIQUE constraint failed: settings.param, settings.group' | ||||
| 			): | ||||
| 				pass | ||||
| 			else: | ||||
| 				print("An error occurred:", e) | ||||
| 	else: | ||||
| 		if kwargs.get('silent') != 1: | ||||
| 			print('Updating... DB has been updated to version 5.3.2') | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| def update_db_v_5_3_2_2(**kwargs): | ||||
| 	cursor = conn.cursor() | ||||
| 	sql = """ | ||||
| 	ALTER TABLE `servers` ADD COLUMN keepalived_alert INTEGER NOT NULL DEFAULT 0; | ||||
| 	""" | ||||
| 	try: | ||||
| 		cursor.execute(sql) | ||||
| 	except Exception as e: | ||||
| 		if kwargs.get('silent') != 1: | ||||
| 			if e.args[0] == 'duplicate column name: keepalived_alert' or str(e) == '(1060, "Duplicate column name \'keepalived_alert\'")': | ||||
| 				print('Updating... DB has been updated to version 5.3.2') | ||||
| 			else: | ||||
| 				print("An error occurred:", e) | ||||
| 	else: | ||||
| 		print("Updating... DB has been updated to version 5.3.2") | ||||
| 
 | ||||
| 
 | ||||
| def update_ver(): | ||||
| 	query = Version.update(version='5.3.1.0') | ||||
| 	query = Version.update(version='5.3.2.0') | ||||
| 	try: | ||||
| 		query.execute() | ||||
| 	except: | ||||
|  | @ -858,6 +895,8 @@ def update_all(): | |||
| 	update_db_v_5_2_6() | ||||
| 	update_db_v_5_3_0() | ||||
| 	update_db_v_5_3_1() | ||||
| 	update_db_v_5_3_2() | ||||
| 	update_db_v_5_3_2_2() | ||||
| 	update_ver() | ||||
| 
 | ||||
| 
 | ||||
|  | @ -888,6 +927,8 @@ def update_all_silent(): | |||
| 	update_db_v_5_2_6(silent=1) | ||||
| 	update_db_v_5_3_0(silent=1) | ||||
| 	update_db_v_5_3_1(silent=1) | ||||
| 	update_db_v_5_3_2(silent=1) | ||||
| 	update_db_v_5_3_2_2(silent=1) | ||||
| 	update_ver() | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -62,6 +62,7 @@ class Server(BaseModel): | |||
|     protected = IntegerField(constraints=[SQL('DEFAULT 0')]) | ||||
|     nginx_metrics = IntegerField(constraints=[SQL('DEFAULT 0')]) | ||||
|     keepalived_active = IntegerField(constraints=[SQL('DEFAULT 0')]) | ||||
|     keepalived_alert = IntegerField(constraints=[SQL('DEFAULT 0')]) | ||||
| 
 | ||||
|     class Meta: | ||||
|         table_name = 'servers' | ||||
|  |  | |||
							
								
								
									
										12
									
								
								app/funct.py
								
								
								
								
							
							
						
						
									
										12
									
								
								app/funct.py
								
								
								
								
							|  | @ -119,6 +119,8 @@ def logging(server_ip, action, **kwargs): | |||
| 	import http.cookies | ||||
| 	import distro | ||||
| 
 | ||||
| 	login = '' | ||||
| 
 | ||||
| 	log_path = get_config_var('main', 'log_path') | ||||
| 	try: | ||||
| 		user_group = get_user_group() | ||||
|  | @ -817,15 +819,21 @@ def install_nginx(server_ip, **kwargs): | |||
| 
 | ||||
| def update_haproxy_wi(service): | ||||
| 	import distro | ||||
| 	restart_service = '' | ||||
| 	if distro.id() == 'ubuntu': | ||||
| 		try: | ||||
| 			if service == 'roxy-wi-keep_alive': | ||||
| 				service = 'roxy-wi-keep-alive' | ||||
| 		except Exception: | ||||
| 			pass | ||||
| 		cmd = 'sudo -S apt-get update && sudo apt-get install ' + service +' && sudo systemctl restart ' + service | ||||
| 
 | ||||
| 		if service == 'roxy-wi': | ||||
| 			restart_service = ' && sudo systemctl restart ' + service | ||||
| 
 | ||||
| 		cmd = 'sudo -S apt-get update && sudo apt-get install ' + service + restart_service | ||||
| 	else: | ||||
| 		cmd = 'sudo -S yum -y update ' + service +' && sudo systemctl restart ' + service | ||||
| 		cmd = 'sudo -S yum -y update ' + service + restart_service | ||||
| 
 | ||||
| 	output, stderr = subprocess_execute(cmd) | ||||
| 	print(output) | ||||
| 	print(stderr) | ||||
|  |  | |||
|  | @ -2051,7 +2051,7 @@ if form.getvalue('updatehapwiserver') is not None: | |||
|     service = form.getvalue('service_name') | ||||
|     sql.update_hapwi_server(hapwi_id, alert, metrics, active, service) | ||||
|     server_ip = sql.select_server_ip_by_id(hapwi_id) | ||||
|     funct.logging(server_ip, 'the server ' + name, ' has been updated ', haproxywi=1, login=1, keep_history=1, service=service) | ||||
|     funct.logging(server_ip, 'The server ' + name + ' has been updated ', haproxywi=1, login=1, keep_history=1, service=service) | ||||
| 
 | ||||
| if form.getvalue('updateserver') is not None: | ||||
|     name = form.getvalue('updateserver') | ||||
|  | @ -2780,9 +2780,14 @@ if form.getvalue('geoip_install'): | |||
| if form.getvalue('nettools_icmp_server_from'): | ||||
|     server_from = form.getvalue('nettools_icmp_server_from') | ||||
|     server_to = form.getvalue('nettools_icmp_server_to') | ||||
|     server_to = funct.is_ip_or_dns(server_to) | ||||
|     action = form.getvalue('nettools_action') | ||||
|     stderr = '' | ||||
| 
 | ||||
|     if server_to == '': | ||||
|         print('warning: enter a correct IP or DNS name') | ||||
|         sys.exit() | ||||
| 
 | ||||
|     if action == 'nettools_ping': | ||||
|         action_for_sending = 'ping -c 4 -W 1 -s 56 -O ' | ||||
|     elif action == 'nettools_trace': | ||||
|  | @ -2800,17 +2805,31 @@ if form.getvalue('nettools_icmp_server_from'): | |||
|         print('error: '+stderr) | ||||
|         sys.exit() | ||||
|     for i in output: | ||||
|         if i == ' ': | ||||
|         if i == ' ' or i == '': | ||||
|             continue | ||||
|         i = i.strip() | ||||
|         print(i + '<br>') | ||||
|         if 'PING' in i: | ||||
|             print('<span style="color: var(--link-dark-blue); display: block; margin-top: -20px;">') | ||||
|         elif 'no reply' in i or 'no answer yet' in i or 'Too many hops' in i or '100% packet loss' in i: | ||||
|             print('<span style="color: var(--red-color);">') | ||||
|         elif 'ms' in i and '100% packet loss' not in i: | ||||
|             print('<span style="color: var(--green-color);">') | ||||
|         else: | ||||
|             print('<span>') | ||||
| 
 | ||||
|         print(i + '</span><br />') | ||||
| 
 | ||||
| if form.getvalue('nettools_telnet_server_from'): | ||||
|     server_from = form.getvalue('nettools_telnet_server_from') | ||||
|     server_to = form.getvalue('nettools_telnet_server_to') | ||||
|     server_to = funct.is_ip_or_dns(server_to) | ||||
|     port_to = form.getvalue('nettools_telnet_port_to') | ||||
|     stderr = '' | ||||
| 
 | ||||
|     if server_to == '': | ||||
|         print('warning: enter a correct IP or DNS name') | ||||
|         sys.exit() | ||||
| 
 | ||||
|     if server_from == 'localhost': | ||||
|         action_for_sending = 'echo "exit"|nc ' + server_to + ' ' + port_to + ' -t -w 1s' | ||||
|         output, stderr = funct.subprocess_execute(action_for_sending) | ||||
|  | @ -2819,7 +2838,7 @@ if form.getvalue('nettools_telnet_server_from'): | |||
|         output = funct.ssh_command(server_from, action_for_sending, raw=1) | ||||
| 
 | ||||
|     if stderr != '': | ||||
|         print('error: '+stderr[5:-1]) | ||||
|         print('error: <b>' + stderr[5:] + '</b>') | ||||
|         sys.exit() | ||||
|     count_string = 0 | ||||
|     for i in output: | ||||
|  | @ -2827,7 +2846,7 @@ if form.getvalue('nettools_telnet_server_from'): | |||
|             continue | ||||
|         i = i.strip() | ||||
|         if i == 'Ncat: Connection timed out.': | ||||
|             print('error: ' + i[5:-1]) | ||||
|             print('error: <b>' + i[5:] + '</b>') | ||||
|             break | ||||
|         print(i + '<br>') | ||||
|         count_string += 1 | ||||
|  | @ -2837,9 +2856,14 @@ if form.getvalue('nettools_telnet_server_from'): | |||
| if form.getvalue('nettools_nslookup_server_from'): | ||||
|     server_from = form.getvalue('nettools_nslookup_server_from') | ||||
|     dns_name = form.getvalue('nettools_nslookup_name') | ||||
|     dns_name = funct.is_ip_or_dns(dns_name) | ||||
|     record_type = form.getvalue('nettools_nslookup_record_type') | ||||
|     stderr = '' | ||||
| 
 | ||||
|     if dns_name == '': | ||||
|         print('warning: enter a correct DNS name') | ||||
|         sys.exit() | ||||
| 
 | ||||
|     action_for_sending = 'dig ' + dns_name + ' ' + record_type + ' |grep -e "SERVER\|' + dns_name + '"' | ||||
| 
 | ||||
|     if server_from == 'localhost': | ||||
|  | @ -2852,7 +2876,7 @@ if form.getvalue('nettools_nslookup_server_from'): | |||
|         print('error: '+stderr[5:-1]) | ||||
|         sys.exit() | ||||
|     count_string = 0 | ||||
|     print('<b>There are the next records for ' + dns_name + ' domain:</b> <br />') | ||||
|     print('<b style="display: block; margin-top:10px;">The <i style="color: var(--blue-color)">' + dns_name + '</i> domain has the following records:</b>') | ||||
|     for i in output: | ||||
|         if 'dig: command not found.' in i: | ||||
|             print('error: Install bind-utils before using NSLookup') | ||||
|  | @ -2860,13 +2884,13 @@ if form.getvalue('nettools_nslookup_server_from'): | |||
|         if ';' in i and ';; SERVER:' not in i: | ||||
|             continue | ||||
|         if 'SOA' in i and record_type != 'SOA': | ||||
|             print('<b>There are not any records for this type') | ||||
|             print('<b style="color: red">There are not any records for this type') | ||||
|             break | ||||
|         if ';; SERVER:' in i: | ||||
|             i = i[10:-1] | ||||
|             i = i[10:] | ||||
|             print('<br><b>From NS server:</b><br>') | ||||
|         i = i.strip() | ||||
|         print(i + '<br>') | ||||
|         print('<i>' + i + '</i><br>') | ||||
|         count_string += 1 | ||||
| 
 | ||||
| if form.getvalue('portscanner_history_server_id'): | ||||
|  |  | |||
							
								
								
									
										25
									
								
								app/sql.py
								
								
								
								
							
							
						
						
									
										25
									
								
								app/sql.py
								
								
								
								
							|  | @ -259,10 +259,10 @@ def update_hapwi_server(server_id, alert, metrics, active, service_name): | |||
| 	try: | ||||
| 		if service_name == 'nginx': | ||||
| 			update_hapwi = Server.update(nginx_alert=alert, metrics=metrics, nginx_active=active, | ||||
| 										 nginx_metrics=metrics).where( | ||||
| 				Server.server_id == server_id) | ||||
| 										 nginx_metrics=metrics).where(Server.server_id == server_id) | ||||
| 		elif service_name == 'keepalived': | ||||
| 			update_hapwi = Server.update(keepalived_active=active).where(Server.server_id == server_id) | ||||
| 			update_hapwi = Server.update(keepalived_alert=alert, keepalived_active=active).where( | ||||
| 				Server.server_id == server_id) | ||||
| 		else: | ||||
| 			update_hapwi = Server.update(alert=alert, metrics=metrics, active=active).where( | ||||
| 				Server.server_id == server_id) | ||||
|  | @ -1766,7 +1766,7 @@ def get_setting(param, **kwargs): | |||
| 					param == 'syslog_server_enable' or param == 'smon_check_interval' or | ||||
| 					param == 'checker_check_interval' or param == 'port_scan_interval' or | ||||
| 					param == 'smon_keep_history_range' or param == 'checker_keep_history_range' or | ||||
| 					param == 'portscanner_keep_history_range' | ||||
| 					param == 'portscanner_keep_history_range' or param == 'checker_maxconn_threshold' | ||||
| 				): | ||||
| 					return int(setting.value) | ||||
| 				else: | ||||
|  | @ -1852,6 +1852,23 @@ def select_nginx_alert(**kwargs): | |||
| 		return query_res | ||||
| 
 | ||||
| 
 | ||||
| def select_keepalived_alert(**kwargs): | ||||
| 	if kwargs.get("group") is not None: | ||||
| 		query = Server.select(Server.ip).where( | ||||
| 			(Server.keepalived_alert == 1) & | ||||
| 			(Server.enable == 1) & | ||||
| 			(Server.groups == kwargs.get('group'))) | ||||
| 	else: | ||||
| 		query = Server.select(Server.ip).where((Server.keepalived_alert == 1) & (Server.enable == 1)) | ||||
| 
 | ||||
| 	try: | ||||
| 		query_res = query.execute() | ||||
| 	except Exception as e: | ||||
| 		out_error(e) | ||||
| 	else: | ||||
| 		return query_res | ||||
| 
 | ||||
| 
 | ||||
| def select_keep_alive(): | ||||
| 	query = Server.select(Server.ip).where(Server.active == 1) | ||||
| 	try: | ||||
|  |  | |||
|  | @ -101,8 +101,10 @@ | |||
| 				{% set additional_status_class = 'div-server-head-down' %} | ||||
| 			{% endif %} | ||||
| 		{% elif service == 'keepalived' %} | ||||
| 			{% set checker_desc = 'Checker monitors Keepalived services. If Keepalived service is down, Checker will alert via Telegram and/or Slack' %} | ||||
| 			{% set is_auto_start_enabled = s.8.0.22 %} | ||||
| 			{% set action_service = 'keepalived' %} | ||||
| 			{% set is_checker_enabled = s.8.0.23 %} | ||||
| 			{% if s.5.0.1 == 'active' %} | ||||
| 				{% set additional_status_class = 'div-server-head-up' %} | ||||
| 			{% else %} | ||||
|  | @ -212,13 +214,15 @@ | |||
| 				{% endif %} | ||||
| 			</div> | ||||
| 			<div class="server-act-links" id="server-{{s.8.0.0|string()}}-{{service}}"> | ||||
| 				{% if role <= 2 and service != 'keepalived' %} | ||||
| 				{% if role <= 2 %} | ||||
| 					{% set id = 'alert-' + s.8.0.0|string() %} | ||||
| 					{% if is_checker_enabled == 1 %} | ||||
| 						{{ checkbox(id, title=checker_desc, value='1', desc='Checker', checked='checked') }} | ||||
| 					{% else %} | ||||
| 						{{ checkbox(id, title=checker_desc, value='1', desc='Checker') }} | ||||
| 					{% endif %} | ||||
| 				{% endif %} | ||||
| 				{% if role <= 2 and service != 'keepalived' %} | ||||
| 					{% set id = 'metrics-' + s.8.0.0|string() %} | ||||
| 					{% if is_metrics_enabled == 1 %} | ||||
| 						{{ checkbox(id, title='Collecting metrics is enabled', value='1', desc='Metrics', checked='checked') }} | ||||
|  | @ -226,12 +230,14 @@ | |||
| 						{{ checkbox(id, title='Enable collecting metrics', value='1', desc='Metrics') }} | ||||
| 					{% endif %} | ||||
| 				{% endif %} | ||||
| 				{% if role <= 2 %} | ||||
| 					{% set id = 'active-' + s.8.0.0|string() %} | ||||
| 					{% if is_auto_start_enabled == 1 %} | ||||
| 						{{ checkbox(id, title='Auto Start is enabled', value='1', desc='Auto Start', checked='checked') }} | ||||
| 					{% else %} | ||||
| 						{{ checkbox(id, title='Enable Auto Start', value='1', desc='Auto Start') }} | ||||
| 					{% endif %} | ||||
| 				{% endif %} | ||||
| 			</div> | ||||
| 			<div class="server-act-links"> | ||||
| 				<a href="/app/config.py?service={{service}}&serv={{s.2}}&showConfig" class="ui-button ui-widget ui-corner-all" title="Open running config">Config</a> | ||||
|  |  | |||
|  | @ -1,16 +1,13 @@ | |||
| {% extends "base.html" %} | ||||
| {% block content %} | ||||
| {% from 'include/input_macros.html' import input, checkbox, select %} | ||||
| {% if servers|length == 0 %} | ||||
|     {% include 'include/getstarted.html' %} | ||||
| {% else %} | ||||
| <style> | ||||
|     .ping_pre { | ||||
|         display: block; | ||||
|         padding: 9.5px; | ||||
|         padding: 10px; | ||||
|         margin: 0 0 10px; | ||||
|         font-family: 'Courier New', monospace; | ||||
|         font-size: 13px; | ||||
|         font-size: 14px; | ||||
|         line-height: 1.42857143; | ||||
|         color: #333; | ||||
|         word-break: break-all; | ||||
|  | @ -23,8 +20,8 @@ | |||
|     <table class="overview"> | ||||
|         <caption><h3>ICMP</h3></caption> | ||||
|         <tr class="overviewHead"> | ||||
|             <th class="padding10 first-collumn">From server</th> | ||||
|             <th class="padding10 first-collumn">To server</th> | ||||
|             <th class="padding10 first-collumn">From</th> | ||||
|             <th class="padding10 first-collumn">To</th> | ||||
|             <th class="padding10 first-collumn"></th> | ||||
|             <th></th> | ||||
|         </tr> | ||||
|  | @ -55,8 +52,8 @@ | |||
|     <table class="overview"> | ||||
|         <caption><h3>Check port</h3></caption> | ||||
|         <tr class="overviewHead"> | ||||
|             <th class="padding10 first-collumn">From server</th> | ||||
|             <th class="padding10 first-collumn">To server</th> | ||||
|             <th class="padding10 first-collumn">From</th> | ||||
|             <th class="padding10 first-collumn">To</th> | ||||
|             <th class="padding10 first-collumn">Port</th> | ||||
|             <th></th> | ||||
|         </tr> | ||||
|  | @ -87,7 +84,7 @@ | |||
|     <table class="overview"> | ||||
|         <caption><h3>NSLookup</h3></caption> | ||||
|         <tr class="overviewHead"> | ||||
|             <th class="padding10 first-collumn">From server</th> | ||||
|             <th class="padding10 first-collumn">From</th> | ||||
|             <th class="padding10 first-collumn">Record type</th> | ||||
|             <th class="padding10 first-collumn">DNS name</th> | ||||
|             <th></th> | ||||
|  | @ -121,8 +118,8 @@ | |||
| <div id="ajax-nettools" style="padding: 20px;"></div> | ||||
| <script> | ||||
|     $("#nettools_nslookup_record_type" ).selectmenu({ | ||||
| 				width: 175 | ||||
| 			}); | ||||
|         width: 175 | ||||
|     }); | ||||
|     $( "#nettools_telnet_form" ).on("click", ":submit", function(e){ | ||||
|         $('#ajax-nettools').html(''); | ||||
|         var frm = $('#nettools_telnet_form'); | ||||
|  | @ -145,13 +142,16 @@ | |||
|             success: function( data ) { | ||||
|                 data = data.replace('\n', '<br>'); | ||||
|                 if (data.indexOf('error: ') != '-1' || data.indexOf('Fatal') != '-1' || data.indexOf('Error(s)') != '-1') { | ||||
|                     $('#ajax-nettools').html('<div class="alert alert-warning">'+data+'</div>'); | ||||
|                     $('#ajax-nettools').html('<div class="ping_pre">'+data+'</div>'); | ||||
|                 } else if (data.indexOf('warning: ') != '-1') { | ||||
|                     toastr.clear(); | ||||
|                     toastr.warning(data) | ||||
|                 } else { | ||||
|                     toastr.clear(); | ||||
|                     if (data.indexOf('') != '-1') { | ||||
|                         $('#ajax-nettools').html('<div class="alert alert-success"><b>Connection has been successful</b></div>'); | ||||
|                         $('#ajax-nettools').html('<div class="ping_pre"><b>Connection has been successful</b></div>'); | ||||
|                     } else { | ||||
|                         $('#ajax-nettools').html('<div class="alert alert-success"><b>Connection has been successful</b>:<br /><br />'+data+'</div>'); | ||||
|                         $('#ajax-nettools').html('<div class="ping_pre"><b>Connection has been successful</b>:<br /><br />'+data+'</div>'); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|  | @ -178,6 +178,9 @@ | |||
|                 if (data.indexOf('error: ') != '-1' || data.indexOf('Fatal') != '-1' || data.indexOf('Error(s)') != '-1') { | ||||
|                     toastr.clear(); | ||||
|                     toastr.error(data); | ||||
|                 } else if (data.indexOf('warning: ') != '-1') { | ||||
|                     toastr.clear(); | ||||
|                     toastr.warning(data) | ||||
|                 } else { | ||||
|                     toastr.clear(); | ||||
|                     $('#ajax-nettools').html('<div class="ping_pre">'+data+'</div>'); | ||||
|  | @ -206,6 +209,9 @@ | |||
|                 if (data.indexOf('error: ') != '-1' || data.indexOf('Fatal') != '-1' || data.indexOf('Error(s)') != '-1') { | ||||
|                     toastr.clear(); | ||||
|                     toastr.error(data); | ||||
|                 } else if (data.indexOf('warning: ') != '-1') { | ||||
|                     toastr.clear(); | ||||
|                     toastr.warning(data) | ||||
|                 } else { | ||||
|                     toastr.clear(); | ||||
|                     $('#ajax-nettools').html('<div class="ping_pre">'+data+'</div>'); | ||||
|  | @ -215,5 +221,4 @@ | |||
|         event.preventDefault(); | ||||
|     }); | ||||
| </script> | ||||
| {% endif %} | ||||
| {% endblock %} | ||||
		Loading…
	
		Reference in New Issue
	
	 Pavel Loginov
						Pavel Loginov