Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding tag community, database and REST API endpoints #6396

Merged
merged 8 commits into from
Oct 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/tribler-common/tribler_common/tag_constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
MIN_TAG_LENGTH = 3
MAX_TAG_LENGTH = 50
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,17 @@
from tribler_core.components.masterkey.masterkey_component import MasterKeyComponent
from tribler_core.components.metadata_store.metadata_store_component import MetadataStoreComponent
from tribler_core.components.restapi import RESTComponent
from tribler_core.components.tag.tag_component import TagComponent


# pylint: disable=protected-access

@pytest.mark.asyncio
async def test_giga_channel_component(tribler_config):
components = [MetadataStoreComponent(), RESTComponent(), MasterKeyComponent(), Ipv8Component(),
tribler_config.ipv8.enabled = True
tribler_config.libtorrent.enabled = True
tribler_config.chant.enabled = True
components = [TagComponent(), MetadataStoreComponent(), RESTComponent(), MasterKeyComponent(), Ipv8Component(),
GigaChannelComponent()]
session = Session(tribler_config, components)
with session:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,22 @@

from tribler_core.components.base import Session
from tribler_core.components.gigachannel_manager.gigachannel_manager_component import GigachannelManagerComponent
from tribler_core.components.ipv8.ipv8_component import Ipv8Component
from tribler_core.components.libtorrent.libtorrent_component import LibtorrentComponent
from tribler_core.components.masterkey.masterkey_component import MasterKeyComponent
from tribler_core.components.metadata_store.metadata_store_component import MetadataStoreComponent
from tribler_core.components.restapi import RESTComponent
from tribler_core.components.socks_servers.socks_servers_component import SocksServersComponent
from tribler_core.components.tag.tag_component import TagComponent


# pylint: disable=protected-access


@pytest.mark.asyncio
async def test_gigachannel_manager_component(tribler_config):
components = [SocksServersComponent(), MasterKeyComponent(), RESTComponent(), MetadataStoreComponent(),
components = [Ipv8Component(), TagComponent(), SocksServersComponent(), MasterKeyComponent(), RESTComponent(),
MetadataStoreComponent(),
LibtorrentComponent(), GigachannelManagerComponent()]
session = Session(tribler_config, components)
with session:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from tribler_core.components.metadata_store.db.store import MetadataStore
from tribler_core.components.metadata_store.utils import generate_test_channels
from tribler_core.components.restapi import RestfulComponent
from tribler_core.components.tag.tag_component import TagComponent
from tribler_core.components.upgrade import UpgradeComponent


Expand Down Expand Up @@ -50,12 +51,17 @@ async def run(self):
endpoints=['search', 'metadata', 'remote_query', 'downloads', 'channels', 'collections', 'statistics'],
values={'mds': metadata_store}
)
tag_component = await self.require_component(TagComponent)
await self.init_endpoints(
endpoints=['channels', 'search'],
values={'tags_db': tag_component.tags_db}
)

self.session.notifier.add_observer(NTFY.TORRENT_METADATA_ADDED,
metadata_store.TorrentMetadata.add_ffa_from_dict)

if config.gui_test_mode:
generate_test_channels(metadata_store)
generate_test_channels(metadata_store, tag_component.tags_db)

async def shutdown(self):
await super().shutdown()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

from ipv8.REST.schema import schema

from marshmallow.fields import Boolean, Dict, Integer, String
from marshmallow.fields import Boolean, Integer, String

from pony.orm import db_session

Expand Down Expand Up @@ -183,6 +183,7 @@ async def get_channel_contents(self, request):
contents_list = [c.to_simple_dict() for c in contents]
total = self.mds.get_total_count(**sanitized) if include_total else None
self.add_download_progress_to_metadata_list(contents_list)
self.add_tags_to_metadata_list(contents_list, hide_xxx=sanitized["hide_xxx"])
response_dict = {
"results": contents_list,
"first": sanitized['first'],
Expand Down Expand Up @@ -486,7 +487,7 @@ async def get_popular_torrents_channel(self, request):
contents = self.mds.get_entries(**sanitized)
contents_list = [c.to_simple_dict() for c in contents]
self.add_download_progress_to_metadata_list(contents_list)

self.add_tags_to_metadata_list(contents_list, hide_xxx=sanitized["hide_xxx"])
response_dict = {
"results": contents_list,
"first": sanitized['first'],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
from binascii import unhexlify
from typing import Optional

from pony.orm import db_session

from tribler_core.components.metadata_store.category_filter.family_filter import default_xxx_filter
from tribler_core.components.metadata_store.db.serialization import CHANNEL_TORRENT, COLLECTION_NODE, REGULAR_TORRENT
from tribler_core.components.tag.db.tag_db import TagDatabase
from tribler_core.restapi.rest_endpoint import RESTEndpoint

# This dict is used to translate JSON fields into the columns used in Pony for _sorting_.
Expand Down Expand Up @@ -32,6 +39,7 @@ class MetadataEndpointBase(RESTEndpoint):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.mds = None
self.tags_db: Optional[TagDatabase] = None

@classmethod
def sanitize_parameters(cls, parameters):
Expand All @@ -56,3 +64,12 @@ def sanitize_parameters(cls, parameters):
mtypes.extend(metadata_type_to_search_scope[arg])
sanitized['metadata_type'] = frozenset(mtypes)
return sanitized

@db_session
def add_tags_to_metadata_list(self, contents_list, hide_xxx=False):
for torrent in contents_list:
if torrent['type'] == REGULAR_TORRENT:
tags = self.tags_db.get_tags(unhexlify(torrent["infohash"]))
if hide_xxx:
tags = [tag.lower() for tag in tags if not default_xxx_filter.isXXX(tag, isFilename=False)]
torrent["tags"] = tags
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@

from ipv8.REST.schema import schema

from marshmallow.fields import Boolean, Integer, String
from marshmallow.fields import Integer, String

from pony.orm import db_session

from tribler_core.components.metadata_store.restapi.metadata_endpoint import MetadataEndpointBase
from tribler_core.components.metadata_store.restapi.metadata_schema import MetadataParameters
from tribler_core.components.metadata_store.restapi.metadata_schema import MetadataParameters, MetadataSchema
from tribler_core.components.metadata_store.db.store import MetadataStore
from tribler_core.restapi.rest_endpoint import HTTP_BAD_REQUEST, RESTResponse
from tribler_core.utilities.utilities import froze_it
Expand Down Expand Up @@ -42,26 +42,12 @@ def sanitize_parameters(cls, parameters):
200: {
'schema': schema(
SearchResponse={
'torrents': [
schema(
Torrent={
'commit_status': Integer,
'num_leechers': Integer,
'date': Integer,
'relevance_score': Integer,
'id': Integer,
'size': Integer,
'category': String,
'public_key': String,
'name': String,
'last_tracker_check': Integer,
'infohash': String,
'num_seeders': Integer,
'type': String,
}
)
],
'chant_dirty': Boolean,
'results': [MetadataSchema],
'first': Integer(),
'last': Integer(),
'sort_by': String(),
'sort_desc': Integer(),
'total': Integer(),
}
)
}
Expand Down Expand Up @@ -98,6 +84,8 @@ def search_db():
self._logger.error("Error while performing DB search: %s: %s", type(e).__name__, e)
return RESTResponse(status=HTTP_BAD_REQUEST)

self.add_tags_to_metadata_list(search_results, hide_xxx=sanitized["hide_xxx"])

response_dict = {
"results": search_results,
"first": sanitized["first"],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import pytest

from tribler_core.components.metadata_store.db.orm_bindings.channel_node import NEW
from tribler_core.components.metadata_store.utils import tag_torrent
from tribler_core.utilities.random_utils import random_infohash


Expand Down Expand Up @@ -41,23 +42,34 @@ def add_fake_torrents_channels(metadata_store):


@pytest.fixture
def my_channel(metadata_store):
def my_channel(metadata_store, tags_db):
"""
Generate a channel with some torrents. Also add a few (random) tags to these torrents.
"""
with db_session:
chan = metadata_store.ChannelMetadata.create_channel('test', 'test')
for ind in range(5):
infohash = random_infohash()
_ = metadata_store.TorrentMetadata(
origin_id=chan.id_, title='torrent%d' % ind, status=NEW, infohash=random_infohash()
origin_id=chan.id_, title='torrent%d' % ind, status=NEW, infohash=infohash
)
tag_torrent(infohash, tags_db)
for ind in range(5, 9):
_ = metadata_store.TorrentMetadata(origin_id=chan.id_, title='torrent%d' % ind, infohash=random_infohash())
infohash = random_infohash()
_ = metadata_store.TorrentMetadata(origin_id=chan.id_, title='torrent%d' % ind, infohash=infohash)
tag_torrent(infohash, tags_db)

chan2 = metadata_store.ChannelMetadata.create_channel('test2', 'test2')
for ind in range(5):
infohash = random_infohash()
_ = metadata_store.TorrentMetadata(
origin_id=chan2.id_, title='torrentB%d' % ind, status=NEW, infohash=random_infohash()
origin_id=chan2.id_, title='torrentB%d' % ind, status=NEW, infohash=infohash
)
tag_torrent(infohash, tags_db)
for ind in range(5, 9):
infohash = random_infohash()
_ = metadata_store.TorrentMetadata(
origin_id=chan2.id_, title='torrentB%d' % ind, infohash=random_infohash()
)
tag_torrent(infohash, tags_db)
return chan
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@

from tribler_core.components.libtorrent.torrentdef import TorrentDef
from tribler_core.components.gigachannel.community.gigachannel_community import NoChannelSourcesException
from tribler_core.components.metadata_store.category_filter.family_filter import default_xxx_filter
from tribler_core.components.metadata_store.db.orm_bindings.channel_node import NEW
from tribler_core.components.metadata_store.restapi.channels_endpoint import ChannelsEndpoint
from tribler_core.components.metadata_store.db.serialization import CHANNEL_TORRENT, COLLECTION_NODE, REGULAR_TORRENT
from tribler_core.components.metadata_store.utils import RequestTimeoutException
from tribler_core.components.metadata_store.utils import RequestTimeoutException, tag_torrent
from tribler_core.restapi.base_api_test import do_request
from tribler_core.restapi.rest_manager import error_middleware
from tribler_core.tests.tools.common import TORRENT_UBUNTU_FILE
Expand All @@ -36,7 +38,7 @@


@pytest.fixture
def rest_api(loop, aiohttp_client, mock_dlmgr, metadata_store): # pylint: disable=unused-argument
def rest_api(loop, aiohttp_client, mock_dlmgr, metadata_store, tags_db): # pylint: disable=unused-argument
mock_gigachannel_manager = Mock()
mock_gigachannel_community = Mock()

Expand All @@ -48,12 +50,14 @@ def return_exc(*args, **kwargs):
mock_gigachannel_community.remote_select_channel_contents = return_exc
collections_endpoint = ChannelsEndpoint()
collections_endpoint.mds = metadata_store
collections_endpoint.tags_db = tags_db
collections_endpoint.download_manager = mock_dlmgr
collections_endpoint.gigachannel_manager = mock_gigachannel_manager
collections_endpoint.gigachannel_community = mock_gigachannel_community

channels_endpoint = ChannelsEndpoint()
channels_endpoint.mds = metadata_store
channels_endpoint.tags_db = tags_db
channels_endpoint.download_manager = mock_dlmgr
channels_endpoint.gigachannel_manager = mock_gigachannel_manager
channels_endpoint.gigachannel_community = mock_gigachannel_community
Expand Down Expand Up @@ -700,3 +704,45 @@ async def test_get_channel_thumbnail(rest_api, metadata_store):
assert response.status == 200
assert await response.read() == PNG_DATA
assert response.headers["Content-Type"] == "image/png"


async def test_get_my_channel_tags(metadata_store, mock_dlmgr_get_download, my_channel, rest_api): # pylint: disable=redefined-outer-name
"""
Test whether tags are correctly returned over the REST API
"""
with db_session:
json_dict = await do_request(
rest_api,
'channels/%s/%d?metadata_type=%d'
% (hexlify(my_channel.public_key), my_channel.id_, REGULAR_TORRENT),
expected_code=200,
)

assert len(json_dict['results']) == 9
for item in json_dict['results']:
assert len(item["tags"]) >= 2


async def test_get_my_channel_tags_xxx(metadata_store, tags_db, mock_dlmgr_get_download, my_channel, rest_api): # pylint: disable=redefined-outer-name
"""
Test whether XXX tags are correctly filtered
"""
with db_session:
chan = metadata_store.ChannelMetadata.create_channel('test', 'test')
infohash = random_infohash()
_ = metadata_store.TorrentMetadata(origin_id=chan.id_, title='taggedtorrent', status=NEW, infohash=infohash)
default_xxx_filter.xxx_terms = {"wrongterm"}

# Add a few tags to our new torrent
tags = ["totally safe", "wrongterm", "wRonGtErM", "a wrongterm b"]
tag_torrent(infohash, tags_db, tags=tags)

json_dict = await do_request(
rest_api,
'channels/%s/%d?metadata_type=%d&hide_xxx=1'
% (hexlify(my_channel.public_key), chan.id_, REGULAR_TORRENT),
expected_code=200,
)

assert len(json_dict['results']) == 1
assert len(json_dict['results'][0]["tags"]) == 1
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@
from tribler_core.utilities.random_utils import random_infohash


# pylint: disable=unused-argument, redefined-outer-name


@pytest.fixture
def needle_in_haystack_mds(metadata_store): # pylint: disable=unused-argument
def needle_in_haystack_mds(metadata_store):
num_hay = 100
with db_session:
_ = metadata_store.ChannelMetadata(title='test', tags='test', subscribed=True, infohash=random_infohash())
Expand All @@ -22,22 +25,23 @@ def needle_in_haystack_mds(metadata_store): # pylint: disable=unused-argument


@pytest.fixture
def rest_api(loop, needle_in_haystack_mds, aiohttp_client): # pylint: disable=unused-argument
def rest_api(loop, needle_in_haystack_mds, aiohttp_client, tags_db):
channels_endpoint = SearchEndpoint()
channels_endpoint.mds = needle_in_haystack_mds
channels_endpoint.tags_db = tags_db
app = Application()
app.add_subapp('/search', channels_endpoint.app)
return loop.run_until_complete(aiohttp_client(app))


async def test_search_no_query(rest_api): # pylint: disable=unused-argument
async def test_search_no_query(rest_api):
"""
Testing whether the API returns an error 400 if no query is passed when doing a search
"""
await do_request(rest_api, 'search', expected_code=400)


async def test_search_wrong_mdtype(rest_api): # pylint: disable=unused-argument
async def test_search_wrong_mdtype(rest_api):
"""
Testing whether the API returns an error 400 if wrong metadata type is passed in the query
"""
Expand Down Expand Up @@ -106,14 +110,14 @@ async def test_search_with_include_total_and_max_rowid(rest_api):
assert len(parsed["results"]) == 1


async def test_completions_no_query(rest_api): # pylint: disable=unused-argument
async def test_completions_no_query(rest_api):
"""
Testing whether the API returns an error 400 if no query is passed when getting search completion terms
"""
await do_request(rest_api, 'search/completions', expected_code=400)


async def test_completions(rest_api): # pylint: disable=unused-argument
async def test_completions(rest_api):
"""
Testing whether the API returns the right terms when getting search completion terms
"""
Expand Down
Loading