Skip to content

Commit

Permalink
change back to v0 posts
Browse files Browse the repository at this point in the history
  • Loading branch information
MHHukiewitz committed Oct 4, 2023
1 parent 0d10120 commit 2409a60
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 78 deletions.
2 changes: 1 addition & 1 deletion src/aleph/sdk/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -617,7 +617,7 @@ async def get_posts(
end_date = end_date.timestamp()
params["endDate"] = end_date

async with self.http_session.get("/api/v1/posts.json", params=params) as resp:
async with self.http_session.get("/api/v0/posts.json", params=params) as resp:
resp.raise_for_status()
response_json = await resp.json()
posts_raw = response_json["posts"]
Expand Down
46 changes: 20 additions & 26 deletions src/aleph/sdk/models.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from datetime import datetime
from typing import Any, Dict, List, Optional
from typing import Any, Dict, List, Optional, Union

from aleph_message.models import AlephMessage, ItemHash
from aleph_message.models import AlephMessage, ItemHash, ChainRef, ItemType, Chain, MessageConfirmation
from pydantic import BaseModel, Field


Expand All @@ -24,29 +23,24 @@ class Post(BaseModel):
A post is a type of message that can be updated. Over the get_posts API
we get the latest version of a post.
"""

item_hash: ItemHash = Field(description="Hash of the content (sha256 by default)")
content: Dict[str, Any] = Field(
description="The content.content of the POST message"
)
original_item_hash: ItemHash = Field(
description="Hash of the original content (sha256 by default)"
)
original_type: str = Field(
description="The original, user-generated 'content-type' of the POST message"
)
address: str = Field(description="The address of the sender of the POST message")
ref: Optional[str] = Field(description="Other message referenced by this one")
channel: Optional[str] = Field(
description="The channel where the POST message was published"
)
created: datetime = Field(description="The time when the POST message was created")
last_updated: datetime = Field(
description="The time when the POST message was last updated"
)

class Config:
allow_extra = False
chain: Chain = Field(description="Blockchain this post is associated with")
item_hash: ItemHash = Field(description="Unique hash for this post")
sender: str = Field(description="Address of the sender")
type: str = Field(description="Type of the POST message")
channel: Optional[str] = Field(description="Channel this post is associated with")
confirmed: bool = Field(description="Whether the post is confirmed or not")
content: Dict[str, Any] = Field(description="The content of the POST message")
item_content: Optional[str] = Field(description="The POSTs content field as serialized JSON, if of type inline")
item_type: ItemType = Field(description="Type of the item content, usually 'inline' or 'storage' for POSTs")
signature: Optional[str] = Field(description="Cryptographic signature of the message by the sender")
size: int = Field(description="Size of the post")
time: float = Field(description="Timestamp of the post")
confirmations: List[MessageConfirmation] = Field(description="Number of confirmations")
original_item_hash: ItemHash = Field(description="Hash of the original content")
original_signature: Optional[str] = Field(description="Cryptographic signature of the original message")
original_type: str = Field(description="The original type of the message")
hash: ItemHash = Field(description="Hash of the original item")
ref: Optional[Union[str, Any]] = Field(description="Other message referenced by this one")


class PostsResponse(PaginationResponse):
Expand Down
6 changes: 2 additions & 4 deletions src/aleph/sdk/node/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
from ..types import GenericMessage, StorageEnum
from .common import db
from .message import MessageModel, get_message_query, message_to_model, model_to_message
from .post import PostModel, get_post_query, message_to_post, model_to_post
from .post import PostModel, get_post_query, message_to_post, model_to_post, post_to_model


class MessageCache(BaseAlephClient):
Expand Down Expand Up @@ -112,9 +112,7 @@ def add(self, messages: Union[AlephMessage, Iterable[AlephMessage]]):
if message.content.type == "amend":
amend_messages.append(message)
continue
post = message_to_post(message).dict()
post["chain"] = message.chain.value
post["tags"] = message.content.content.get("tags", None)
post = post_to_model(message_to_post(message))
post_data.append(post)
# Check if we can now add any amend messages that had missing refs
if message.item_hash in self.missing_posts:
Expand Down
14 changes: 4 additions & 10 deletions src/aleph/sdk/node/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,15 @@
from peewee import SqliteDatabase
from playhouse.sqlite_ext import JSONField
from pydantic import BaseModel
from pydantic.json import pydantic_encoder

from aleph.sdk.conf import settings

db = SqliteDatabase(settings.CACHE_DATABASE_PATH)
T = TypeVar("T", bound=BaseModel)


class JSONDictEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, BaseModel):
return obj.dict()
return json.JSONEncoder.default(self, obj)


pydantic_json_dumps = partial(json.dumps, cls=JSONDictEncoder)
pydantic_json_dumps = partial(json.dumps, default=pydantic_encoder)


class PydanticField(JSONField, Generic[T]):
Expand All @@ -36,9 +30,9 @@ def __init__(self, *args, **kwargs):
def db_value(self, value: Optional[T]) -> Optional[str]:
if value is None:
return None
return value.json()
return pydantic_json_dumps(value)

def python_value(self, value: Optional[str]) -> Optional[T]:
if value is None:
if not value:
return None
return self.type.parse_raw(value)
100 changes: 64 additions & 36 deletions src/aleph/sdk/node/post.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
from datetime import datetime
from typing import Any, Dict, Iterable, Optional, Union
from typing import Any, Dict, Iterable, Optional, Union, List

from aleph_message.models import PostMessage
from peewee import CharField, DateTimeField, Model
from aleph_message.models import PostMessage, MessageConfirmation
from peewee import CharField, Model, BooleanField, IntegerField, FloatField
from playhouse.shortcuts import model_to_dict
from playhouse.sqlite_ext import JSONField

from aleph.sdk.models import Post
from aleph.sdk.node.common import db, pydantic_json_dumps
from aleph.sdk.node.common import db, pydantic_json_dumps, PydanticField


class PostModel(Model):
Expand All @@ -16,56 +16,84 @@ class PostModel(Model):
"""

original_item_hash = CharField(primary_key=True)
item_hash = CharField()
content = JSONField(json_dumps=pydantic_json_dumps)
original_type = CharField()
address = CharField()
ref = CharField(null=True)
original_signature = CharField()
item_hash = CharField()
chain = CharField(5)
type = CharField()
sender = CharField()
channel = CharField(null=True)
created = DateTimeField()
last_updated = DateTimeField()
confirmations: PydanticField[MessageConfirmation] = PydanticField(
type=MessageConfirmation, null=True
)
confirmed = BooleanField()
signature = CharField()
size = IntegerField(null=True)
time = FloatField()
item_type = CharField(7)
item_content = CharField(null=True)
content = JSONField(json_dumps=pydantic_json_dumps)
tags = JSONField(json_dumps=pydantic_json_dumps, null=True)
chain = CharField(5)
key = CharField(null=True)
ref = CharField(null=True)
content_type = CharField(null=True)

class Meta:
database = db


def post_to_model(post: Post) -> Dict:
return {
"item_hash": str(post.item_hash),
"content": post.content,
"item_hash": str(post.original_item_hash),
"chain": post.chain.value,
"type": post.type,
"sender": post.sender,
"channel": post.channel,
"confirmations": post.confirmations[0] if post.confirmations else None,
"confirmed": post.confirmed,
"signature": post.signature,
"size": post.size,
"time": post.time,
"original_item_hash": str(post.original_item_hash),
"original_type": post.original_type,
"address": post.address,
"original_type": post.original_type if post.original_type else post.type,
"original_signature": post.original_signature if post.original_signature else post.signature,
"item_type": post.item_type,
"item_content": post.item_content,
"content": post.content,
"tags": post.content.content.get("tags", None) if hasattr(post.content, "content") else None,
"ref": post.ref,
"channel": post.channel,
"created": post.created,
"last_updated": post.last_updated,
}


def message_to_post(message: PostMessage) -> Post:
return Post.parse_obj(
{
"item_hash": str(message.item_hash),
"content": message.content,
"original_item_hash": str(message.item_hash),
"original_type": message.content.type
if hasattr(message.content, "type")
else None,
"address": message.sender,
"ref": message.content.ref if hasattr(message.content, "ref") else None,
"channel": message.channel,
"created": datetime.fromtimestamp(message.time),
"last_updated": datetime.fromtimestamp(message.time),
}
return Post(
chain=message.chain,
item_hash=message.item_hash,
sender=message.sender,
type=message.content.type,
channel=message.channel,
confirmed=message.confirmed if message.confirmed else False,
confirmations=message.confirmations if message.confirmations else [],
content=message.content,
item_content=message.item_content,
item_type=message.item_type,
signature=message.signature,
size=message.size if message.size else len(message.content.json().encode()),
time=message.time,
original_item_hash=message.item_hash,
original_signature=message.signature,
original_type=message.content.type,
hash=message.item_hash,
ref=message.content.ref,
)


def model_to_post(item: Any) -> Post:
to_exclude = [PostModel.tags, PostModel.chain]
return Post.parse_obj(model_to_dict(item, exclude=to_exclude))
to_exclude = [PostModel.tags]
model_dict = model_to_dict(item, exclude=to_exclude)
model_dict["confirmations"] = [model_dict["confirmations"]] if model_dict["confirmations"] else []
model_dict["hash"] = model_dict["item_hash"]
return Post.parse_obj(model_dict)


def query_field(field_name, field_values: Iterable[str]):
Expand All @@ -88,14 +116,14 @@ def get_post_query(
start_date: Optional[Union[datetime, float]] = None,
end_date: Optional[Union[datetime, float]] = None,
):
query = PostModel.select().order_by(PostModel.created.desc())
query = PostModel.select().order_by(PostModel.time.desc())
conditions = []
if types:
conditions.append(query_field("original_type", types))
if refs:
conditions.append(query_field("ref", refs))
if addresses:
conditions.append(query_field("address", addresses))
conditions.append(query_field("sender", addresses))
if tags:
for tag in tags:
conditions.append(PostModel.tags.contains(tag))
Expand Down
4 changes: 3 additions & 1 deletion tests/unit/test_node_get.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,15 +176,17 @@ async def mock_message_stream():
address=get_fallback_account().get_address(),
time=0,
)
item_hash = sha256(json.dumps(content.dict()).encode()).hexdigest()
message = PostMessage(
sender=get_fallback_account().get_address(),
item_hash=sha256(json.dumps(content.dict()).encode()).hexdigest(),
item_hash=item_hash,
chain=Chain.ETH.value,
type=MessageType.post.value,
item_type="inline",
time=0,
content=content,
item_content=json.dumps(content.dict()),
signature="",
)
yield message

Expand Down

0 comments on commit 2409a60

Please sign in to comment.