Finished making dashboards
This commit is contained in:
		@@ -42,10 +42,10 @@
 | 
				
			|||||||
                            aria-labelledby="dropdown-account"
 | 
					                            aria-labelledby="dropdown-account"
 | 
				
			||||||
                        >
 | 
					                        >
 | 
				
			||||||
                            <li>
 | 
					                            <li>
 | 
				
			||||||
                                <a href="{{ url_for('admin_views.users') }}" id="link-users" class="dropdown-item">Manage Users</a>
 | 
					                                <a href="{{ url_for('admin_views.users') }}" id="link-users" class="dropdown-item">Users</a>
 | 
				
			||||||
                            </li>
 | 
					                            </li>
 | 
				
			||||||
                            <li>
 | 
					                            <li>
 | 
				
			||||||
                                <a href="{{ url_for('admin_views.questions') }}" id="link-questions" class="dropdown-item">Manage Questions</a>
 | 
					                                <a href="{{ url_for('admin_views.questions') }}" id="link-questions" class="dropdown-item">Question Datasets</a>
 | 
				
			||||||
                            </li>
 | 
					                            </li>
 | 
				
			||||||
                        </ul>
 | 
					                        </ul>
 | 
				
			||||||
                    </li>
 | 
					                    </li>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1 +1,93 @@
 | 
				
			|||||||
{% extends "admin/components/base.html" %}
 | 
					{% extends "admin/components/base.html" %}
 | 
				
			||||||
 | 
					{% block title %}Settings — SKA Referee Test | Admin Console{% endblock %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% block content %}
 | 
				
			||||||
 | 
					    <h1>
 | 
				
			||||||
 | 
					        Settings
 | 
				
			||||||
 | 
					    </h1>
 | 
				
			||||||
 | 
					    <div class="container">
 | 
				
			||||||
 | 
					        <div class="row">
 | 
				
			||||||
 | 
					            <div class="col-sm">
 | 
				
			||||||
 | 
					                <div class="card m-3">
 | 
				
			||||||
 | 
					                    <div class="card-body">
 | 
				
			||||||
 | 
					                        <h5 class="card-title">Admin Users</h5>
 | 
				
			||||||
 | 
					                        <div class="card-text">
 | 
				
			||||||
 | 
					                            <table class="table table-striped">
 | 
				
			||||||
 | 
					                                <thead>
 | 
				
			||||||
 | 
					                                    <tr>
 | 
				
			||||||
 | 
					                                        <th>
 | 
				
			||||||
 | 
					                                            Username
 | 
				
			||||||
 | 
					                                        </th>
 | 
				
			||||||
 | 
					                                        <th>
 | 
				
			||||||
 | 
					                                            Email Address
 | 
				
			||||||
 | 
					                                        </th>
 | 
				
			||||||
 | 
					                                    </tr>
 | 
				
			||||||
 | 
					                                </thead>
 | 
				
			||||||
 | 
					                                <tbody>
 | 
				
			||||||
 | 
					                                    {% for user in users %}
 | 
				
			||||||
 | 
					                                        <tr>
 | 
				
			||||||
 | 
					                                            <td>
 | 
				
			||||||
 | 
					                                                <a href="
 | 
				
			||||||
 | 
					                                                {% if user._id == get_id_from_cookie() %}
 | 
				
			||||||
 | 
					                                                    {{ url_for('admin_auth.account') }}
 | 
				
			||||||
 | 
					                                                {% else %}
 | 
				
			||||||
 | 
					                                                    {{ url_for('admin_views.update_user', _id=user._id) }}
 | 
				
			||||||
 | 
					                                                {% endif%}
 | 
				
			||||||
 | 
					                                                ">{{ user.username }}</a>
 | 
				
			||||||
 | 
					                                            </td>
 | 
				
			||||||
 | 
					                                            <td>
 | 
				
			||||||
 | 
					                                                <a href="mailto:{{ user.email }}">{{ user.email }}</a>
 | 
				
			||||||
 | 
					                                            </td>
 | 
				
			||||||
 | 
					                                        </tr>
 | 
				
			||||||
 | 
					                                    {% endfor %}
 | 
				
			||||||
 | 
					                                </tbody>
 | 
				
			||||||
 | 
					                            </table>
 | 
				
			||||||
 | 
					                        </div>
 | 
				
			||||||
 | 
					                        <a href="{{ url_for('admin_views.users') }}" class="btn btn-primary">Manage Users</a>
 | 
				
			||||||
 | 
					                    </div>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					            <div class="col-sm">
 | 
				
			||||||
 | 
					                <div class="card m-3">
 | 
				
			||||||
 | 
					                    <div class="card-body">
 | 
				
			||||||
 | 
					                        <h5 class="card-title">Question Datasets</h5>
 | 
				
			||||||
 | 
					                        {% if datasets %}
 | 
				
			||||||
 | 
					                            <div class="card-text">
 | 
				
			||||||
 | 
					                                <table class="table table-striped">
 | 
				
			||||||
 | 
					                                    <thead>
 | 
				
			||||||
 | 
					                                        <tr>
 | 
				
			||||||
 | 
					                                            <th>
 | 
				
			||||||
 | 
					                                                File Name
 | 
				
			||||||
 | 
					                                            </th>
 | 
				
			||||||
 | 
					                                            <th>
 | 
				
			||||||
 | 
					                                                Exams
 | 
				
			||||||
 | 
					                                            </th>
 | 
				
			||||||
 | 
					                                        </tr>
 | 
				
			||||||
 | 
					                                    </thead>
 | 
				
			||||||
 | 
					                                    <tbody>
 | 
				
			||||||
 | 
					                                        {% for dataset in datasets %}
 | 
				
			||||||
 | 
					                                            <tr>
 | 
				
			||||||
 | 
					                                                <td>
 | 
				
			||||||
 | 
					                                                    {{ dataset.filename }}
 | 
				
			||||||
 | 
					                                                </td>
 | 
				
			||||||
 | 
					                                                <td>
 | 
				
			||||||
 | 
					                                                    {{ dataset.use }}
 | 
				
			||||||
 | 
					                                                </td>
 | 
				
			||||||
 | 
					                                            </tr>
 | 
				
			||||||
 | 
					                                        {% endfor %}
 | 
				
			||||||
 | 
					                                    </tbody>
 | 
				
			||||||
 | 
					                                </table>
 | 
				
			||||||
 | 
					                            </div>
 | 
				
			||||||
 | 
					                            <a href="{{ url_for('admin_views.questions') }}" class="btn btn-primary">Manage Datasets</a>
 | 
				
			||||||
 | 
					                        {% else %}
 | 
				
			||||||
 | 
					                            <div class="alert alert-primary">
 | 
				
			||||||
 | 
					                                There are currently no question datasets uploaded.
 | 
				
			||||||
 | 
					                            </div>
 | 
				
			||||||
 | 
					                            <a href="{{ url_for('admin_views.questions') }}" class="btn btn-primary">Upload Dataset</a>
 | 
				
			||||||
 | 
					                        {% endif %}
 | 
				
			||||||
 | 
					                    </div>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					{% endblock %}
 | 
				
			||||||
@@ -16,7 +16,7 @@ import secrets
 | 
				
			|||||||
from main import mail
 | 
					from main import mail
 | 
				
			||||||
from datetime import datetime, date
 | 
					from datetime import datetime, date
 | 
				
			||||||
from .models.tests import Test
 | 
					from .models.tests import Test
 | 
				
			||||||
from common.data_tools import get_default_dataset, get_time_options, available_datasets
 | 
					from common.data_tools import get_default_dataset, get_time_options, available_datasets, get_datasets
 | 
				
			||||||
 | 
					
 | 
				
			||||||
views = Blueprint(
 | 
					views = Blueprint(
 | 
				
			||||||
    'admin_views',
 | 
					    'admin_views',
 | 
				
			||||||
@@ -76,13 +76,26 @@ def disable_if_logged_in(function):
 | 
				
			|||||||
@admin_account_required
 | 
					@admin_account_required
 | 
				
			||||||
@login_required
 | 
					@login_required
 | 
				
			||||||
def home():
 | 
					def home():
 | 
				
			||||||
    return render_template('/admin/index.html')
 | 
					    tests = db.tests.find()
 | 
				
			||||||
 | 
					    results = decrypt_find(db.entries, {})
 | 
				
			||||||
 | 
					    current_tests = [ test for test in tests if test['expiry_date'].date() >= date.today() and test['start_date'].date() <= date.today() ]
 | 
				
			||||||
 | 
					    current_tests.sort(key= lambda x: x['expiry_date'], reverse=True)
 | 
				
			||||||
 | 
					    upcoming_tests = [ test for test in tests if test['start_date'].date() > date.today()]
 | 
				
			||||||
 | 
					    upcoming_tests.sort(key= lambda x: x['start_date'])
 | 
				
			||||||
 | 
					    recent_results = [result for result in results if 'submission_time' in result ]
 | 
				
			||||||
 | 
					    recent_results.sort(key= lambda x: x['submission_time'], reverse=True)
 | 
				
			||||||
 | 
					    for result in recent_results:
 | 
				
			||||||
 | 
					        result['percent'] = round(100*result['results']['score']/result['results']['max'])
 | 
				
			||||||
 | 
					    return render_template('/admin/index.html', current_tests = current_tests[:5], upcomimg_tests = upcoming_tests[:5], recent_results = recent_results[:5])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@views.route('/settings/')
 | 
					@views.route('/settings/')
 | 
				
			||||||
@admin_account_required
 | 
					@admin_account_required
 | 
				
			||||||
@login_required
 | 
					@login_required
 | 
				
			||||||
def settings():
 | 
					def settings():
 | 
				
			||||||
    return render_template('/admin/settings/index.html')
 | 
					    users = decrypt_find(db.users, {})
 | 
				
			||||||
 | 
					    users.sort(key= lambda x: x['username'])
 | 
				
			||||||
 | 
					    datasets = get_datasets()
 | 
				
			||||||
 | 
					    return render_template('/admin/settings/index.html', users=users[:5], datasets=datasets[:5])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@views.route('/settings/users/', methods=['GET','POST'])
 | 
					@views.route('/settings/users/', methods=['GET','POST'])
 | 
				
			||||||
@admin_account_required
 | 
					@admin_account_required
 | 
				
			||||||
@@ -245,22 +258,7 @@ def questions():
 | 
				
			|||||||
    from common.data_tools import check_json_format, validate_json_contents, store_data_file
 | 
					    from common.data_tools import check_json_format, validate_json_contents, store_data_file
 | 
				
			||||||
    form = UploadDataForm()
 | 
					    form = UploadDataForm()
 | 
				
			||||||
    if request.method == 'GET':
 | 
					    if request.method == 'GET':
 | 
				
			||||||
        files = glob(os.path.join(app.config["DATA_FILE_DIRECTORY"],'*.json'))
 | 
					        data = get_datasets()
 | 
				
			||||||
        data = []
 | 
					 | 
				
			||||||
        if files:
 | 
					 | 
				
			||||||
            for file in files:
 | 
					 | 
				
			||||||
                filename = file.rsplit('/')[-1]
 | 
					 | 
				
			||||||
                with open(file) as _file:
 | 
					 | 
				
			||||||
                    load = loads(_file.read())
 | 
					 | 
				
			||||||
                _author = load['meta']['author']
 | 
					 | 
				
			||||||
                author = decrypt_find_one(db.users, {'_id': _author})['username']
 | 
					 | 
				
			||||||
                data_element = {
 | 
					 | 
				
			||||||
                    'filename': filename,
 | 
					 | 
				
			||||||
                    'timestamp': datetime.strptime(load['meta']['timestamp'], '%Y-%m-%d %H%M%S'),
 | 
					 | 
				
			||||||
                    'author': author,
 | 
					 | 
				
			||||||
                    'use': len(load['meta']['tests'])
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                data.append(data_element)
 | 
					 | 
				
			||||||
        default = get_default_dataset()
 | 
					        default = get_default_dataset()
 | 
				
			||||||
        return render_template('/admin/settings/questions.html', form=form, data=data, default=default)
 | 
					        return render_template('/admin/settings/questions.html', form=form, data=data, default=default)
 | 
				
			||||||
    if request.method == 'POST':
 | 
					    if request.method == 'POST':
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,13 +3,12 @@ import pathlib
 | 
				
			|||||||
from json import dump, loads
 | 
					from json import dump, loads
 | 
				
			||||||
from datetime import datetime, timedelta
 | 
					from datetime import datetime, timedelta
 | 
				
			||||||
from glob import glob
 | 
					from glob import glob
 | 
				
			||||||
 | 
					 | 
				
			||||||
from flask.json import jsonify
 | 
					 | 
				
			||||||
from main import app
 | 
					 | 
				
			||||||
from random import shuffle
 | 
					from random import shuffle
 | 
				
			||||||
 | 
					 | 
				
			||||||
from werkzeug.utils import secure_filename
 | 
					from werkzeug.utils import secure_filename
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from main import app, db
 | 
				
			||||||
 | 
					from .security.database import decrypt_find_one
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def check_data_folder_exists():
 | 
					def check_data_folder_exists():
 | 
				
			||||||
    if not os.path.exists(app.config['DATA_FILE_DIRECTORY']):
 | 
					    if not os.path.exists(app.config['DATA_FILE_DIRECTORY']):
 | 
				
			||||||
        pathlib.Path(app.config['DATA_FILE_DIRECTORY']).mkdir(parents='True', exist_ok='True')
 | 
					        pathlib.Path(app.config['DATA_FILE_DIRECTORY']).mkdir(parents='True', exist_ok='True')
 | 
				
			||||||
@@ -199,4 +198,23 @@ def get_time_options():
 | 
				
			|||||||
        ('90', '1 hour 30 minutes'),
 | 
					        ('90', '1 hour 30 minutes'),
 | 
				
			||||||
        ('120', '2 hours')
 | 
					        ('120', '2 hours')
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
    return time_options
 | 
					    return time_options
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_datasets():
 | 
				
			||||||
 | 
					    files = glob(os.path.join(app.config["DATA_FILE_DIRECTORY"],'*.json'))
 | 
				
			||||||
 | 
					    data = []
 | 
				
			||||||
 | 
					    if files:
 | 
				
			||||||
 | 
					        for file in files:
 | 
				
			||||||
 | 
					            filename = file.rsplit('/')[-1]
 | 
				
			||||||
 | 
					            with open(file) as _file:
 | 
				
			||||||
 | 
					                load = loads(_file.read())
 | 
				
			||||||
 | 
					            _author = load['meta']['author']
 | 
				
			||||||
 | 
					            author = decrypt_find_one(db.users, {'_id': _author})['username']
 | 
				
			||||||
 | 
					            data_element = {
 | 
				
			||||||
 | 
					                'filename': filename,
 | 
				
			||||||
 | 
					                'timestamp': datetime.strptime(load['meta']['timestamp'], '%Y-%m-%d %H%M%S'),
 | 
				
			||||||
 | 
					                'author': author,
 | 
				
			||||||
 | 
					                'use': len(load['meta']['tests'])
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            data.append(data_element)
 | 
				
			||||||
 | 
					    return data
 | 
				
			||||||
		Reference in New Issue
	
	Block a user