implement pages, clean web service, add option to disable fallback

This commit is contained in:
KF7EEL 2022-09-24 12:24:59 -07:00
parent 1e311d86c6
commit 391e76d72c
18 changed files with 359 additions and 143 deletions

View File

@ -1,4 +1,4 @@
## HBNet is still under heavy development. Documentation is being added to the Wiki as I write it, so check perodically to see if there is any new information. V1.0 will be ready in the next few months. See [HBNet.xyz](https://hbnet.xyz) or [here](https://github.com/kf7eel/hbnet/discussions/33) for the development news.
## HBNet is still under heavy development and currently undergoing a partiaql rewrite. Documentation is being added to the Wiki as I write it, so check perodically to see if there is any new information. V1.0 will be ready in the next few months. See [here](https://github.com/kf7eel/hbnet/discussions/33) for the development news.
![ ](https://raw.githubusercontent.com/kf7eel/hblink3/hbnet/HBNet.png "Logo")

View File

@ -1691,6 +1691,9 @@ if __name__ == '__main__':
except Exception as e:
logger.error('Control server unreachable or other error. Using local config.')
logger.error(e)
if LOCAL_CONFIG['WEB_SERVICE']['DISABLE_FALLBACK']:
logger.info('Falback disabled. Exiting...')
sys.exit()
spec = importlib.util.spec_from_file_location("module.name", cli_args.RULES_FILE)
rules_module = importlib.util.module_from_spec(spec)
try:
@ -1763,5 +1766,6 @@ if __name__ == '__main__':
pass
else:
Path('/tmp/' + (CONFIG['LOGGER']['LOG_NAME'] + '_PEERS/')).mkdir()
reactor.run()

View File

@ -161,6 +161,7 @@ def build_config(_config_file):
'THIS_SERVER_NAME': config.get(section, 'THIS_SERVER_NAME'),
'URL': config.get(section, 'URL'),
'REMOTE_CONFIG_ENABLED': config.getboolean(section, 'REMOTE_CONFIG_ENABLED'),
'DISABLE_FALLBACK': config.getboolean(section, 'DISABLE_FALLBACK'),
'APPEND_INT': config.getint(section, 'APPEND_INT'),
'EXTRA_INT_1': config.getint(section, 'EXTRA_INT_1'),
'EXTRA_INT_2': config.getint(section, 'EXTRA_INT_2'),

View File

@ -110,6 +110,8 @@ STALE_DAYS: 7
# This is where to configure the details for use with a user managment script
[WEB_SERVICE]
THIS_SERVER_NAME: MMDVM_Server
# When web service unreachable, die.
DISABLE_FALLBACK: True
REMOTE_CONFIG_ENABLED: True
# URL of the user managment server
URL: http://localhost:8080/svr
@ -197,7 +199,7 @@ REG_ACL: DENY:1
SUB_ACL: DENY:1
TGID_TS1_ACL: PERMIT:ALL
TGID_TS2_ACL: PERMIT:ALL
OTHER_OPTIONS:
# PEER INSTANCES - DUPLICATE SECTION FOR MULTIPLE PEERS
# There are a LOT of errors in the HB Protocol specifications on this one!
# MOST of these items are just strings and will be properly dealt with by the program

View File

@ -13,4 +13,5 @@ cryptography
setproctitle
scapy
paho-mqtt
service_identity

View File

@ -53,8 +53,10 @@ import os, ast
from cryptography.fernet import Fernet
from flaskext.markdown import Markdown
peer_locations = {}
hbnet_version = 'HWS 0.0.1-pre_pre_alpha/MQTT'
hbnet_version = 'V 09102022'
# Query radioid.net for list of IDs
def get_ids(callsign):
@ -138,6 +140,7 @@ def hbnet_web_service():
# Create Flask app load app.config
mail = Mail()
app = Flask(__name__)
Markdown(app)
app.config.from_object(__name__+'.ConfigClass')
# Initialize Flask-BabelEx
@ -544,7 +547,14 @@ def hbnet_web_service():
boo_2 = db.Column(db.Boolean(), nullable=True, server_default='1')
time = db.Column(db.DateTime())
class Pages(db.Model):
__tablename__ = 'pages'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(1000))
enabled = db.Column(db.Boolean(), nullable=False, server_default='1')
notes = db.Column(db.String(1000))
data = db.Column(db.String(10000))
time = db.Column(db.DateTime())
@ -642,24 +652,26 @@ def hbnet_web_service():
time = datetime.datetime.utcnow()
)
db.session.add(flash_entry_add)
tos_entry_add = Misc(
field_1 = 'terms_of_service',
field_2 = '''<div class="panel panel-default">
<div class="panel-heading" style="text-align: center;"><h4>Terms of Use</h4></div>
<div class="panel-body">
<p>By using <strong>''' + title + '''</strong>, you agree not to do anything malicious. You agree to use the system with respect and courtesy to others. Please operate within the laws of your country.</p>
</div>
</div>''',
add_pg = Pages(
name='Home Page',
data="Welcome to your HBNet installation.",
notes = "Created on first start",
time = datetime.datetime.utcnow()
)
db.session.add(tos_entry_add)
home_entry_add = Misc(
field_1 = 'home_page',
field_2 = '<p>Welcome to <strong>' + title + '</strong>.</p>',
)
db.session.add(add_pg)
add_tos = Pages(
name='Terms of Service',
data='''### Terms of Use
By using this service, you agree not to do anything malicious. You agree to use the system with respect and courtesy to others. Please operate within the laws of your country.
''',
notes = "Created on first start",
time = datetime.datetime.utcnow()
)
db.session.add(home_entry_add)
)
db.session.add(add_tos)
ping_list_initial = Misc(
field_1 = 'ping_list',
field_2 = '{}',
@ -681,6 +693,15 @@ def hbnet_web_service():
time = datetime.datetime.utcnow()
)
db.session.add(script_links_initial)
add_news = News(
subject = 'Welcome',
date = 'Today',
text = 'Welcome',
time = datetime.datetime.utcnow()
)
db.session.add(add_news)
db.session.commit()
# Query radioid.net for list of DMR IDs, then add to DB
@ -787,37 +808,85 @@ def hbnet_web_service():
@app.route('/')
def home_page():
if mode == 'FULL' or mode == 'DMR_ONLY':
home_text = Misc.query.filter_by(field_1='home_page').first()
home_text = Pages.query.filter_by(id=1).first()
#content = Markup('<strong>Index</strong>')
try:
l_news = News.query.order_by(News.time.desc()).first()
content = '''
<div class="card">
<div class="card-body">
<h4 class="card-title"><a href="news/''' + str(l_news.id) + '''">''' + l_news.subject + '''</h4></a>
<hr />
&nbsp;
<p style="text-align: center;">''' + l_news.date + '''</p>
<hr />
&nbsp;
<p class="card-text">''' + l_news.text + '''</p>
<p style="text-align: center;"></p>
</div>
</div>
'''
except:
content = ''
return render_template('index.html', news = Markup(content), content_block = Markup(home_text.field_2))
content = ''
# try:
l_news = News.query.order_by(News.time.desc()).first()
return render_template('index.html', news = Markup(content), content_block = Markup(home_text.data), text = l_news.text, subject = l_news.subject, date = l_news.date, news_id = l_news.id)
# except:
# content = ''
# return render_template('index.html', content_block = Markup(home_text.data))
else:
return redirect('/data_overview')
@app.route('/tos')
def tos_page():
tos_text = Misc.query.filter_by(field_1='terms_of_service').first()
content = tos_text.field_2
tos_text = Pages.query.filter_by(id=2).first()
return render_template('generic.html', markup_content = Markup(content))
return render_template('generic.html', markup_content = tos_text.data)
@app.route('/page/<id>')
def other_page(id):
page = Pages.query.filter_by(id=int(id)).first()
# return render_template('index.html')
return render_template('page.html', content=Markup(page.data), page_title = page.name, page_time = local_time(page.time))
@app.route('/pages')
def all_pages():
content = ''
all_pages = Pages.query.order_by(Pages.name).all()
for i in all_pages:
if i.id == 1 or i.id == 2:
pass
else:
content = content + '<tr><td><a href="/page/' + str(i.id) + '">' + i.name + '</a></td><td>' + i.notes + '</td></tr>'
return render_template('view_pages.html', content = Markup(content))
@app.route('/manage_page', methods=['GET', 'POST'])
@login_required
@roles_required('Admin')
def manage_page():
if request.args.get('new'):
return render_template('add_page.html')
elif request.args.get('save'):
add_page(request.form.get('name'), request.form.get('data'), request.form.get('notes'))
content = '''<h3 style="text-align: center;">Page Saved.</h3>
<p style="text-align: center;">Redirecting in 3 seconds.</p>
<meta http-equiv="refresh" content="3; URL=/manage_page" /> '''
return render_template('flask_user_layout.html', markup_content=Markup(content))
elif request.args.get('delete'):
delete_page(int(request.args.get('delete')))
content = '''<h3 style="text-align: center;">Page Deleted.</h3>
<p style="text-align: center;">Redirecting in 3 seconds.</p>
<meta http-equiv="refresh" content="3; URL=/manage_page" /> '''
return render_template('flask_user_layout.html', markup_content=Markup(content))
elif request.args.get('edit'):
page = Pages.query.filter_by(id=int(request.args.get('edit'))).first()
return render_template('edit_page.html', name = page.name, notes = page.notes, data = page.data, id = page.id)
elif request.args.get('edit_save'):
edit_page(int(request.args.get('edit_save')), request.form.get('name'), request.form.get('data'), request.form.get('notes'))
content = '''<h3 style="text-align: center;">Page Saved.</h3>
<p style="text-align: center;">Redirecting in 3 seconds.</p>
<meta http-equiv="refresh" content="3; URL=/manage_page" /> '''
return render_template('flask_user_layout.html', markup_content=Markup(content))
else:
content = ''
all_pages = Pages.query.order_by(Pages.name).all()
for i in all_pages:
delete_button = ' - <a href="/manage_page?delete=' + str(i.id) + '"><button type="button" class="btn btn-danger">Delete</button></a>'
if i.id == 1 or i.id == 2:
delete_button = ''
content = content + '<tr><td><a href="/page/' + str(i.id) + '">' + i.name + '</a> - <a href="/manage_page?edit=' + str(i.id) + '"><button type="button" class="btn btn-primary">Edit</button></a>' + delete_button + '</td><td>' + i.notes + '</td></tr>'
return render_template('view_pages.html', content = Markup(content), admin_page = True)
@app.route('/map_gps/<call_ssid>')
@ -2162,54 +2231,24 @@ def hbnet_web_service():
## view_news = News.query.order_by(News.time.desc()).paginate(page=page, per_page=1)
#content = '''<table style="width: 600px; margin-left: auto; margin-right: auto;" border="1"><tbody>'''
content = ''
news_content = ''
art_count = 0
for article in view_news:
if request.args.get('all_news'):
art_count = 1
if art_count < 16:
news_content = news_content + '''
<div class="card">
<div class="card-body">
<h4 class="card-title"><a href="news/''' + str(article.id) + '''">''' + article.subject + '''</h4></a>
<hr />
&nbsp;
<p style="text-align: center;">''' + article.date + '''</p>
<hr />
&nbsp;
<p class="card-text">''' + article.text + '''</p>
<p style="text-align: center;"></p>
</div>
</div>
<p>&nbsp;</p>
'''
art_count = art_count + 1
#content = content + '''</tbody></table><p>&nbsp;</p>'''
return render_template('news.html', markup_content = Markup(news_content))
print(view_news)
for i in view_news:
content = content + '<tr><td><a href="/news/' + str(i.id) + '">' + i.subject + '</a></td><td>' + i.date + '</td></tr>'
return render_template('news_list.html', content = Markup(content))
@app.route('/news/<article>') #, methods=['POST', 'GET'])
def view_arts(article):
view_arti = News.query.filter_by(id=article).first()
content = '''
<div class="card">
<div class="card-body">
<h4 class="card-title">''' + view_arti.subject + '''</h4>
<hr />
&nbsp;
<p style="text-align: center;">''' + view_arti.date + '''</p>
<hr />
&nbsp;
<p class="card-text">''' + view_arti.text + '''</p>
<p style="text-align: center;"></p>
</div>
</div>
'''
return render_template('news.html', markup_content = Markup(content))
content = ''
return render_template('news.html', markup_content = Markup(content), subject = view_arti.subject, date = view_arti.date, text = view_arti.text)
@ -2284,10 +2323,14 @@ def hbnet_web_service():
<tbody>
'''
for a in view_news:
if a.id == 1:
delete_button = ''
else:
delete_button = '''<a href="manage_news?delete=''' + str(a.id )+ '''"><button type="button" class="btn btn-danger">Delete</button></a>'''
content = content + '''
<tr>
<td><a href="news/''' + str(a.id) + '''">''' + a.subject + '''</a> | <a href="manage_news?delete=''' + str(a.id )+ '''"><button type="button" class="btn btn-danger">Delete</button></a></td>
<td><a href="news/''' + str(a.id) + '''">''' + a.subject + '''</a> | ''' + delete_button + '''</td>
<td>''' + a.date + '''</td>
<td>''' + str(a.id) + '''</td>
@ -2313,16 +2356,6 @@ def hbnet_web_service():
content = '''<h3 style="text-align: center;">Saved flash text.</h3>
<p style="text-align: center;">Redirecting in 3 seconds.</p>
<meta http-equiv="refresh" content="3; URL=misc_settings" /> '''
elif request.args.get('home') == 'save':
misc_edit_field_1('home_page', request.form.get('home_text'), None, None, None, None, None, None, None, None)
content = '''<h3 style="text-align: center;">Saved home page.</h3>
<p style="text-align: center;">Redirecting in 3 seconds.</p>
<meta http-equiv="refresh" content="3; URL=misc_settings" /> '''
elif request.args.get('tos') == 'save':
misc_edit_field_1('terms_of_service', request.form.get('tos_text'), None, None, None, None, None, None, None, None)
content = '''<h3 style="text-align: center;">Saved terms of service.</h3>
<p style="text-align: center;">Redirecting in 3 seconds.</p>
<meta http-equiv="refresh" content="3; URL=misc_settings" /> '''
elif request.args.get('aprs') == 'save':
misc_edit_field_1('unregistered_aprs', request.form.get('aprs_text'), None, None, None, None, None, None, None, None)
content = '''<h3 style="text-align: center;">Saved terms of service.</h3>
@ -2372,39 +2405,6 @@ def hbnet_web_service():
<p>&nbsp;</p>
<form action="misc_settings?home=save" method="POST">
<table style="width: 500px; margin-left: auto; margin-right: auto;" border="1">
<tbody>
<tr style="height: 51.1667px;">
<td style="height: 51.1667px; text-align: center;"><label for="home_text">Homepage (HTML OK, 5000 characters max):</label><br /> <textarea id="home_text" cols="65" name="home_text" rows="4">''' + home_text.field_2 + '''</textarea></td>
</tr>
<tr style="height: 27px;">
<td style="text-align: center; height: 27px;">
<p>&nbsp;</p>
<p><input type="submit" value="Submit" /></p>
</td>
</tr>
</tbody>
</table>
</form>
<p>&nbsp;</p>
<form action="misc_settings?tos=save" method="POST">
<table style="width: 500px; margin-left: auto; margin-right: auto;" border="1">
<tbody>
<tr style="height: 51.1667px;">
<td style="height: 51.1667px; text-align: center;"><label for="tos_text">Terms of Service (HTML OK, 5000 characters max):</label><br /> <textarea id="tos_text" cols="65" name="tos_text" rows="4">''' + tos_text.field_2 + '''</textarea></td>
</tr>
<tr style="height: 27px;">
<td style="text-align: center; height: 27px;">
<p>&nbsp;</p>
<p><input type="submit" value="Submit" /></p>
</td>
</tr>
</tbody>
</table>
</form>
<p>&nbsp;</p>
<form action="misc_settings?aprs=save" method="POST">
<table style="width: 500px; margin-left: auto; margin-right: auto;" border="1">
@ -3404,6 +3404,38 @@ Name: <strong>''' + p.name + '''</strong>&nbsp; -&nbsp; Port: <strong>''' + str(
###### DB functions #############################
def local_time(time_utc):
l_time = (time_utc + datetime.timedelta(hours=hbnet_tz)).strftime(time_format)
return l_time
def local_time_to_utc(time):
u_time = (time - datetime.timedelta(hours=hbnet_tz))
return u_time
def add_page(name, data, notes):
add_pg = Pages(
name=name,
data=data,
notes = notes,
time = datetime.datetime.utcnow()
)
db.session.add(add_pg)
db.session.commit()
def edit_page(id, name, data, notes):
page = Pages.query.filter_by(id=id).first()
page.name = name
page.data = data
page.time = datetime.datetime.utcnow()
page.notes = notes
db.session.commit()
def delete_page(id):
page = Pages.query.filter_by(id=id).first()
db.session.delete(page)
db.session.commit()
def sms_que(_server):
que_db = SMS_Que.query.filter_by(server=_server).all()
que_list = []

View File

@ -46,15 +46,15 @@ default_account_state = True
# Allow users to generate and send SMS messages via the web service
# and API.
allow_user_sms = True
allow_user_sms = False
# Legacy passphrase used in hblink.cfg
legacy_passphrase = 'passw0rd'
# Coordinates to center map over
center_map = [45.372, -121.6972]
center_map = [00.000, 000.0000]
# Default map zoom level
map_zoom = 5
map_zoom = 10
# Passphrase calculation config. If REMOTE_CONFIG is not used in your DMR server config
# (hblink.cfg), then the values in section [USER_MANAGER] MUST match the values below.

View File

@ -11,3 +11,4 @@ libscrc
dmr_utils3
cryptography
uwsgi
Flask-Markdown

View File

@ -0,0 +1,34 @@
{% extends 'flask_user/_public_base.html' %}
{% block content %}
<h2 style="text-align: center;">Add Page</h2>
<form action="/manage_page?save=true" method="post">
<div class="input-group mb-3">
<span class="input-group-text" id="basic-addon1">Title</span>
<input type="text" name="name" class="form-control" aria-describedby="basic-addon1">
</div>
<br />
<textarea id="ed1" name="data" class="form-control" aria-label="Data"></textarea>
<br />
<div class="input-group">
<span class="input-group-text">Notes</span>
<textarea id="ed1" name="notes" class="form-control" aria-label="Notes"></textarea>
</div>
<br />
<p style="text-align: center;"><input class="btn btn-primary" type="submit" value="Save" /></form></p>
<br />
<script>
const easyMDE = new EasyMDE({element: document.getElementById('ed1')});
</script>
{% endblock %}

View File

@ -7,12 +7,15 @@
<div class="container">
<div class="row">
<div class="container-fluid col-centered">
{{markup_content}}
</div>
</div>
</div>

View File

@ -0,0 +1,33 @@
{% extends 'flask_user/_public_base.html' %}
{% block content %}
<h2 style="text-align: center;">Add Page</h2>
<form action="/manage_page?edit_save={{id}}" method="post">
<div class="input-group mb-3">
<span class="input-group-text" id="basic-addon1">Title</span>
<input type="text" name="name" class="form-control" aria-describedby="basic-addon1" value="{{name}}">
</div>
<br />
<textarea id="ed1" name="data" class="form-control" aria-label="Data">{{data}}</textarea>
<br />
<div class="input-group">
<span class="input-group-text">Notes</span>
<textarea id="ed1" name="notes" class="form-control" aria-label="Notes">{{notes}}</textarea>
</div>
<br />
<p style="text-align: center;"><input class="btn btn-primary" type="submit" value="Save" /></form></p>
<br />
<script>
const easyMDE = new EasyMDE({element: document.getElementById('ed1')});
</script>
{% endblock %}

View File

@ -6,10 +6,17 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{ user_manager.USER_APP_NAME }}</title>
<!-- Bootstrap -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<link rel="stylesheet" href="https://unpkg.com/bootstrap-table@1.15.5/dist/bootstrap-table.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.5.0/font/bootstrap-icons.css">
<!-- Bootstrap -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<link rel="stylesheet" href="https://unpkg.com/bootstrap-table@1.15.5/dist/bootstrap-table.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.5.0/font/bootstrap-icons.css">
<!-- Markdown editor -->
<link rel="stylesheet" href="https://unpkg.com/easymde/dist/easymde.min.css">
<script src="https://unpkg.com/easymde/dist/easymde.min.js"></script>
<!--Bootstrap select-->
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-select@1.14.0-beta3/dist/css/bootstrap-select.min.css">
<!-- In-lining styles to avoid needing a separate .css file -->
@ -48,6 +55,9 @@
<li class="nav-item">
<a class="nav-link" href="{{url}}/"><i class="bi bi-house-fill"></i> Home </a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{url}}/pages"><i class="bi bi-file-earmark-break-fill"></i> Pages </a>
</li>
{% if global_config['mode'] == 'FULL' or global_config['mode'] == 'DMR_ONLY' %}
<li class="nav-item">
<a class="nav-link" href="{{url}}/talkgroups"><i class="bi bi-card-list"></i> Talkgroups </a>
@ -133,6 +143,7 @@
<li><a class="dropdown-item" href="{{url}}/approve_users">Waiting Approval</a></li>
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item" href="{{url}}/manage_news">Manage News</a></li>
<li><a class="dropdown-item" href="/manage_page"> Manage Pages </a></li>
<li><a class="dropdown-item" href="{{url}}/misc_settings">Misc Options</a></li>
{% if global_config['mode'] == 'FULL' or global_config['mode'] == 'DMR_ONLY' %}
<li><a class="dropdown-item" href="{{url}}/auth_log">Authorization Log</a></li>
@ -238,8 +249,10 @@
<!-- Bootstrap -->
<script src="https://cdn.jsdelivr.net/npm/jquery/dist/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.bundle.min.js" integrity="sha384-ygbV9kiqUc6oa4msXn9868pTtWMgiQaeYH7/t7LECLbyPA2x65Kgf80OJFdroafW" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
<script src="https://unpkg.com/bootstrap-table@1.18.3/dist/bootstrap-table.min.js"></script>
<!-- Latest compiled and minified JavaScript -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap-select@1.14.0-beta3/dist/js/bootstrap-select.min.js"></script>
{# *** Allow sub-templates to insert extra html to the bottom of the body *** #}

View File

@ -5,7 +5,7 @@
<div class="row">
{{markup_content}}
{{markup_content|markdown}}
</div>

View File

@ -5,7 +5,7 @@
<div class="row">
{{content_block}}
{{content_block|markdown}}
</div>
@ -18,6 +18,20 @@
<td style="text-align: center;">
<h4>Latest News:</h4>
{{news}}
<div class="card">
<div class="card-body">
<h4 class="card-title"><a href="news/{{news_id}}">{{subject}}</h4></a>
<hr />
&nbsp;
<p style="text-align: center;">{{date}}</p>
<hr />
&nbsp;
<p class="card-text">{{text|markdown}}</p>
<p style="text-align: center;"></p>
</div>
</div>
</td>
</tr>
</tbody>

View File

@ -2,7 +2,21 @@
{% block content %}
<p style="text-align: center;"><a href="/news?all_news=true"><strong><button type="button" class="btn btn-primary">View All News</button></strong></a></p>
<div class="row">
<div class="col-lg-12">{{markup_content}}</div>
<div class="col-lg-12">
<div class="card">
<div class="card-body">
<h4 class="card-title">{{subject}}</h4>
<hr />
&nbsp;
<p style="text-align: center;">{{date}}</p>
<hr />
&nbsp;
<p class="card-text">{{text|markdown}}</p>
<p style="text-align: center;"></p>
</div>
</div>
</div>
</div>
<p>&nbsp;</p>

View File

@ -0,0 +1,16 @@
{% extends 'flask_user/_public_base.html' %}
{% block content %}
<table data-toggle="table" data-pagination="true" data-search="true" >
<thead>
<tr>
<th>Subject</th>
<th>Date</th>
</tr>
</thead>
<tbody>
{{content}}
</tbody>
</table>
{% endblock %}

14
web/templates/page.html Normal file
View File

@ -0,0 +1,14 @@
{% extends 'flask_user/_public_base.html' %}
{% block content %}
<h2 style="text-align: center;">{{page_title}}</h2>
<p style="text-align: center;">Last updated: {{page_time}}</p>
<br />
{{content|markdown}}
<br />
{% endblock %}

View File

@ -0,0 +1,34 @@
{% extends 'flask_user/_public_base.html' %}
{% block content %}
<h1 style="text-align: center;">Pages</h1>
{% if admin_page %}
{% if call_or_get(current_user.has_roles(['Admin'])) %}
<table style="margin-left: auto; margin-right: auto;">
<tbody>
<tr>
<td><a href="/manage_page?new=yes"><button type="button" class="btn btn-success">Add Page</button></a></td>
<td>.</td>
<td>.</td>
<td>.</td>
</tr>
</tbody>
</table>
{% endif %}
{% endif %}
<table data-toggle="table" data-pagination="true" data-search="true" >
<thead>
<tr>
<th>Name</th>
<th>Notes</th>
</tr>
</thead>
<tbody>
{{content}}
</tbody>
</table>
{% endblock %}