|
@@ -3,7 +3,6 @@ from urllib.parse import urlparse
|
|
|
import webbrowser
|
|
|
from emailtool.emailer import Emailer
|
|
|
from flask import Flask, render_template, request, redirect, url_for, session, send_file
|
|
|
-import configparser
|
|
|
from gevent.pywsgi import WSGIServer
|
|
|
import socket
|
|
|
import logging
|
|
@@ -35,17 +34,68 @@ class IlsUser(Model):
|
|
|
database = db
|
|
|
|
|
|
|
|
|
-config = configparser.ConfigParser()
|
|
|
-config.read('settings.ini')
|
|
|
-application_settings = config['application']
|
|
|
-smtp_settings = config['smtp']
|
|
|
-http_settings = config['http']
|
|
|
-domain_settings = config['domain']
|
|
|
+class Settings(Model):
|
|
|
+ name = CharField()
|
|
|
+ value = CharField()
|
|
|
+
|
|
|
+ class Meta:
|
|
|
+ database = db
|
|
|
+
|
|
|
+
|
|
|
+class Schedule(Model):
|
|
|
+ days = CharField()
|
|
|
+
|
|
|
+ class Meta:
|
|
|
+ database = db
|
|
|
+
|
|
|
+
|
|
|
+class Log(Model):
|
|
|
+ date = DateTimeField(default=datetime.datetime.now)
|
|
|
+ username = CharField()
|
|
|
+ action = CharField()
|
|
|
+
|
|
|
+ class Meta:
|
|
|
+ database = db
|
|
|
+
|
|
|
+
|
|
|
+class PasswordResetLog(Model):
|
|
|
+ date = DateTimeField(default=datetime.datetime.now)
|
|
|
+ username = CharField()
|
|
|
+
|
|
|
+ class Meta:
|
|
|
+ database = db
|
|
|
+
|
|
|
+
|
|
|
+settings = Settings.select().execute()
|
|
|
+
|
|
|
+debug_setting = Settings.get(Settings.name == 'Debug Mode')
|
|
|
+debug = debug_setting.value
|
|
|
+
|
|
|
+http_port_setting = Settings.get(Settings.name == 'HTTP Port')
|
|
|
+http_port = http_port_setting.value
|
|
|
+
|
|
|
+smtp_host_setting = Settings.get(Settings.name == 'SMTP Host')
|
|
|
+smtp_host = smtp_host_setting.value
|
|
|
+
|
|
|
+smtp_port_setting = Settings.get(Settings.name == 'SMTP Port')
|
|
|
+smtp_port = smtp_port_setting.value
|
|
|
+
|
|
|
+smtp_username_setting = Settings.get(Settings.name == 'SMTP Username')
|
|
|
+smtp_username = smtp_username_setting.value
|
|
|
+
|
|
|
+smtp_password_setting = Settings.get(Settings.name == 'SMTP Password')
|
|
|
+smtp_password = smtp_password_setting.value
|
|
|
+
|
|
|
+domain_name_setting = Settings.get(Settings.name == 'Domain Name')
|
|
|
+domain_name = domain_name_setting.value
|
|
|
+
|
|
|
+password_reset_url_setting = Settings.get(Settings.name == 'Password Reset URL')
|
|
|
+password_reset_url = password_reset_url_setting.value
|
|
|
|
|
|
log = logging.getLogger('werkzeug')
|
|
|
log.setLevel(logging.INFO)
|
|
|
|
|
|
-if application_settings['debug'].lower() == 'true':
|
|
|
+if debug.lower() == 'true':
|
|
|
debug = True
|
|
|
else:
|
|
|
debug = False
|
|
@@ -53,10 +103,10 @@ else:
|
|
|
|
|
|
def send_email(to, subject, body):
|
|
|
# Get settings from smtp_settings
|
|
|
- host = smtp_settings['host']
|
|
|
- port = smtp_settings['port']
|
|
|
- username = smtp_settings['username']
|
|
|
- password = smtp_settings['password']
|
|
|
+ host = smtp_host
|
|
|
+ port = smtp_port
|
|
|
+ username = smtp_username
|
|
|
+ password = smtp_password
|
|
|
|
|
|
# Create an instance of the Emailer class
|
|
|
emailer = Emailer(host, port, username, password)
|
|
@@ -119,10 +169,30 @@ if db.table_exists('user') is False:
|
|
|
if db.table_exists('ilsuser') is False:
|
|
|
db.create_tables([IlsUser])
|
|
|
|
|
|
+if db.table_exists('settings') is False:
|
|
|
+ db.create_tables([Settings])
|
|
|
+ Settings.create(name='Debug Mode', value=False).save()
|
|
|
+ Settings.create(name='HTTP Port', value=5055).save()
|
|
|
+ Settings.create(name='SMTP Host', value="").save()
|
|
|
+ Settings.create(name='SMTP Port', value="587").save()
|
|
|
+ Settings.create(name='SMTP Username', value="").save()
|
|
|
+ Settings.create(name='SMTP Password', value="").save()
|
|
|
+ Settings.create(name='Domain Name', value="lynx").save()
|
|
|
+ Settings.create(name='Password Reset URL', value="https://terminal.idaho-lynx.org").save()
|
|
|
+
|
|
|
+if db.table_exists('log') is False:
|
|
|
+ db.create_tables([Log])
|
|
|
+
|
|
|
+if db.table_exists('password_reset_log') is False:
|
|
|
+ db.create_tables([PasswordResetLog])
|
|
|
+
|
|
|
+if db.table_exists('schedule') is False:
|
|
|
+ db.create_tables([Schedule])
|
|
|
+
|
|
|
db.close()
|
|
|
|
|
|
app = Flask(__name__)
|
|
|
-app.secret_key = 'super secret key'
|
|
|
+app.secret_key = os.urandom(24)
|
|
|
|
|
|
|
|
|
@app.before_request
|
|
@@ -142,7 +212,7 @@ def index():
|
|
|
# send_email('aday@twinfallspubliclibrary.org', 'TEST', 'This is a test email')
|
|
|
error = None
|
|
|
reset = False
|
|
|
- reset_url = is_valid_url(domain_settings['reset_url'])
|
|
|
+ reset_url = is_valid_url(password_reset_url)
|
|
|
reset_url_error = False
|
|
|
|
|
|
if reset_url is False:
|
|
@@ -161,6 +231,7 @@ def index():
|
|
|
if user:
|
|
|
# Reset login datetime
|
|
|
user.reset_datetime = datetime.datetime.now()
|
|
|
+ PasswordResetLog.create(username=user.username, date_created=datetime.datetime.now()).save()
|
|
|
user.save()
|
|
|
|
|
|
# Open the reset URL in a new tab if the URL is valid
|
|
@@ -172,7 +243,7 @@ def index():
|
|
|
error = 'Invalid username'
|
|
|
|
|
|
context = {
|
|
|
- 'domain': domain_settings['name'],
|
|
|
+ 'domain': domain_name,
|
|
|
'error': error,
|
|
|
'reset': reset,
|
|
|
'reset_url': reset_url,
|
|
@@ -216,6 +287,7 @@ def admin_users():
|
|
|
User.create(username=username, password=encrypt_password(password),
|
|
|
date_created=datetime.datetime.now(), logged_in=False).save()
|
|
|
message = 'User created successfully'
|
|
|
+ Log.create(username=session['username'], action='Created admin user: %s' % username, ).save()
|
|
|
else:
|
|
|
message = 'Passwords do not match'
|
|
|
|
|
@@ -243,7 +315,9 @@ def admin_users_delete(id):
|
|
|
# Unset session variable if the user is deleting their own account
|
|
|
if user.username == session['username']:
|
|
|
session.pop('username', None)
|
|
|
+ username = user.username
|
|
|
user.delete_instance()
|
|
|
+ Log.create(username=session['username'], action='Removed admin user: %s' % username, ).save()
|
|
|
|
|
|
return redirect(url_for('admin_users'))
|
|
|
|
|
@@ -270,7 +344,8 @@ def admin_ils_users():
|
|
|
else:
|
|
|
|
|
|
IlsUser.create(username=username, email=email, reset_datetime=datetime.datetime.now()).save()
|
|
|
- message = 'User created successfully'
|
|
|
+ message = 'ILS User: %s created successfully' % username
|
|
|
+ Log.create(username=session['username'], action='Created ILS User: %s' % username,).save()
|
|
|
|
|
|
# Get all admin users from the DB
|
|
|
users = IlsUser.select().execute()
|
|
@@ -291,8 +366,9 @@ def admin_ils_users_delete(id):
|
|
|
|
|
|
# Get the user from the DB
|
|
|
user = IlsUser.get(IlsUser.id == id)
|
|
|
+ username = user.username
|
|
|
user.delete_instance()
|
|
|
-
|
|
|
+ Log.create(username=session['username'], action='Removed ILS user: %s' % username, ).save()
|
|
|
return redirect(url_for('admin_ils_users'))
|
|
|
|
|
|
|
|
@@ -309,7 +385,7 @@ def admin_ils_users_csv_download():
|
|
|
users = IlsUser.select().execute()
|
|
|
for user in users:
|
|
|
writer.writerow([user.username, user.email])
|
|
|
-
|
|
|
+ Log.create(username=session['username'], action='Downloaded ILS user CSV file.').save()
|
|
|
# return the CSV file to the user
|
|
|
return send_file('users.csv', as_attachment=True)
|
|
|
|
|
@@ -362,12 +438,87 @@ def admin_ils_users_csv_import():
|
|
|
return render_template('csv.html', context=context)
|
|
|
|
|
|
|
|
|
+@app.route('/admin/settings', methods=['GET', 'POST'])
|
|
|
+def settings():
|
|
|
+ # Check to see if user is logged in
|
|
|
+ if not requires_auth():
|
|
|
+ return redirect(url_for('login'))
|
|
|
+
|
|
|
+ message = None
|
|
|
+
|
|
|
+ # Process form submission
|
|
|
+ if request.method == 'POST':
|
|
|
+ # Assign form values to variables
|
|
|
+ id = request.form.get('id')
|
|
|
+ value = request.form.get('value')
|
|
|
+
|
|
|
+ # Check if the setting exists
|
|
|
+ try:
|
|
|
+ setting = Settings.get(Settings.id == id)
|
|
|
+ except Exception as e:
|
|
|
+ print(e)
|
|
|
+ setting = None
|
|
|
+
|
|
|
+ if setting:
|
|
|
+ # Update the setting
|
|
|
+ old_value = setting.value
|
|
|
+ setting.value = value
|
|
|
+ setting.save()
|
|
|
+ Log.create(username=session['username'], action='Changed %s setting from "%s" to "%s"' % (setting.name,
|
|
|
+ old_value,
|
|
|
+ value)).save()
|
|
|
+ message = '%s updated successfully' % setting.name
|
|
|
+
|
|
|
+ # Get settings from DB
|
|
|
+ all_settings = Settings.select().execute()
|
|
|
+
|
|
|
+ context = {
|
|
|
+ 'settings': all_settings,
|
|
|
+ 'message': message,
|
|
|
+ }
|
|
|
+
|
|
|
+ return render_template('settings.html', context=context)
|
|
|
+
|
|
|
+
|
|
|
+@app.route('/admin/system/log')
|
|
|
+def system_log():
|
|
|
+ # Check to see if user is logged in
|
|
|
+ if not requires_auth():
|
|
|
+ return redirect(url_for('login'))
|
|
|
+
|
|
|
+ # Get all logs from the DB
|
|
|
+ logs = Log.select().order_by(Log.id.desc()).execute()
|
|
|
+
|
|
|
+ context = {
|
|
|
+ 'logs': logs,
|
|
|
+ }
|
|
|
+
|
|
|
+ return render_template('system_log.html', context=context)
|
|
|
+
|
|
|
+
|
|
|
+@app.route('/admin/system/log/password/resets')
|
|
|
+def password_reset_log():
|
|
|
+ # Check to see if user is logged in
|
|
|
+ if not requires_auth():
|
|
|
+ return redirect(url_for('login'))
|
|
|
+
|
|
|
+ # Get all logs from the DB
|
|
|
+ logs = PasswordResetLog.select().order_by(PasswordResetLog.id.desc()).execute()
|
|
|
+
|
|
|
+ context = {
|
|
|
+ 'logs': logs,
|
|
|
+ }
|
|
|
+
|
|
|
+ return render_template('password_reset_log.html', context=context)
|
|
|
+
|
|
|
+
|
|
|
@app.route('/logout')
|
|
|
def logout():
|
|
|
if 'username' in session:
|
|
|
username = session['username']
|
|
|
user = User.get(User.username == username)
|
|
|
user.logged_in = False
|
|
|
+ Log.create(username=session['username'], action='Logged out').save()
|
|
|
user.save()
|
|
|
session.pop('username', None)
|
|
|
return redirect(url_for('login'))
|
|
@@ -390,6 +541,7 @@ def login():
|
|
|
# Login user
|
|
|
session['username'] = request.form.get('username')
|
|
|
user.logged_in = True
|
|
|
+ Log.create(username=session['username'], action='Logged in').save()
|
|
|
user.save()
|
|
|
|
|
|
return redirect(url_for('admin'))
|
|
@@ -413,20 +565,20 @@ def login():
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
print("------------------------- Start up -----------------------------")
|
|
|
- print("Starting HTTP Service on port %s..." % http_settings['port'])
|
|
|
+ print("Starting HTTP Service on port %s..." % http_port)
|
|
|
|
|
|
if debug is True:
|
|
|
print("Debug mode is enabled.")
|
|
|
- http_server = WSGIServer(('0.0.0.0', int(http_settings['port'])), app)
|
|
|
+ http_server = WSGIServer(('0.0.0.0', int(http_port)), app)
|
|
|
else:
|
|
|
- http_server = WSGIServer(('0.0.0.0', int(http_settings['port'])), app, log=log, error_log=log)
|
|
|
+ http_server = WSGIServer(('0.0.0.0', int(http_port)), app, log=log, error_log=log)
|
|
|
print("HTTP Service Started.")
|
|
|
print("--------------------- Application Details ---------------------")
|
|
|
print("Application started at %s" % datetime.datetime.now())
|
|
|
print("System IP Address: %s" % get_ip_address())
|
|
|
print("System Hostname: %s" % get_hostname())
|
|
|
print("Access the Dashboard using a web browser using any of the following:")
|
|
|
- print("http://%s:%s or http://%s:%s" % (get_hostname(), http_settings['port'], get_ip_address(), http_settings['port']))
|
|
|
+ print("http://%s:%s or http://%s:%s" % (get_hostname(), http_port, get_ip_address(), http_port))
|
|
|
print("---------------------------------------------------------------")
|
|
|
print("To stop the application close this window.")
|
|
|
print("---------------------------------------------------------------")
|