mirror of
https://github.com/yzernik/squeaknode.git
synced 2026-08-15 12:50:47 +02:00
Include bearer token in twitter account (#1881)
* Got twitter forwarder working with bearer token in twitter accounts table * Update frontend to use bearer token in twitter account * Update frontend build
This commit is contained in:
parent
ae88dcc75f
commit
9f0d5e4097
27 changed files with 164 additions and 462 deletions
|
|
@ -29,11 +29,13 @@ export default function AddTwitterAccountDialog({
|
|||
const classes = useStyles();
|
||||
|
||||
const [twitterHandle, setTwitterHandle] = useState('');
|
||||
const [bearerToken, setBearerToken] = useState('');
|
||||
const [profileId, setProfileId] = useState(-1);
|
||||
const [signingProfiles, setSigningProfiles] = useState([]);
|
||||
|
||||
const resetFields = () => {
|
||||
setTwitterHandle('');
|
||||
setBearerToken('');
|
||||
setProfileId(-1);
|
||||
};
|
||||
|
||||
|
|
@ -41,6 +43,10 @@ export default function AddTwitterAccountDialog({
|
|||
setTwitterHandle(event.target.value);
|
||||
};
|
||||
|
||||
const handleChangeBearerToken = (event) => {
|
||||
setBearerToken(event.target.value);
|
||||
};
|
||||
|
||||
const handleChangeProfileId = (event) => {
|
||||
setProfileId(event.target.value);
|
||||
};
|
||||
|
|
@ -53,8 +59,8 @@ export default function AddTwitterAccountDialog({
|
|||
alert(`Error adding twitter account: ${err}`);
|
||||
};
|
||||
|
||||
const addTwitterAccount = (twitterHandle, profileId) => {
|
||||
addTwitterAccountRequest(twitterHandle, profileId, handleResponse, handleErr);
|
||||
const addTwitterAccount = (twitterHandle, profileId, bearerToken) => {
|
||||
addTwitterAccountRequest(twitterHandle, profileId, bearerToken, handleResponse, handleErr);
|
||||
};
|
||||
|
||||
const loadSigningProfiles = () => {
|
||||
|
|
@ -73,7 +79,11 @@ export default function AddTwitterAccountDialog({
|
|||
alert('twitterHandle cannot be empty.');
|
||||
return;
|
||||
}
|
||||
addTwitterAccount(twitterHandle, profileId);
|
||||
if (!bearerToken) {
|
||||
alert('bearerToken cannot be empty.');
|
||||
return;
|
||||
}
|
||||
addTwitterAccount(twitterHandle, profileId, bearerToken);
|
||||
handleClose();
|
||||
}
|
||||
|
||||
|
|
@ -107,6 +117,22 @@ export default function AddTwitterAccountDialog({
|
|||
);
|
||||
}
|
||||
|
||||
function BearerTokenInput() {
|
||||
return (
|
||||
<TextField
|
||||
id="standard-textarea-bearer-token"
|
||||
label="Bearer Token"
|
||||
variant="outlined"
|
||||
margin="normal"
|
||||
required
|
||||
value={bearerToken}
|
||||
onChange={handleChangeBearerToken}
|
||||
fullWidth
|
||||
inputProps={{ maxLength: 128 }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function SelectSigningProfile() {
|
||||
return (
|
||||
<FormControl className={classes.formControl} required style={{ minWidth: 120 }}>
|
||||
|
|
@ -156,6 +182,7 @@ export default function AddTwitterAccountDialog({
|
|||
<form className={classes.root} onSubmit={handleSubmit} noValidate autoComplete="off">
|
||||
<DialogContent>
|
||||
{AccountHandleInput()}
|
||||
{BearerTokenInput()}
|
||||
{SelectSigningProfile()}
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
|
|
|
|||
|
|
@ -1,121 +0,0 @@
|
|||
import React, { useState } from 'react';
|
||||
import {
|
||||
Dialog,
|
||||
DialogTitle,
|
||||
DialogContent,
|
||||
TextField,
|
||||
DialogActions,
|
||||
Button,
|
||||
} from '@material-ui/core';
|
||||
|
||||
// styles
|
||||
import useStyles from './styles';
|
||||
|
||||
import {
|
||||
setTwitterBearerTokenRequest,
|
||||
} from '../../squeakclient/requests';
|
||||
|
||||
|
||||
export default function SetBearerTokenDialog({
|
||||
open,
|
||||
handleClose,
|
||||
reloadBearerTokenFn,
|
||||
...props
|
||||
}) {
|
||||
const classes = useStyles();
|
||||
|
||||
const [bearerToken, setBearerToken] = useState('');
|
||||
|
||||
const resetFields = () => {
|
||||
setBearerToken('');
|
||||
};
|
||||
|
||||
const handleChangeBearerToken = (event) => {
|
||||
setBearerToken(event.target.value);
|
||||
};
|
||||
|
||||
const handleResponse = (response) => {
|
||||
// goToProfilePage(history, response.getProfileId());
|
||||
// TODO
|
||||
|
||||
if (reloadBearerTokenFn) {
|
||||
reloadBearerTokenFn();
|
||||
}
|
||||
};
|
||||
|
||||
const handleErr = (err) => {
|
||||
alert(`Error setting bearer token: ${err}`);
|
||||
};
|
||||
|
||||
const setBearerTokenRequest = (bearerToken) => {
|
||||
setTwitterBearerTokenRequest(bearerToken, handleResponse, handleErr);
|
||||
};
|
||||
|
||||
function handleSubmit(event) {
|
||||
event.preventDefault();
|
||||
console.log('bearerToken:', bearerToken);
|
||||
if (!bearerToken) {
|
||||
alert('Bearer Token cannot be empty.');
|
||||
return;
|
||||
}
|
||||
setBearerTokenRequest(bearerToken);
|
||||
handleClose();
|
||||
}
|
||||
|
||||
function SetBearerTokenInput() {
|
||||
return (
|
||||
<TextField
|
||||
id="standard-textarea"
|
||||
label="Bearer Token"
|
||||
variant="outlined"
|
||||
margin="normal"
|
||||
required
|
||||
autoFocus
|
||||
value={bearerToken}
|
||||
onChange={handleChangeBearerToken}
|
||||
fullWidth
|
||||
inputProps={{ maxLength: 256 }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function CancelButton() {
|
||||
return (
|
||||
<Button
|
||||
onClick={handleClose}
|
||||
variant="contained"
|
||||
color="secondary"
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
function SetBearerTokenButton() {
|
||||
return (
|
||||
<Button
|
||||
type="submit"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
className={classes.button}
|
||||
>
|
||||
Set Bearer Token
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Dialog open={open} onEnter={resetFields} onClose={handleClose} aria-labelledby="form-dialog-title">
|
||||
<DialogTitle id="form-dialog-title">Set Bearer Token</DialogTitle>
|
||||
<form className={classes.root} onSubmit={handleSubmit} noValidate autoComplete="off">
|
||||
<DialogContent>
|
||||
{SetBearerTokenInput()}
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
{CancelButton()}
|
||||
{SetBearerTokenButton()}
|
||||
</DialogActions>
|
||||
</form>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
{
|
||||
"name": "SetBearerTokenDialog",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"main": "SetBearerTokenDialog.js"
|
||||
}
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
import { makeStyles } from '@material-ui/styles';
|
||||
|
||||
export default makeStyles((theme) => ({
|
||||
widgetWrapper: {
|
||||
display: 'flex',
|
||||
minHeight: '100%',
|
||||
},
|
||||
widgetHeader: {
|
||||
padding: theme.spacing(3),
|
||||
paddingBottom: theme.spacing(1),
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
},
|
||||
widgetRoot: {
|
||||
boxShadow: theme.customShadows.widget,
|
||||
},
|
||||
widgetBody: {
|
||||
paddingBottom: theme.spacing(3),
|
||||
paddingRight: theme.spacing(3),
|
||||
paddingLeft: theme.spacing(3),
|
||||
},
|
||||
noPadding: {
|
||||
padding: 0,
|
||||
},
|
||||
paper: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
flexGrow: 1,
|
||||
overflow: 'hidden',
|
||||
},
|
||||
moreButton: {
|
||||
margin: -theme.spacing(1),
|
||||
padding: 0,
|
||||
width: 40,
|
||||
height: 40,
|
||||
color: theme.palette.text.hint,
|
||||
'&:hover': {
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
color: 'rgba(255, 255, 255, 0.35)',
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
|
@ -7,35 +7,25 @@ import {
|
|||
AppBar,
|
||||
Box,
|
||||
CircularProgress,
|
||||
Typography,
|
||||
} from '@material-ui/core';
|
||||
|
||||
// styles
|
||||
|
||||
// styles
|
||||
import useStyles from './styles';
|
||||
|
||||
// components
|
||||
import Widget from '../../components/Widget';
|
||||
import SetBearerTokenDialog from '../../components/SetBearerTokenDialog';
|
||||
import AddTwitterAccountDialog from '../../components/AddTwitterAccountDialog';
|
||||
import TwitterAccountListItem from '../../components/TwitterAccountListItem';
|
||||
|
||||
import CheckIcon from '@mui/icons-material/Check';
|
||||
import CloudOffIcon from '@mui/icons-material/CloudOff';
|
||||
|
||||
|
||||
import {
|
||||
getTwitterAccountsRequest,
|
||||
getTwitterStreamStatusRequest,
|
||||
} from '../../squeakclient/requests';
|
||||
|
||||
export default function Twitter() {
|
||||
const classes = useStyles();
|
||||
const [accounts, setAccounts] = useState([]);
|
||||
const [streamStatus, setStreamStatus] = useState(null);
|
||||
const [waitingForAccounts, setWaitingForAccounts] = useState(false);
|
||||
const [setBearerTokenDialogOpen, setSetBearerTokenDialogOpen] = useState(false);
|
||||
const [addAccountDialogOpen, setAddAccountDialogOpen] = useState(false);
|
||||
|
||||
|
||||
|
|
@ -54,20 +44,6 @@ export default function Twitter() {
|
|||
});
|
||||
};
|
||||
|
||||
const getStreamStatus = () => {
|
||||
getTwitterStreamStatusRequest((resp) => {
|
||||
setStreamStatus(resp);
|
||||
});
|
||||
};
|
||||
|
||||
const handleClickOpenSetBearerTokenDialog = () => {
|
||||
setSetBearerTokenDialogOpen(true);
|
||||
};
|
||||
|
||||
const handleCloseSetBearerTokenDialog = () => {
|
||||
setSetBearerTokenDialogOpen(false);
|
||||
};
|
||||
|
||||
const handleClickOpenAddAccountDialog = () => {
|
||||
setAddAccountDialogOpen(true);
|
||||
};
|
||||
|
|
@ -79,9 +55,7 @@ export default function Twitter() {
|
|||
useEffect(() => {
|
||||
getAccounts();
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
getStreamStatus();
|
||||
}, []);
|
||||
|
||||
|
||||
function TabPanel(props) {
|
||||
const {
|
||||
|
|
@ -103,43 +77,6 @@ export default function Twitter() {
|
|||
);
|
||||
}
|
||||
|
||||
function StreamStatusSummary() {
|
||||
const isStreamActive = (streamStatus ? streamStatus.getIsStreamActive() : false);
|
||||
return (
|
||||
<Grid item xs={12}>
|
||||
<Box
|
||||
p={1}
|
||||
>
|
||||
{isStreamActive
|
||||
? StreamActiveDisplay()
|
||||
: StreamNotActiveDisplay()
|
||||
}
|
||||
</Box>
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
|
||||
function StreamActiveDisplay() {
|
||||
return (
|
||||
<>
|
||||
<Typography variant="h5" component="h5">
|
||||
Twitter mirroring successfully
|
||||
</Typography>
|
||||
<CheckIcon fontSize="large" style={{ fill: 'green' }} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function StreamNotActiveDisplay() {
|
||||
return (
|
||||
<>
|
||||
<Typography variant="h5" component="h5">
|
||||
Twitter not connected
|
||||
</Typography>
|
||||
<CloudOffIcon fontSize="large" style={{ fill: 'red' }} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function AccountsGridItem(accounts) {
|
||||
return (
|
||||
|
|
@ -173,25 +110,6 @@ export default function Twitter() {
|
|||
);
|
||||
}
|
||||
|
||||
function SetBearerTokenButton() {
|
||||
return (
|
||||
<>
|
||||
<Grid item xs={12}>
|
||||
<div className={classes.root}>
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={() => {
|
||||
handleClickOpenSetBearerTokenDialog();
|
||||
}}
|
||||
>
|
||||
Set Bearer Token
|
||||
</Button>
|
||||
</div>
|
||||
</Grid>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function AddAccountButton() {
|
||||
return (
|
||||
<>
|
||||
|
|
@ -223,9 +141,7 @@ export default function Twitter() {
|
|||
<Grid container spacing={4}>
|
||||
<Grid item xs={12}>
|
||||
<Widget disableWidgetMenu>
|
||||
{SetBearerTokenButton()}
|
||||
{AddAccountButton()}
|
||||
{StreamStatusSummary()}
|
||||
{AccountsContent()}
|
||||
</Widget>
|
||||
</Grid>
|
||||
|
|
@ -251,17 +167,6 @@ export default function Twitter() {
|
|||
);
|
||||
}
|
||||
|
||||
function SetBearerTokenDialogContent() {
|
||||
return (
|
||||
<>
|
||||
<SetBearerTokenDialog
|
||||
open={setBearerTokenDialogOpen}
|
||||
handleClose={handleCloseSetBearerTokenDialog}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function AddAccountDialogContent() {
|
||||
return (
|
||||
<>
|
||||
|
|
@ -288,7 +193,6 @@ export default function Twitter() {
|
|||
return (
|
||||
<>
|
||||
{GridContent()}
|
||||
{SetBearerTokenDialogContent()}
|
||||
{AddAccountDialogContent()}
|
||||
< />
|
||||
);
|
||||
|
|
|
|||
|
|
@ -125,10 +125,6 @@ import {
|
|||
GetPeerByAddressReply,
|
||||
GetDefaultPeerPortRequest,
|
||||
GetDefaultPeerPortReply,
|
||||
GetTwitterBearerTokenRequest,
|
||||
GetTwitterBearerTokenReply,
|
||||
SetTwitterBearerTokenRequest,
|
||||
SetTwitterBearerTokenReply,
|
||||
GetTwitterAccountsRequest,
|
||||
GetTwitterAccountsReply,
|
||||
AddTwitterAccountRequest,
|
||||
|
|
@ -1160,29 +1156,6 @@ export function getDefaultPeerPortRequest(handleResponse) {
|
|||
);
|
||||
}
|
||||
|
||||
export function setTwitterBearerTokenRequest(bearerToken, handleResponse) {
|
||||
const request = new SetTwitterBearerTokenRequest();
|
||||
request.setBearerToken(bearerToken);
|
||||
makeRequest(
|
||||
'settwitterbearertoken',
|
||||
request,
|
||||
SetTwitterBearerTokenReply.deserializeBinary,
|
||||
handleResponse,
|
||||
);
|
||||
}
|
||||
|
||||
export function getTwitterBearerTokenRequest(handleResponse) {
|
||||
const request = new GetTwitterBearerTokenRequest();
|
||||
makeRequest(
|
||||
'gettwitterbearertoken',
|
||||
request,
|
||||
GetTwitterBearerTokenReply.deserializeBinary,
|
||||
(response) => {
|
||||
handleResponse(response.getBearerToken());
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
export function getTwitterAccountsRequest(handleResponse) {
|
||||
const request = new GetTwitterAccountsRequest();
|
||||
makeRequest(
|
||||
|
|
@ -1195,10 +1168,11 @@ export function getTwitterAccountsRequest(handleResponse) {
|
|||
);
|
||||
}
|
||||
|
||||
export function addTwitterAccountRequest(twitterHandle, profileId, handleResponse) {
|
||||
export function addTwitterAccountRequest(twitterHandle, profileId, bearerToken, handleResponse) {
|
||||
const request = new AddTwitterAccountRequest();
|
||||
request.setHandle(twitterHandle);
|
||||
request.setProfileId(profileId);
|
||||
request.setBearerToken(bearerToken);
|
||||
makeRequest(
|
||||
'addtwitteraccount',
|
||||
request,
|
||||
|
|
|
|||
|
|
@ -336,14 +336,6 @@ service SqueakAdmin {
|
|||
*/
|
||||
rpc GetSellPrice (GetSellPriceRequest) returns (GetSellPriceReply) {}
|
||||
|
||||
/** sqkadmin: `settwitterbearertoken`
|
||||
*/
|
||||
rpc SetTwitterBearerToken (SetTwitterBearerTokenRequest) returns (SetTwitterBearerTokenReply) {}
|
||||
|
||||
/** sqkadmin: `gettwitterbearertoken`
|
||||
*/
|
||||
rpc GetTwitterBearerToken (GetTwitterBearerTokenRequest) returns (GetTwitterBearerTokenReply) {}
|
||||
|
||||
/** sqkadmin: `addtwitteraccount`
|
||||
*/
|
||||
rpc AddTwitterAccount (AddTwitterAccountRequest) returns (AddTwitterAccountReply) {}
|
||||
|
|
@ -1273,22 +1265,6 @@ message GetSellPriceReply {
|
|||
int64 default_price_msat = 3;
|
||||
}
|
||||
|
||||
message SetTwitterBearerTokenRequest {
|
||||
/// The bearer token string.
|
||||
string bearer_token = 1;
|
||||
}
|
||||
|
||||
message SetTwitterBearerTokenReply {
|
||||
}
|
||||
|
||||
message GetTwitterBearerTokenRequest {
|
||||
}
|
||||
|
||||
message GetTwitterBearerTokenReply {
|
||||
/// The bearer token string.
|
||||
string bearer_token = 1;
|
||||
}
|
||||
|
||||
message TwitterAccount {
|
||||
/// The twitter account id
|
||||
int32 twitter_account_id = 1;
|
||||
|
|
@ -1312,6 +1288,9 @@ message AddTwitterAccountRequest {
|
|||
|
||||
/// The profile id
|
||||
int32 profile_id = 2;
|
||||
|
||||
/// The bearer token string.
|
||||
string bearer_token = 3;
|
||||
}
|
||||
|
||||
message AddTwitterAccountReply {
|
||||
|
|
|
|||
|
|
@ -1071,31 +1071,19 @@ class SqueakAdminServerHandler(object):
|
|||
default_price_msat=default_sell_price_msat,
|
||||
)
|
||||
|
||||
def handle_set_twitter_bearer_token(self, request):
|
||||
twitter_bearer_token = request.bearer_token
|
||||
logger.info("Handle set twitter bearer token with value: {}".format(
|
||||
twitter_bearer_token,
|
||||
))
|
||||
self.squeak_controller.set_twitter_bearer_token(twitter_bearer_token)
|
||||
return squeak_admin_pb2.SetTwitterBearerTokenReply()
|
||||
|
||||
def handle_get_twitter_bearer_token(self, request):
|
||||
logger.info("Handle get twitter bearer token")
|
||||
twitter_bearer_token = self.squeak_controller.get_twitter_bearer_token()
|
||||
return squeak_admin_pb2.GetTwitterBearerTokenReply(
|
||||
bearer_token=twitter_bearer_token,
|
||||
)
|
||||
|
||||
def handle_add_twitter_account(self, request):
|
||||
handle = request.handle
|
||||
profile_id = request.profile_id
|
||||
logger.info("Handle add twitter account with handle: {} and profile_id: {}".format(
|
||||
bearer_token = request.bearer_token
|
||||
logger.info("Handle add twitter account with handle: {}, profile_id: {}, bearer token: {}".format(
|
||||
handle,
|
||||
profile_id,
|
||||
bearer_token,
|
||||
))
|
||||
twitter_account_id = self.squeak_controller.add_twitter_account(
|
||||
handle,
|
||||
profile_id,
|
||||
bearer_token,
|
||||
)
|
||||
return squeak_admin_pb2.AddTwitterAccountReply(
|
||||
twitter_account_id=twitter_account_id,
|
||||
|
|
|
|||
|
|
@ -529,18 +529,6 @@ def create_app(handler, username, password):
|
|||
def getsellprice(msg):
|
||||
return handler.handle_get_sell_price(msg)
|
||||
|
||||
@app.route("/settwitterbearertoken", methods=["POST"])
|
||||
@login_required
|
||||
@protobuf_serialized(squeak_admin_pb2.SetTwitterBearerTokenRequest())
|
||||
def settwitterbearertoken(msg):
|
||||
return handler.handle_set_twitter_bearer_token(msg)
|
||||
|
||||
@app.route("/gettwitterbearertoken", methods=["POST"])
|
||||
@login_required
|
||||
@protobuf_serialized(squeak_admin_pb2.GetTwitterBearerTokenRequest())
|
||||
def gettwitterbearertoken(msg):
|
||||
return handler.handle_get_twitter_bearer_token(msg)
|
||||
|
||||
@app.route("/addtwitteraccount", methods=["POST"])
|
||||
@login_required
|
||||
@protobuf_serialized(squeak_admin_pb2.AddTwitterAccountRequest())
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
{
|
||||
"files": {
|
||||
"main.js": "/static/js/main.01fc1efa.chunk.js",
|
||||
"main.js.map": "/static/js/main.01fc1efa.chunk.js.map",
|
||||
"main.js": "/static/js/main.170c2962.chunk.js",
|
||||
"main.js.map": "/static/js/main.170c2962.chunk.js.map",
|
||||
"runtime-main.js": "/static/js/runtime-main.48a1d1b9.js",
|
||||
"runtime-main.js.map": "/static/js/runtime-main.48a1d1b9.js.map",
|
||||
"static/css/2.f68b60d4.chunk.css": "/static/css/2.f68b60d4.chunk.css",
|
||||
"static/js/2.cc4c0ab4.chunk.js": "/static/js/2.cc4c0ab4.chunk.js",
|
||||
"static/js/2.cc4c0ab4.chunk.js.map": "/static/js/2.cc4c0ab4.chunk.js.map",
|
||||
"static/js/2.033499f7.chunk.js": "/static/js/2.033499f7.chunk.js",
|
||||
"static/js/2.033499f7.chunk.js.map": "/static/js/2.033499f7.chunk.js.map",
|
||||
"index.html": "/index.html",
|
||||
"static/css/2.f68b60d4.chunk.css.map": "/static/css/2.f68b60d4.chunk.css.map",
|
||||
"static/js/2.cc4c0ab4.chunk.js.LICENSE.txt": "/static/js/2.cc4c0ab4.chunk.js.LICENSE.txt",
|
||||
"static/js/2.033499f7.chunk.js.LICENSE.txt": "/static/js/2.033499f7.chunk.js.LICENSE.txt",
|
||||
"static/media/font-awesome.min.css": "/static/media/fontawesome-webfont.f691f37e.woff",
|
||||
"static/media/google.a4fa9b6f.svg": "/static/media/google.a4fa9b6f.svg",
|
||||
"static/media/logo.31df0ce8.svg": "/static/media/logo.31df0ce8.svg"
|
||||
|
|
@ -17,7 +17,7 @@
|
|||
"entrypoints": [
|
||||
"static/js/runtime-main.48a1d1b9.js",
|
||||
"static/css/2.f68b60d4.chunk.css",
|
||||
"static/js/2.cc4c0ab4.chunk.js",
|
||||
"static/js/main.01fc1efa.chunk.js"
|
||||
"static/js/2.033499f7.chunk.js",
|
||||
"static/js/main.170c2962.chunk.js"
|
||||
]
|
||||
}
|
||||
|
|
@ -1 +1 @@
|
|||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="shortcut icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"/><meta name="theme-color" content="#000000"/><link rel="manifest" href="/manifest.json"/><title>Squeaknode</title><meta name="description" content="Squeaknode is a frontend for accessing a squeak node"><meta name="keywords" content="squeak, bitcoin, lightning"><meta name="author" content="Flatlogic LLC."><link href="/static/css/2.f68b60d4.chunk.css" rel="stylesheet"></head><body style="font-family:Roboto,sans-serif"><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(e){function r(r){for(var n,f,l=r[0],a=r[1],i=r[2],c=0,s=[];c<l.length;c++)f=l[c],Object.prototype.hasOwnProperty.call(o,f)&&o[f]&&s.push(o[f][0]),o[f]=0;for(n in a)Object.prototype.hasOwnProperty.call(a,n)&&(e[n]=a[n]);for(p&&p(r);s.length;)s.shift()();return u.push.apply(u,i||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,l=1;l<t.length;l++){var a=t[l];0!==o[a]&&(n=!1)}n&&(u.splice(r--,1),e=f(f.s=t[0]))}return e}var n={},o={1:0},u=[];function f(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,f),t.l=!0,t.exports}f.m=e,f.c=n,f.d=function(e,r,t){f.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},f.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},f.t=function(e,r){if(1&r&&(e=f(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(f.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)f.d(t,n,function(r){return e[r]}.bind(null,n));return t},f.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return f.d(r,"a",r),r},f.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},f.p="/";var l=this["webpackJsonpsqueak-node-frontend"]=this["webpackJsonpsqueak-node-frontend"]||[],a=l.push.bind(l);l.push=r,l=l.slice();for(var i=0;i<l.length;i++)r(l[i]);var p=a;t()}([])</script><script src="/static/js/2.cc4c0ab4.chunk.js"></script><script src="/static/js/main.01fc1efa.chunk.js"></script></body></html>
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="shortcut icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"/><meta name="theme-color" content="#000000"/><link rel="manifest" href="/manifest.json"/><title>Squeaknode</title><meta name="description" content="Squeaknode is a frontend for accessing a squeak node"><meta name="keywords" content="squeak, bitcoin, lightning"><meta name="author" content="Flatlogic LLC."><link href="/static/css/2.f68b60d4.chunk.css" rel="stylesheet"></head><body style="font-family:Roboto,sans-serif"><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(e){function r(r){for(var n,f,l=r[0],a=r[1],i=r[2],c=0,s=[];c<l.length;c++)f=l[c],Object.prototype.hasOwnProperty.call(o,f)&&o[f]&&s.push(o[f][0]),o[f]=0;for(n in a)Object.prototype.hasOwnProperty.call(a,n)&&(e[n]=a[n]);for(p&&p(r);s.length;)s.shift()();return u.push.apply(u,i||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,l=1;l<t.length;l++){var a=t[l];0!==o[a]&&(n=!1)}n&&(u.splice(r--,1),e=f(f.s=t[0]))}return e}var n={},o={1:0},u=[];function f(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,f),t.l=!0,t.exports}f.m=e,f.c=n,f.d=function(e,r,t){f.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},f.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},f.t=function(e,r){if(1&r&&(e=f(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(f.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)f.d(t,n,function(r){return e[r]}.bind(null,n));return t},f.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return f.d(r,"a",r),r},f.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},f.p="/";var l=this["webpackJsonpsqueak-node-frontend"]=this["webpackJsonpsqueak-node-frontend"]||[],a=l.push.bind(l);l.push=r,l=l.slice();for(var i=0;i<l.length;i++)r(l[i]);var p=a;t()}([])</script><script src="/static/js/2.033499f7.chunk.js"></script><script src="/static/js/main.170c2962.chunk.js"></script></body></html>
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -28,3 +28,4 @@ class TwitterAccount(NamedTuple):
|
|||
twitter_account_id: Optional[int]
|
||||
handle: str
|
||||
profile_id: int
|
||||
bearer_token: str
|
||||
|
|
|
|||
|
|
@ -30,4 +30,5 @@ class TwitterAccountEntry(NamedTuple):
|
|||
twitter_account_id: Optional[int]
|
||||
handle: str
|
||||
profile_id: int
|
||||
bearer_token: str
|
||||
profile: Optional[SqueakProfile]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,55 @@
|
|||
# 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.
|
||||
"""Include bearer token in twitter account.
|
||||
|
||||
Revision ID: b78f8169d063
|
||||
Revises: b6cf462aaf7c
|
||||
Create Date: 2021-12-22 13:49:11.692654
|
||||
|
||||
"""
|
||||
import sqlalchemy as sa
|
||||
from alembic import op
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'b78f8169d063'
|
||||
down_revision = 'b6cf462aaf7c'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
with op.batch_alter_table('config', schema=None) as batch_op:
|
||||
batch_op.drop_column('twitter_bearer_token')
|
||||
|
||||
with op.batch_alter_table('twitter_account', schema=None) as batch_op:
|
||||
batch_op.add_column(sa.Column('bearer_token', sa.String(
|
||||
), nullable=False, server_default=sa.text("''")))
|
||||
|
||||
|
||||
def downgrade():
|
||||
with op.batch_alter_table('twitter_account', schema=None) as batch_op:
|
||||
batch_op.drop_column('bearer_token')
|
||||
|
||||
with op.batch_alter_table('config', schema=None) as batch_op:
|
||||
batch_op.add_column(
|
||||
sa.Column('twitter_bearer_token', sa.VARCHAR(), nullable=True))
|
||||
|
|
@ -193,7 +193,6 @@ class Models:
|
|||
"config",
|
||||
self.metadata,
|
||||
Column("username", String, primary_key=True),
|
||||
Column("twitter_bearer_token", String, nullable=True),
|
||||
Column("sell_price_msat", Integer, nullable=True),
|
||||
)
|
||||
|
||||
|
|
@ -203,4 +202,5 @@ class Models:
|
|||
Column("twitter_account_id", Integer, primary_key=True),
|
||||
Column("handle", String, unique=True, nullable=False),
|
||||
Column("profile_id", Integer, nullable=False),
|
||||
Column("bearer_token", String, nullable=False),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1357,7 +1357,6 @@ class SqueakDb:
|
|||
"""
|
||||
ins = self.configs.insert().values(
|
||||
username=user_config.username,
|
||||
twitter_bearer_token=user_config.twitter_bearer_token,
|
||||
)
|
||||
with self.get_connection() as connection:
|
||||
try:
|
||||
|
|
@ -1378,16 +1377,6 @@ class SqueakDb:
|
|||
return None
|
||||
return self._parse_user_config(row)
|
||||
|
||||
def set_config_twitter_bearer_token(self, username: str, twitter_bearer_token: str) -> None:
|
||||
""" Set a config twitter bearer token. """
|
||||
stmt = (
|
||||
self.configs.update()
|
||||
.where(self.configs.c.username == username)
|
||||
.values(twitter_bearer_token=twitter_bearer_token)
|
||||
)
|
||||
with self.get_connection() as connection:
|
||||
connection.execute(stmt)
|
||||
|
||||
def set_config_sell_price_msat(self, username: str, sell_price_msat: int) -> None:
|
||||
""" Set a config sell price msat. """
|
||||
stmt = (
|
||||
|
|
@ -1417,6 +1406,7 @@ class SqueakDb:
|
|||
ins = self.twitter_accounts.insert().values(
|
||||
handle=twitter_account.handle,
|
||||
profile_id=twitter_account.profile_id,
|
||||
bearer_token=twitter_account.bearer_token,
|
||||
)
|
||||
with self.get_connection() as connection:
|
||||
try:
|
||||
|
|
@ -1600,7 +1590,6 @@ class SqueakDb:
|
|||
def _parse_user_config(self, row) -> UserConfig:
|
||||
return UserConfig(
|
||||
username=row["username"],
|
||||
twitter_bearer_token=row["twitter_bearer_token"],
|
||||
sell_price_msat=row["sell_price_msat"],
|
||||
)
|
||||
|
||||
|
|
@ -1610,5 +1599,6 @@ class SqueakDb:
|
|||
twitter_account_id=row["twitter_account_id"],
|
||||
handle=row["handle"],
|
||||
profile_id=row["profile_id"],
|
||||
bearer_token=row["bearer_token"],
|
||||
profile=profile,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -893,30 +893,15 @@ class SqueakController:
|
|||
def get_default_sell_price_msat(self) -> int:
|
||||
return self.config.node.price_msat
|
||||
|
||||
def set_twitter_bearer_token(self, twitter_bearer_token: str) -> None:
|
||||
self.insert_user_config()
|
||||
self.squeak_db.set_config_twitter_bearer_token(
|
||||
username=self.config.webadmin.username,
|
||||
twitter_bearer_token=twitter_bearer_token,
|
||||
)
|
||||
self.create_update_twitter_stream_event()
|
||||
|
||||
def get_twitter_bearer_token(self) -> Optional[str]:
|
||||
user_config = self.squeak_db.get_config(
|
||||
username=self.config.webadmin.username,
|
||||
)
|
||||
if user_config is None:
|
||||
return None
|
||||
return user_config.twitter_bearer_token
|
||||
|
||||
def get_twitter_stream_status(self) -> bool:
|
||||
return self.tweet_forwarder.is_processing()
|
||||
|
||||
def add_twitter_account(self, handle: str, profile_id: int) -> Optional[int]:
|
||||
def add_twitter_account(self, handle: str, profile_id: int, bearer_token: str) -> Optional[int]:
|
||||
twitter_account = TwitterAccount(
|
||||
twitter_account_id=None,
|
||||
handle=handle,
|
||||
profile_id=profile_id,
|
||||
bearer_token=bearer_token,
|
||||
)
|
||||
account_id = self.squeak_db.insert_twitter_account(twitter_account)
|
||||
self.create_update_twitter_stream_event()
|
||||
|
|
|
|||
|
|
@ -21,8 +21,7 @@
|
|||
# SOFTWARE.
|
||||
import logging
|
||||
import threading
|
||||
from typing import List
|
||||
from typing import Optional
|
||||
from typing import Dict
|
||||
|
||||
from squeaknode.core.twitter_account_entry import TwitterAccountEntry
|
||||
from squeaknode.node.squeak_controller import SqueakController
|
||||
|
|
@ -40,27 +39,37 @@ class TwitterForwarder:
|
|||
):
|
||||
self.retry_s = retry_s
|
||||
self.lock = threading.Lock()
|
||||
self.current_task: Optional[TwitterForwarderTask] = None
|
||||
self.current_tasks: Dict[str, TwitterForwarderTask] = {}
|
||||
|
||||
def start_processing(self, squeak_controller: SqueakController):
|
||||
with self.lock:
|
||||
if self.current_task is not None:
|
||||
self.current_task.stop_processing()
|
||||
self.current_task = TwitterForwarderTask(
|
||||
squeak_controller,
|
||||
self.retry_s,
|
||||
)
|
||||
self.current_task.start_processing()
|
||||
# Stop existing running tasks.
|
||||
for handle, task in list(self.current_tasks.items()):
|
||||
task.stop_processing()
|
||||
del self.current_tasks[handle]
|
||||
|
||||
# Start new tasks.
|
||||
for account in squeak_controller.get_twitter_accounts():
|
||||
task = TwitterForwarderTask(
|
||||
squeak_controller,
|
||||
account,
|
||||
self.retry_s,
|
||||
)
|
||||
task.start_processing()
|
||||
self.current_tasks[account.handle] = task
|
||||
|
||||
def stop_processing(self):
|
||||
with self.lock:
|
||||
if self.current_task is not None:
|
||||
self.current_task.stop_processing()
|
||||
for handle, task in list(self.current_tasks.items()):
|
||||
task.stop_processing()
|
||||
del self.current_tasks[handle]
|
||||
|
||||
def is_processing(self) -> bool:
|
||||
with self.lock:
|
||||
if self.current_task is not None:
|
||||
return self.current_task.is_processing()
|
||||
# if self.current_task is not None:
|
||||
# return self.current_task.is_processing()
|
||||
# return False
|
||||
# TODO:
|
||||
return False
|
||||
|
||||
|
||||
|
|
@ -69,9 +78,11 @@ class TwitterForwarderTask:
|
|||
def __init__(
|
||||
self,
|
||||
squeak_controller: SqueakController,
|
||||
twitter_account: TwitterAccountEntry,
|
||||
retry_s: int,
|
||||
):
|
||||
self.squeak_controller = squeak_controller
|
||||
self.twitter_account = twitter_account
|
||||
self.retry_s = retry_s
|
||||
self.stopped = threading.Event()
|
||||
self.tweet_stream = None
|
||||
|
|
@ -84,15 +95,18 @@ class TwitterForwarderTask:
|
|||
daemon=True,
|
||||
).start()
|
||||
|
||||
def setup_stream(self, bearer_token, handles):
|
||||
logger.info("Starting Twitter stream with bearer token: {} and twitter handles: {}".format(
|
||||
bearer_token,
|
||||
handles,
|
||||
def setup_stream(self):
|
||||
logger.info("Starting Twitter stream with bearer token: {} and twitter handle: {}".format(
|
||||
self.twitter_account.bearer_token,
|
||||
self.twitter_account.handle,
|
||||
))
|
||||
with self.lock:
|
||||
if self.stopped.is_set():
|
||||
return
|
||||
twitter_stream = TwitterStream(bearer_token, handles)
|
||||
twitter_stream = TwitterStream(
|
||||
self.twitter_account.bearer_token,
|
||||
[self.twitter_account.handle],
|
||||
)
|
||||
self.tweet_stream = twitter_stream.get_tweets()
|
||||
|
||||
def stop_processing(self):
|
||||
|
|
@ -111,13 +125,7 @@ class TwitterForwarderTask:
|
|||
|
||||
while not self.stopped.is_set():
|
||||
try:
|
||||
bearer_token = self.get_bearer_token()
|
||||
handles = self.get_twitter_handles()
|
||||
if not bearer_token:
|
||||
return
|
||||
if not handles:
|
||||
return
|
||||
self.setup_stream(bearer_token, handles)
|
||||
self.setup_stream()
|
||||
for tweet in self.tweet_stream.result_stream:
|
||||
self.handle_tweet(tweet)
|
||||
# TODO: use more specific error.
|
||||
|
|
@ -131,23 +139,20 @@ class TwitterForwarderTask:
|
|||
self.stopped.wait(wait_s)
|
||||
wait_s *= 2
|
||||
|
||||
def get_bearer_token(self) -> str:
|
||||
return self.squeak_controller.get_twitter_bearer_token() or ''
|
||||
# def get_twitter_handles(self) -> List[str]:
|
||||
# twitter_accounts = self.squeak_controller.get_twitter_accounts()
|
||||
# handles = [account.handle for account in twitter_accounts]
|
||||
# return handles
|
||||
|
||||
def get_twitter_handles(self) -> List[str]:
|
||||
twitter_accounts = self.squeak_controller.get_twitter_accounts()
|
||||
handles = [account.handle for account in twitter_accounts]
|
||||
return handles
|
||||
|
||||
def is_tweet_a_match(self, tweet: dict, account: TwitterAccountEntry) -> bool:
|
||||
def is_tweet_a_match(self, tweet: dict) -> bool:
|
||||
for rule in tweet['matching_rules']:
|
||||
if rule['tag'] == account.handle:
|
||||
if rule['tag'] == self.twitter_account.handle:
|
||||
return True
|
||||
return False
|
||||
|
||||
def forward_tweet(self, tweet: dict, account: TwitterAccountEntry) -> None:
|
||||
def forward_tweet(self, tweet: dict) -> None:
|
||||
self.squeak_controller.make_squeak(
|
||||
profile_id=account.profile_id,
|
||||
profile_id=self.twitter_account.profile_id,
|
||||
content_str=tweet['data']['text'],
|
||||
replyto_hash=None,
|
||||
)
|
||||
|
|
@ -155,7 +160,5 @@ class TwitterForwarderTask:
|
|||
def handle_tweet(self, tweet: dict):
|
||||
logger.info(
|
||||
"Got tweet: {}".format(tweet))
|
||||
twitter_accounts = self.squeak_controller.get_twitter_accounts()
|
||||
for account in twitter_accounts:
|
||||
if self.is_tweet_a_match(tweet, account):
|
||||
self.forward_tweet(tweet, account)
|
||||
if self.is_tweet_a_match(tweet):
|
||||
self.forward_tweet(tweet)
|
||||
|
|
|
|||
|
|
@ -386,20 +386,6 @@ def duplicate_inserted_user_config_username(squeak_db, user_config, inserted_use
|
|||
yield squeak_db.insert_config(user_config)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def user_config_with_twitter_bearer_token_username(
|
||||
squeak_db,
|
||||
user_config,
|
||||
inserted_user_config_username,
|
||||
twitter_bearer_token,
|
||||
):
|
||||
squeak_db.set_config_twitter_bearer_token(
|
||||
inserted_user_config_username,
|
||||
twitter_bearer_token,
|
||||
)
|
||||
yield inserted_user_config_username
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def user_config_with_sell_price_msat_username(
|
||||
squeak_db,
|
||||
|
|
@ -415,11 +401,12 @@ def user_config_with_sell_price_msat_username(
|
|||
|
||||
|
||||
@pytest.fixture
|
||||
def twitter_account(inserted_signing_profile_id):
|
||||
def twitter_account(inserted_signing_profile_id, twitter_bearer_token):
|
||||
yield TwitterAccount(
|
||||
twitter_account_id=None,
|
||||
handle="fake_twitter_handle",
|
||||
profile_id=inserted_signing_profile_id,
|
||||
bearer_token=twitter_bearer_token,
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -1577,17 +1564,6 @@ def test_get_config_missing(squeak_db):
|
|||
assert retrieved_config is None
|
||||
|
||||
|
||||
def test_set_twitter_bearer_token(
|
||||
squeak_db,
|
||||
user_config_with_twitter_bearer_token_username,
|
||||
twitter_bearer_token,
|
||||
):
|
||||
retrieved_config = squeak_db.get_config(
|
||||
user_config_with_twitter_bearer_token_username)
|
||||
|
||||
assert retrieved_config.twitter_bearer_token == twitter_bearer_token
|
||||
|
||||
|
||||
def test_set_sell_price_msat(
|
||||
squeak_db,
|
||||
user_config_with_sell_price_msat_username,
|
||||
|
|
@ -1609,6 +1585,7 @@ def test_get_twitter_account(
|
|||
|
||||
assert retrieved_twitter_accounts[0].handle == twitter_account.handle
|
||||
assert retrieved_twitter_accounts[0].profile_id == twitter_account.profile_id
|
||||
assert retrieved_twitter_accounts[0].bearer_token == twitter_account.bearer_token
|
||||
assert retrieved_twitter_accounts[0].profile._replace(profile_id=None) == \
|
||||
signing_profile
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue