Skip to content

Commit

Permalink
Display Authorization URL
Browse files Browse the repository at this point in the history
This commit makes the URL for authorizing the Hydator at Twitter visible
for users where the Hydrator was prevented from opening the window
directly. See #38 and #27 for context.

In addition the User's screen name is collected after linking so that
can be displayed along with the keys.
  • Loading branch information
edsu committed May 21, 2020
1 parent 09b6dd0 commit 72e4a4a
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 25 deletions.
37 changes: 27 additions & 10 deletions app/main/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import storage from 'electron-json-storage'
import TwitterPinAuth from 'twitter-pin-auth'
import { app, shell, crashReporter, BrowserWindow, Menu, ipcMain } from 'electron'

import { hydrateToStream, toCsv } from '../utils/twitter'
import { hydrateToStream, toCsv, getUserSettings } from '../utils/twitter'
import { GET_SAVED_STORE, SAVE, AUTOSAVE, AUTHORIZE, SEND_PIN } from '../renderer/actions/settings'
import { START_CSV_EXPORT, STOP_CSV_EXPORT, START_HYDRATION, STOP_HYDRATION, STOPPED_HYDRATION,
FINISH_HYDRATION, DELETE_DATASET } from '../renderer/actions/dataset'
Expand Down Expand Up @@ -126,23 +126,40 @@ app.on('ready', async () => {
})
})

ipcMain.on(AUTHORIZE, () => {
ipcMain.on(AUTHORIZE, event => {
twitterPinAuth.requestAuthUrl().
then(url => {
event.returnValue = url
shell.openExternal(url)
}).catch(err => {
console.error(err)
})
})

ipcMain.on(SEND_PIN, (event, arg) => {
twitterPinAuth.authorize(arg.pin)
.then(credentials => {
event.returnValue = credentials
}).catch(err => {
console.error(err)
event.returnValue = null
})
ipcMain.on(SEND_PIN, async (event, arg) => {
let result = null
try {
const credentials = await twitterPinAuth.authorize(arg.pin)
if (credentials) {
// use keys to get the screenName of the authenticating user
const auth = {
consumer_key: "TWITTER_CONSUMER_KEY",
consumer_secret: "TWITTER_CONSUMER_SECRET",
access_token: credentials.accessTokenKey,
access_token_secret: credentials.accessTokenSecret
}
const settings = await getUserSettings(auth)
if (settings) {
result = {
...credentials,
screenName: settings.screen_name
}
}
}
} catch(e) {
console.error(e)
}
event.returnValue = result
})

ipcMain.on(START_CSV_EXPORT, (event, arg) => {
Expand Down
8 changes: 5 additions & 3 deletions app/renderer/actions/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ export const GET_SAVED_STORE = 'GET_SAVED_STORE'
export const AUTOSAVE = 'AUTOSAVE'

export function authorize() {
ipcRenderer.send(AUTHORIZE)
const url = ipcRenderer.sendSync(AUTHORIZE)
return {
type: AUTHORIZE
type: AUTHORIZE,
url: url
}
}

Expand All @@ -29,7 +30,8 @@ export function getTwitterCredentials(pin) {
return {
type: SET_TWITTER_CREDENTIALS,
twitterAccessKey: credentials.accessTokenKey,
twitterAccessSecret: credentials.accessTokenSecret
twitterAccessSecret: credentials.accessTokenSecret,
twitterScreenName: credentials.screenName
}
}
}
Expand Down
62 changes: 51 additions & 11 deletions app/renderer/components/Settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,21 @@ const Container = styled.div`
input {
width: auto;
}
form {
padding: 0px;
}
`

const Key = styled.div`
overflow-wrap: nowrap;
font-size: smaller;
`

const ScreenName = styled.div`
font-size: smaller;
color: blue;
`

const Reset = styled.button`
color: red;
`
Expand All @@ -20,6 +28,11 @@ const Error = styled.div`
color: red;
`

const TwitterAuthUrl = styled.div`
font-style: italic;
font-size: smaller;
`

export default class Settings extends Component {

reset() {
Expand All @@ -38,6 +51,13 @@ export default class Settings extends Component {
e.preventDefault()
this.props.getTwitterCredentials(pin.value)
}}>
<p>
Note: If a browser window did not open for you please open this URL in your browser
and follow the instructions to obtain your PIN:
<br />
<br />
<TwitterAuthUrl>{this.props.settings.authorize}</TwitterAuthUrl>
</p>
<input
ref={node => pin = node}
name="twitterPin"
Expand All @@ -48,6 +68,7 @@ export default class Settings extends Component {
type="text" />
&nbsp; &nbsp; &nbsp;
<button>Submit PIN</button>
<br />
</form>
} else {
form =
Expand All @@ -59,28 +80,47 @@ export default class Settings extends Component {
</form>
}

let screenName = ""
if (this.props.settings.twitterScreenName) {
screenName = <>
<label htmlFor="screenName">Twitter Account</label>
<ScreenName>@{this.props.settings.twitterScreenName}</ScreenName>
<br />
</>
}

let settings = ""
if (this.props.settings.twitterAccessKey) {
settings = <>
{screenName}
<label htmlFor="accessKey">Access Key</label>
<Key>{ this.props.settings.twitterAccessKey }</Key>
<br />
<label htmlFor="accessKeySecret">Access Key Secret</label>
<Key>{ this.props.settings.twitterAccessSecret }</Key>
<br />
<br />
<Reset onClick={(e) => this.reset()}>Reset</Reset>
</>
}

return (
<Container>
<details open>
<summary>Settings</summary>
<p>
These are your settings that control who you connect
to the Twitter API as. You will be directed over to
Twitter to grant your Hydrator application permission to
use your account to retrieve Twitter data.
These settings that control who you connect
to the Twitter API as. When you click Link Your Twitter Account
you will be directed to Twitter to grant your Hydrator
application permission to use your account to retrieve Twitter
data.
</p>
</details>
{ form }
<br />
<label htmlFor="accessKey">Access Key:</label>
<Key>{ this.props.settings.twitterAccessKey }</Key>
<br />
<label htmlFor="accessKeySecret">Access Key Secret:</label>
<Key>{ this.props.settings.twitterAccessSecret }</Key>
{ settings }
<br />
<Error>{ error }</Error>
<br />
<Reset onClick={(e) => this.reset()}>Reset Settings</Reset>
</Container>
)
}
Expand Down
4 changes: 3 additions & 1 deletion app/renderer/reducers/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export default function settings(state = {}, action) {
...state,
twitterAccessKey: state.twitterAccessKey,
twitterAccessSecret: state.twitterAccessSecret,
twitterScreenName: state.twitterScreenName,
authorize: false,
invalidPin: false
}
Expand All @@ -20,7 +21,7 @@ export default function settings(state = {}, action) {
case AUTHORIZE: {
return {
...state,
authorize: true,
authorize: action.url,
invalidPin: false
}
}
Expand All @@ -40,6 +41,7 @@ export default function settings(state = {}, action) {
invalidPin: false,
twitterAccessKey: action.twitterAccessKey,
twitterAccessSecret: action.twitterAccessSecret,
twitterScreenName: action.twitterScreenName,
}
}

Expand Down
16 changes: 16 additions & 0 deletions app/utils/twitter.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,22 @@ export function checkTweetIdFile(path) {
})
}

/**
* Returns the Twitter account settings for the supplied keys.
* @param {*} auth an object containing Twitter API authentication keys
*/

export async function getUserSettings(auth) {
var twitter = Twit({
consumer_key: auth.consumer_key,
consumer_secret: auth.consumer_secret,
access_token: auth.access_token,
access_token_secret: auth.access_token_secret
})
const resp = await twitter.get('account/settings')
return resp.data
}

/**
* This is kind of an awful function with tons of side effects which
* will write hdyrated tweets for a set of tweet ids to an output stream
Expand Down

0 comments on commit 72e4a4a

Please sign in to comment.