Browse Source

changes to database and how relationships are added

joel
Simon Bowie 2 years ago
parent
commit
325a1f74a5
12 changed files with 109 additions and 65 deletions
  1. +21
    -4
      database_functions.sh
  2. +1
    -0
      web/Dockerfile
  3. +2
    -1
      web/app/book.py
  4. +2
    -1
      web/app/create.py
  5. +4
    -0
      web/app/models.py
  6. +8
    -7
      web/app/practice.py
  7. +2
    -1
      web/app/publisher.py
  8. +53
    -0
      web/app/relationships.py
  9. +0
    -42
      web/app/resources.py
  10. +5
    -2
      web/app/templates/edit.html
  11. +3
    -0
      web/app/templates/resource.html
  12. +8
    -7
      web/app/tool.py

+ 21
- 4
database_functions.sh View File

# 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;;

+ 1
- 0
web/Dockerfile View File

# 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

+ 2
- 1
web/app/book.py View File

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

+ 2
- 1
web/app/create.py View File

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'

+ 4
- 0
web/app/models.py View File

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)

+ 8
- 7
web/app/practice.py View File

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',))

+ 2
- 1
web/app/publisher.py View File

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

+ 53
- 0
web/app/relationships.py View File

# @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()

+ 0
- 42
web/app/resources.py View File

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()

+ 5
- 2
web/app/templates/edit.html View File

{% 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 %}

+ 3
- 0
web/app/templates/resource.html View File

{% 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>

+ 8
- 7
web/app/tool.py View File

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',))

Loading…
Cancel
Save