Skip to content

Commit

Permalink
[twitter] Add donator twitter account to donations
Browse files Browse the repository at this point in the history
  • Loading branch information
nikicat committed Nov 23, 2022
1 parent 2c130d5 commit d7b6395
Show file tree
Hide file tree
Showing 21 changed files with 175 additions and 47 deletions.
5 changes: 5 additions & 0 deletions donate4fun/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
from .api_utils import get_donator, load_donator, get_db_session, task_group
from .lnd import PayInvoiceError, LnurlWithdrawResponse, lnd
from .pubsub import pubsub
from .twitter import query_or_fetch_twitter_account
from . import api_twitter, api_youtube


Expand Down Expand Up @@ -114,6 +115,10 @@ async def donate(
await apply_target(donation, request.target, db_session)
else:
raise ValidationError("donation should have a target, channel_id or receiver_id")
if request.donator_twitter_handle:
donation.donator_twitter_account = await query_or_fetch_twitter_account(
db=db_session, handle=request.donator_twitter_handle,
)
donator = await load_donator(db_session, donator.id)
# If donator has enough money (and not fulfilling his own balance) - try to pay donation instantly
use_balance = request.receiver_id != donator.id and donator.balance >= request.amount
Expand Down
1 change: 1 addition & 0 deletions donate4fun/db_donations.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ async def create_donation(self, donation: Donation):
youtube_video_id=donation.youtube_video and donation.youtube_video.id,
twitter_account_id=donation.twitter_account and donation.twitter_account.id,
twitter_tweet_id=donation.twitter_tweet and donation.twitter_tweet.id,
donator_twitter_account_id=donation.donator_twitter_account and donation.donator_twitter_account.id,
)
)
return donation
Expand Down
5 changes: 4 additions & 1 deletion donate4fun/db_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,11 +125,14 @@ class DonationDb(Base):
youtube_video = relationship(YoutubeVideoDb, lazy='joined')

twitter_account_id = Column(Uuid(as_uuid=True), ForeignKey(TwitterAuthorDb.id))
twitter_account = relationship(TwitterAuthorDb, lazy='joined')
twitter_account = relationship(TwitterAuthorDb, lazy='joined', foreign_keys=[twitter_account_id])

twitter_tweet_id = Column(Uuid(as_uuid=True), ForeignKey(TwitterTweetDb.id))
twitter_tweet = relationship(TwitterTweetDb, lazy='joined')

donator_twitter_account_id = Column(Uuid(as_uuid=True), ForeignKey(TwitterAuthorDb.id))
donator_twitter_account = relationship(TwitterAuthorDb, lazy='joined', foreign_keys=[donator_twitter_account_id])


class YoutubeChannelLink(Base):
__tablename__ = 'youtube_channel_link'
Expand Down
14 changes: 2 additions & 12 deletions donate4fun/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,28 +32,17 @@ def from_jwt(cls, token: str):
return cls(**jwt.decode(token, settings.jwt_secret, algorithms=["HS256"]))


class DonationRequest(BaseModel):
r_hash: RequestHash
donator: str
donatee: str
trigger: str | None
message: str | None


class WithdrawalToken(BaseModel):
withdrawal_id: UUID


class LoginToken(BaseModel):
donator_id: UUID


class DonateRequest(BaseModel):
amount: int
receiver_id: UUID | None
channel_id: UUID | None
twitter_account_id: UUID | None
target: HttpUrl | None
donator_twitter_handle: str | None
message: str | None


Expand Down Expand Up @@ -163,6 +152,7 @@ class Donation(BaseModel):
youtube_video: YoutubeVideo | None
twitter_account: TwitterAccount | None
twitter_tweet: TwitterTweet | None
donator_twitter_account: TwitterAccount | None
created_at: datetime = Field(default_factory=datetime.utcnow)
message: str | None = None
paid_at: datetime | None = None
Expand Down
1 change: 0 additions & 1 deletion donate4fun/screenshot.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,6 @@ async def donation_image(donation_id: UUID, screenshoter=Depends(get_screenshote
png_image: bytes = await screenshoter.take_screenshot(
'twitter-donation-sharing.html',
json=TwitterDonationShareInfo(
donator_twitter_account=None,
**donation.dict(),
).json(),
)
Expand Down
2 changes: 1 addition & 1 deletion extensions/src/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ const Options = {
options: {
twitterDefaultReply: {
type: "text",
default: "Absolutely! Take a %amount% sats tip @donate4_fun",
default: "Absolutely! Here is a %amount% sats tip via @donate4_fun %link%",
description: "Default Twitter reply",
},
},
Expand Down
7 changes: 4 additions & 3 deletions extensions/src/lib/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -218,11 +218,12 @@ async function apiPost(path, data) {
return await worker.fetch("post", path, data);
}

async function donate(amount, target) {
async function donate(amount, target, donator_twitter_handle=null) {
// Make a donation
const response = await apiPost('donate', {
amount: amount,
target: target,
amount,
target,
donator_twitter_handle,
});
const donation = response.donation;
if (donation.paid_at) {
Expand Down
13 changes: 8 additions & 5 deletions extensions/src/twitter/Bolt.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import HoldButton from "$lib/HoldButton.svelte";
import { cLog, cInfo } from "$lib/log.js";
import { worker, donate, getStatic, waitElement, pageScript, selectByPattern } from "$extlib/common.js";
import { getCurrentAccountHandle } from "./twitter.js";
export let tweetUrl;
let donating = false;
Expand All @@ -20,7 +21,7 @@
donating = true;
amount = event.detail.amount || await worker.getConfig('amount');
try {
const donation = await donate(amount, tweetUrl);
const donation = await donate(amount, tweetUrl, getCurrentAccountHandle());
donating = false;
onPaid(donation);
} catch (err) {
Expand All @@ -42,18 +43,20 @@
confetti = false;
cLog("amount", donation.amount);
if (await worker.getConfig("enableComment") && !hasReply) {
await postReply(donation.amount);
await postReply(donation);
}
});
}
async function postReply(amount) {
async function postReply(donation) {
const apiHost = await worker.getConfig("apiHost");
const replyButton = elem.parentElement.parentElement.querySelector('[data-testid="reply"]');
replyButton.click();
await waitElement('[contenteditable="true"]');
cLog("posting comment", amount);
cLog("posting comment", donation);
let comment = await worker.getConfig("twitterDefaultReply");
comment = comment.replace('%amount%', amount);
comment = comment.replace('%amount%', donation.amount);
comment = comment.replace('%link%', `${apiHost}/donation/${donation.id}`);
await pageScript.emulateKeypresses(":focus", comment);
const textElement = document.activeElement.querySelector('[data-text="true"]');
if (textElement === null)
Expand Down
4 changes: 3 additions & 1 deletion extensions/src/twitter/Popup.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@
async function donate(amount) {
try {
contentScript.onPaid(await contentScript.donate(amount, tweetUrl));
const donatorHandle = await contentScript.getCurrentTwitterHandle();
const donation = await contentScript.donate(amount, tweetUrl, donatorHandle);
contentScript.onPaid(donation);
} catch (err) {
console.error("Failed to donate", err);
const rejected = err.message === 'User rejected';
Expand Down
2 changes: 2 additions & 0 deletions extensions/src/twitter/contentscript.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import Bolt from "./Bolt.svelte";
import { cLog, cError } from "$lib/log.js";
import { registerHandlers, injectPageScript, worker } from "$extlib/common.js";
import { apiOrigin } from "$lib/api.js";
import { getCurrentAccountHandle } from "./twitter.js";

const buttonClass = "donate4fun";
let observer;
Expand All @@ -12,6 +13,7 @@ async function init() {
registerHandlers({
getTweetInfo,
isTweetPage,
getCurrentAccountHandle,
popupPath: () => "/twitter",
});
const apiHost = await worker.getConfig("apiHost");
Expand Down
6 changes: 6 additions & 0 deletions extensions/src/twitter/twitter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export function getCurrentAccountHandle() {
const prefix = 'UserAvatar-Container-';
const avatar = document.querySelector(`[data-testid="SideNav_AccountSwitcher_Button"] [data-testid^="${prefix}"]`)
return avatar.dataset.testid.replace(prefix, '');
}

20 changes: 15 additions & 5 deletions frontend/src/lib/LinkedItems.svelte
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
<script>
import { link } from "svelte-navigator";
import Button from "$lib/Button.svelte";
import Amount from "$lib/Amount.svelte";
import api from "$lib/api.js";
import { capitalize } from "$lib/utils.js";
export let items;
export let basePath;
Expand All @@ -19,7 +22,8 @@

<div class="container">
<div class="header">
<h2>Linked <b>Twitter</b> accounts:</h2>
<h2>Linked <b>{capitalize(basePath)}</b> accounts:</h2>
<a use:link href="/{basePath}/prove">Add</a>
</div>
{#await load() then}
<ul>
Expand All @@ -32,9 +36,6 @@
</div>
</li>
{/each}
<li class="add">
<Button --width=170px class="white" link="/{basePath}/prove">Add more</Button>
</li>
</ul>
{/await}
</div>
Expand All @@ -51,9 +52,17 @@
justify-content: space-between;
align-items: center;
}
h2 {
.header > h2 {
font-weight: 500;
font-size: 18px;
line-height: 24px;
font-size: 20px;
}
.header > a {
font-weight: 700;
font-size: 16px;
line-height: 19px;
}
ul {
display: flex;
flex-direction: column;
Expand All @@ -67,6 +76,7 @@ li {
justify-content: space-between;
gap: 17px;
padding: 16px;
padding-right: 0;
height: 72px;
background: linear-gradient(90deg, rgba(157, 237, 162, 0.15) 0%, rgba(157, 237, 162, 0) 100%);
border-radius: 8px;
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/lib/TwitterAccount.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
.container {
display: flex;
align-items: center;
gap: 16px;
gap: var(--gap, 0.4em);
}
.avatar {
width: var(--image-size, 32px);
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/lib/YoutubeChannel.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
span {
display: flex;
align-items: center;
gap: 0.4em;
gap: var(--gap, 0.4em);
}
img {
width: 2em;
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,9 @@ export async function sendPayment(request) {
const result = await webln.sendPayment(request);
cLog("webln.sendPayment result", result);
}

export function capitalize(s) {
if (typeof s !== 'string')
return '';
return s.charAt(0).toUpperCase() + s.slice(1);
}
32 changes: 18 additions & 14 deletions frontend/src/routes/DonatorPage.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,15 @@
</div>
<div style="height: 56px;"></div>
<LinkedItems let:item={channel} basePath="youtube" transferPath="channel">
<ChannelLogo url={channel.thumbnail_url} size=40px />
<div class="channel-name">
<YoutubeChannel linkto="withdraw" channel={channel} />
<div class="linked-item">
<YoutubeChannel linkto="withdraw" channel={channel} logo --gap=16px />
</div>
</LinkedItems>
<div style="height: 40px;"></div>
<LinkedItems let:item={account} basePath="twitter" transferPath="account">
<TwitterAccount account={account} />
<div class="linked-item">
<TwitterAccount account={account} --gap=16px />
</div>
</LinkedItems>
{:else}
<p>{donator.name}</p>
Expand All @@ -81,19 +82,21 @@
<div>Status</div>
</div>
{#each donations as donation}
{#if donation.paid_at}
<Datetime dt={donation.paid_at}/>
{:else}
<Datetime dt={donation.created_at}/>
{/if}
<a use:link href="/donation/{donation.id}">
{#if donation.paid_at}
<Datetime dt={donation.paid_at}/>
{:else}
<Datetime dt={donation.created_at}/>
{/if}
</a>
{#if donation.youtube_video}
<YoutubeVideo video={donation.youtube_video} />
{:else if donation.youtube_channel}
<YoutubeChannel channel={donation.youtube_channel} class="ellipsis" linkto=withdraw logo />
<YoutubeChannel channel={donation.youtube_channel} class="ellipsis" linkto=withdraw logo --gap=16px />
{:else if donation.twitter_account}
<TwitterAccount account={donation.twitter_account} class="ellipsis" />
<TwitterAccount account={donation.twitter_account} class="ellipsis" --image-size=24px --gap=16px />
{:else}
<Donator user={donation.receiver} ellipsis --gap=5px />
<Donator user={donation.receiver} ellipsis --gap=16px />
{/if}
<Amount amount={toText(donation.amount)}/>
<div>
Expand All @@ -119,15 +122,15 @@
flex-direction: column;
align-items: center;
gap: 8px;
padding: 36px 24px 123px;
padding: 36px 34px 123px;
}
.balance-actions {
width: 300px;
display: flex;
flex-direction: column;
gap: 8px;
}
.channel-name {
.linked-item {
width: 100%;
}
.transactions {
Expand All @@ -146,5 +149,6 @@
grid-template-columns: 109px 199px 83px 45px;
column-gap: 20px;
row-gap: 26px;
align-items: center;
}
</style>
1 change: 1 addition & 0 deletions tests/autofixtures/donate_twitter_author.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ json:
lnauth_pubkey: null
name: Admiring Serene Khorana
donator_id: 00000000-0000-0000-0000-000000000000
donator_twitter_account: null
id: 00000000-0000-0000-0000-000000000001
message: null
paid_at: null
Expand Down
8 changes: 8 additions & 0 deletions tests/autofixtures/donate_twitter_tweet.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ json:
lnauth_pubkey: null
name: Admiring Serene Khorana
donator_id: 00000000-0000-0000-0000-000000000000
donator_twitter_account:
balance: 0
handle: donate4_fun
id: 00000000-0000-0000-0000-000000000001
name: Donate4.Fun
profile_image_url: https://pbs.twimg.com/profile_images/1574697734535348224/dzdW0yfs_normal.png
total_donated: 0
user_id: 1572908920485576704
id: 00000000-0000-0000-0000-000000000001
message: null
paid_at: null
Expand Down
Loading

0 comments on commit d7b6395

Please sign in to comment.