From 1c5d3081da5b7addf0a8940a39eaa78eb86fb371 Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Tue, 18 Oct 2022 09:39:59 +0200 Subject: [PATCH 1/3] Renamed TagsEndpoint to KnowledgeEndpoint --- ...tags_endpoint.py => knowledge_endpoint.py} | 16 ++++----- ...endpoint.py => test_knowledge_endpoint.py} | 36 +++++++++---------- .../components/restapi/restapi_component.py | 4 +-- src/tribler/gui/dialogs/addtagsdialog.py | 2 +- src/tribler/gui/widgets/lazytableview.py | 2 +- 5 files changed, 30 insertions(+), 30 deletions(-) rename src/tribler/core/components/knowledge/restapi/{tags_endpoint.py => knowledge_endpoint.py} (90%) rename src/tribler/core/components/knowledge/restapi/tests/{test_tags_endpoint.py => test_knowledge_endpoint.py} (69%) diff --git a/src/tribler/core/components/knowledge/restapi/tags_endpoint.py b/src/tribler/core/components/knowledge/restapi/knowledge_endpoint.py similarity index 90% rename from src/tribler/core/components/knowledge/restapi/tags_endpoint.py rename to src/tribler/core/components/knowledge/restapi/knowledge_endpoint.py index c9ea823391d..c90c78b0802 100644 --- a/src/tribler/core/components/knowledge/restapi/tags_endpoint.py +++ b/src/tribler/core/components/knowledge/restapi/knowledge_endpoint.py @@ -17,9 +17,9 @@ @froze_it -class TagsEndpoint(RESTEndpoint): +class KnowledgeEndpoint(RESTEndpoint): """ - Top-level endpoint for tags. + Top-level endpoint for knowledge management. """ def __init__(self, db: KnowledgeDatabase, community: KnowledgeCommunity): @@ -40,14 +40,14 @@ def validate_infohash(infohash: bytes) -> Tuple[bool, Optional[RESTResponse]]: def setup_routes(self): self.app.add_routes( [ - web.patch('/{infohash}', self.update_tags_entries), + web.patch('/{infohash}', self.update_knowledge_entries), web.get('/{infohash}/suggestions', self.get_suggestions), ] ) @docs( tags=["General"], - summary="Update a particular torrent with tags.", + summary="Update the metadata associated with a particular torrent.", responses={ 200: { "schema": schema(UpdateTagsResponse={'success': Boolean()}) @@ -55,12 +55,12 @@ def setup_routes(self): HTTP_BAD_REQUEST: { "schema": HandledErrorSchema, 'example': {"error": "Invalid tag length"}}, }, - description="This endpoint updates a particular torrent with the provided tags." + description="This endpoint updates a particular torrent with the provided metadata." ) - async def update_tags_entries(self, request): + async def update_knowledge_entries(self, request): params = await request.json() infohash = request.match_info["infohash"] - ih_valid, error_response = TagsEndpoint.validate_infohash(infohash) + ih_valid, error_response = KnowledgeEndpoint.validate_infohash(infohash) if not ih_valid: return error_response @@ -116,7 +116,7 @@ async def get_suggestions(self, request): Get suggestions for a particular tag. """ infohash = request.match_info["infohash"] - ih_valid, error_response = TagsEndpoint.validate_infohash(infohash) + ih_valid, error_response = KnowledgeEndpoint.validate_infohash(infohash) if not ih_valid: return error_response diff --git a/src/tribler/core/components/knowledge/restapi/tests/test_tags_endpoint.py b/src/tribler/core/components/knowledge/restapi/tests/test_knowledge_endpoint.py similarity index 69% rename from src/tribler/core/components/knowledge/restapi/tests/test_tags_endpoint.py rename to src/tribler/core/components/knowledge/restapi/tests/test_knowledge_endpoint.py index 30f8d6f0118..9a5ff355ee0 100644 --- a/src/tribler/core/components/knowledge/restapi/tests/test_tags_endpoint.py +++ b/src/tribler/core/components/knowledge/restapi/tests/test_knowledge_endpoint.py @@ -8,7 +8,7 @@ from tribler.core.components.knowledge.community.knowledge_payload import StatementOperation from tribler.core.components.knowledge.db.knowledge_db import Operation, ResourceType -from tribler.core.components.knowledge.restapi.tags_endpoint import TagsEndpoint +from tribler.core.components.knowledge.restapi.knowledge_endpoint import KnowledgeEndpoint from tribler.core.components.restapi.rest.base_api_test import do_request from tribler.core.conftest import TEST_PERSONAL_KEY from tribler.core.utilities.unicode import hexlify @@ -17,18 +17,18 @@ # pylint: disable=redefined-outer-name @pytest.fixture -def tags_endpoint(knowledge_db): +def knowledge_endpoint(knowledge_db): community = Mock() community.key = TEST_PERSONAL_KEY community.sign = Mock(return_value=b'') - endpoint = TagsEndpoint(knowledge_db, community) + endpoint = KnowledgeEndpoint(knowledge_db, community) return endpoint @pytest.fixture -def rest_api(loop, aiohttp_client, tags_endpoint): +def rest_api(loop, aiohttp_client, knowledge_endpoint): app = Application() - app.add_subapp('/tags', tags_endpoint.app) + app.add_subapp('/knowledge', knowledge_endpoint.app) return loop.run_until_complete(aiohttp_client(app)) @@ -37,8 +37,8 @@ async def test_add_tag_invalid_infohash(rest_api): Test whether an error is returned if we try to add a tag to content with an invalid infohash """ post_data = {"tags": ["abc", "def"]} - await do_request(rest_api, 'tags/3f3', request_type="PATCH", expected_code=400, post_data=post_data) - await do_request(rest_api, 'tags/3f3f', request_type="PATCH", expected_code=400, post_data=post_data) + await do_request(rest_api, 'knowledge/3f3', request_type="PATCH", expected_code=400, post_data=post_data) + await do_request(rest_api, 'knowledge/3f3f', request_type="PATCH", expected_code=400, post_data=post_data) async def test_add_invalid_tag(rest_api): @@ -47,11 +47,11 @@ async def test_add_invalid_tag(rest_api): """ post_data = {"tags": ["a"]} infohash = b'a' * 20 - await do_request(rest_api, f'tags/{hexlify(infohash)}', request_type="PATCH", expected_code=400, + await do_request(rest_api, f'knowledge/{hexlify(infohash)}', request_type="PATCH", expected_code=400, post_data=post_data) post_data = {"tags": ["a" * 60]} - await do_request(rest_api, f'tags/{hexlify(infohash)}', request_type="PATCH", expected_code=400, + await do_request(rest_api, f'knowledge/{hexlify(infohash)}', request_type="PATCH", expected_code=400, post_data=post_data) @@ -62,7 +62,7 @@ async def test_modify_tags(rest_api, knowledge_db): post_data = {"tags": ["abc", "def"]} infohash = 'a' * 40 with freeze_time("2015-01-01") as frozen_time: - await do_request(rest_api, f'tags/{infohash}', request_type="PATCH", expected_code=200, + await do_request(rest_api, f'knowledge/{infohash}', request_type="PATCH", expected_code=200, post_data=post_data) with db_session: tags = knowledge_db.get_objects(infohash, predicate=ResourceType.TAG) @@ -71,17 +71,17 @@ async def test_modify_tags(rest_api, knowledge_db): # Now remove a tag frozen_time.move_to("2016-01-01") post_data = {"tags": ["abc"]} - await do_request(rest_api, f'tags/{infohash}', request_type="PATCH", expected_code=200, + await do_request(rest_api, f'knowledge/{infohash}', request_type="PATCH", expected_code=200, post_data=post_data) with db_session: tags = knowledge_db.get_objects(infohash, predicate=ResourceType.TAG) assert tags == ["abc"] -async def test_modify_tags_no_community(knowledge_db, tags_endpoint): - tags_endpoint.community = None +async def test_modify_tags_no_community(knowledge_db, knowledge_endpoint): + knowledge_endpoint.community = None infohash = 'a' * 20 - tags_endpoint.modify_tags(infohash, {"abc", "def"}) + knowledge_endpoint.modify_tags(infohash, {"abc", "def"}) with db_session: tags = knowledge_db.get_objects(infohash, predicate=ResourceType.TAG) @@ -94,8 +94,8 @@ async def test_get_suggestions_invalid_infohash(rest_api): Test whether an error is returned if we fetch suggestions from content with an invalid infohash """ post_data = {"tags": ["abc", "def"]} - await do_request(rest_api, 'tags/3f3/suggestions', expected_code=400, post_data=post_data) - await do_request(rest_api, 'tags/3f3f/suggestions', expected_code=400, post_data=post_data) + await do_request(rest_api, 'knowledge/3f3/suggestions', expected_code=400, post_data=post_data) + await do_request(rest_api, 'knowledge/3f3f/suggestions', expected_code=400, post_data=post_data) async def test_get_suggestions(rest_api, knowledge_db): @@ -104,7 +104,7 @@ async def test_get_suggestions(rest_api, knowledge_db): """ infohash = b'a' * 20 infohash_str = hexlify(infohash) - response = await do_request(rest_api, f'tags/{infohash_str}/suggestions') + response = await do_request(rest_api, f'knowledge/{infohash_str}/suggestions') assert "suggestions" in response assert not response["suggestions"] @@ -120,5 +120,5 @@ def _add_operation(op=Operation.ADD): _add_operation(op=Operation.ADD) _add_operation(op=Operation.REMOVE) - response = await do_request(rest_api, f'tags/{infohash_str}/suggestions') + response = await do_request(rest_api, f'knowledge/{infohash_str}/suggestions') assert response["suggestions"] == ["test"] diff --git a/src/tribler/core/components/restapi/restapi_component.py b/src/tribler/core/components/restapi/restapi_component.py index 6e09f952618..e4e6300c9e6 100644 --- a/src/tribler/core/components/restapi/restapi_component.py +++ b/src/tribler/core/components/restapi/restapi_component.py @@ -11,7 +11,7 @@ from tribler.core.components.ipv8.ipv8_component import Ipv8Component from tribler.core.components.key.key_component import KeyComponent from tribler.core.components.knowledge.knowledge_component import KnowledgeComponent -from tribler.core.components.knowledge.restapi.tags_endpoint import TagsEndpoint +from tribler.core.components.knowledge.restapi.knowledge_endpoint import KnowledgeEndpoint from tribler.core.components.libtorrent.libtorrent_component import LibtorrentComponent from tribler.core.components.libtorrent.restapi.create_torrent_endpoint import CreateTorrentEndpoint from tribler.core.components.libtorrent.restapi.downloads_endpoint import DownloadsEndpoint @@ -124,7 +124,7 @@ async def run(self): tags_db=knowledge_component.knowledge_db) self.maybe_add('/remote_query', RemoteQueryEndpoint, gigachannel_component.community, metadata_store_component.mds) - self.maybe_add('/tags', TagsEndpoint, db=knowledge_component.knowledge_db, + self.maybe_add('/knowledge', KnowledgeEndpoint, db=knowledge_component.knowledge_db, community=knowledge_component.community) if not isinstance(ipv8_component, NoneComponent): diff --git a/src/tribler/gui/dialogs/addtagsdialog.py b/src/tribler/gui/dialogs/addtagsdialog.py index 2faeb613851..9500b83472e 100644 --- a/src/tribler/gui/dialogs/addtagsdialog.py +++ b/src/tribler/gui/dialogs/addtagsdialog.py @@ -39,7 +39,7 @@ def __init__(self, parent: QWidget, infohash: str) -> None: self.dialog_widget.suggestions_container.hide() # Fetch suggestions - TriblerNetworkRequest(f"tags/{infohash}/suggestions", self.on_received_suggestions) + TriblerNetworkRequest(f"knowledge/{infohash}/suggestions", self.on_received_suggestions) self.update_window() diff --git a/src/tribler/gui/widgets/lazytableview.py b/src/tribler/gui/widgets/lazytableview.py index b6cf205a32f..dbfb4844253 100644 --- a/src/tribler/gui/widgets/lazytableview.py +++ b/src/tribler/gui/widgets/lazytableview.py @@ -284,7 +284,7 @@ def on_tags_edited(self, index, tags): def save_edited_tags(self, index: QModelIndex, tags: List[str]): data_item = self.model().data_items[index.row()] TriblerNetworkRequest( - f"tags/{data_item['infohash']}", + f"knowledge/{data_item['infohash']}", lambda _, ind=index, tgs=tags: self.on_tags_edited(ind, tgs), raw_data=json.dumps({"tags": tags}), method='PATCH', From d50e672076d4fb3d067b051492f1eeb5f24fa829 Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Tue, 18 Oct 2022 10:53:50 +0200 Subject: [PATCH 2/3] Updated REST API to process statements --- .../knowledge/restapi/knowledge_endpoint.py | 43 +++++++++++-------- .../restapi/tests/test_knowledge_endpoint.py | 22 ++++++---- src/tribler/gui/dialogs/addtagsdialog.py | 12 +++++- src/tribler/gui/tests/test_gui.py | 16 ++++--- src/tribler/gui/widgets/lazytableview.py | 19 ++++---- 5 files changed, 69 insertions(+), 43 deletions(-) diff --git a/src/tribler/core/components/knowledge/restapi/knowledge_endpoint.py b/src/tribler/core/components/knowledge/restapi/knowledge_endpoint.py index c90c78b0802..e4c0368a58f 100644 --- a/src/tribler/core/components/knowledge/restapi/knowledge_endpoint.py +++ b/src/tribler/core/components/knowledge/restapi/knowledge_endpoint.py @@ -1,5 +1,5 @@ import binascii -from typing import Optional, Set, Tuple +from typing import Optional, Set, Tuple, Dict from aiohttp import web from aiohttp_apispec import docs @@ -64,36 +64,45 @@ async def update_knowledge_entries(self, request): if not ih_valid: return error_response - # Validate whether the size of the tag is within the allowed range - tags = set(params["tags"]) - for tag in tags: - if len(tag) < MIN_RESOURCE_LENGTH or len(tag) > MAX_RESOURCE_LENGTH: + # Validate whether the size of the tag is within the allowed range and filter out duplicate tags. + tags = set() + statements = [] + for statement in params["statements"]: + obj = statement["object"] + if statement["predicate"] == ResourceType.TAG and \ + (len(obj) < MIN_RESOURCE_LENGTH or len(obj) > MAX_RESOURCE_LENGTH): return RESTResponse({"error": "Invalid tag length"}, status=HTTP_BAD_REQUEST) - self.modify_tags(infohash, tags) + if obj not in tags: + tags.add(obj) + statements.append(statement) + + self.modify_statements(infohash, statements) return RESTResponse({"success": True}) @db_session - def modify_tags(self, infohash: str, new_tags: Set[str]): + def modify_statements(self, infohash: str, statements): """ - Modify the tags of a particular content item. + Modify the statements of a particular content item. """ if not self.community: return - # First, get the current tags and compute the diff between the old and new tags - old_tags = set(self.db.get_objects(infohash, predicate=ResourceType.TAG)) - added_tags = new_tags - old_tags - removed_tags = old_tags - new_tags + # First, get the current statements and compute the diff between the old and new statements + old_statements = set([(stmt.predicate, stmt.object) for stmt in self.db.get_statements(infohash)]) + new_statements = set([(stmt["predicate"], stmt["object"]) for stmt in statements]) + added_statements = new_statements - old_statements + removed_statements = old_statements - new_statements - # Create individual tag operations for the added/removed tags + # Create individual statement operations for the added/removed statements public_key = self.community.key.pub().key_to_bin() - for tag in added_tags.union(removed_tags): - type_of_operation = Operation.ADD if tag in added_tags else Operation.REMOVE + for stmt in added_statements.union(removed_statements): + predicate, obj = stmt + type_of_operation = Operation.ADD if stmt in added_statements else Operation.REMOVE operation = StatementOperation(subject_type=ResourceType.TORRENT, subject=infohash, - predicate=ResourceType.TAG, - object=tag, operation=type_of_operation, clock=0, + predicate=predicate, + object=obj, operation=type_of_operation, clock=0, creator_public_key=public_key) operation.clock = self.db.get_clock(operation) + 1 signature = self.community.sign(operation) diff --git a/src/tribler/core/components/knowledge/restapi/tests/test_knowledge_endpoint.py b/src/tribler/core/components/knowledge/restapi/tests/test_knowledge_endpoint.py index 9a5ff355ee0..162c1ccf897 100644 --- a/src/tribler/core/components/knowledge/restapi/tests/test_knowledge_endpoint.py +++ b/src/tribler/core/components/knowledge/restapi/tests/test_knowledge_endpoint.py @@ -1,3 +1,4 @@ +from typing import Dict from unittest.mock import Mock import pytest @@ -32,11 +33,15 @@ def rest_api(loop, aiohttp_client, knowledge_endpoint): return loop.run_until_complete(aiohttp_client(app)) +def tag_to_statement(tag: str) -> Dict: + return {"predicate": ResourceType.TAG, "object": tag} + + async def test_add_tag_invalid_infohash(rest_api): """ Test whether an error is returned if we try to add a tag to content with an invalid infohash """ - post_data = {"tags": ["abc", "def"]} + post_data = {"knowledge": [tag_to_statement("abc"), tag_to_statement("def")]} await do_request(rest_api, 'knowledge/3f3', request_type="PATCH", expected_code=400, post_data=post_data) await do_request(rest_api, 'knowledge/3f3f', request_type="PATCH", expected_code=400, post_data=post_data) @@ -45,12 +50,12 @@ async def test_add_invalid_tag(rest_api): """ Test whether an error is returned if we try to add a tag that is too short or long. """ - post_data = {"tags": ["a"]} + post_data = {"statements": [tag_to_statement("a")]} infohash = b'a' * 20 await do_request(rest_api, f'knowledge/{hexlify(infohash)}', request_type="PATCH", expected_code=400, post_data=post_data) - post_data = {"tags": ["a" * 60]} + post_data = {"statements": [tag_to_statement("a" * 60)]} await do_request(rest_api, f'knowledge/{hexlify(infohash)}', request_type="PATCH", expected_code=400, post_data=post_data) @@ -59,7 +64,7 @@ async def test_modify_tags(rest_api, knowledge_db): """ Test modifying tags """ - post_data = {"tags": ["abc", "def"]} + post_data = {"statements": [tag_to_statement("abc"), tag_to_statement("def")]} infohash = 'a' * 40 with freeze_time("2015-01-01") as frozen_time: await do_request(rest_api, f'knowledge/{infohash}', request_type="PATCH", expected_code=200, @@ -70,7 +75,7 @@ async def test_modify_tags(rest_api, knowledge_db): # Now remove a tag frozen_time.move_to("2016-01-01") - post_data = {"tags": ["abc"]} + post_data = {"statements": [tag_to_statement("abc")]} await do_request(rest_api, f'knowledge/{infohash}', request_type="PATCH", expected_code=200, post_data=post_data) with db_session: @@ -81,7 +86,7 @@ async def test_modify_tags(rest_api, knowledge_db): async def test_modify_tags_no_community(knowledge_db, knowledge_endpoint): knowledge_endpoint.community = None infohash = 'a' * 20 - knowledge_endpoint.modify_tags(infohash, {"abc", "def"}) + knowledge_endpoint.modify_statements(infohash, [tag_to_statement("abc"), tag_to_statement("def")]) with db_session: tags = knowledge_db.get_objects(infohash, predicate=ResourceType.TAG) @@ -93,9 +98,8 @@ async def test_get_suggestions_invalid_infohash(rest_api): """ Test whether an error is returned if we fetch suggestions from content with an invalid infohash """ - post_data = {"tags": ["abc", "def"]} - await do_request(rest_api, 'knowledge/3f3/suggestions', expected_code=400, post_data=post_data) - await do_request(rest_api, 'knowledge/3f3f/suggestions', expected_code=400, post_data=post_data) + await do_request(rest_api, 'knowledge/3f3/suggestions', expected_code=400) + await do_request(rest_api, 'knowledge/3f3f/suggestions', expected_code=400) async def test_get_suggestions(rest_api, knowledge_db): diff --git a/src/tribler/gui/dialogs/addtagsdialog.py b/src/tribler/gui/dialogs/addtagsdialog.py index 9500b83472e..85cb00231c4 100644 --- a/src/tribler/gui/dialogs/addtagsdialog.py +++ b/src/tribler/gui/dialogs/addtagsdialog.py @@ -1,9 +1,10 @@ -from typing import Dict, Optional +from typing import Dict, Optional, List from PyQt5 import uic from PyQt5.QtCore import QModelIndex, QPoint, pyqtSignal from PyQt5.QtWidgets import QSizePolicy, QWidget +from tribler.core.components.knowledge.db.knowledge_db import ResourceType from tribler.core.components.knowledge.knowledge_constants import MAX_RESOURCE_LENGTH, MIN_RESOURCE_LENGTH from tribler.gui.defs import TAG_HORIZONTAL_MARGIN @@ -44,6 +45,8 @@ def __init__(self, parent: QWidget, infohash: str) -> None: self.update_window() def on_save_tags_button_clicked(self, _) -> None: + statements: List[Dict] = [] + # Sanity check the entered tags entered_tags = self.dialog_widget.edit_tags_input.get_entered_tags() for tag in entered_tags: @@ -57,7 +60,12 @@ def on_save_tags_button_clicked(self, _) -> None: self.dialog_widget.error_text_label.setHidden(False) return - self.save_button_clicked.emit(self.index, entered_tags) + statements.append({ + "predicate": ResourceType.TAG, + "object": tag, + }) + + self.save_button_clicked.emit(self.index, statements) def on_received_suggestions(self, data: Dict) -> None: self.suggestions_loaded.emit() diff --git a/src/tribler/gui/tests/test_gui.py b/src/tribler/gui/tests/test_gui.py index 917be2a4db1..9750792c192 100644 --- a/src/tribler/gui/tests/test_gui.py +++ b/src/tribler/gui/tests/test_gui.py @@ -10,8 +10,9 @@ from PyQt5.QtWidgets import QListWidget, QTableView, QTextEdit, QTreeWidget, QTreeWidgetItem import tribler.gui -from tribler.core.components.reporter.reported_error import ReportedError +from tribler.core.components.knowledge.db.knowledge_db import ResourceType from tribler.core.components.knowledge.knowledge_constants import MIN_RESOURCE_LENGTH +from tribler.core.components.reporter.reported_error import ReportedError from tribler.core.sentry_reporter.sentry_reporter import SentryReporter from tribler.core.tests.tools.common import TESTS_DATA_DIR from tribler.core.utilities.rest_utils import path_to_url @@ -733,7 +734,7 @@ def test_tags_dialog(window): screenshot(window, name="edit_tags_dialog_long_tag_removed") QTest.mouseClick(widget.content_table.add_tags_dialog.dialog_widget.save_button, Qt.LeftButton) - wait_for_signal(widget.content_table.edited_tags) + wait_for_signal(widget.content_table.edited_metadata) QTest.qWait(200) # It can take a bit of time to hide the dialog @@ -747,10 +748,13 @@ def test_no_tags(window): wait_for_list_populated(widget.content_table) idx = widget.content_table.model().index(0, 0) - widget.content_table.save_edited_tags(idx, []) # Remove all tags - wait_for_signal(widget.content_table.edited_tags) + widget.content_table.save_edited_metadata(idx, []) # Remove all tags + wait_for_signal(widget.content_table.edited_metadata) screenshot(window, name="content_item_no_tags") # Put some tags back (so further tests do not fail) - widget.content_table.save_edited_tags(idx, ["abc", "def"]) - wait_for_signal(widget.content_table.edited_tags) + statements = [] + for tag in ["abc", "def"]: + statements.append({"predicate": ResourceType.TAG, "object": tag}) + widget.content_table.save_edited_metadata(idx, statements) + wait_for_signal(widget.content_table.edited_metadata) diff --git a/src/tribler/gui/widgets/lazytableview.py b/src/tribler/gui/widgets/lazytableview.py index dbfb4844253..7616b43a256 100644 --- a/src/tribler/gui/widgets/lazytableview.py +++ b/src/tribler/gui/widgets/lazytableview.py @@ -1,10 +1,11 @@ import json -from typing import List +from typing import List, Dict from PyQt5.QtCore import QEvent, QModelIndex, QRect, QTimer, Qt, pyqtSignal from PyQt5.QtGui import QGuiApplication, QMouseEvent, QMovie from PyQt5.QtWidgets import QAbstractItemView, QApplication, QHeaderView, QLabel, QTableView +from tribler.core.components.knowledge.db.knowledge_db import ResourceType from tribler.core.components.metadata_store.db.orm_bindings.channel_node import LEGACY_ENTRY from tribler.core.components.metadata_store.db.serialization import CHANNEL_TORRENT, COLLECTION_NODE, REGULAR_TORRENT, \ SNIPPET @@ -53,7 +54,7 @@ class TriblerContentTableView(QTableView): channel_clicked = pyqtSignal(dict) torrent_clicked = pyqtSignal(dict) torrent_doubleclicked = pyqtSignal(dict) - edited_tags = pyqtSignal(dict) + edited_metadata = pyqtSignal(dict) def __init__(self, parent=None): QTableView.__init__(self, parent) @@ -202,7 +203,7 @@ def on_edit_tags_clicked(self, index: QModelIndex) -> None: self.add_tags_dialog.dialog_widget.edit_tags_input.set_tags(data_item.get("tags", ())) self.add_tags_dialog.dialog_widget.content_name_label.setText(data_item["name"]) self.add_tags_dialog.show() - connect(self.add_tags_dialog.save_button_clicked, self.save_edited_tags) + connect(self.add_tags_dialog.save_button_clicked, self.save_edited_metadata) def on_download_popular_torrent_clicked(self, index: QModelIndex, torrent_index: int) -> None: data_item = index.model().data_items[index.row()] @@ -270,22 +271,22 @@ def start_download_from_index(self, index): def start_download_from_dataitem(self, data_item): self.window().start_download_from_uri(data_item2uri(data_item)) - def on_tags_edited(self, index, tags): + def on_metadata_edited(self, index, statements: List[Dict]): if self.add_tags_dialog: self.add_tags_dialog.close_dialog() self.add_tags_dialog = None data_item = self.model().data_items[index.row()] - data_item["tags"] = tags + data_item["tags"] = [stmt["object"] for stmt in statements if stmt["predicate"] == ResourceType.TAG] self.redraw(index, True) - self.edited_tags.emit(data_item) + self.edited_metadata.emit(data_item) - def save_edited_tags(self, index: QModelIndex, tags: List[str]): + def save_edited_metadata(self, index: QModelIndex, statements: List[Dict]): data_item = self.model().data_items[index.row()] TriblerNetworkRequest( f"knowledge/{data_item['infohash']}", - lambda _, ind=index, tgs=tags: self.on_tags_edited(ind, tgs), - raw_data=json.dumps({"tags": tags}), + lambda _, ind=index, stmts=statements: self.on_metadata_edited(ind, statements), + raw_data=json.dumps({"statements": statements}), method='PATCH', ) From 8262795529f66731e1c83f923fecb1873ed28c86 Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Tue, 18 Oct 2022 12:15:48 +0200 Subject: [PATCH 3/3] Renamed /suggestions to /tag_suggestions --- .../components/knowledge/restapi/knowledge_endpoint.py | 4 ++-- .../knowledge/restapi/tests/test_knowledge_endpoint.py | 8 ++++---- src/tribler/gui/dialogs/addtagsdialog.py | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/tribler/core/components/knowledge/restapi/knowledge_endpoint.py b/src/tribler/core/components/knowledge/restapi/knowledge_endpoint.py index e4c0368a58f..bd5ecfe2eb5 100644 --- a/src/tribler/core/components/knowledge/restapi/knowledge_endpoint.py +++ b/src/tribler/core/components/knowledge/restapi/knowledge_endpoint.py @@ -41,7 +41,7 @@ def setup_routes(self): self.app.add_routes( [ web.patch('/{infohash}', self.update_knowledge_entries), - web.get('/{infohash}/suggestions', self.get_suggestions), + web.get('/{infohash}/tag_suggestions', self.get_tag_suggestions), ] ) @@ -120,7 +120,7 @@ def modify_statements(self, infohash: str, statements): }, description="This endpoint updates a particular torrent with the provided tags." ) - async def get_suggestions(self, request): + async def get_tag_suggestions(self, request): """ Get suggestions for a particular tag. """ diff --git a/src/tribler/core/components/knowledge/restapi/tests/test_knowledge_endpoint.py b/src/tribler/core/components/knowledge/restapi/tests/test_knowledge_endpoint.py index 162c1ccf897..20dae0a2a09 100644 --- a/src/tribler/core/components/knowledge/restapi/tests/test_knowledge_endpoint.py +++ b/src/tribler/core/components/knowledge/restapi/tests/test_knowledge_endpoint.py @@ -98,8 +98,8 @@ async def test_get_suggestions_invalid_infohash(rest_api): """ Test whether an error is returned if we fetch suggestions from content with an invalid infohash """ - await do_request(rest_api, 'knowledge/3f3/suggestions', expected_code=400) - await do_request(rest_api, 'knowledge/3f3f/suggestions', expected_code=400) + await do_request(rest_api, 'knowledge/3f3/tag_suggestions', expected_code=400) + await do_request(rest_api, 'knowledge/3f3f/tag_suggestions', expected_code=400) async def test_get_suggestions(rest_api, knowledge_db): @@ -108,7 +108,7 @@ async def test_get_suggestions(rest_api, knowledge_db): """ infohash = b'a' * 20 infohash_str = hexlify(infohash) - response = await do_request(rest_api, f'knowledge/{infohash_str}/suggestions') + response = await do_request(rest_api, f'knowledge/{infohash_str}/tag_suggestions') assert "suggestions" in response assert not response["suggestions"] @@ -124,5 +124,5 @@ def _add_operation(op=Operation.ADD): _add_operation(op=Operation.ADD) _add_operation(op=Operation.REMOVE) - response = await do_request(rest_api, f'knowledge/{infohash_str}/suggestions') + response = await do_request(rest_api, f'knowledge/{infohash_str}/tag_suggestions') assert response["suggestions"] == ["test"] diff --git a/src/tribler/gui/dialogs/addtagsdialog.py b/src/tribler/gui/dialogs/addtagsdialog.py index 85cb00231c4..3c6f2c2694b 100644 --- a/src/tribler/gui/dialogs/addtagsdialog.py +++ b/src/tribler/gui/dialogs/addtagsdialog.py @@ -40,7 +40,7 @@ def __init__(self, parent: QWidget, infohash: str) -> None: self.dialog_widget.suggestions_container.hide() # Fetch suggestions - TriblerNetworkRequest(f"knowledge/{infohash}/suggestions", self.on_received_suggestions) + TriblerNetworkRequest(f"knowledge/{infohash}/tag_suggestions", self.on_received_tag_suggestions) self.update_window() @@ -67,7 +67,7 @@ def on_save_tags_button_clicked(self, _) -> None: self.save_button_clicked.emit(self.index, statements) - def on_received_suggestions(self, data: Dict) -> None: + def on_received_tag_suggestions(self, data: Dict) -> None: self.suggestions_loaded.emit() if data["suggestions"]: self.dialog_widget.suggestions_container.show()