Skip to content
Snippets Groups Projects
Verified Commit e9eca452 authored by Robert Metcalf's avatar Robert Metcalf
Browse files

add CSV upload interface, support updating workspaces in place

parent 026e479e
Branches 12-import-working-spaces-csv
No related tags found
2 merge requests!21Resolve "Add form for adding latitude and longitude positions",!11Resolve "Import working spaces CSV"
......@@ -90,24 +90,48 @@ class Workspace:
def validate(self):
errors = []
if len(self.name.strip()) <= 0:
if type(self.name) != str:
errors.append("Name must be a string")
elif len(self.name.strip()) <= 0:
errors.append("Name must not be empty")
if len(self.address.strip()) <= 0:
if type(self.address) != str:
errors.append("Address must be a string")
elif len(self.address.strip()) <= 0:
errors.append("Address must not be empty")
if len(self.main_photo.strip()) <= 0:
if type(self.main_photo) != str:
errors.append("Main photo must be a string")
elif len(self.main_photo.strip()) <= 0:
errors.append("Main photo must not be empty")
if len(self.description.strip()) <= 0:
if type(self.description) != str:
errors.append("Description must be a string")
elif len(self.description.strip()) <= 0:
errors.append("Description must not be empty")
if len(self.website.strip()) <= 0:
if type(self.website) != str:
errors.append("Website must be a string")
elif len(self.website.strip()) <= 0:
errors.append("Website must not be empty")
if len(self.email.strip()) <= 0:
if type(self.email) != str:
errors.append("Email must be a string")
elif len(self.email.strip()) <= 0:
errors.append("Email must not be empty")
if len(self.phone_number.strip()) <= 0:
if type(self.phone_number) != str:
errors.append("Phone number must be a string")
elif len(self.phone_number.strip()) <= 0:
errors.append("Phone number must not be empty")
if len(self.opening_hours.strip()) <= 0:
if type(self.opening_hours) != str:
errors.append("Opening hours must be a string")
elif len(self.opening_hours.strip()) <= 0:
errors.append("Opening hours must not be empty")
if type(self.additional_photos) != list:
errors.append("Additional photos must be a list")
if type(self.checkin_instructions) != str:
errors.append("Checkin instructions must be a string")
for x in self.additional_photos:
if type(x) != str:
errors.append("Each edditional photos must be a string")
if len(x.strip()) <= 0:
errors.append("Each edditional photos must not be empty")
......@@ -115,27 +139,76 @@ class Workspace:
def from_query(conn, tuple):
(id, name, address, main_photo, description, website, email, phone_number, opening_hours, checkin_instructions) = tuple
additional_photos = []
additional_photos = get_additional_photos_inner(conn, id)
workspace = Workspace(name, address, main_photo, additional_photos, description, website, email, phone_number, opening_hours, checkin_instructions)
workspace.id = str(id)
return workspace
def get_additional_photos_inner(conn: Connection, id):
additional_photos = []
if id != None:
conn.execute("SELECT url FROM AdditionalPhotos WHERE workspace_id = ?", (str(id)))
for x in conn.cursor.fetchall():
additional_photos.append(x[0])
workspace = Workspace(name, address, main_photo, additional_photos, description, website, email, phone_number, opening_hours, checkin_instructions)
workspace.id = id
return workspace
return additional_photos
def add_additional_photos_inner(conn: Connection, workspace: Workspace):
old_photos = get_additional_photos_inner(conn, workspace.id)
for url in old_photos:
if url not in workspace.additional_photos:
conn.execute("DELETE FROM AdditionalPhotos WHERE url = ? AND workspace_id = ?", (url, workspace.id))
for url in workspace.additional_photos:
if url not in old_photos:
conn.execute("INSERT INTO AdditionalPhotos (url, workspace_id) VALUES (?, ?)", (url, workspace.id))
def add_workspace_inner(conn: Connection, workspace: Workspace):
conn.execute(
"INSERT INTO Workspaces (name, address, main_photo, description, website, email, phone_number, opening_hours, checkin_instructions) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
(workspace.name, workspace.address, workspace.main_photo, workspace.description, workspace.website, workspace.email, workspace.phone_number, workspace.opening_hours, workspace.checkin_instructions)
)
id = conn.cursor.lastrowid
workspace.id = str(id)
add_additional_photos_inner(conn, workspace)
conn.commit()
return id
def add_workspace(workspace: Workspace):
with Connection() as conn:
conn.execute(
"INSERT INTO Workspaces (name, address, main_photo, description, website, email, phone_number, opening_hours, checkin_instructions) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
(workspace.name, workspace.address, workspace.main_photo, workspace.description, workspace.website, workspace.email, workspace.phone_number, workspace.opening_hours, workspace.checkin_instructions)
)
id = conn.cursor.lastrowid
for url in workspace.additional_photos:
conn.execute("INSERT INTO AdditionalPhotos (url, workspace_id) VALUES (?, ?)", (url, id))
conn.commit()
return id
return add_workspace_inner(conn, workspace)
def update_workspace_inner(conn: Connection, workspace: Workspace):
conn.execute(
"UPDATE Workspaces SET address = ?, main_photo = ?, description = ?, website = ?, email = ?, phone_number = ?, opening_hours = ?, checkin_instructions = ? WHERE name = ?",
(workspace.address, workspace.main_photo, workspace.description, workspace.website, workspace.email, workspace.phone_number, workspace.opening_hours, workspace.checkin_instructions, workspace.name)
)
if conn.cursor.rowcount == 0:
return None
if workspace.id == None:
conn.execute("SELECT id FROM Workspaces WHERE name = ? LIMIT 1", (workspace.name,))
id = conn.fetch_all()[0][0]
workspace.id = str(id)
add_additional_photos_inner(conn, workspace)
conn.commit()
return id
def update_workspace(workspace: Workspace):
with Connection() as conn:
return update_workspace_inner(conn, workspace)
def add_or_update(workspace: Workspace):
with Connection() as conn:
id = update_workspace_inner(conn, workspace)
if id == None:
return (False, add_workspace_inner(conn, workspace))
else:
return (True, id)
def get_workspaces():
with Connection() as conn:
......
......@@ -20,7 +20,7 @@ def import_workspace(data):
if latlong != None:
database.set_address_latlong(workspace.address, (latlong[0], latlong[1]))
database.add_workspace(workspace)
database.add_or_update(workspace)
file = os.path.join(os.path.dirname(os.path.abspath(__file__)), "workspaces.json")
......
from flask import Flask, request, render_template, redirect
import database
import json
import csv
import re
app = Flask(__name__)
......@@ -82,5 +83,42 @@ def add_workspace():
return render_template("add-workspace-result.html", messages = messages)
@app.route("/admin/import-workspaces", methods = ["GET", "POST"])
def import_workspaces():
if request.method == "GET":
return render_template("import-workspaces.html")
if request.method == "POST":
file = request.files["csv"]
reader = csv.DictReader([x.decode("utf-8-sig") for x in file])
messages = []
for entry in reader:
additional_photos = entry.get("additional_photo")
additional_photos = [x.strip() for x in additional_photos.split(",")] if type(additional_photos) == str and len(additional_photos) > 0 else []
workspace = database.Workspace(
entry.get("name"),
entry.get("address"),
entry.get("main_photo"),
additional_photos,
entry.get("description"),
entry.get("website"),
entry.get("email"),
entry.get("phone_number"),
entry.get("opening_hours"),
entry.get("checkin_instructions")
)
errors = workspace.validate()
if len(errors) > 0:
messages.append(f"Errors were found with {workspace.name}:")
messages.extend(errors)
else:
update = database.add_or_update(workspace)[0]
messages.append(f"Workspace updated successfully ({workspace.name})" if update else f"Workspace added successfully ({workspace.name})")
if len(messages) == 0:
messages = ["No workspaces were found"]
return render_template("import-workspaces-result.html", messages = messages)
if __name__ == "__main__":
app.run(debug = True)
{% extends "main.html" %}
{% block title %}Import Workspaces{% endblock %}
{% block mainBlock %}
{% for message in messages %}
<div>{{ message }}</div>
{% endfor %}
{% endblock %}
\ No newline at end of file
{% extends "main.html" %}
{% block title %}Import Workspaces{% endblock %}
{% block mainBlock %}
<form action="/admin/import-workspaces" method="POST" enctype="multipart/form-data">
<div><input type="file" name="csv"></div>
<div><input type="submit"></div>
</form>
{% endblock %}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment