Introduced URL encoding, Art2Presence relations

URL parameters are now URL decoded by the webservice
The tests now URL encode the parameters for every request.

Art2Presence relations are now creatable with POST requests to /artnet/metadata/art and listing the presences in the body.

Art2Presence tests have been introduced with relate_art.py

Also updated column name artist.description artist.name to fit a db schema update.
master
Peery 2 years ago
parent bf120f2d8d
commit b8e07eb528

@ -15,7 +15,7 @@ class Topic(TopicNoId):
class ArtistNoId(BaseModel):
description: str
name: str
topics: Optional[List[int]]
class Config:
@ -50,6 +50,34 @@ class ArtnoID(BaseModel):
orm_mode = True
class TagnoID(BaseModel):
name: Optional[str]
description: Optional[str]
category_id: Optional[TagCategory]
class Config:
orm_mode = True
class Tag(TagnoID):
tag_ID: int
class Config:
orm_mode = True
class ArtnoID(BaseModel):
hash: Optional[str]
path: Optional[str]
title: Optional[str] = None
link: Optional[str] = None
presences: Optional[List[Presence]]
tags: Optional[List[Tag]]
class Config:
orm_mode = True
class Art(ArtnoID):
id: int

@ -1,3 +1,4 @@
from urllib.parse import unquote
from fastapi import FastAPI, HTTPException
import uvicorn
from typing import List, Tuple
@ -11,9 +12,8 @@ db = Database()
@app.get("/artnet/metadata/art")
async def art(id: int = None, hash: str = None, tag_id: int = None):
hash = unquote(hash) if hash is not None else None
print(f"Received GET on /artnet/metadata/art (id={id}, hash={hash}, tag_id={tag_id})")
#if id is None and hash is None and tag_id is None:
#raise HTTPException(status_code=406, detail="requires id or hash param")
result = None
if id is not None:
@ -38,46 +38,59 @@ async def art(art: ArtnoID, id: int = None):
if art.presences is None: # tried to create art without any presence
raise HTTPException(status_code=422, detail="No presences were listed")
try:
for presence in art.presences:
r = db.get_presence(name=presence.name, domain=presence.domain)
#if db.get_presence(name=presence.name, domain=presence.domain) is None:
# raise HTTPException(status_code=422,
# detail=f"Presence ({presence.name}, {presence.domain}) is unknown!")
#db.create # create presence-art relationship
# TODO validate & create presence-art relationship
new_id = db.create_art_by_model(art)
new_id = db.create_art_by_model(art).id
return {"id": new_id}
except ValueError as e:
raise HTTPException(status_code=422, detail=str(e))
else: # update existing art entry
if db.get_art_by_id(id) is None:
return HTTPException(status_code=404, detail="The specified art could not be found!")
raise HTTPException(status_code=404, detail="The specified art could not be found!")
# TODO implement linking to one or multiple presences
# TODO enforcing at least one presence
updated_art = Art(id=id)
updated_art.hash = art.hash
updated_art.link = art.link
updated_art.title = art.title
updated_art.path = art.path
if art.presences is not None:
updated_art.presences = art.presences
db.update_art_by_model(updated_art)
return True
@app.delete("/artnet/metadata/art")
async def art(id: int):
print(f"Received DELETE on /artnet/metadata/art (id={id})")
async def art(id: int, presence_name: str = None, presence_domain: str = None):
presence_name = unquote(presence_name) if presence_name is not None else None
presence_domain = unquote(presence_domain) if presence_domain is not None else None
print(f"Received DELETE on /artnet/metadata/art (id={id}, presence_name={presence_name}, "
f"presence_domain={presence_domain})")
print("All art available is", [a.id for a in db.get_art_list()])
if db.get_art_by_id(id) is None:
raise HTTPException(status_code=404, detail="Art has not been found!")
db.delete_art_by_id(id)
if id is not None and presence_name is None and presence_domain is None:
db.delete_art_by_id(id)
return
elif id is not None and presence_name is not None and presence_domain is not None:
try:
db.delete_art_presences_by_id(art_id=id, presence_name=presence_name, presence_domain=presence_domain)
except ValueError:
raise HTTPException(status_code=404, detail="The art-presence relation could not be found!")
return
raise HTTPException(status_code=422, detail="Unknown parameter combination!")
@app.get("/artnet/metadata/presence")
async def presence(name: str = None, domain: str = None, artist_id: int = None, art_id: int = None,
art_md5: str = None):
name = unquote(name) if name is not None else None
domain = unquote(domain) if domain is not None else None
art_md5 = unquote(art_md5) if art_md5 is not None else None
print(f"Received GET on /artnet/metadata/presence (name={name}, domain={domain}, artist_id={artist_id}"
f", art_id={art_id}, art_md5={art_md5})")
result = None
@ -127,18 +140,19 @@ async def presence(name: str, domain: str):
@app.get("/artnet/metadata/artist")
async def artist(id: int = None, topic_id: int = None, description: str = None):
print(f"Received GET on /artnet/metadata/artist (id={id}, topic_id={topic_id}, description={description})")
async def artist(id: int = None, topic_id: int = None, name: str = None):
name = unquote(name) if name is not None else None
print(f"Received GET on /artnet/metadata/artist (id={id}, topic_id={topic_id}, name={name})")
result = None
if id is None and topic_id is None and description is None:
if id is None and topic_id is None and name is None:
result = db.get_artist_list()
if id is not None:
result = db.get_artist(id)
elif topic_id is not None:
result = db.get_topic_artists(topic_id)
elif description is not None:
result = db.search_artist(description)
elif name is not None:
result = db.search_artist(name)
if result is not None:
return result
@ -149,12 +163,12 @@ async def artist(id: int = None, topic_id: int = None, description: str = None):
async def artist(artist: ArtistNoId, id: int = None):
print(f"Received POST on /artnet/metadata/artist (id={id}) body: artist={artist}")
if id is None: # create new artist
db_artist = db.create_artist(name=artist.description, topics=artist.topics)
db_artist = db.create_artist(name=artist.name, topics=artist.topics)
return db_artist.id
else:
if db.get_artist(id) is not None:
db.update_artist(artist_id=id, name=artist.description, topics=artist.topics)
db.update_artist(artist_id=id, name=artist.name, topics=artist.topics)
else:
raise HTTPException(status_code=404, detail="Tried to edit unknown artist. ID was not found!")
@ -167,9 +181,9 @@ async def artist(id: int):
db.delete_artist(id)
@app.get("/artnet/metadata/topic")
async def topic(name: str = None, id: int = None, artist_id: int = None):
name = unquote(name) if name is not None else None
print(f"Received GET on /artnet/metadata/topic (name={name}, id={id}, artist_id={artist_id})")
if name is None and id is None and artist_id is None:
raise HTTPException(status_code=406)
@ -191,6 +205,8 @@ async def topic(name: str = None, id: int = None, artist_id: int = None):
@app.get("/artnet/metadata/tag")
async def tag(id: int = None, name: str = None, fuzzy: bool = False, category: int = None):
name = unquote(name) if name is not None else None
print(f"Received GET on /artnet/metadata/tag (name={name}, id={id}, name={category}, fuzzy={fuzzy})")
if id is None and name is None and category is None:
raise HTTPException(status_code=406)
@ -216,8 +232,11 @@ async def tag(id: int = None, name: str = None, fuzzy: bool = False, category: i
@app.get("/artnet/metadata/category")
async def category(name: str = None, id: int = None):
name = unquote(name) if name is not None else None
print(f"Received GET on /artnet/metadata/category (name={name}, id={id})")
if name is None and id is None:
raise HTTPException(status_code=406)
result = db.get_category_list()
return result
result = None
if id is not None:

@ -1,4 +1,5 @@
import requests
import urllib.parse
import json
from typing import List, Tuple
@ -63,7 +64,7 @@ def update_art_entries(url: str, port: int):
raise Exception("Update Art Entry Test: FAILED")
for i in range(len(test_art_entries)):
r = requests.get(f"http://{url}:{port}/artnet/metadata/art?id={test_art_entries[i]['ID']}")
r = requests.get(f"http://{url}:{port}/artnet/metadata/art?id={urllib.parse.quote(str(test_art_entries[i]['ID']))}")
if json.loads(r.text)["title"].split(" ")[-1] != "updated":
raise Exception("Update Art Entry Test: Failed (unexpected or no updated title)")
if json.loads(r.text)["link"] != test_art_entries[i]["link"]:
@ -79,10 +80,7 @@ def delete_art_entries(url: str, port: int):
if "id" in arts[i].keys():
r = delete_art_by_id(url, port, art_id=arts[i]["id"])
else:
try:
r = delete_art_by_hash(url, port, md5_hash=arts[i]["hash"])
except ValueError:
r = None
r = delete_art_by_hash(url, port, md5_hash=arts[i]["hash"])
if r is not None and r.status_code != 200:
raise Exception(f"Could not delete the art! {r.status_code}, {r.text}")
@ -112,20 +110,20 @@ def update_art(url: str, port: int, art_id: int, md5_hash: str = None, path: str
if presences is not None:
body["presences"] = [{"name": presence[0], "domain": presence[1]} for presence in presences]
r = requests.post(f"http://{url}:{port}/artnet/metadata/art?id={art_id}",
r = requests.post(f"http://{url}:{port}/artnet/metadata/art?id={urllib.parse.quote(str(art_id))}",
json=body)
return r
def delete_art_by_id(url: str, port: int, art_id: int):
r = requests.delete(f"http://{url}:{port}/artnet/metadata/art?id={art_id}")
r = requests.delete(f"http://{url}:{port}/artnet/metadata/art?id={urllib.parse.quote(str(art_id))}")
return r
def delete_art_by_hash(url: str, port: int, md5_hash: str):
r1 = requests.get(f"http://{url}:{port}/artnet/metadata/art?hash={md5_hash}")
r1 = requests.get(f"http://{url}:{port}/artnet/metadata/art?hash={urllib.parse.quote(md5_hash)}")
if r1.status_code != 200:
raise ValueError("Could not delete art because it could not be found!")
data = json.loads(str(r1.text))
@ -154,7 +152,7 @@ def run_art_test(url: str, port: int):
print(f"Creating {len(test_art_entries)} art entries ...")
create_art_entries(url, port)
create_art_result = False if not len(list_art(url, port)) == 3 else True
create_art_result = False if not len(list_art(url, port)) == len(test_art_entries) else True
print(f"Found {len(list_art(url, port))} art entries!")
if not create_art_result:
print(f"Failure! Unexpected number of art entries!")
@ -164,8 +162,6 @@ def run_art_test(url: str, port: int):
update_art_result = True # given, the update function would raise an exception on error
print(f"Found {len(list_art(url, port))} art entries!")
# TODO write test for updating presence-art relation
print("Deleting all art entries ...")
delete_art_entries(url, port)
delete_art_result = False if not len(list_art(url, port)) == 0 else True

@ -1,4 +1,5 @@
import requests
import urllib.parse
from typing import List
import json
@ -56,7 +57,7 @@ def create_artist(url: str, port: int, name: str, topics: List[int]):
def delete_artist(url: str, port: int, id: int):
r = requests.delete(f"http://{url}:{port}/artnet/metadata/artist?id={id}")
r = requests.delete(f"http://{url}:{port}/artnet/metadata/artist?id={urllib.parse.quote(str(id))}")
return r

@ -1,4 +1,5 @@
import requests
import urllib.parse
import json
from typing import List, Tuple
@ -30,7 +31,8 @@ def create_presence(url: str, port: int, name: str, domain: str, artist_id: int)
def delete_presence(url: str, port: int, name: str, domain: str):
r = requests.delete(f"http://{url}:{port}/artnet/metadata/presence?name={name}&domain={domain}")
r = requests.delete(f"http://{url}:{port}/artnet/metadata/presence?name={urllib.parse.quote(name)}"
f"&domain={urllib.parse.quote(domain)}")
if r.status_code != 200:
print(f"Deleting Presence entry {name}@{domain}: FAILED")

@ -7,10 +7,10 @@ from tests.createAPI.create_delete_presence import test_presence_entries, list_p
from tests.createAPI.create_delete_art import test_art_entries, list_art, create_art_entries, delete_art_entries
test_art_presence_relations = [
{"art_hash": test_art_entries[0]["hash"], "presence_name": test_presence_entries[0]["name"], "presence_domain": test_presence_entries[0]["domain"]},
{"art_hash": test_art_entries[1]["hash"], "presence_name": test_presence_entries[0]["name"], "presence_domain": test_presence_entries[0]["domain"]},
{"art_hash": test_art_entries[2]["hash"], "presence_name": test_presence_entries[0]["name"], "presence_domain": test_presence_entries[0]["domain"]},
{"art_hash": test_art_entries[2]["hash"], "presence_name": test_presence_entries[1]["name"], "presence_domain": test_presence_entries[1]["domain"]},
{"art_hash": test_art_entries[0]["hash"], "presence_name": test_art_entries[0]["presences"][0][0], "presence_domain": test_art_entries[0]["presences"][0][1]},
{"art_hash": test_art_entries[1]["hash"], "presence_name": test_art_entries[1]["presences"][0][0], "presence_domain": test_art_entries[1]["presences"][0][1]},
{"art_hash": test_art_entries[2]["hash"], "presence_name": test_art_entries[2]["presences"][0][0], "presence_domain": test_art_entries[1]["presences"][0][1]},
{"art_hash": test_art_entries[2]["hash"], "presence_name": test_art_entries[2]["presences"][1][0], "presence_domain": test_art_entries[2]["presences"][1][1]},
]
@ -38,6 +38,8 @@ def list_art_to_presence_relations(url: str, port: int):
def art_hash_to_id(arts: List[dict]):
"""
Converts a list of arts into the format of {hash: id, hash1: id1}
This allows reverse mapping of the usual ID->hash to hash->ID.
:param arts:
:return:
"""
@ -77,6 +79,35 @@ def create_art_presence_relation(url: str, port: int, presence_name: str, presen
return r
def delete_art_presence_relations(url: str, port: int):
arts = list_art(url, port)
art_hash_id = art_hash_to_id(arts)
for i in range(len(test_art_presence_relations)):
print(f"Deleting art-presence relation with id:{art_hash_id[test_art_presence_relations[i]['art_hash']]} "
f"presence_name:{test_art_presence_relations[i]['presence_name']} "
f"presence_domain:{test_art_presence_relations[i]['presence_domain']}")
r = delete_art_presence_relation(url, port, art_id=art_hash_id[test_art_presence_relations[i]["art_hash"]],
presence_name=test_art_presence_relations[i]["presence_name"],
presence_domain=test_art_presence_relations[i]["presence_domain"])
if r.status_code != 200:
print(f"Tried to delete art-presence relation with name:{test_art_presence_relations[i]['presence_name']} "
f"domain:{test_art_presence_relations[i]['presence_domain']}"
f" art_id:{art_hash_id[test_art_presence_relations[i]['art_hash']]}")
print(f"Deleting Relation failed with {r.status_code} and reason {r.text}!")
raise Exception("Couldn't delete art-presence relation!")
l = list_art_to_presence_relations(url, port)
if len(l[0]) == 0 and len(l[1]) == 0 and len(l[2]) == 0:
return True
else:
return False
def delete_art_presence_relation(url: str, port: int, presence_name: str, presence_domain: str, art_id: int):
return requests.delete(f"http://{url}:{port}/artnet/metadata/art?id={art_id}&presence_name={presence_name}"
f"&presence_domain={presence_domain}")
def run_art_presence_relation_test(url, port):
print()
print("----------------")
@ -87,7 +118,7 @@ def run_art_presence_relation_test(url, port):
print("Deleting leftover art entries ...")
delete_art_entries(url, port)
print(f"Starting presence test with "
print(f"Leftover entries for the test are "
f"({len(list_presences(url, port))}) presences, "
f"({len(list_art(url, port))}) art!")
@ -96,6 +127,10 @@ def run_art_presence_relation_test(url, port):
create_presence_entries(url, port)
create_art_entries(url, port)
print(f"Starting art2presence test with "
f"({len(list_presences(url, port))}) presences, "
f"({len(list_art(url, port))}) art!")
art = list_art(url, port) # debug
presences = list_presences(url, port) # debug
@ -109,6 +144,14 @@ def run_art_presence_relation_test(url, port):
create_result = create_art_presence_relations(url, port)
print(f"Found {sum([len(x) for x in list_art_to_presence_relations(url, port)])} art-presence relations!")
# TODO delete art-presence relation test
delete_result = delete_art_presence_relations(url, port)
print(f"Found {sum([len(x) for x in list_art_to_presence_relations(url, port)])} art-presence relations!")
return create_result
delete_art_entries(url, port)
delete_artist_entries(url, port)
print(f"Ending art2presence test with "
f"({len(list_presences(url, port))}) presences, "
f"({len(list_art(url, port))}) art!")
return create_result, delete_result

@ -1,6 +1,7 @@
from tests.createAPI.create_delete_art import run_art_test, list_art, delete_art_entries
from tests.createAPI.create_delete_presence import run_presence_test, list_presences
from tests.createAPI.create_delete_artist import delete_artist_entries, list_artists, run_artist_test
from tests.createAPI.create_delete_tag_category import delete_category_entries, list_tag_categories, run_tag_category_test
from tests.relationAPI.relate_art import run_art_presence_relation_test
@ -18,10 +19,15 @@ def run_tests(url: str, port: int):
if len(list_art(url, port)) > 0:
print("Deleting leftover art ...")
delete_art_entries(url, port)
if len(list_tag_categories(url, port)) > 0:
print("Deleting leftover tag categories ...")
delete_category_entries(url, port)
create_artist_result, delete_artist_result = run_artist_test(url, port)
create_presence_result, delete_presence_result, cascade_delete_presence_result = run_presence_test(url, port)
create_art_result, update_art_result, delete_art_result = run_art_test(url, port)
create_art2presence_result, delete_art2presence_result = run_art_presence_relation_test(url, port)
create_category_result, update_category_result, delete_category_result = run_tag_category_test(url, port)
print()
print("-------- Test Results ---------")
@ -32,16 +38,32 @@ def run_tests(url: str, port: int):
print(f"Presences: {len(r)}, {r}")
r = list_art(url, port)
print(f"Art: {len(r)}, {r}")
r = list_tag_categories(url, port)
print(f"Tag Categories: {len(r)}, {r}")
print()
print("Functions:")
print(f"Artists: \tCreate: {create_artist_result} \tUpdate: {'N/A'} \tDelete: {delete_artist_result} \t(Direct)")
print(f"Presences: \tCreate: {create_presence_result} \tUpdate: {'N/A'} "
print(f"Artists: \t\t\t\tCreate: {create_artist_result} \tUpdate: {'N/A'} "
f"\tDelete: {delete_artist_result} \t(Direct)")
print(f"Presences: \t\t\t\tCreate: {create_presence_result} \tUpdate: {'N/A'} "
f"\tDelete: {delete_presence_result} \t(Direct), {cascade_delete_presence_result} \t(cascade@artist)")
print(f"Art: \t\tCreate: {create_art_result} \tUpdate: {update_art_result} "
print(f"Art: \t\t\t\t\tCreate: {create_art_result} \tUpdate: {update_art_result} "
f"\tDelete: {delete_art_result} \t(Direct)")
print(f"Art2Presence: \t\t\tCreate: {create_art2presence_result} \tUpdate: {'N/A'} "
f"\tDelete: {delete_art2presence_result} \t(Direct)")
print(f"Tag Category: \t\t\tCreate: {create_category_result} \tUpdate: {update_category_result} "
f"\tDelete: {delete_category_result} \t(Direct)")
print(f"Tag: \t\t\t\t\tN/A")
print(f"(Artist) Topic: \t\tN/A")
print(f"Art Collection: \t\tN/A")
print(f"Art2Art Collection: \tN/A")
print(f"Artist2Topic: \t\t\tN/A")
print(f"Art2Tag: \t\t\t\tN/A")
print(f"Tag Alias: \t\t\t\tN/A")
print(f"Tag Implication: \t\tN/A")
print("-------------------------------")
if __name__ == "__main__":
#run_tests("127.0.0.1", 8000)
run_art_presence_relation_test("127.0.0.1", 8000)
run_tests("127.0.0.1", 8000)

Loading…
Cancel
Save