mirror of https://gitlab.com/bashrc2/epicyon
Offers collection for shared items
parent
ed804adf85
commit
81f3b1d6a4
83
daemon.py
83
daemon.py
|
@ -185,6 +185,7 @@ from webapp_podcast import html_podcast_episode
|
||||||
from webapp_theme_designer import html_theme_designer
|
from webapp_theme_designer import html_theme_designer
|
||||||
from webapp_minimalbutton import set_minimal
|
from webapp_minimalbutton import set_minimal
|
||||||
from webapp_minimalbutton import is_minimal
|
from webapp_minimalbutton import is_minimal
|
||||||
|
from webapp_utils import get_shares_collection
|
||||||
from webapp_utils import load_buy_sites
|
from webapp_utils import load_buy_sites
|
||||||
from webapp_utils import get_default_path
|
from webapp_utils import get_default_path
|
||||||
from webapp_utils import get_avatar_image_url
|
from webapp_utils import get_avatar_image_url
|
||||||
|
@ -17230,6 +17231,88 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.server.debug)
|
self.server.debug)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# shared items offers collection for this instance
|
||||||
|
# this is only accessible to instance members or to
|
||||||
|
# other instances which present an authorization token
|
||||||
|
if self.path.startswith('/users/') and '/offers' in self.path:
|
||||||
|
offers_collection_authorized = authorized
|
||||||
|
nickname = self.path.split('/users/')[1]
|
||||||
|
if '/' in nickname:
|
||||||
|
nickname = nickname.split('/')[0]
|
||||||
|
page_number = 1
|
||||||
|
if '?page=' in self.path:
|
||||||
|
page_number_str = self.path.split('?page=')[1]
|
||||||
|
if ';' in page_number_str:
|
||||||
|
page_number_str = page_number_str.split(';')[0]
|
||||||
|
if page_number_str.isdigit():
|
||||||
|
page_number = int(page_number_str)
|
||||||
|
if not offers_collection_authorized:
|
||||||
|
if self.server.debug:
|
||||||
|
print('Offers collection access is not authorized. ' +
|
||||||
|
'Checking Authorization header')
|
||||||
|
# Check the authorization token
|
||||||
|
if self.headers.get('Origin') and \
|
||||||
|
self.headers.get('Authorization'):
|
||||||
|
permitted_domains = \
|
||||||
|
self.server.shared_items_federated_domains
|
||||||
|
shared_item_tokens = \
|
||||||
|
self.server.shared_item_federation_tokens
|
||||||
|
if authorize_shared_items(permitted_domains,
|
||||||
|
self.server.base_dir,
|
||||||
|
self.headers['Origin'],
|
||||||
|
calling_domain,
|
||||||
|
self.headers['Authorization'],
|
||||||
|
self.server.debug,
|
||||||
|
shared_item_tokens):
|
||||||
|
offers_collection_authorized = True
|
||||||
|
elif self.server.debug:
|
||||||
|
print('Authorization token refused for ' +
|
||||||
|
'offers collection federation')
|
||||||
|
# show offers collection for federation
|
||||||
|
if self._has_accept(calling_domain) and \
|
||||||
|
offers_collection_authorized:
|
||||||
|
if self.server.debug:
|
||||||
|
print('Preparing offers collection')
|
||||||
|
|
||||||
|
domain_full = self.server.domain_full
|
||||||
|
http_prefix = self.server.http_prefix
|
||||||
|
nickname = self.path.split('/users/')[1]
|
||||||
|
if '/' in nickname:
|
||||||
|
nickname = nickname.split('/')[0]
|
||||||
|
if self.server.debug:
|
||||||
|
print('Offers collection for account: ' + nickname)
|
||||||
|
base_dir = self.server.base_dir
|
||||||
|
offers_items_per_page = 12
|
||||||
|
max_shares_per_account = offers_items_per_page
|
||||||
|
shared_items_federated_domains = \
|
||||||
|
self.server.shared_items_federated_domains
|
||||||
|
actor = \
|
||||||
|
local_actor_url(http_prefix, nickname, domain_full) + \
|
||||||
|
'/offers'
|
||||||
|
offers_json = \
|
||||||
|
get_shares_collection(actor, page_number,
|
||||||
|
offers_items_per_page, base_dir,
|
||||||
|
self.server.domain, nickname,
|
||||||
|
max_shares_per_account,
|
||||||
|
shared_items_federated_domains,
|
||||||
|
'shares')
|
||||||
|
msg_str = json.dumps(offers_json,
|
||||||
|
ensure_ascii=False)
|
||||||
|
msg_str = self._convert_domains(calling_domain,
|
||||||
|
referer_domain,
|
||||||
|
msg_str)
|
||||||
|
msg = msg_str.encode('utf-8')
|
||||||
|
msglen = len(msg)
|
||||||
|
accept_str = self.headers['Accept']
|
||||||
|
protocol_str = \
|
||||||
|
get_json_content_from_accept(accept_str)
|
||||||
|
self._set_headers(protocol_str, msglen,
|
||||||
|
None, calling_domain, False)
|
||||||
|
self._write(msg)
|
||||||
|
return
|
||||||
|
self._400()
|
||||||
|
return
|
||||||
|
|
||||||
# shared items catalog for this instance
|
# shared items catalog for this instance
|
||||||
# this is only accessible to instance members or to
|
# this is only accessible to instance members or to
|
||||||
# other instances which present an authorization token
|
# other instances which present an authorization token
|
||||||
|
|
35
shares.py
35
shares.py
|
@ -1032,6 +1032,41 @@ def get_shared_items_catalog_via_server(session, nickname: str, password: str,
|
||||||
return catalog_json
|
return catalog_json
|
||||||
|
|
||||||
|
|
||||||
|
def get_offers_via_server(session, nickname: str, password: str,
|
||||||
|
domain: str, port: int,
|
||||||
|
http_prefix: str, debug: bool,
|
||||||
|
signing_priv_key_pem: str) -> {}:
|
||||||
|
"""Returns the offers collection for shared items via c2s
|
||||||
|
"""
|
||||||
|
if not session:
|
||||||
|
print('WARN: No session for get_offers_via_server')
|
||||||
|
return 6
|
||||||
|
|
||||||
|
auth_header = create_basic_auth_header(nickname, password)
|
||||||
|
|
||||||
|
headers = {
|
||||||
|
'host': domain,
|
||||||
|
'Content-type': 'application/json',
|
||||||
|
'Authorization': auth_header,
|
||||||
|
'Accept': 'application/json'
|
||||||
|
}
|
||||||
|
domain_full = get_full_domain(domain, port)
|
||||||
|
url = local_actor_url(http_prefix, nickname, domain_full) + '/offers'
|
||||||
|
if debug:
|
||||||
|
print('Offers collection request to: ' + url)
|
||||||
|
offers_json = get_json(signing_priv_key_pem, session, url, headers, None,
|
||||||
|
debug, __version__, http_prefix, None)
|
||||||
|
if not offers_json:
|
||||||
|
if debug:
|
||||||
|
print('DEBUG: GET offers collection failed for c2s to ' + url)
|
||||||
|
# return 5
|
||||||
|
|
||||||
|
if debug:
|
||||||
|
print('DEBUG: c2s GET offers collection success')
|
||||||
|
|
||||||
|
return offers_json
|
||||||
|
|
||||||
|
|
||||||
def outbox_share_upload(base_dir: str, http_prefix: str,
|
def outbox_share_upload(base_dir: str, http_prefix: str,
|
||||||
nickname: str, domain: str, port: int,
|
nickname: str, domain: str, port: int,
|
||||||
message_json: {}, debug: bool, city: str,
|
message_json: {}, debug: bool, city: str,
|
||||||
|
|
12
tests.py
12
tests.py
|
@ -198,6 +198,7 @@ from shares import update_shared_item_federation_token
|
||||||
from shares import merge_shared_item_tokens
|
from shares import merge_shared_item_tokens
|
||||||
from shares import send_share_via_server
|
from shares import send_share_via_server
|
||||||
from shares import get_shared_items_catalog_via_server
|
from shares import get_shared_items_catalog_via_server
|
||||||
|
from shares import get_offers_via_server
|
||||||
from cwlists import add_cw_from_lists
|
from cwlists import add_cw_from_lists
|
||||||
from cwlists import load_cw_lists
|
from cwlists import load_cw_lists
|
||||||
from happening import dav_month_via_server
|
from happening import dav_month_via_server
|
||||||
|
@ -2080,6 +2081,17 @@ def test_shared_items_federation(base_dir: str) -> None:
|
||||||
assert 'DFC:supplies' in catalog_json
|
assert 'DFC:supplies' in catalog_json
|
||||||
assert len(catalog_json.get('DFC:supplies')) == 3
|
assert len(catalog_json.get('DFC:supplies')) == 3
|
||||||
|
|
||||||
|
offers_json = \
|
||||||
|
get_offers_via_server(session_bob, 'bob', bob_password,
|
||||||
|
bob_domain, bob_port,
|
||||||
|
http_prefix, True,
|
||||||
|
signing_priv_key_pem)
|
||||||
|
assert offers_json
|
||||||
|
print('Offers collection:')
|
||||||
|
pprint(offers_json)
|
||||||
|
assert isinstance(offers_json, list)
|
||||||
|
assert len(offers_json) == 1
|
||||||
|
|
||||||
print('\n\n*********************************************************')
|
print('\n\n*********************************************************')
|
||||||
print('Alice sends a message to Bob')
|
print('Alice sends a message to Bob')
|
||||||
alice_tokens_filename = \
|
alice_tokens_filename = \
|
||||||
|
|
2
utils.py
2
utils.py
|
@ -2398,7 +2398,7 @@ def _get_reserved_words() -> str:
|
||||||
'mention', 'http', 'https', 'ipfs', 'ipns',
|
'mention', 'http', 'https', 'ipfs', 'ipns',
|
||||||
'ontologies', 'data', 'postedit', 'moved',
|
'ontologies', 'data', 'postedit', 'moved',
|
||||||
'inactive', 'activitypub', 'actors',
|
'inactive', 'activitypub', 'actors',
|
||||||
'notes')
|
'notes', 'offers', 'wanted')
|
||||||
|
|
||||||
|
|
||||||
def get_nickname_validation_pattern() -> str:
|
def get_nickname_validation_pattern() -> str:
|
||||||
|
|
|
@ -11,6 +11,7 @@ import os
|
||||||
from shutil import copyfile
|
from shutil import copyfile
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from session import get_json
|
from session import get_json
|
||||||
|
from utils import get_media_extensions
|
||||||
from utils import dangerous_markup
|
from utils import dangerous_markup
|
||||||
from utils import acct_handle_dir
|
from utils import acct_handle_dir
|
||||||
from utils import remove_id_ending
|
from utils import remove_id_ending
|
||||||
|
@ -556,6 +557,94 @@ def shares_timeline_json(actor: str, page_number: int, items_per_page: int,
|
||||||
return result_json, last_page
|
return result_json, last_page
|
||||||
|
|
||||||
|
|
||||||
|
def get_shares_collection(actor: str, page_number: int, items_per_page: int,
|
||||||
|
base_dir: str, domain: str, nickname: str,
|
||||||
|
max_shares_per_account: int,
|
||||||
|
shared_items_federated_domains: [],
|
||||||
|
shares_file_type: str) -> {}:
|
||||||
|
"""Returns an ActivityStreams collection of Offer activities
|
||||||
|
https://www.w3.org/TR/activitystreams-vocabulary/#dfn-offer
|
||||||
|
"""
|
||||||
|
shares_collection = []
|
||||||
|
shares_json, _ = \
|
||||||
|
shares_timeline_json(actor, page_number, items_per_page,
|
||||||
|
base_dir, domain, nickname,
|
||||||
|
max_shares_per_account,
|
||||||
|
shared_items_federated_domains, shares_file_type)
|
||||||
|
|
||||||
|
if shares_file_type == 'shares':
|
||||||
|
share_type = 'Offer'
|
||||||
|
else:
|
||||||
|
share_type = 'Want'
|
||||||
|
|
||||||
|
for _, shared_item in shares_json.items():
|
||||||
|
if not shared_item.get('shareId'):
|
||||||
|
continue
|
||||||
|
if not shared_item.get('itemType'):
|
||||||
|
continue
|
||||||
|
share_id = shared_item['shareId'].replace('___', '://')
|
||||||
|
share_id = share_id.replace('--', '/')
|
||||||
|
offer_item = {
|
||||||
|
"@context": "https://www.w3.org/ns/activitystreams",
|
||||||
|
"summary": shared_item['summary'],
|
||||||
|
"type": share_type,
|
||||||
|
"actor": shared_item['actor'],
|
||||||
|
"id": share_id,
|
||||||
|
"published": shared_item['published'],
|
||||||
|
"object": {
|
||||||
|
"id": share_id,
|
||||||
|
"type": shared_item['itemType'].title(),
|
||||||
|
"name": shared_item['displayName'],
|
||||||
|
"published": shared_item['published'],
|
||||||
|
"attachment": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if shared_item['category']:
|
||||||
|
offer_item['object']['attachment'].append({
|
||||||
|
"type": "PropertyValue",
|
||||||
|
"name": "category",
|
||||||
|
"value": shared_item['category']
|
||||||
|
})
|
||||||
|
if shared_item['location']:
|
||||||
|
offer_item['object']['attachment'].append({
|
||||||
|
"@context": "https://www.w3.org/ns/activitystreams",
|
||||||
|
"type": "Place",
|
||||||
|
"name": shared_item['location'].title()
|
||||||
|
})
|
||||||
|
if shared_item['imageUrl']:
|
||||||
|
if '://' in shared_item['imageUrl']:
|
||||||
|
file_extension = None
|
||||||
|
accepted_types = get_media_extensions()
|
||||||
|
for mtype in accepted_types:
|
||||||
|
if shared_item['imageUrl'].endswith('.' + mtype):
|
||||||
|
if mtype == 'jpg':
|
||||||
|
mtype = 'jpeg'
|
||||||
|
if mtype == 'mp3':
|
||||||
|
mtype = 'mpeg'
|
||||||
|
file_extension = mtype
|
||||||
|
if file_extension:
|
||||||
|
media_type = 'image/' + file_extension
|
||||||
|
offer_item['object']['attachment'].append({
|
||||||
|
'mediaType': media_type,
|
||||||
|
'name': shared_item['displayName'],
|
||||||
|
'type': 'Document',
|
||||||
|
'url': shared_item['imageUrl']
|
||||||
|
})
|
||||||
|
if shared_item['itemPrice'] and shared_item['itemCurrency']:
|
||||||
|
offer_item['object']['attachment'].append({
|
||||||
|
"type": "PropertyValue",
|
||||||
|
"name": "price",
|
||||||
|
"value": shared_item['itemPrice']
|
||||||
|
})
|
||||||
|
offer_item['object']['attachment'].append({
|
||||||
|
"type": "PropertyValue",
|
||||||
|
"name": "currency",
|
||||||
|
"value": shared_item['itemCurrency']
|
||||||
|
})
|
||||||
|
shares_collection.append(offer_item)
|
||||||
|
return shares_collection
|
||||||
|
|
||||||
|
|
||||||
def post_contains_public(post_json_object: {}) -> bool:
|
def post_contains_public(post_json_object: {}) -> bool:
|
||||||
"""Does the given post contain #Public
|
"""Does the given post contain #Public
|
||||||
"""
|
"""
|
||||||
|
|
Loading…
Reference in New Issue