| @@ -26,7 +26,7 @@ Help() | |||
| # Display Help | |||
| echo "This script performs database functions for the ExPub Compendium" | |||
| 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 "l Print the MIT License notification." | |||
| echo "h Print this Help." | |||
| @@ -34,6 +34,7 @@ Help() | |||
| echo "i Import whole database." | |||
| echo "c Export single table as tab-delimited txt." | |||
| echo "v Import tab-delimited txt file to table." | |||
| echo "d Drop table." | |||
| echo | |||
| } | |||
| @@ -58,6 +59,11 @@ Table_import() | |||
| 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 # | |||
| @@ -67,8 +73,8 @@ Table_import() | |||
| # set variables | |||
| CONTAINER=mariadb | |||
| DATABASE=toolkit | |||
| USERNAME=xxxxxxxx | |||
| PASSWORD=xxxxxxxx | |||
| USERNAME=xxxxxxxxx | |||
| PASSWORD=xxxxxxxxx | |||
| EXPORT_SQL_FILENAME=toolkit_db_ | |||
| IMPORT_SQL_DIRECTORY="/Users/ad7588/Downloads" | |||
| IMPORT_SQL_FILENAME=toolkit_db.sql | |||
| @@ -82,7 +88,7 @@ if (( $# == 0 )); then | |||
| fi | |||
| # get the options | |||
| while getopts ":hleicv" flag; do | |||
| while getopts ":hleicvd" flag; do | |||
| case $flag in | |||
| l) # display License | |||
| License | |||
| @@ -119,6 +125,17 @@ while getopts ":hleicv" flag; do | |||
| Table_import | |||
| exit 1 | |||
| 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 | |||
| Help | |||
| exit;; | |||
| @@ -1,5 +1,6 @@ | |||
| # syntax=docker/dockerfile:1 | |||
| FROM python:3.8-slim-buster | |||
| RUN apt update && apt install -y apt-transport-https ca-certificates sqlite3 | |||
| WORKDIR /code | |||
| COPY requirements.txt requirements.txt | |||
| RUN pip install -r requirements.txt | |||
| @@ -10,6 +10,7 @@ from flask import Blueprint, render_template, request, flash, redirect, url_for | |||
| from flask_login import login_required, current_user | |||
| from .models import Resource | |||
| from .resources import * | |||
| from .relationships import * | |||
| from werkzeug.exceptions import abort | |||
| from . import db | |||
| import os | |||
| @@ -26,7 +27,7 @@ def get_books(): | |||
| @book.route('/books/<int:book_id>') | |||
| def show_book(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) | |||
| # route for editing a single book based on the ID in the database | |||
| @@ -11,6 +11,7 @@ from flask_login import login_required, current_user | |||
| from .models import Resource | |||
| from .models import Relationship | |||
| from .resources import * | |||
| from .relationships import * | |||
| from werkzeug.exceptions import abort | |||
| from . import db | |||
| import os | |||
| @@ -54,7 +55,7 @@ def create_resource(): | |||
| if 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() | |||
| add_linked_resource(tool.id, linked_resource) | |||
| add_relationship(tool.id, linked_resource) | |||
| elif request.form.get('resource_type') == 'practice': | |||
| type = 'practice' | |||
| @@ -28,8 +28,12 @@ class Resource(db.Model): | |||
| type = db.Column(db.Text) | |||
| name = db.Column(db.Text) | |||
| description = db.Column(db.Text) | |||
| developer = db.Column(db.Text) | |||
| developerUrl = db.Column(db.Text) | |||
| projectUrl = db.Column(db.Text) | |||
| repositoryUrl = db.Column(db.Text) | |||
| license = db.Column(db.Text) | |||
| scriptingLanguage = db.Column(db.Text) | |||
| expertiseToUse = db.Column(db.Text) | |||
| expertiseToHost = db.Column(db.Text) | |||
| dependencies = db.Column(db.Text) | |||
| @@ -10,6 +10,7 @@ from flask import Blueprint, render_template, request, flash, redirect, url_for | |||
| from flask_login import login_required, current_user | |||
| from .models import Resource | |||
| from .resources import * | |||
| from .relationships import * | |||
| from werkzeug.exceptions import abort | |||
| from . import db | |||
| import os | |||
| @@ -26,7 +27,7 @@ def get_practices(): | |||
| @practice.route('/practices/<int:practice_id>') | |||
| def show_practice(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) | |||
| # route for editing a single practice based on the ID in the database | |||
| @@ -35,7 +36,7 @@ def show_practice(practice_id): | |||
| def edit_practice(practice_id): | |||
| practice = get_resource(practice_id) | |||
| resource_dropdown = Resource.query | |||
| links = get_linked_resources(practice_id) | |||
| existing_relationships = get_relationships(practice_id) | |||
| if request.method == 'POST': | |||
| name = request.form['name'] | |||
| @@ -53,16 +54,16 @@ def edit_practice(practice_id): | |||
| if linked_resources: | |||
| for linked_resource in linked_resources: | |||
| 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: | |||
| for remove_linked_resource in remove_linked_resources: | |||
| delete_relationship(practice_id, remove_linked_resource) | |||
| 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 | |||
| @practice.route('/practices/<int:practice_id>/delete', methods=('POST',)) | |||
| @@ -10,6 +10,7 @@ from flask import Blueprint, render_template, request, flash, redirect, url_for | |||
| from flask_login import login_required, current_user | |||
| from .models import Resource | |||
| from .resources import * | |||
| from .relationships import * | |||
| from werkzeug.exceptions import abort | |||
| from . import db | |||
| import os | |||
| @@ -26,7 +27,7 @@ def get_publishers(): | |||
| @publisher.route('/publishers/<int:publisher_id>') | |||
| def show_publisher(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) | |||
| # route for editing a single publisher based on the ID in the database | |||
| @@ -0,0 +1,53 @@ | |||
| # @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() | |||
| @@ -8,7 +8,6 @@ | |||
| from flask import Blueprint, render_template, request, flash, redirect, url_for | |||
| from flask_login import login_required, current_user | |||
| from .models import Resource | |||
| from .models import Relationship | |||
| from werkzeug.exceptions import abort | |||
| from . import db | |||
| @@ -19,50 +18,9 @@ def get_resource(resource_id): | |||
| abort(404) | |||
| 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 | |||
| def delete_resource(resource_id): | |||
| deletion = Resource.query.get(resource_id) | |||
| db.session.delete(deletion) | |||
| db.session.commit() | |||
| 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() | |||
| @@ -1,6 +1,9 @@ | |||
| {% extends 'base.html' %} | |||
| {% block content %} | |||
| {{linked_resources}} | |||
| <h1>{% block title %} Edit "{{ resource['name'] }}" {% endblock %}</h1> | |||
| <form method="post"> | |||
| @@ -83,7 +86,7 @@ | |||
| {% for resource_dropdown in resource_dropdown %} | |||
| {% if resource_dropdown['type'] != 'tool' %} | |||
| {% 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 %} | |||
| <option value="{{ resource_dropdown['id'] }}">{{ resource_dropdown['name'] }}</option> | |||
| {% endif %} | |||
| @@ -101,7 +104,7 @@ | |||
| {% for resource_dropdown in resource_dropdown %} | |||
| {% if resource_dropdown['type'] != 'practice' %} | |||
| {% 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 %} | |||
| <option value="{{ resource_dropdown['id'] }}">{{ resource_dropdown['name'] }}</option> | |||
| {% endif %} | |||
| @@ -1,6 +1,9 @@ | |||
| {% extends 'base.html' %} | |||
| {% block content %} | |||
| {{linked_resources}} | |||
| <div class="row"> | |||
| <div class="col"> | |||
| <h1 class="text-center">{% block title %} {{ resource['name'] }} {% endblock %}</h1> | |||
| @@ -10,6 +10,7 @@ from flask import Blueprint, render_template, request, flash, redirect, url_for | |||
| from flask_login import login_required, current_user | |||
| from .models import Resource | |||
| from .resources import * | |||
| from .relationships import * | |||
| from werkzeug.exceptions import abort | |||
| from . import db | |||
| import os | |||
| @@ -26,7 +27,7 @@ def get_tools(): | |||
| @tool.route('/tools/<int:tool_id>') | |||
| def show_tool(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) | |||
| # route for editing a single tool based on the ID in the database | |||
| @@ -35,7 +36,7 @@ def show_tool(tool_id): | |||
| def edit_tool(tool_id): | |||
| tool = get_resource(tool_id) | |||
| resource_dropdown = Resource.query | |||
| links = get_linked_resources(tool_id) | |||
| existing_relationships = get_relationships(tool_id) | |||
| if request.method == 'POST': | |||
| name = request.form['name'] | |||
| @@ -69,16 +70,16 @@ def edit_tool(tool_id): | |||
| if linked_resources: | |||
| for linked_resource in linked_resources: | |||
| 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: | |||
| for remove_linked_resource in remove_linked_resources: | |||
| delete_relationship(tool_id, remove_linked_resource) | |||
| 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 | |||
| @tool.route('/tools/<int:tool_id>/delete', methods=('POST',)) | |||