Skip to content

Commit

Permalink
Update WebApp to handle Twitter V2 API -- Sign in with Twitter is wor…
Browse files Browse the repository at this point in the history
  • Loading branch information
SailingSteve committed Mar 3, 2024
1 parent 85ba568 commit d3ad999
Show file tree
Hide file tree
Showing 13 changed files with 114 additions and 40 deletions.
7 changes: 6 additions & 1 deletion docs/working/SECURE_CERTIFICATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,17 @@ In WebApp/src/js/config.js, set SECURE_CERTIFICATE_INSTALLED to true, and then u

WebApp will startup at http://localhost:3000

## Signing in with Facebook on your dev machine
## Signing in with Facebook and Twitter on your dev machine
### Make a small necessary change to your /etc/hosts

Facebook will no longer redirect to localhost, so we make a second alias for 127.0.0.1 with this specific made up
domain: `wevotedeveloper.com` by running the following command in a terminal:

This `wevotedeveloper.com` is also needed to debug "Sign in with Twitter" while using the `wevotedeveloper.com` domain for your local Python API server.
NOTE: As of March 2024, Chrome stopped responding to this domain (possibly since it can't match it with a public DNS lookup), so you will have to debug this setup with Safari.
Safari has a version of Devtools called "Web Inspector" that you get to by right-clicking in the tab, and clicking "Inspect Element". Devtools and Web
Inspector share the Chromium code base and have almost identical capabilities.

`sudo node node/updateHosts.js`

The run will look like this
Expand Down
1 change: 1 addition & 0 deletions src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,7 @@ class App extends Component {
<Route path="/terms" component={TermsOfService} />
<Route path="/twitter_sign_in" exact><TwitterSignInProcess /></Route>
<Route path="/twittersigninprocess/:sign_in_step" component={TwitterSignInProcess} />
<Route path="/twittersigninprocess" component={TwitterSignInProcess} />
<Route path="/unsubscribe/:subscription_secret_key/:unsubscribe_modifier/instant" exact component={(props) => <UnsubscribeRoot {...props} instantUnsubscribe />} />
<Route path="/unsubscribe/:subscription_secret_key/:unsubscribe_modifier" exact component={UnsubscribeRoot} />
<Route path="/unsubscribe/:subscription_secret_key" exact component={UnsubscribeRoot} />
Expand Down
17 changes: 9 additions & 8 deletions src/js/actions/TwitterActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,6 @@ export default {
});
},

twitterNativeSignInSave (twitterAccessToken, twitterAccessTokenSecret) {
Dispatcher.loadEndpoint('twitterNativeSignInSave',
{
twitter_access_token: twitterAccessToken,
twitter_access_token_secret: twitterAccessTokenSecret,
});
},

twitterProcessDeferredImages (twitterImageLoadInfo) {
Dispatcher.loadEndpoint('twitterProcessDeferredImages', {
status: twitterImageLoadInfo.status,
Expand All @@ -54,4 +46,13 @@ export default {
});
},

twitterOauth1UserHandler (oauthToken, oauthVerifier) { // For twitter V2 API, March 2024
// console.log('twitterOauth1UserHandler: ', oauthToken, oauthVerifier);
Dispatcher.loadEndpoint('twitterOauth1UserHandler',
{
oauth_token: oauthToken,
oauth_verifier: oauthVerifier,
});
},

};
1 change: 1 addition & 0 deletions src/js/components/Twitter/TwitterSignIn.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ class TwitterSignIn extends Component {
twitterSignInCrash: false,
twitterSignInStartSubmitted: false,
};
oAuthLog(`twitterSignIn redirect url = ${returnURL}`);
}

componentDidMount () {
Expand Down
53 changes: 53 additions & 0 deletions src/js/config - wevotedeveloper SSL Web and local API.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/* eslint-disable */
// Note that we import these values where needed as "webAppConfig"
module.exports = {
WE_VOTE_URL_PROTOCOL: 'https://', // "http://" for local dev or "https://" for live server
WE_VOTE_HOSTNAME: 'wevotedeveloper.com:3000', // This should be without "http...". This is "WeVote.US" on live server.
WE_VOTE_IMAGE_PATH_FOR_CORDOVA: 'https://wevote.us', // If you are not working with Cordova, you don't need to change this
SECURE_CERTIFICATE_INSTALLED: false,

WE_VOTE_SERVER_ROOT_URL: 'https://wevotedeveloper.com:8000/',
WE_VOTE_SERVER_ADMIN_ROOT_URL: 'https://wevotedeveloper.com:8000/admin/',
WE_VOTE_SERVER_API_ROOT_URL: 'https://wevotedeveloper.com:8000/apis/v1/',
WE_VOTE_SERVER_API_CDN_ROOT_URL: 'https://wevotedeveloper.com:8000/apis/v1/',

ENABLE_NEXT_RELEASE_FEATURES: false,
ENABLE_WORKBOX_SERVICE_WORKER: false, // After setting this false, recompile, then in Chrome DevTools go to Application Tab, Application/Service Worker and for the sw.js click the "unregister" button to the right

DEBUG_MODE: false,
SHOW_TEST_OPTIONS: false, // On the DeviceDialog

LOG_RENDER_EVENTS: false,
LOG_ONLY_FIRST_RENDER_EVENTS: false,
LOG_HTTP_REQUESTS: false,
LOG_ROUTING: false,
LOG_SIGNIN_STEPS: false,
LOG_CORDOVA_OFFSETS: false,
SHOW_CORDOVA_URL_FIELD: false, // Only needed for debugging in Cordova

// Use 1 or 0 as opposed to true or false
test: {
use_test_election: 0,
},

location: {
text_for_map_search: '',
},

ENABLE_FACEBOOK: false,
ENABLE_TWITTER: true,
ENABLE_PAY_TO_PROMOTE: false,

// API Keys, some of these are publishable (not secret)
FACEBOOK_APP_ID: "1097389196952441",
FULL_STORY_ORG: '',
GOOGLE_ADS_TRACKING_ID: 'T',
GOOGLE_ANALYTICS_TRACKING_ID: '',
GOOGLE_MAPS_API_KEY: '',
GOOGLE_PEOPLE_API_KEY: '',
GOOGLE_PEOPLE_API_CLIENT_ID: '',
GOOGLE_RECAPTCHA_KEY: '',
OPEN_REPLAY_PROJECT_KEY: '',
OPEN_REPLAY_INGEST_POINT: 'https://openreplay.wevote.us/ingest',
STRIPE_API_KEY: "",
};
29 changes: 27 additions & 2 deletions src/js/pages/Process/TwitterSignInProcess.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,29 @@ export default class TwitterSignInProcess extends Component {
savingAccount: false,
redirectInProgress: false,
twitterAuthResponse: {},
redirectCount: 0,
};
this.twitterOauthLeg3 = this.twitterOauthLeg3.bind(this);
}

componentDidMount () {
// console.log('--------------- TwitterSignInProcess componentDidMount');
this.appStateSubscription = messageService.getMessage().subscribe(() => this.onAppObservableStoreChange());
this.twitterStoreListener = TwitterStore.addListener(this.onTwitterStoreChange.bind(this));
this.voterStoreListener = VoterStore.addListener(this.onVoterStoreChange.bind(this));
this.twitterSignInRetrieve();
window.scrollTo(0, 0);
const { location: { search } } = this.props;
const { redirectCount } = this.state;
oAuthLog('TwitterSignInProcess search props: ', search);
const urlParams = new URLSearchParams(search);
const oauthToken = urlParams.get('oauth_token');
const oauthVerifier = urlParams.get('oauth_verifier');
if (oauthToken && oauthVerifier && redirectCount === 0) {
oAuthLog('TwitterSignInProcess received redirect from Twitter redirectCount: ', redirectCount, ', oauthToken: ', oauthToken, ', oauthVerifier: ', oauthVerifier);
this.setState({ redirectCount: (redirectCount + 1) });
TwitterActions.twitterOauth1UserHandler(oauthToken, oauthVerifier);
this.twitterSignInRetrieve();
}
}

componentWillUnmount () {
Expand All @@ -54,7 +68,10 @@ export default class TwitterSignInProcess extends Component {
const { mergingTwoAccounts, savingAccount } = this.state;
console.log('TwitterSignInProcess onTwitterStoreChange, twitterAuthResponse:', twitterAuthResponse);

if (twitterAuthResponse.twitter_sign_in_failed) {
if (twitterAuthResponse.twitter_sign_in_failed === undefined && twitterAuthResponse.twitter_oauth_voter_info_stored_in_db) {
oAuthLog('Twitter sign undefined, but oauth_voter_info_stored_in_db - calling twitterSignInRetrieve()');
this.twitterSignInRetrieve();
} else if (twitterAuthResponse.twitter_sign_in_failed) {
oAuthLog('Twitter sign in failed - push to /settings/account');
historyPush({
pathname: '/settings/account', // SnackNotifier that handles this is in SettingsDashboard
Expand Down Expand Up @@ -191,9 +208,17 @@ export default class TwitterSignInProcess extends Component {
}

twitterSignInRetrieve () {
oAuthLog('Twitter twitterSignInRetrieve on TwitterSignInProcess component mount');
TwitterActions.twitterSignInRetrieve();
}

twitterOauthLeg3 (oauthToken, oauthVerifier) {
const { redirectCount } = this.state;
oAuthLog('TwitterSignInProcess received redirect from Twitter redirectCount: ', redirectCount, ', oauthToken: ', oauthToken, ', oauthVerifier: ', oauthVerifier);
this.setState({ redirectCount: (redirectCount + 1) });
TwitterActions.twitterOauth1UserHandler(oauthToken, oauthVerifier);
}

render () {
renderLog('TwitterSignInProcess'); // Set LOG_RENDER_EVENTS to log all renders
const { redirectInProgress, twitterAuthResponse } = this.state;
Expand Down
1 change: 0 additions & 1 deletion src/js/stores/BallotStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -879,7 +879,6 @@ class BallotStore extends ReduceStore {
BallotActions.voterBallotItemsRetrieve();
return this.resetState();

case 'twitterNativeSignInSave':
case 'twitterSignInRetrieve':
case 'voterEmailAddressSignIn':
case 'voterFacebookSignInRetrieve':
Expand Down
1 change: 0 additions & 1 deletion src/js/stores/FriendStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,6 @@ class FriendStore extends ReduceStore {
currentFriendsOrganizationWeVoteIds,
};

case 'twitterNativeSignInSave':
case 'twitterSignInRetrieve':
case 'voterEmailAddressSignIn':
case 'voterFacebookSignInRetrieve':
Expand Down
1 change: 0 additions & 1 deletion src/js/stores/IssueStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -966,7 +966,6 @@ class IssueStore extends ReduceStore {
issueWeVoteIdsUnderEachBallotItem,
organizationWeVoteIdsLinkedToIssueDict,
};
case 'twitterNativeSignInSave':
case 'twitterSignInRetrieve':
case 'voterEmailAddressSignIn':
case 'voterFacebookSignInRetrieve':
Expand Down
1 change: 0 additions & 1 deletion src/js/stores/OrganizationStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -1006,7 +1006,6 @@ class OrganizationStore extends ReduceStore {
organizationWeVoteIdsVoterIsIgnoring,
};

case 'twitterNativeSignInSave':
case 'twitterSignInRetrieve':
case 'voterEmailAddressSignIn':
case 'voterFacebookSignInRetrieve':
Expand Down
1 change: 0 additions & 1 deletion src/js/stores/SupportStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,6 @@ class SupportStore extends ReduceStore {
SupportActions.voterAllPositionsRetrieve();
return this.resetState();

case 'twitterNativeSignInSave':
case 'twitterSignInRetrieve':
case 'voterEmailAddressSignIn':
case 'voterFacebookSignInRetrieve':
Expand Down
40 changes: 17 additions & 23 deletions src/js/stores/TwitterStore.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { ReduceStore } from 'flux/utils';
import CandidateActions from '../actions/CandidateActions';
import OrganizationActions from '../actions/OrganizationActions';
import TwitterActions from '../actions/TwitterActions';
import VoterActions from '../actions/VoterActions';
import Dispatcher from '../common/dispatcher/Dispatcher';

class TwitterStore extends ReduceStore {
getInitialState () {
// return {
// success: true,
// };
return {
twitter_store_initialized: true,
twitter_oauth_voter_info_stored_in_db: false,
};
}

get () {
Expand Down Expand Up @@ -101,6 +101,7 @@ class TwitterStore extends ReduceStore {
existing_twitter_account_found: this.getState().existing_twitter_account_found,
voter_we_vote_id_attached_to_twitter: this.getState().voter_we_vote_id_attached_to_twitter,
twitter_image_load_info: this.getState().twitter_image_load_info,
twitter_oauth_voter_info_stored_in_db: this.getState().twitter_oauth_voter_info_stored_in_db,
};
}

Expand Down Expand Up @@ -156,21 +157,6 @@ class TwitterStore extends ReduceStore {
status: action.res.status,
};

case 'twitterNativeSignInSave':
// Exit if we don't have a successful response (since we expect certain variables in a successful response below)
if (!action.res || !action.res.success) return state;
if (action.res.success) {
TwitterActions.twitterSignInRetrieve();
}

return {
// ...state,
voter_device_id: action.res.voter_device_id,
twitter_handle: action.res.twitter_handle,
twitter_handle_found: action.res.twitter_handle_found,
twitter_secret_key: action.res.twitter_secret_key,
};

case 'twitterProcessDeferredImages':
if (!action.res || !action.res.success) return state;
// console.log('twitter twitterProcessDeferredImages', action.res);
Expand All @@ -183,10 +169,12 @@ class TwitterStore extends ReduceStore {
we_vote_hosted_profile_image_url_tiny: action.res.we_vote_hosted_profile_image_url_tiny,
};


case 'twitterSignInRetrieve':
// Exit if we don't have a successful response (since we expect certain variables in a successful response below)
if (!action.res || !action.res.success) return state;
// console.log('twitterSignInRetrieve in TwitterStore received: ', action.res);
if (!action.res || !action.res.success) {
// Exit if we don't have a successful response (since we expect certain variables in a successful response below)
return state;
}
if (action.res.twitter_sign_in_verified) {
VoterActions.voterRetrieve();
VoterActions.twitterRetrieveIdsIfollow();
Expand Down Expand Up @@ -217,10 +205,16 @@ class TwitterStore extends ReduceStore {
// return this.resetState();
return this.resetVoterSpecificData();

default:
case 'twitterOauth1UserHandler':
if (!action.res || !action.res.success) return state;
console.log('twitterOauth1UserHandler res: ', action.res);
return {
...state,
twitter_oauth_voter_info_stored_in_db: true,
};

default:
return state;
}
}
}
Expand Down
1 change: 0 additions & 1 deletion src/js/stores/VoterGuideStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -868,7 +868,6 @@ class VoterGuideStore extends ReduceStore {
organizationWeVoteIdsToFollowForLatestBallotItem: state.organizationWeVoteIdsToFollowForLatestBallotItem.filter((existingOrgWeVoteId) => existingOrgWeVoteId !== organizationWeVoteId),
};

case 'twitterNativeSignInSave':
case 'twitterSignInRetrieve':
case 'voterEmailAddressSignIn':
case 'voterFacebookSignInRetrieve':
Expand Down

0 comments on commit d3ad999

Please sign in to comment.