| # Display Help | # Display Help | ||||
| echo "This script performs database functions for the ExPub Compendium" | echo "This script performs database functions for the ExPub Compendium" | ||||
| echo | echo | ||||
| echo "Syntax: database_functions.sh [-l|h|e|i|c]" | |||||
| echo "Syntax: database_functions.sh [-l|h|e|i|c|v|d]" | |||||
| echo "options:" | echo "options:" | ||||
| echo "l Print the MIT License notification." | echo "l Print the MIT License notification." | ||||
| echo "h Print this Help." | echo "h Print this Help." | ||||
| echo "i Import whole database." | echo "i Import whole database." | ||||
| echo "c Export single table as tab-delimited txt." | echo "c Export single table as tab-delimited txt." | ||||
| echo "v Import tab-delimited txt file to table." | echo "v Import tab-delimited txt file to table." | ||||
| echo "d Drop table." | |||||
| echo | echo | ||||
| } | } | ||||
| docker exec -i $CONTAINER bash -c "mysql -u $USERNAME -p$PASSWORD $DATABASE -e 'LOAD DATA LOCAL INFILE '\''/tmp/import_file'\'' REPLACE INTO TABLE $TABLE FIELDS TERMINATED BY '\''\t'\'' LINES TERMINATED BY '\''\n'\'' IGNORE 1 ROWS;'" | docker exec -i $CONTAINER bash -c "mysql -u $USERNAME -p$PASSWORD $DATABASE -e 'LOAD DATA LOCAL INFILE '\''/tmp/import_file'\'' REPLACE INTO TABLE $TABLE FIELDS TERMINATED BY '\''\t'\'' LINES TERMINATED BY '\''\n'\'' IGNORE 1 ROWS;'" | ||||
| } | } | ||||
| Drop_table() | |||||
| { | |||||
| docker exec -i $CONTAINER bash -c "mysql -u $USERNAME -p$PASSWORD $DATABASE -e 'DROP TABLE IF EXISTS $TABLE;'" | |||||
| } | |||||
| ############################################################ | ############################################################ | ||||
| ############################################################ | ############################################################ | ||||
| # main program # | # main program # | ||||
| # set variables | # set variables | ||||
| CONTAINER=mariadb | CONTAINER=mariadb | ||||
| DATABASE=toolkit | DATABASE=toolkit | ||||
| USERNAME=xxxxxxxx | |||||
| PASSWORD=xxxxxxxx | |||||
| USERNAME=xxxxxxxxx | |||||
| PASSWORD=xxxxxxxxx | |||||
| EXPORT_SQL_FILENAME=toolkit_db_ | EXPORT_SQL_FILENAME=toolkit_db_ | ||||
| IMPORT_SQL_DIRECTORY="/Users/ad7588/Downloads" | IMPORT_SQL_DIRECTORY="/Users/ad7588/Downloads" | ||||
| IMPORT_SQL_FILENAME=toolkit_db.sql | IMPORT_SQL_FILENAME=toolkit_db.sql | ||||
| fi | fi | ||||
| # get the options | # get the options | ||||
| while getopts ":hleicv" flag; do | |||||
| while getopts ":hleicvd" flag; do | |||||
| case $flag in | case $flag in | ||||
| l) # display License | l) # display License | ||||
| License | License | ||||
| Table_import | Table_import | ||||
| exit 1 | exit 1 | ||||
| fi;; | fi;; | ||||
| d) # drop table | |||||
| if [ -z "$2" ] | |||||
| then | |||||
| echo "-d requires a table name as an argument" | |||||
| echo | |||||
| echo "Syntax: database_functions.sh -d [table name]" | |||||
| else | |||||
| TABLE=$2 | |||||
| Drop_table | |||||
| exit 1 | |||||
| fi;; | |||||
| \?) # Invalid option | \?) # Invalid option | ||||
| Help | Help | ||||
| exit;; | exit;; |
| # syntax=docker/dockerfile:1 | # syntax=docker/dockerfile:1 | ||||
| FROM python:3.8-slim-buster | FROM python:3.8-slim-buster | ||||
| RUN apt update && apt install -y apt-transport-https ca-certificates sqlite3 | |||||
| WORKDIR /code | WORKDIR /code | ||||
| COPY requirements.txt requirements.txt | COPY requirements.txt requirements.txt | ||||
| RUN pip install -r requirements.txt | RUN pip install -r requirements.txt |
| from flask_login import login_required, current_user | from flask_login import login_required, current_user | ||||
| from .models import Resource | from .models import Resource | ||||
| from .resources import * | from .resources import * | ||||
| from .relationships import * | |||||
| from werkzeug.exceptions import abort | from werkzeug.exceptions import abort | ||||
| from . import db | from . import db | ||||
| import os | import os | ||||
| @book.route('/books/<int:book_id>') | @book.route('/books/<int:book_id>') | ||||
| def show_book(book_id): | def show_book(book_id): | ||||
| book = get_resource(book_id) | book = get_resource(book_id) | ||||
| links = get_linked_resources(book_id) | |||||
| links = get_relationships(book_id) | |||||
| return render_template('resource.html', resource=book, links=links) | return render_template('resource.html', resource=book, links=links) | ||||
| # route for editing a single book based on the ID in the database | # route for editing a single book based on the ID in the database |
| from .models import Resource | from .models import Resource | ||||
| from .models import Relationship | from .models import Relationship | ||||
| from .resources import * | from .resources import * | ||||
| from .relationships import * | |||||
| from werkzeug.exceptions import abort | from werkzeug.exceptions import abort | ||||
| from . import db | from . import db | ||||
| import os | import os | ||||
| if request.form.getlist('linked_resources'): | if request.form.getlist('linked_resources'): | ||||
| for linked_resource in request.form.getlist('linked_resources'): | for linked_resource in request.form.getlist('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_linked_resource(tool.id, linked_resource) | |||||
| add_relationship(tool.id, linked_resource) | |||||
| elif request.form.get('resource_type') == 'practice': | elif request.form.get('resource_type') == 'practice': | ||||
| type = 'practice' | type = 'practice' |
| type = db.Column(db.Text) | type = db.Column(db.Text) | ||||
| name = db.Column(db.Text) | name = db.Column(db.Text) | ||||
| description = db.Column(db.Text) | description = db.Column(db.Text) | ||||
| developer = db.Column(db.Text) | |||||
| developerUrl = db.Column(db.Text) | |||||
| projectUrl = db.Column(db.Text) | projectUrl = db.Column(db.Text) | ||||
| repositoryUrl = db.Column(db.Text) | repositoryUrl = db.Column(db.Text) | ||||
| license = db.Column(db.Text) | |||||
| scriptingLanguage = db.Column(db.Text) | |||||
| expertiseToUse = db.Column(db.Text) | expertiseToUse = db.Column(db.Text) | ||||
| expertiseToHost = db.Column(db.Text) | expertiseToHost = db.Column(db.Text) | ||||
| dependencies = db.Column(db.Text) | dependencies = db.Column(db.Text) |
| from flask_login import login_required, current_user | from flask_login import login_required, current_user | ||||
| from .models import Resource | from .models import Resource | ||||
| from .resources import * | from .resources import * | ||||
| from .relationships import * | |||||
| from werkzeug.exceptions import abort | from werkzeug.exceptions import abort | ||||
| from . import db | from . import db | ||||
| import os | import os | ||||
| @practice.route('/practices/<int:practice_id>') | @practice.route('/practices/<int:practice_id>') | ||||
| def show_practice(practice_id): | def show_practice(practice_id): | ||||
| practice = get_resource(practice_id) | practice = get_resource(practice_id) | ||||
| links = get_linked_resources(practice_id) | |||||
| links = get_relationships(practice_id) | |||||
| return render_template('resource.html', resource=practice, links=links) | return render_template('resource.html', resource=practice, links=links) | ||||
| # route for editing a single practice based on the ID in the database | # route for editing a single practice based on the ID in the database | ||||
| def edit_practice(practice_id): | def edit_practice(practice_id): | ||||
| practice = get_resource(practice_id) | practice = get_resource(practice_id) | ||||
| resource_dropdown = Resource.query | resource_dropdown = Resource.query | ||||
| links = get_linked_resources(practice_id) | |||||
| existing_relationships = get_relationships(practice_id) | |||||
| if request.method == 'POST': | if request.method == 'POST': | ||||
| name = request.form['name'] | name = request.form['name'] | ||||
| if linked_resources: | if linked_resources: | ||||
| for linked_resource in linked_resources: | for linked_resource in linked_resources: | ||||
| link = Resource.query.get(linked_resource) | link = Resource.query.get(linked_resource) | ||||
| if links and link not in links: | |||||
| add_linked_resource(practice_id, linked_resource) | |||||
| elif not links: | |||||
| add_linked_resource(practice_id, linked_resource) | |||||
| if existing_relationships and link not in existing_relationships: | |||||
| add_relationship(practice_id, linked_resource) | |||||
| elif not existing_relationships: | |||||
| add_relationship(practice_id, linked_resource) | |||||
| if remove_linked_resources: | if remove_linked_resources: | ||||
| for remove_linked_resource in remove_linked_resources: | for remove_linked_resource in remove_linked_resources: | ||||
| delete_relationship(practice_id, remove_linked_resource) | delete_relationship(practice_id, remove_linked_resource) | ||||
| return redirect(url_for('practice.get_practices',_external=True,_scheme=os.environ.get('SSL_SCHEME'))) | return redirect(url_for('practice.get_practices',_external=True,_scheme=os.environ.get('SSL_SCHEME'))) | ||||
| return render_template('edit.html', resource=practice, resource_dropdown=resource_dropdown, links=links) | |||||
| return render_template('edit.html', resource=practice, resource_dropdown=resource_dropdown, links=existing_relationships) | |||||
| # route for function to delete a single practice from the edit page | # route for function to delete a single practice from the edit page | ||||
| @practice.route('/practices/<int:practice_id>/delete', methods=('POST',)) | @practice.route('/practices/<int:practice_id>/delete', methods=('POST',)) |
| from flask_login import login_required, current_user | from flask_login import login_required, current_user | ||||
| from .models import Resource | from .models import Resource | ||||
| from .resources import * | from .resources import * | ||||
| from .relationships import * | |||||
| from werkzeug.exceptions import abort | from werkzeug.exceptions import abort | ||||
| from . import db | from . import db | ||||
| import os | import os | ||||
| @publisher.route('/publishers/<int:publisher_id>') | @publisher.route('/publishers/<int:publisher_id>') | ||||
| def show_publisher(publisher_id): | def show_publisher(publisher_id): | ||||
| publisher = get_resource(publisher_id) | publisher = get_resource(publisher_id) | ||||
| links = get_linked_resources(publisher_id) | |||||
| links = get_relationships(publisher_id) | |||||
| return render_template('resource.html', resource=publisher, links=links) | return render_template('resource.html', resource=publisher, links=links) | ||||
| # route for editing a single publisher based on the ID in the database | # route for editing a single publisher based on the ID in the database |
| # @name: relationships.py | |||||
| # @creation_date: 2022-04-11 | |||||
| # @license: The MIT License <https://opensource.org/licenses/MIT> | |||||
| # @author: Simon Bowie <ad7588@coventry.ac.uk> | |||||
| # @purpose: functions for relationships | |||||
| # @acknowledgements: | |||||
| from flask import Blueprint, render_template, request, flash, redirect, url_for | |||||
| from .models import Resource | |||||
| from .models import Relationship | |||||
| from werkzeug.exceptions import abort | |||||
| from . import db | |||||
| # function to retrieve linked resources | |||||
| def get_relationships(primary_id): | |||||
| primary_relationships = Relationship.query.filter_by(first_resource_id=primary_id).all() | |||||
| links = [] | |||||
| if primary_relationships: | |||||
| links = [] | |||||
| for relationship in primary_relationships: | |||||
| secondary_id = relationship.second_resource_id | |||||
| links.extend(Resource.query.filter_by(id=secondary_id).all()) | |||||
| secondary_relationships = Relationship.query.filter_by(second_resource_id=primary_id).all() | |||||
| if secondary_relationships: | |||||
| for relationship in secondary_relationships: | |||||
| primary_id = relationship.first_resource_id | |||||
| links.extend(Resource.query.filter_by(id=primary_id).all()) | |||||
| return links | |||||
| else: | |||||
| secondary_relationships = Relationship.query.filter_by(second_resource_id=primary_id).all() | |||||
| if secondary_relationships: | |||||
| links = [] | |||||
| for relationship in secondary_relationships: | |||||
| primary_id = relationship.first_resource_id | |||||
| links.extend(Resource.query.filter_by(id=primary_id).all()) | |||||
| return links | |||||
| # function to add a relationship to a linked resource | |||||
| def add_relationship(resource_id, linked_resource_id): | |||||
| first_resource_id = resource_id | |||||
| second_resource_id = linked_resource_id | |||||
| new_relationship = Relationship(first_resource_id=first_resource_id, second_resource_id=second_resource_id) | |||||
| # add the new relationship to the database | |||||
| db.session.add(new_relationship) | |||||
| db.session.commit() | |||||
| # function to delete a single relationship | |||||
| def delete_relationship(main_id, for_deletion_id): | |||||
| relation = Relationship.query.filter(((Relationship.first_resource_id == main_id) & (Relationship.second_resource_id == for_deletion_id)) | ((Relationship.first_resource_id == for_deletion_id) & (Relationship.second_resource_id == main_id))).first() | |||||
| deletion = Relationship.query.get(relation.id) | |||||
| db.session.delete(deletion) | |||||
| db.session.commit() |
| from flask import Blueprint, render_template, request, flash, redirect, url_for | from flask import Blueprint, render_template, request, flash, redirect, url_for | ||||
| from flask_login import login_required, current_user | from flask_login import login_required, current_user | ||||
| from .models import Resource | from .models import Resource | ||||
| from .models import Relationship | |||||
| from werkzeug.exceptions import abort | from werkzeug.exceptions import abort | ||||
| from . import db | from . import db | ||||
| abort(404) | abort(404) | ||||
| return resource | return resource | ||||
| # function to retrieve linked resources | |||||
| def get_linked_resources(primary_id): | |||||
| primary_relationships = Relationship.query.filter_by(first_resource_id=primary_id).all() | |||||
| links = [] | |||||
| if primary_relationships: | |||||
| links = [] | |||||
| for relationship in primary_relationships: | |||||
| secondary_id = relationship.second_resource_id | |||||
| links.extend(Resource.query.filter_by(id=secondary_id).all()) | |||||
| secondary_relationships = Relationship.query.filter_by(second_resource_id=primary_id).all() | |||||
| if secondary_relationships: | |||||
| for relationship in secondary_relationships: | |||||
| primary_id = relationship.first_resource_id | |||||
| links.extend(Resource.query.filter_by(id=primary_id).all()) | |||||
| return links | |||||
| else: | |||||
| secondary_relationships = Relationship.query.filter_by(second_resource_id=primary_id).all() | |||||
| if secondary_relationships: | |||||
| links = [] | |||||
| for relationship in secondary_relationships: | |||||
| primary_id = relationship.first_resource_id | |||||
| links.extend(Resource.query.filter_by(id=primary_id).all()) | |||||
| return links | |||||
| # function to add a relationship to a linked resource | |||||
| def add_linked_resource(resource_id, linked_resource_id): | |||||
| first_resource_id = resource_id | |||||
| second_resource_id = linked_resource_id | |||||
| new_relationship = Relationship(first_resource_id=first_resource_id, second_resource_id=second_resource_id) | |||||
| # add the new relationship to the database | |||||
| db.session.add(new_relationship) | |||||
| db.session.commit() | |||||
| # function to delete a single resource | # function to delete a single resource | ||||
| def delete_resource(resource_id): | def delete_resource(resource_id): | ||||
| deletion = Resource.query.get(resource_id) | deletion = Resource.query.get(resource_id) | ||||
| db.session.delete(deletion) | db.session.delete(deletion) | ||||
| db.session.commit() | db.session.commit() | ||||
| flash('Successfully deleted!') | flash('Successfully deleted!') | ||||
| # function to delete a single relationship | |||||
| def delete_relationship(main_id, for_deletion_id): | |||||
| relation = Relationship.query.filter(((Relationship.first_resource_id == main_id) & (Relationship.second_resource_id == for_deletion_id)) | ((Relationship.first_resource_id == for_deletion_id) & (Relationship.second_resource_id == main_id))).first() | |||||
| deletion = Relationship.query.get(relation.id) | |||||
| db.session.delete(deletion) | |||||
| db.session.commit() |
| {% extends 'base.html' %} | {% extends 'base.html' %} | ||||
| {% block content %} | {% block content %} | ||||
| {{linked_resources}} | |||||
| <h1>{% block title %} Edit "{{ resource['name'] }}" {% endblock %}</h1> | <h1>{% block title %} Edit "{{ resource['name'] }}" {% endblock %}</h1> | ||||
| <form method="post"> | <form method="post"> | ||||
| {% for resource_dropdown in resource_dropdown %} | {% for resource_dropdown in resource_dropdown %} | ||||
| {% if resource_dropdown['type'] != 'tool' %} | {% if resource_dropdown['type'] != 'tool' %} | ||||
| {% if links and resource_dropdown in links %} | {% if links and resource_dropdown in links %} | ||||
| <option value="" selected>{{ resource_dropdown['name'] }}</option> | |||||
| <option value="{{ resource_dropdown['id'] }}" selected>{{ resource_dropdown['name'] }}</option> | |||||
| {% else %} | {% else %} | ||||
| <option value="{{ resource_dropdown['id'] }}">{{ resource_dropdown['name'] }}</option> | <option value="{{ resource_dropdown['id'] }}">{{ resource_dropdown['name'] }}</option> | ||||
| {% endif %} | {% endif %} | ||||
| {% for resource_dropdown in resource_dropdown %} | {% for resource_dropdown in resource_dropdown %} | ||||
| {% if resource_dropdown['type'] != 'practice' %} | {% if resource_dropdown['type'] != 'practice' %} | ||||
| {% if links and resource_dropdown in links %} | {% if links and resource_dropdown in links %} | ||||
| <option value="" selected>{{ resource_dropdown['name'] }}</option> | |||||
| <option value="{{ resource_dropdown['id'] }}" selected>{{ resource_dropdown['name'] }}</option> | |||||
| {% else %} | {% else %} | ||||
| <option value="{{ resource_dropdown['id'] }}">{{ resource_dropdown['name'] }}</option> | <option value="{{ resource_dropdown['id'] }}">{{ resource_dropdown['name'] }}</option> | ||||
| {% endif %} | {% endif %} |
| {% extends 'base.html' %} | {% extends 'base.html' %} | ||||
| {% block content %} | {% block content %} | ||||
| {{linked_resources}} | |||||
| <div class="row"> | <div class="row"> | ||||
| <div class="col"> | <div class="col"> | ||||
| <h1 class="text-center">{% block title %} {{ resource['name'] }} {% endblock %}</h1> | <h1 class="text-center">{% block title %} {{ resource['name'] }} {% endblock %}</h1> |
| from flask_login import login_required, current_user | from flask_login import login_required, current_user | ||||
| from .models import Resource | from .models import Resource | ||||
| from .resources import * | from .resources import * | ||||
| from .relationships import * | |||||
| from werkzeug.exceptions import abort | from werkzeug.exceptions import abort | ||||
| from . import db | from . import db | ||||
| import os | import os | ||||
| @tool.route('/tools/<int:tool_id>') | @tool.route('/tools/<int:tool_id>') | ||||
| def show_tool(tool_id): | def show_tool(tool_id): | ||||
| tool = get_resource(tool_id) | tool = get_resource(tool_id) | ||||
| links = get_linked_resources(tool_id) | |||||
| links = get_relationships(tool_id) | |||||
| return render_template('resource.html', resource=tool, links=links) | return render_template('resource.html', resource=tool, links=links) | ||||
| # route for editing a single tool based on the ID in the database | # route for editing a single tool based on the ID in the database | ||||
| def edit_tool(tool_id): | def edit_tool(tool_id): | ||||
| tool = get_resource(tool_id) | tool = get_resource(tool_id) | ||||
| resource_dropdown = Resource.query | resource_dropdown = Resource.query | ||||
| links = get_linked_resources(tool_id) | |||||
| existing_relationships = get_relationships(tool_id) | |||||
| if request.method == 'POST': | if request.method == 'POST': | ||||
| name = request.form['name'] | name = request.form['name'] | ||||
| if linked_resources: | if linked_resources: | ||||
| for linked_resource in linked_resources: | for linked_resource in linked_resources: | ||||
| link = Resource.query.get(linked_resource) | link = Resource.query.get(linked_resource) | ||||
| if links and link not in links: | |||||
| add_linked_resource(tool_id, linked_resource) | |||||
| elif not links: | |||||
| add_linked_resource(tool_id, linked_resource) | |||||
| if existing_relationships and link not in existing_relationships: | |||||
| add_relationship(tool_id, linked_resource) | |||||
| elif not existing_relationships: | |||||
| add_relationship(tool_id, linked_resource) | |||||
| if remove_linked_resources: | if remove_linked_resources: | ||||
| for remove_linked_resource in remove_linked_resources: | for remove_linked_resource in remove_linked_resources: | ||||
| delete_relationship(tool_id, remove_linked_resource) | delete_relationship(tool_id, remove_linked_resource) | ||||
| return redirect(url_for('tool.get_tools',_external=True,_scheme=os.environ.get('SSL_SCHEME'))) | return redirect(url_for('tool.get_tools',_external=True,_scheme=os.environ.get('SSL_SCHEME'))) | ||||
| return render_template('edit.html', resource=tool, resource_dropdown=resource_dropdown, links=links) | |||||
| return render_template('edit.html', resource=tool, resource_dropdown=resource_dropdown, links=existing_relationships) | |||||
| # route for function to delete a single tool from the edit page | # route for function to delete a single tool from the edit page | ||||
| @tool.route('/tools/<int:tool_id>/delete', methods=('POST',)) | @tool.route('/tools/<int:tool_id>/delete', methods=('POST',)) |