The database is a MariaDB SQL database with a basic structure of Resources, Relationships, and Users. Resources are divided into tools, practices, and books and the table contains fields for these various types of resources. Relationships defines the links between resources using the resource ID in the Resource table: these are rendered on the site as connections between, say, a tool and a practice. Users contains the site's users with basic details like email address and hashed password. This simple structure provides flexibility for displaying resources with filters and to illustrate the connections between various resources. | The database is a MariaDB SQL database with a basic structure of Resources, Relationships, and Users. Resources are divided into tools, practices, and books and the table contains fields for these various types of resources. Relationships defines the links between resources using the resource ID in the Resource table: these are rendered on the site as connections between, say, a tool and a practice. Users contains the site's users with basic details like email address and hashed password. This simple structure provides flexibility for displaying resources with filters and to illustrate the connections between various resources. | ||||
### admin interface | |||||
There's an admin interface for editing resources and relationships in the browser. To login with a user account that has been previously set up, go to ./login and enter your email address and password. | |||||
Once logged in, you can access the page to add a new resource at ./create. Select using the dropdown whether you want to create a tool, a practice, or a book. At the bottom of the form, you will be able to add relationships between your new resource and other resources: to select multiple resources to create relationships with, hold Ctrl on your keyboard while selecting options in the selection list. | |||||
You can also use the 'edit' link which will appear next to every resource to edit an existing resource, add new relationships between existing resources, and delete an existing resource. | |||||
Logged in users can log out at ./logout. | |||||
### RESTful API | ### RESTful API | ||||
The application has a simple RESTful API deployed using [Marshmallow](https://marshmallow.readthedocs.io/en/stable/index.html) to define schemas based on the SQLAlchemy database models. It allows a simple JSON export of users (login required), tools, practices, and books. | The application has a simple RESTful API deployed using [Marshmallow](https://marshmallow.readthedocs.io/en/stable/index.html) to define schemas based on the SQLAlchemy database models. It allows a simple JSON export of users (login required), tools, practices, and books. |
db.session.add(new_tool) | db.session.add(new_tool) | ||||
db.session.commit() | db.session.commit() | ||||
if request.form.getlist('linked_resources'): | |||||
for linked_resource in request.form.getlist('linked_resources'): | |||||
if request.form.getlist('linked_practices') or request.form.getlist('linked_books'): | |||||
linked_resources = request.form.getlist('linked_practices') + request.form.getlist('linked_books') | |||||
for linked_resource in linked_resources: | |||||
tool = Resource.query.filter_by(type='tool').filter_by(name=name).first() | tool = Resource.query.filter_by(type='tool').filter_by(name=name).first() | ||||
add_relationship(tool.id, linked_resource) | add_relationship(tool.id, linked_resource) | ||||
db.session.add(new_practice) | db.session.add(new_practice) | ||||
db.session.commit() | db.session.commit() | ||||
if request.form.getlist('linked_tools') or request.form.getlist('linked_books'): | |||||
linked_resources = request.form.getlist('linked_tools') + request.form.getlist('linked_books') | |||||
for linked_resource in linked_resources: | |||||
practice = Resource.query.filter_by(type='practice').filter_by(name=name).first() | |||||
add_relationship(practice.id, linked_resource) | |||||
elif request.form.get('resource_type') == 'book': | elif request.form.get('resource_type') == 'book': | ||||
type = 'book' | type = 'book' | ||||
name = request.form.get('book_name') | name = request.form.get('book_name') | ||||
db.session.add(new_book) | db.session.add(new_book) | ||||
db.session.commit() | db.session.commit() | ||||
resource_dropdown = Resource.query | |||||
if request.form.getlist('linked_tools') or request.form.getlist('linked_practices'): | |||||
linked_resources = request.form.getlist('linked_tools') + request.form.getlist('linked_practices') | |||||
for linked_resource in linked_resources: | |||||
book = Resource.query.filter_by(type='book').filter_by(name=name).first() | |||||
add_relationship(book.id, linked_resource) | |||||
resource_dropdown = Resource.query.order_by(Resource.name) | |||||
return render_template('create.html', resource_dropdown=resource_dropdown) | return render_template('create.html', resource_dropdown=resource_dropdown) |
<input class="form-control" type="text" name="status" placeholder="Platform status" autofocus=""> | <input class="form-control" type="text" name="status" placeholder="Platform status" autofocus=""> | ||||
</div> | </div> | ||||
<div class="mb-3 mt-3"> | <div class="mb-3 mt-3"> | ||||
<label for="linked_practice_id">Linked resources</label> | |||||
<label for="linked_practices">Add practices relationship(s) (hold Ctrl to select multiple options)</label> | |||||
</div> | </div> | ||||
<div class="mb-3 mt-3"> | <div class="mb-3 mt-3"> | ||||
<select name="linked_resources" id="linked_resources" aria-label="Linked resources" class="selectpicker" data-live-search="true" multiple> | |||||
<select name="linked_practices" id="linked_practices" aria-label="Add practices relationships" class="selectpicker" data-live-search="true" multiple> | |||||
{% for resource_dropdown in resource_dropdown %} | {% for resource_dropdown in resource_dropdown %} | ||||
{% if resource_dropdown['type'] != 'tool' %} | |||||
<option value="{{ resource_dropdown['id'] }}">{{ resource_dropdown['name'] }}</option> | |||||
{% if resource_dropdown['type'] == 'practice' %} | |||||
<option value="{{ resource_dropdown['id'] }}">{{ resource_dropdown['name'] }}</option> | |||||
{% endif %} | |||||
{% endfor %} | |||||
</select> | |||||
</div> | |||||
<div class="mb-3 mt-3"> | |||||
<label for="linked_books">Add books relationship(s) (hold Ctrl to select multiple options)</label> | |||||
</div> | |||||
<div class="mb-3 mt-3"> | |||||
<select name="linked_books" id="linked_books" aria-label="Add books relationships" class="selectpicker" data-live-search="true" multiple> | |||||
{% for resource_dropdown in resource_dropdown %} | |||||
{% if resource_dropdown['type'] == 'book' %} | |||||
<option value="{{ resource_dropdown['id'] }}">{{ resource_dropdown['name'] }}</option> | |||||
{% endif %} | {% endif %} | ||||
{% endfor %} | {% endfor %} | ||||
</select> | </select> | ||||
<label for="references">Further reading</label> | <label for="references">Further reading</label> | ||||
<textarea class="form-control" rows="4" type="text" name="references" placeholder="Further reading" autofocus=""></textarea> | <textarea class="form-control" rows="4" type="text" name="references" placeholder="Further reading" autofocus=""></textarea> | ||||
</div> | </div> | ||||
<div class="mb-3 mt-3"> | |||||
<label for="linked_tools">Add tools relationship(s) (hold Ctrl to select multiple options)</label> | |||||
</div> | |||||
<div class="mb-3 mt-3"> | |||||
<select name="linked_tools" id="linked_tools" aria-label="Add tools relationships" class="selectpicker" data-live-search="true" multiple> | |||||
{% for resource_dropdown in resource_dropdown %} | |||||
{% if resource_dropdown['type'] == 'tool' %} | |||||
<option value="{{ resource_dropdown['id'] }}">{{ resource_dropdown['name'] }}</option> | |||||
{% endif %} | |||||
{% endfor %} | |||||
</select> | |||||
</div> | |||||
<div class="mb-3 mt-3"> | |||||
<label for="linked_books">Add books relationship(s) (hold Ctrl to select multiple options)</label> | |||||
</div> | |||||
<div class="mb-3 mt-3"> | |||||
<select name="linked_books" id="linked_books" aria-label="Add books relationships" class="selectpicker" data-live-search="true" multiple> | |||||
{% for resource_dropdown in resource_dropdown %} | |||||
{% if resource_dropdown['type'] == 'book' %} | |||||
<option value="{{ resource_dropdown['id'] }}">{{ resource_dropdown['name'] }}</option> | |||||
{% endif %} | |||||
{% endfor %} | |||||
</select> | |||||
</div> | |||||
</div> | </div> | ||||
<div id="resource_type_book" class="resource_type_input" style="display: none;"> | <div id="resource_type_book" class="resource_type_input" style="display: none;"> | ||||
<div class="mb-3 mt-3"> | <div class="mb-3 mt-3"> | ||||
<label for="isbn">ISBN</label> | <label for="isbn">ISBN</label> | ||||
<input class="form-control" type="text" name="isbn" placeholder="ISBN" autofocus=""> | <input class="form-control" type="text" name="isbn" placeholder="ISBN" autofocus=""> | ||||
</div> | </div> | ||||
<div class="mb-3 mt-3"> | |||||
<label for="linked_tools">Add tools relationship(s) (hold Ctrl to select multiple options)</label> | |||||
</div> | |||||
<div class="mb-3 mt-3"> | |||||
<select name="linked_tools" id="linked_tools" aria-label="Add tools relationships" class="selectpicker" data-live-search="true" multiple> | |||||
{% for resource_dropdown in resource_dropdown %} | |||||
{% if resource_dropdown['type'] == 'tool' %} | |||||
<option value="{{ resource_dropdown['id'] }}">{{ resource_dropdown['name'] }}</option> | |||||
{% endif %} | |||||
{% endfor %} | |||||
</select> | |||||
</div> | |||||
<div class="mb-3 mt-3"> | |||||
<label for="linked_practices">Add practices relationship(s) (hold Ctrl to select multiple options)</label> | |||||
</div> | |||||
<div class="mb-3 mt-3"> | |||||
<select name="linked_practices" id="linked_practices" aria-label="Add practices relationships" class="selectpicker" data-live-search="true" multiple> | |||||
{% for resource_dropdown in resource_dropdown %} | |||||
{% if resource_dropdown['type'] == 'practice' %} | |||||
<option value="{{ resource_dropdown['id'] }}">{{ resource_dropdown['name'] }}</option> | |||||
{% endif %} | |||||
{% endfor %} | |||||
</select> | |||||
</div> | |||||
</div> | </div> | ||||
<button type="submit" class="btn btn-default">Submit</button> | <button type="submit" class="btn btn-default">Submit</button> | ||||
</form> | </form> |
</input> | </input> | ||||
</div> | </div> | ||||
<div class="mb-3 mt-3"> | <div class="mb-3 mt-3"> | ||||
<label for="linked_practices">Add link to practices (press Ctrl to select multiple options)</label> | |||||
<label for="linked_practices">Add practices relationship(s) (hold Ctrl to select multiple options)</label> | |||||
</div> | </div> | ||||
<div class="mb-3 mt-3"> | <div class="mb-3 mt-3"> | ||||
<select name="linked_practices" id="linked_practices" aria-label="Add link to practices" class="selectpicker" data-live-search="true" multiple> | |||||
<select name="linked_practices" id="linked_practices" aria-label="Add practices relationships" class="selectpicker" data-live-search="true" multiple> | |||||
{% for resource_dropdown in resource_dropdown %} | {% for resource_dropdown in resource_dropdown %} | ||||
{% if resource_dropdown['type'] == 'practice' %} | {% if resource_dropdown['type'] == 'practice' %} | ||||
{% if relationships and resource_dropdown in relationships %} | {% if relationships and resource_dropdown in relationships %} | ||||
</select> | </select> | ||||
</div> | </div> | ||||
<div class="mb-3 mt-3"> | <div class="mb-3 mt-3"> | ||||
<label for="linked_books">Add link to books (press Ctrl to select multiple options)</label> | |||||
<label for="linked_books">Add books relationship(s) (hold Ctrl to select multiple options)</label> | |||||
</div> | </div> | ||||
<div class="mb-3 mt-3"> | <div class="mb-3 mt-3"> | ||||
<select name="linked_books" id="linked_books" aria-label="Add link to books" class="selectpicker" data-live-search="true" multiple> | |||||
<select name="linked_books" id="linked_books" aria-label="Add books relationships" class="selectpicker" data-live-search="true" multiple> | |||||
{% for resource_dropdown in resource_dropdown %} | {% for resource_dropdown in resource_dropdown %} | ||||
{% if resource_dropdown['type'] == 'book' %} | {% if resource_dropdown['type'] == 'book' %} | ||||
{% if relationships and resource_dropdown in relationships %} | {% if relationships and resource_dropdown in relationships %} | ||||
class="form-control">{{ request.form['references'] or resource['references'] }}</textarea> | class="form-control">{{ request.form['references'] or resource['references'] }}</textarea> | ||||
</div> | </div> | ||||
<div class="mb-3 mt-3"> | <div class="mb-3 mt-3"> | ||||
<label for="linked_tools">Add link to tools (press Ctrl to select multiple options)</label> | |||||
<label for="linked_tools">Add tools relationship(s) (hold Ctrl to select multiple options)</label> | |||||
</div> | </div> | ||||
<div class="mb-3 mt-3"> | <div class="mb-3 mt-3"> | ||||
<select name="linked_tools" id="linked_tools" aria-label="Add link to tools" class="selectpicker" data-live-search="true" multiple> | |||||
<select name="linked_tools" id="linked_tools" aria-label="Add tools relationships" class="selectpicker" data-live-search="true" multiple> | |||||
{% for resource_dropdown in resource_dropdown %} | {% for resource_dropdown in resource_dropdown %} | ||||
{% if resource_dropdown['type'] == 'tool' %} | {% if resource_dropdown['type'] == 'tool' %} | ||||
{% if relationships and resource_dropdown in relationships %} | {% if relationships and resource_dropdown in relationships %} | ||||
</select> | </select> | ||||
</div> | </div> | ||||
<div class="mb-3 mt-3"> | <div class="mb-3 mt-3"> | ||||
<label for="linked_books">Add link to books (press Ctrl to select multiple options)</label> | |||||
<label for="linked_books">Add books relationship(s) (hold Ctrl to select multiple options)</label> | |||||
</div> | </div> | ||||
<div class="mb-3 mt-3"> | <div class="mb-3 mt-3"> | ||||
<select name="linked_books" id="linked_books" aria-label="Add link to books" class="selectpicker" data-live-search="true" multiple> | |||||
<select name="linked_books" id="linked_books" aria-label="Add books relationships" class="selectpicker" data-live-search="true" multiple> | |||||
{% for resource_dropdown in resource_dropdown %} | {% for resource_dropdown in resource_dropdown %} | ||||
{% if resource_dropdown['type'] == 'book' %} | {% if resource_dropdown['type'] == 'book' %} | ||||
{% if relationships and resource_dropdown in relationships %} | {% if relationships and resource_dropdown in relationships %} | ||||
</input> | </input> | ||||
</div> | </div> | ||||
<div class="mb-3 mt-3"> | <div class="mb-3 mt-3"> | ||||
<label for="linked_tools">Add link to tools (press Ctrl to select multiple options)</label> | |||||
<label for="linked_tools">Add tools relationship(s) (hold Ctrl to select multiple options)</label> | |||||
</div> | </div> | ||||
<div class="mb-3 mt-3"> | <div class="mb-3 mt-3"> | ||||
<select name="linked_tools" id="linked_tools" aria-label="Add link to tools" class="selectpicker" data-live-search="true" multiple> | |||||
<select name="linked_tools" id="linked_tools" aria-label="Add tools relationships" class="selectpicker" data-live-search="true" multiple> | |||||
{% for resource_dropdown in resource_dropdown %} | {% for resource_dropdown in resource_dropdown %} | ||||
{% if resource_dropdown['type'] == 'tool' %} | {% if resource_dropdown['type'] == 'tool' %} | ||||
{% if relationships and resource_dropdown in relationships %} | {% if relationships and resource_dropdown in relationships %} | ||||
</select> | </select> | ||||
</div> | </div> | ||||
<div class="mb-3 mt-3"> | <div class="mb-3 mt-3"> | ||||
<label for="linked_practices">Add link to practices (press Ctrl to select multiple options)</label> | |||||
<label for="linked_practices">Add practices relationship(s) (hold Ctrl to select multiple options)</label> | |||||
</div> | </div> | ||||
<div class="mb-3 mt-3"> | <div class="mb-3 mt-3"> | ||||
<select name="linked_practices" id="linked_practices" aria-label="Add link to practices" class="selectpicker" data-live-search="true" multiple> | |||||
<select name="linked_practices" id="linked_practices" aria-label="Add practices relationships" class="selectpicker" data-live-search="true" multiple> | |||||
{% for resource_dropdown in resource_dropdown %} | {% for resource_dropdown in resource_dropdown %} | ||||
{% if resource_dropdown['type'] == 'practice' %} | {% if resource_dropdown['type'] == 'practice' %} | ||||
{% if relationships and resource_dropdown in relationships %} | {% if relationships and resource_dropdown in relationships %} | ||||
{% if relationships %} | {% if relationships %} | ||||
<div class="mb-3 mt-3"> | <div class="mb-3 mt-3"> | ||||
<label for="linked_practice_id">Remove link</label> | |||||
<label for="linked_practice_id">Remove relationship(s)</label> | |||||
</div> | </div> | ||||
<div class="mb-3 mt-3"> | <div class="mb-3 mt-3"> | ||||
<select name="remove_linked_resources" id="remove_linked_resources" aria-label="Remove link" class="selectpicker" data-live-search="true" multiple> | <select name="remove_linked_resources" id="remove_linked_resources" aria-label="Remove link" class="selectpicker" data-live-search="true" multiple> |