summaryrefslogtreecommitdiffstats
path: root/api/activitypub/utils.py
blob: 3eb6030e1cbb8e14a2df1fade5cf47effc3a551e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
from flask import current_app
from little_boxes.activitypub import ActivityType
from little_boxes import activitypub as ap
from typing import Dict, Any
from .vars import DEFAULT_CTX

ObjectType = Dict[str, Any]


def ap_url(klass, username):
    if klass == "url":
        return f"https://{current_app.config['AP_DOMAIN']}/user/{username}"
    elif klass == "shared_inbox":
        return f"https://{current_app.config['AP_DOMAIN']}/inbox"
    elif klass == "inbox":
        return f"https://{current_app.config['AP_DOMAIN']}" f"/user/{username}/inbox"
    elif klass == "outbox":
        return f"https://{current_app.config['AP_DOMAIN']}" f"/user/{username}/outbox"
    elif klass == "followings":
        return f"https://{current_app.config['AP_DOMAIN']}" f"/user/{username}/followings"
    elif klass == "followers":
        return f"https://{current_app.config['AP_DOMAIN']}" f"/user/{username}/followers"
    else:
        return None


def full_url(path):
    if path.startswith("http://") or path.startswith("https://"):
        return path
    root = current_app.config["AP_DOMAIN"]
    if path.startswith("/"):
        return root + path[1:]
    elif path.startswith("/"):
        return root + "/" + path
    else:
        return root + path


def embed_collection(total_items, first_page_id):
    """Helper creating a root OrderedCollection
    with a link to the first page."""
    return {
        "type": ap.ActivityType.ORDERED_COLLECTION.value,
        "totalItems": total_items,
        "first": f"{first_page_id}?page=first",
        "id": first_page_id,
    }


def add_extra_collection(item: Dict[str, Any]) -> Dict[str, Any]:
    if item["type"] != ActivityType.CREATE.value:
        return item

    item["object"]["replies"] = embed_collection(
        item.get("meta", {}).get("count_direct_reply", 0), f'{item["id"]}/replies'
    )

    item["object"]["likes"] = embed_collection(item.get("meta", {}).get("count_like", 0), f'{item["id"]}/likes')

    item["object"]["shares"] = embed_collection(item.get("meta", {}).get("count_boost", 0), f'{item["id"]}/shares')

    return item


def remove_context(activity: Dict[str, Any]) -> Dict[str, Any]:
    if "@context" in activity:
        del activity["@context"]
    return activity


def activity_from_doc(item: Dict[str, Any], embed: bool = False) -> Dict[str, Any]:
    item = add_extra_collection(item)
    activity = clean_activity(item)
    if embed:
        return remove_context(activity)
    return activity


def clean_activity(activity: ObjectType) -> Dict[str, Any]:
    """Clean the activity before rendering it.
    - Remove the hidden bco and bcc field
    """
    for field in ["bto", "bcc", "source"]:
        if field in activity:
            del activity[field]
        if activity["type"] == "Create" and field in activity["object"]:
            del activity["object"][field]
    return activity


def build_ordered_collection(items, actor_id, page, limit=50, switch_side=False):
    try:
        total_items = len(items)
    except TypeError:
        total_items = items.count()

    if total_items <= 0:
        return {
            "@context": DEFAULT_CTX,
            "id": f"{actor_id}/followers",
            "totalItems": 0,
            "type": ap.ActivityType.ORDERED_COLLECTION.value,
            "orderedItems": [],
        }

    if not page:
        resp = {
            "@context": DEFAULT_CTX,
            "id": f"{actor_id}/followers",
            "totalItems": total_items,
            "type": ap.ActivityType.ORDERED_COLLECTION.value,
            "first": {
                "id": f"{actor_id}/followers?page=0",
                "orderedItems": [(item.target.url if switch_side else item.actor.url) for item in items],
                "partOf": f"{actor_id}/followers",
                "totalItems": total_items,
                "type": ap.ActivityType.ORDERED_COLLECTION_PAGE.value,
            },
        }
        if total_items == limit:
            resp["first"]["next"] = f"{actor_id}/followers?page=1"

        return resp

    # return resp