Updrage squeaklib to 0.7.1 (#1194)

* Updrage squeaklib to 0.7.1

* Add case to handle secret key msg in peer msg handler

* Add fields for custom price and use custom price to profile table

* Got itest working with new profile fields

* Use default values for profile struct constructor

* Fix db migration to use use profile columns

* Got itest passing for set use custom price

* Show custom price or default price in profile page

* Change wording of selling with price in profile page

* Got set use custom price toggle working in configure profile dialog
This commit is contained in:
Jonathan Zernik 2021-09-05 12:30:58 -07:00 committed by GitHub
parent 8c029040bf
commit 76ad744936
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 206 additions and 19 deletions

View file

@ -17,6 +17,7 @@ import useStyles from './styles';
import {
setSqueakProfileFollowingRequest,
setSqueakProfileUseCustomPriceRequest,
} from '../../squeakclient/requests';
export default function ConfigureProfileDialog({
@ -34,12 +35,24 @@ export default function ConfigureProfileDialog({
});
};
const setUseCustomPrice = (id, useCustomPrice) => {
setSqueakProfileUseCustomPriceRequest(id, useCustomPrice, () => {
reloadProfile();
});
};
const handleSettingsFollowingChange = (event) => {
console.log(`Following changed for profile id: ${squeakProfile.getProfileId()}`);
console.log(`Following changed to: ${event.target.checked}`);
setFollowing(squeakProfile.getProfileId(), event.target.checked);
};
const handleSettingsUseCustomPriceChange = (event) => {
console.log(`UseCustomPrice changed for profile id: ${squeakProfile.getProfileId()}`);
console.log(`UseCustomPrice changed to: ${event.target.checked}`);
setUseCustomPrice(squeakProfile.getProfileId(), event.target.checked);
};
function MakeCancelButton() {
return (
<Button
@ -61,6 +74,10 @@ export default function ConfigureProfileDialog({
control={<Switch checked={squeakProfile.getFollowing()} onChange={handleSettingsFollowingChange} />}
label="Following"
/>
<FormControlLabel
control={<Switch checked={squeakProfile.getUseCustomPrice()} onChange={handleSettingsUseCustomPriceChange} />}
label="UseCustomPrice"
/>
</FormGroup>
</FormControl>
);

View file

@ -17,6 +17,7 @@ import CardHeader from '@material-ui/core/CardHeader';
import MoreVertIcon from '@material-ui/icons/MoreVert';
import VpnKeyIcon from '@material-ui/icons/VpnKey';
import LocalOfferIcon from '@material-ui/icons/LocalOffer';
// styles
import useStyles from './styles';
@ -225,6 +226,19 @@ export default function SqueakProfileDetailItem({
);
}
function CustomPriceContent() {
return (
<Typography variant="body2" color="textSecondary" component="p">
<LocalOfferIcon />
{' '}
{(squeakProfile.getUseCustomPrice()) ?
<>Selling with custom price: {squeakProfile.getCustomPriceMsat()} msats</> :
<>Selling with default price</>
}
</Typography>
);
}
return (
<>
<Card className={classes.root}>
@ -271,6 +285,9 @@ export default function SqueakProfileDetailItem({
<SqueakProfileFollowingIndicator
squeakProfile={squeakProfile}
/>
<CustomPriceContent
/>
</CardContent>
<CardActions>
<Button

View file

@ -18,6 +18,7 @@ import {
GetSqueakProfileRequest,
GetTimelineSqueakDisplaysRequest,
SetSqueakProfileFollowingRequest,
SetSqueakProfileUseCustomPriceRequest,
GetPeersRequest,
PayOfferRequest,
GetBuyOffersRequest,
@ -183,6 +184,15 @@ export function setSqueakProfileFollowingRequest(id, following, handleResponse)
});
}
export function setSqueakProfileUseCustomPriceRequest(id, useCustomPrice, handleResponse) {
const request = new SetSqueakProfileUseCustomPriceRequest();
request.setProfileId(id);
request.setUseCustomPrice(useCustomPrice);
client.setSqueakProfileUseCustomPrice(request, {}, (err, response) => {
handleResponse(response);
});
}
export function renameSqueakProfileRequest(id, profileName, handleResponse) {
const request = new RenameSqueakProfileRequest();
request.setProfileId(id);

View file

@ -309,6 +309,32 @@ def test_set_profile_following(admin_stub, contact_profile_id):
assert not squeak_profile.following
def test_set_profile_use_custom_price(admin_stub, contact_profile_id):
# Set the profile to use_custom_price
admin_stub.SetSqueakProfileUseCustomPrice(
squeak_admin_pb2.SetSqueakProfileUseCustomPriceRequest(
profile_id=contact_profile_id,
use_custom_price=True,
)
)
# Get the squeak profile again
squeak_profile = get_squeak_profile(admin_stub, contact_profile_id)
assert squeak_profile.use_custom_price
# Set the profile to not use custom price
admin_stub.SetSqueakProfileUseCustomPrice(
squeak_admin_pb2.SetSqueakProfileUseCustomPriceRequest(
profile_id=contact_profile_id,
use_custom_price=False,
)
)
# Get the squeak profile again
squeak_profile = get_squeak_profile(admin_stub, contact_profile_id)
assert not squeak_profile.use_custom_price
def test_rename_profile(admin_stub, contact_profile_id, random_name):
# Rename the profile to something new
admin_stub.RenameSqueakProfile(

View file

@ -104,6 +104,10 @@ service SqueakAdmin {
*/
rpc SetSqueakProfileFollowing (SetSqueakProfileFollowingRequest) returns (SetSqueakProfileFollowingReply) {}
/** sqkadmin: `setsqueakprofileusecustomprice`
*/
rpc SetSqueakProfileUseCustomPrice (SetSqueakProfileUseCustomPriceRequest) returns (SetSqueakProfileUseCustomPriceReply) {}
/** sqkadmin: `renamesqueakprofile`
*/
rpc RenameSqueakProfile (RenameSqueakProfileRequest) returns (RenameSqueakProfileReply) {}
@ -411,6 +415,17 @@ message SetSqueakProfileFollowingRequest {
message SetSqueakProfileFollowingReply {
}
message SetSqueakProfileUseCustomPriceRequest {
/// The profile id
int32 profile_id = 1;
/// Use custom price
bool use_custom_price = 2;
}
message SetSqueakProfileUseCustomPriceReply {
}
message RenameSqueakProfileRequest {
/// The profile id
int32 profile_id = 1;
@ -475,11 +490,17 @@ message SqueakProfile {
/// Following
bool following = 5;
/// Following
bool use_custom_price = 6;
/// The price in msats
int64 custom_price_msat = 7;
/// The profile image
string profile_image = 6;
string profile_image = 8;
/// Has custom profile image
bool has_custom_profile_image = 7;
bool has_custom_profile_image = 9;
}
message MakeSqueakRequest {

View file

@ -4,4 +4,4 @@ grpcio
grpcio-tools
importlib_resources==1.4.0
pytest
squeakpy==0.7.0
squeakpy==0.7.1

View file

@ -15,5 +15,5 @@ psycopg2
pyzmq
requests
SQLAlchemy
squeakpy==0.7.0
squeakpy==0.7.1
typed-config

View file

@ -103,7 +103,7 @@ setup(
include_package_data=True,
zip_safe=False,
install_requires=[
'squeakpy>=0.7.0',
'squeakpy>=0.7.1',
'importlib_resources',
'argparse',
'googleapis-common-protos',

View file

@ -83,6 +83,8 @@ def squeak_profile_to_message(squeak_profile: SqueakProfile) -> squeak_admin_pb2
has_private_key=has_private_key,
address=squeak_profile.address,
following=squeak_profile.following,
use_custom_price=squeak_profile.use_custom_price,
custom_price_msat=squeak_profile.custom_price_msat,
profile_image=image_base64_str,
has_custom_profile_image=has_custom_profile_image,
)

View file

@ -223,6 +223,19 @@ class SqueakAdminServerHandler(object):
profile_id, following)
return squeak_admin_pb2.SetSqueakProfileFollowingReply()
def handle_set_squeak_profile_use_custom_price(self, request):
profile_id = request.profile_id
use_custom_price = request.use_custom_price
logger.info(
"Handle set squeak profile use_custom_price with profile id: {}, use_custom_price: {}".format(
profile_id,
use_custom_price,
)
)
self.squeak_controller.set_squeak_profile_use_custom_price(
profile_id, use_custom_price)
return squeak_admin_pb2.SetSqueakProfileUseCustomPriceReply()
def handle_rename_squeak_profile(self, request):
profile_id = request.profile_id
profile_name = request.profile_name

View file

@ -128,6 +128,9 @@ class SqueakAdminServerServicer(squeak_admin_pb2_grpc.SqueakAdminServicer):
def SetSqueakProfileFollowing(self, request, context):
return self.handler.handle_set_squeak_profile_following(request)
def SetSqueakProfileUseCustomPrice(self, request, context):
return self.handler.handle_set_squeak_profile_use_custom_price(request)
def RenameSqueakProfile(self, request, context):
return self.handler.handle_rename_squeak_profile(request)

View file

@ -25,9 +25,11 @@ from typing import Optional
class SqueakProfile(NamedTuple):
"""Represents a user who can author squeaks."""
profile_id: Optional[int]
profile_name: str
private_key: Optional[bytes]
address: str
following: bool
profile_image: Optional[bytes]
profile_id: Optional[int] = None
private_key: Optional[bytes] = None
following: bool = True
use_custom_price: bool = False
custom_price_msat: int = 0
profile_image: Optional[bytes] = None

View file

@ -0,0 +1,58 @@
# MIT License
#
# Copyright (c) 2020 Jonathan Zernik
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
"""Add custom price and use custom price columns to profile
Revision ID: af0082f29c93
Revises: 814be7653a69
Create Date: 2021-09-05 09:45:54.290859
"""
import sqlalchemy as sa
from alembic import op
from sqlalchemy import text
from sqlalchemy.sql import expression
# revision identifiers, used by Alembic.
revision = 'af0082f29c93'
down_revision = '814be7653a69'
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('use_custom_price',
sa.Boolean(), nullable=False, server_default=expression.false()))
batch_op.add_column(sa.Column('custom_price_msat',
sa.Integer(), nullable=False, server_default=text('0')))
# ### 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('custom_price_msat')
batch_op.drop_column('use_custom_price')
# ### end Alembic commands ###

View file

@ -106,6 +106,8 @@ class Models:
Column("private_key", Binary, nullable=True),
Column("address", String(35), unique=True, nullable=False),
Column("following", Boolean, nullable=False),
Column("use_custom_price", Boolean, nullable=False, default=False),
Column("custom_price_msat", Integer, nullable=False, default=0),
Column("profile_image", Binary, nullable=True),
sqlite_autoincrement=True,
)

View file

@ -757,6 +757,16 @@ class SqueakDb:
with self.get_connection() as connection:
connection.execute(stmt)
def set_profile_use_custom_price(self, profile_id: int, use_custom_price: bool) -> None:
""" Set a profile use custom price. """
stmt = (
self.profiles.update()
.where(self.profiles.c.profile_id == profile_id)
.values(use_custom_price=use_custom_price)
)
with self.get_connection() as connection:
connection.execute(stmt)
def set_profile_name(self, profile_id: int, profile_name: str) -> None:
""" Set a profile name. """
stmt = (
@ -1270,6 +1280,8 @@ class SqueakDb:
private_key=private_key,
address=row["address"],
following=row["following"],
use_custom_price=row["use_custom_price"],
custom_price_msat=row["custom_price_msat"],
profile_image=row["profile_image"],
)

View file

@ -85,6 +85,8 @@ class PeerMessageHandler:
self.handle_notfound(msg)
elif msg.command == b'offer':
self.handle_offer(msg)
elif msg.command == b'secretkey':
self.handle_secret_key(msg)
elif msg.command == b'subscribe':
self.handle_subscribe(msg)
else:
@ -167,6 +169,12 @@ class PeerMessageHandler:
self.peer.remote_address,
)
def handle_secret_key(self, msg):
self.squeak_controller.unlock_squeak(
msg.hashSqk,
msg.secretKey,
)
def handle_subscribe(self, msg):
self._send_reply_invs(msg.locator)
self.peer.set_subscription(msg)

View file

@ -205,12 +205,9 @@ class SqueakController:
signing_key_str = str(signing_key)
signing_key_bytes = signing_key_str.encode()
squeak_profile = SqueakProfile(
profile_id=None,
profile_name=profile_name,
private_key=signing_key_bytes,
address=str(address),
following=True,
profile_image=None,
)
profile_id = self.squeak_db.insert_profile(squeak_profile)
self.update_subscriptions()
@ -223,12 +220,9 @@ class SqueakController:
signing_key_str = str(signing_key)
signing_key_bytes = signing_key_str.encode()
squeak_profile = SqueakProfile(
profile_id=None,
profile_name=profile_name,
private_key=signing_key_bytes,
address=str(address),
following=True,
profile_image=None,
)
profile_id = self.squeak_db.insert_profile(squeak_profile)
self.update_subscriptions()
@ -246,12 +240,8 @@ class SqueakController:
),
)
squeak_profile = SqueakProfile(
profile_id=None,
profile_name=profile_name,
private_key=None,
address=squeak_address,
following=True,
profile_image=None,
)
profile_id = self.squeak_db.insert_profile(squeak_profile)
self.update_subscriptions()
@ -279,6 +269,10 @@ class SqueakController:
self.squeak_db.set_profile_following(profile_id, following)
self.update_subscriptions()
def set_squeak_profile_use_custom_price(self, profile_id: int, use_custom_price: bool) -> None:
self.squeak_db.set_profile_use_custom_price(
profile_id, use_custom_price)
def rename_squeak_profile(self, profile_id: int, profile_name: str) -> None:
self.squeak_db.set_profile_name(profile_id, profile_name)

View file

@ -90,6 +90,8 @@ def signing_profile():
private_key=signing_key_bytes,
address=str(address),
following=False,
use_custom_price=False,
custom_price_msat=0,
profile_image=None,
)