mirror of
https://github.com/yzernik/squeaknode.git
synced 2026-08-19 13:18:26 +02:00
Add custom profile image (#745)
* Add profile image field to db * Add set profile image rpc * Got clear profile image working * Add has custom profile image field in profile rpc respones
This commit is contained in:
parent
4c004a60bd
commit
627acea07c
13 changed files with 226 additions and 20 deletions
|
|
@ -1,3 +1,4 @@
|
|||
import os
|
||||
import uuid
|
||||
|
||||
import grpc
|
||||
|
|
@ -7,6 +8,7 @@ from squeak.params import SelectParams
|
|||
from proto import squeak_admin_pb2
|
||||
from proto import squeak_admin_pb2_grpc
|
||||
from proto import squeak_server_pb2_grpc
|
||||
from tests.util import bytes_to_base64_string
|
||||
from tests.util import generate_signing_key
|
||||
from tests.util import get_address
|
||||
from tests.util import load_lightning_client
|
||||
|
|
@ -143,3 +145,13 @@ def peer_id(server_stub, admin_stub):
|
|||
@pytest.fixture
|
||||
def random_name():
|
||||
yield "random_name_{}".format(uuid.uuid1())
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def random_image():
|
||||
yield os.urandom(567)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def random_image_base64_string(random_image):
|
||||
yield bytes_to_base64_string(random_image)
|
||||
|
|
|
|||
|
|
@ -475,14 +475,6 @@ def test_make_contact_profile(server_stub, admin_stub):
|
|||
|
||||
|
||||
def test_set_profile_following(server_stub, admin_stub, contact_profile_id):
|
||||
# Get the existing profile
|
||||
get_squeak_profile_response = admin_stub.GetSqueakProfile(
|
||||
squeak_admin_pb2.GetSqueakProfileRequest(
|
||||
profile_id=contact_profile_id,
|
||||
)
|
||||
)
|
||||
assert not get_squeak_profile_response.squeak_profile.following
|
||||
|
||||
# Set the profile to be following
|
||||
admin_stub.SetSqueakProfileFollowing(
|
||||
squeak_admin_pb2.SetSqueakProfileFollowingRequest(
|
||||
|
|
@ -499,16 +491,24 @@ def test_set_profile_following(server_stub, admin_stub, contact_profile_id):
|
|||
)
|
||||
assert get_squeak_profile_response.squeak_profile.following
|
||||
|
||||
# Set the profile to be not following
|
||||
admin_stub.SetSqueakProfileFollowing(
|
||||
squeak_admin_pb2.SetSqueakProfileFollowingRequest(
|
||||
profile_id=contact_profile_id,
|
||||
following=False,
|
||||
)
|
||||
)
|
||||
|
||||
def test_set_profile_sharing(server_stub, admin_stub, contact_profile_id):
|
||||
# Get the existing profile
|
||||
# Get the squeak profile again
|
||||
get_squeak_profile_response = admin_stub.GetSqueakProfile(
|
||||
squeak_admin_pb2.GetSqueakProfileRequest(
|
||||
profile_id=contact_profile_id,
|
||||
)
|
||||
)
|
||||
assert not get_squeak_profile_response.squeak_profile.sharing
|
||||
assert not get_squeak_profile_response.squeak_profile.following
|
||||
|
||||
|
||||
def test_set_profile_sharing(server_stub, admin_stub, contact_profile_id):
|
||||
# Set the profile to be sharing
|
||||
admin_stub.SetSqueakProfileSharing(
|
||||
squeak_admin_pb2.SetSqueakProfileSharingRequest(
|
||||
|
|
@ -525,6 +525,22 @@ def test_set_profile_sharing(server_stub, admin_stub, contact_profile_id):
|
|||
)
|
||||
assert get_squeak_profile_response.squeak_profile.sharing
|
||||
|
||||
# Set the profile to be not sharing
|
||||
admin_stub.SetSqueakProfileSharing(
|
||||
squeak_admin_pb2.SetSqueakProfileSharingRequest(
|
||||
profile_id=contact_profile_id,
|
||||
sharing=False,
|
||||
)
|
||||
)
|
||||
|
||||
# Get the squeak profile again
|
||||
get_squeak_profile_response = admin_stub.GetSqueakProfile(
|
||||
squeak_admin_pb2.GetSqueakProfileRequest(
|
||||
profile_id=contact_profile_id,
|
||||
)
|
||||
)
|
||||
assert not get_squeak_profile_response.squeak_profile.sharing
|
||||
|
||||
|
||||
def test_rename_profile(server_stub, admin_stub, contact_profile_id, random_name):
|
||||
# Rename the profile to something new
|
||||
|
|
@ -544,6 +560,49 @@ def test_rename_profile(server_stub, admin_stub, contact_profile_id, random_name
|
|||
assert get_squeak_profile_response.squeak_profile.profile_name == random_name
|
||||
|
||||
|
||||
def test_set_profile_image(server_stub, admin_stub, contact_profile_id, random_image, random_image_base64_string):
|
||||
print("random_image: {}".format(random_image))
|
||||
print("random_image_base64_string: {}".format(random_image_base64_string))
|
||||
# Set the profile image to something new
|
||||
admin_stub.SetSqueakProfileImage(
|
||||
squeak_admin_pb2.SetSqueakProfileImageRequest(
|
||||
profile_id=contact_profile_id,
|
||||
profile_image=random_image,
|
||||
)
|
||||
)
|
||||
|
||||
# Get the squeak profile
|
||||
get_squeak_profile_response = admin_stub.GetSqueakProfile(
|
||||
squeak_admin_pb2.GetSqueakProfileRequest(
|
||||
profile_id=contact_profile_id,
|
||||
)
|
||||
)
|
||||
print("get_squeak_profile_response.squeak_profile.profile_image: {}".format(
|
||||
get_squeak_profile_response.squeak_profile.profile_image,
|
||||
))
|
||||
assert get_squeak_profile_response.squeak_profile.profile_image == random_image_base64_string
|
||||
assert get_squeak_profile_response.squeak_profile.has_custom_profile_image
|
||||
|
||||
# Clear the profile image
|
||||
admin_stub.ClearSqueakProfileImage(
|
||||
squeak_admin_pb2.ClearSqueakProfileImageRequest(
|
||||
profile_id=contact_profile_id,
|
||||
)
|
||||
)
|
||||
|
||||
# Get the squeak profile
|
||||
get_squeak_profile_response = admin_stub.GetSqueakProfile(
|
||||
squeak_admin_pb2.GetSqueakProfileRequest(
|
||||
profile_id=contact_profile_id,
|
||||
)
|
||||
)
|
||||
print("get_squeak_profile_response.squeak_profile.profile_image: {}".format(
|
||||
get_squeak_profile_response.squeak_profile.profile_image,
|
||||
))
|
||||
assert get_squeak_profile_response.squeak_profile.profile_image != random_image_base64_string
|
||||
assert not get_squeak_profile_response.squeak_profile.has_custom_profile_image
|
||||
|
||||
|
||||
def test_delete_profile(server_stub, admin_stub, contact_profile_id):
|
||||
# Delete the profile
|
||||
admin_stub.DeleteSqueakProfile(
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
from __future__ import print_function
|
||||
|
||||
import base64
|
||||
import time
|
||||
from contextlib import contextmanager
|
||||
|
||||
|
|
@ -100,6 +101,11 @@ def subtract_tweak(n, tweak):
|
|||
return scalar_to_bytes(sum_int)
|
||||
|
||||
|
||||
def bytes_to_base64_string(data: bytes) -> str:
|
||||
encoded_string = base64.b64encode(data)
|
||||
return encoded_string.decode('utf-8')
|
||||
|
||||
|
||||
@contextmanager
|
||||
def connect_peer(lightning_client, lightning_host, remote_pubkey):
|
||||
# Connect the peer
|
||||
|
|
|
|||
|
|
@ -116,6 +116,14 @@ service SqueakAdmin {
|
|||
*/
|
||||
rpc DeleteSqueakProfile (DeleteSqueakProfileRequest) returns (DeleteSqueakProfileReply) {}
|
||||
|
||||
/** sqkadmin: `setsqueakprofileimage`
|
||||
*/
|
||||
rpc SetSqueakProfileImage (SetSqueakProfileImageRequest) returns (SetSqueakProfileImageReply) {}
|
||||
|
||||
/** sqkadmin: `clearsqueakprofileimage`
|
||||
*/
|
||||
rpc ClearSqueakProfileImage (ClearSqueakProfileImageRequest) returns (ClearSqueakProfileImageReply) {}
|
||||
|
||||
/** sqkadmin: `makesqueak`
|
||||
*/
|
||||
rpc MakeSqueak (MakeSqueakRequest) returns (MakeSqueakReply) {}
|
||||
|
|
@ -359,6 +367,28 @@ message DeleteSqueakProfileRequest {
|
|||
message DeleteSqueakProfileReply {
|
||||
}
|
||||
|
||||
message SetSqueakProfileImageRequest {
|
||||
/// The profile id
|
||||
int32 profile_id = 1;
|
||||
|
||||
/// The profile image
|
||||
bytes profile_image = 2;
|
||||
}
|
||||
|
||||
message SetSqueakProfileImageReply {
|
||||
}
|
||||
|
||||
message ClearSqueakProfileImageRequest {
|
||||
/// The profile id
|
||||
int32 profile_id = 1;
|
||||
|
||||
/// The profile image
|
||||
bytes profile_image = 2;
|
||||
}
|
||||
|
||||
message ClearSqueakProfileImageReply {
|
||||
}
|
||||
|
||||
message SqueakProfile {
|
||||
/// The profile id
|
||||
int32 profile_id = 1;
|
||||
|
|
@ -377,6 +407,12 @@ message SqueakProfile {
|
|||
|
||||
/// Following
|
||||
bool following = 6;
|
||||
|
||||
/// The profile image
|
||||
string profile_image = 7;
|
||||
|
||||
/// Has custom profile image
|
||||
bool has_custom_profile_image = 8;
|
||||
}
|
||||
|
||||
message MakeSqueakRequest {
|
||||
|
|
|
|||
|
|
@ -145,7 +145,11 @@ class SqueakAdminServerHandler(object):
|
|||
squeak_profile = self.squeak_controller.get_squeak_profile(profile_id)
|
||||
if squeak_profile is None:
|
||||
return None
|
||||
logger.info("Got squeak profile with image: {}".format(
|
||||
squeak_profile.profile_image))
|
||||
squeak_profile_msg = squeak_profile_to_message(squeak_profile)
|
||||
logger.info("Got squeak profile msg with image: {}".format(
|
||||
squeak_profile_msg.profile_image))
|
||||
return squeak_admin_pb2.GetSqueakProfileReply(
|
||||
squeak_profile=squeak_profile_msg,
|
||||
)
|
||||
|
|
@ -215,6 +219,35 @@ class SqueakAdminServerHandler(object):
|
|||
self.squeak_controller.delete_squeak_profile(profile_id)
|
||||
return squeak_admin_pb2.DeleteSqueakProfileReply()
|
||||
|
||||
def handle_set_squeak_profile_image(self, request):
|
||||
profile_id = request.profile_id
|
||||
profile_image = request.profile_image
|
||||
logger.info(
|
||||
"Handle set squeak profile image with profile id: {}".format(
|
||||
profile_id,
|
||||
)
|
||||
)
|
||||
logger.info(
|
||||
"Handle set squeak profile image with image: {}".format(
|
||||
profile_image,
|
||||
)
|
||||
)
|
||||
self.squeak_controller.set_squeak_profile_image(
|
||||
profile_id, profile_image)
|
||||
return squeak_admin_pb2.SetSqueakProfileImageReply()
|
||||
|
||||
def handle_clear_squeak_profile_image(self, request):
|
||||
profile_id = request.profile_id
|
||||
logger.info(
|
||||
"Handle clear squeak profile image with profile id: {}".format(
|
||||
profile_id,
|
||||
)
|
||||
)
|
||||
self.squeak_controller.clear_squeak_profile_image(
|
||||
profile_id,
|
||||
)
|
||||
return squeak_admin_pb2.ClearSqueakProfileImageReply()
|
||||
|
||||
def handle_get_squeak_profile_private_key(self, request):
|
||||
profile_id = request.profile_id
|
||||
logger.info(
|
||||
|
|
|
|||
|
|
@ -97,6 +97,12 @@ class SqueakAdminServerServicer(squeak_admin_pb2_grpc.SqueakAdminServicer):
|
|||
def DeleteSqueakProfile(self, request, context):
|
||||
return self.handler.handle_delete_squeak_profile(request)
|
||||
|
||||
def SetSqueakProfileImage(self, request, context):
|
||||
return self.handler.handle_set_squeak_profile_image(request)
|
||||
|
||||
def ClearSqueakProfileImage(self, request, context):
|
||||
return self.handler.handle_clear_squeak_profile_image(request)
|
||||
|
||||
def GetSqueakProfilePrivateKey(self, request, context):
|
||||
return self.handler.handle_get_squeak_profile_private_key(request)
|
||||
|
||||
|
|
|
|||
|
|
@ -54,6 +54,9 @@ def squeak_profile_to_message(squeak_profile):
|
|||
if squeak_profile is None:
|
||||
return None
|
||||
has_private_key = squeak_profile.private_key is not None
|
||||
profile_image = squeak_profile.profile_image or DEFAULT_PROFILE_IMAGE
|
||||
has_custom_profile_image = squeak_profile.profile_image is not None
|
||||
image_base64_str = bytes_to_base64_string(profile_image)
|
||||
return squeak_admin_pb2.SqueakProfile(
|
||||
profile_id=squeak_profile.profile_id,
|
||||
profile_name=squeak_profile.profile_name,
|
||||
|
|
@ -61,6 +64,8 @@ def squeak_profile_to_message(squeak_profile):
|
|||
address=squeak_profile.address,
|
||||
sharing=squeak_profile.sharing,
|
||||
following=squeak_profile.following,
|
||||
profile_image=image_base64_str,
|
||||
has_custom_profile_image=has_custom_profile_image,
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -130,8 +130,9 @@ class SqueakController:
|
|||
profile_name=profile_name,
|
||||
private_key=signing_key_bytes,
|
||||
address=str(address),
|
||||
sharing=False,
|
||||
following=False,
|
||||
sharing=True,
|
||||
following=True,
|
||||
profile_image=None,
|
||||
)
|
||||
return self.squeak_db.insert_profile(squeak_profile)
|
||||
|
||||
|
|
@ -148,6 +149,7 @@ class SqueakController:
|
|||
address=str(address),
|
||||
sharing=False,
|
||||
following=False,
|
||||
profile_image=None,
|
||||
)
|
||||
return self.squeak_db.insert_profile(squeak_profile)
|
||||
|
||||
|
|
@ -161,7 +163,8 @@ class SqueakController:
|
|||
private_key=None,
|
||||
address=squeak_address,
|
||||
sharing=False,
|
||||
following=False,
|
||||
following=True,
|
||||
profile_image=None,
|
||||
)
|
||||
return self.squeak_db.insert_profile(squeak_profile)
|
||||
|
||||
|
|
@ -193,6 +196,12 @@ class SqueakController:
|
|||
def delete_squeak_profile(self, profile_id: int):
|
||||
self.squeak_db.delete_profile(profile_id)
|
||||
|
||||
def set_squeak_profile_image(self, profile_id: int, profile_image: bytes):
|
||||
self.squeak_db.set_profile_image(profile_id, profile_image)
|
||||
|
||||
def clear_squeak_profile_image(self, profile_id: int):
|
||||
self.squeak_db.set_profile_image(profile_id, None)
|
||||
|
||||
def get_squeak_profile_private_key(self, profile_id: int):
|
||||
profile = self.get_squeak_profile(profile_id)
|
||||
if profile.private_key is None:
|
||||
|
|
|
|||
|
|
@ -10,3 +10,4 @@ class SqueakProfile(NamedTuple):
|
|||
address: str
|
||||
sharing: bool
|
||||
following: bool
|
||||
profile_image: Optional[bytes]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
"""Add profile image column to profile table
|
||||
|
||||
Revision ID: 6851569c46e3
|
||||
Revises: d5a06570ed3e
|
||||
Create Date: 2021-01-28 23:25:31.015184
|
||||
|
||||
"""
|
||||
import sqlalchemy as sa
|
||||
from alembic import op
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '6851569c46e3'
|
||||
down_revision = 'd5a06570ed3e'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
with op.batch_alter_table('profile', schema=None) as batch_op:
|
||||
batch_op.add_column(
|
||||
sa.Column('profile_image', sa.Binary(), nullable=True))
|
||||
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
with op.batch_alter_table('profile', schema=None) as batch_op:
|
||||
batch_op.drop_column('profile_image')
|
||||
|
||||
# ### end Alembic commands ###
|
||||
|
|
@ -66,6 +66,7 @@ class Models:
|
|||
Column("address", String(35), unique=True, nullable=False),
|
||||
Column("sharing", Boolean, nullable=False),
|
||||
Column("following", Boolean, nullable=False),
|
||||
Column("profile_image", Binary, nullable=True),
|
||||
)
|
||||
|
||||
self.peers = Table(
|
||||
|
|
|
|||
|
|
@ -652,12 +652,15 @@ class SqueakDb:
|
|||
with self.get_connection() as connection:
|
||||
connection.execute(delete_profile_stmt)
|
||||
|
||||
# sql = """
|
||||
# DELETE FROM profile
|
||||
# WHERE profile_id=%s;
|
||||
# """
|
||||
# with self.get_cursor() as curs:
|
||||
# curs.execute(sql, (profile_id,))
|
||||
def set_profile_image(self, profile_id: int, profile_image: bytes):
|
||||
""" Set a profile image. """
|
||||
stmt = (
|
||||
self.profiles.update()
|
||||
.where(self.profiles.c.profile_id == profile_id)
|
||||
.values(profile_image=profile_image)
|
||||
)
|
||||
with self.get_connection() as connection:
|
||||
connection.execute(stmt)
|
||||
|
||||
def get_unverified_block_squeaks(self) -> List[bytes]:
|
||||
""" Get all squeaks without block header. """
|
||||
|
|
@ -1157,6 +1160,7 @@ class SqueakDb:
|
|||
address=row["address"],
|
||||
sharing=row["sharing"],
|
||||
following=row["following"],
|
||||
profile_image=row["profile_image"],
|
||||
)
|
||||
|
||||
def _parse_squeak_entry_with_profile(self, row) -> SqueakEntryWithProfile:
|
||||
|
|
|
|||
|
|
@ -75,6 +75,7 @@ def signing_profile():
|
|||
address=str(address),
|
||||
sharing=False,
|
||||
following=False,
|
||||
profile_image=None,
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue