Merge pull request #10 from hyperspacedev/b2u1

B2u1
This commit is contained in:
Marquis Kurt 2019-04-23 13:16:19 -04:00 committed by GitHub
commit 2e70cc09f6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 158 additions and 59 deletions

View File

@ -1,5 +1,5 @@
{
"version": "1.0.0beta2",
"version": "1.0.0beta2u1",
"location": "https://hyperspaceapp-next.herokuapp.com",
"branding": {
"name": "Hyperspace",

View File

@ -508,7 +508,7 @@ export class Post extends React.Component<any, IPostState> {
</Tooltip>
<Typography>{post.reblog? post.reblog.reblogs_count: post.reblogs_count}</Typography>
<Tooltip className={classes.desktopOnly} title="View thread">
<LinkableIconButton to={`/conversation/${post.id}`}>
<LinkableIconButton to={`/conversation/${post.reblog? post.reblog.id: post.id}`}>
<ForumIcon />
</LinkableIconButton>
</Tooltip>
@ -550,7 +550,7 @@ export class Post extends React.Component<any, IPostState> {
}
<div className={classes.mobileOnly}>
<Divider/>
<LinkableMenuItem to={`/conversation/${post.id}`}>View thread</LinkableMenuItem>
<LinkableMenuItem to={`/conversation/${post.reblog? post.reblog.id: post.id}`}>View thread</LinkableMenuItem>
<MenuItem component="a" href={this.getMastodonUrl(post)} rel="noreferrer" target="_blank">Open in Web</MenuItem>
</div>
{

View File

@ -1,5 +1,5 @@
import React, { Component } from 'react';
import {withStyles, Paper, Typography, Button, TextField, Fade, Link, CircularProgress, Tooltip} from '@material-ui/core';
import {withStyles, Paper, Typography, Button, TextField, Fade, Link, CircularProgress, Tooltip, Dialog, DialogTitle, DialogActions, DialogContent} from '@material-ui/core';
import {styles} from './WelcomePage.styles';
import Mastodon from 'megalodon';
import {SaveClientSession} from '../types/SessionData';
@ -7,6 +7,11 @@ import { createHyperspaceApp } from '../utilities/login';
import {parseUrl} from 'query-string';
import { getConfig } from '../utilities/settings';
import axios from 'axios';
import {withSnackbar, withSnackbarProps} from 'notistack';
interface IWelcomeProps extends withSnackbarProps {
classes: any;
}
interface IWelcomeState {
logoUrl?: string;
@ -26,9 +31,12 @@ interface IWelcomeState {
license?: string;
repo?: string;
defaultRedirectAddress: string;
openAuthDialog: boolean;
authCode: string;
emergencyMode: boolean;
}
class WelcomePage extends Component<any, IWelcomeState> {
class WelcomePage extends Component<IWelcomeProps, IWelcomeState> {
client: any;
@ -42,7 +50,10 @@ class WelcomePage extends Component<any, IWelcomeState> {
foundSavedLogin: false,
authority: false,
userInputErrorMessage: '',
defaultRedirectAddress: ''
defaultRedirectAddress: '',
openAuthDialog: false,
authCode: '',
emergencyMode: false
}
getConfig().then((result: any) => {
@ -64,44 +75,62 @@ class WelcomePage extends Component<any, IWelcomeState> {
})
}
updateUserInfo(user: string) {
this.setState({ user });
}
updateAuthCode(code: string) {
this.setState({ authCode: code });
}
toggleAuthDialog() {
this.setState({ openAuthDialog: !this.state.openAuthDialog });
}
readyForAuth() {
if (localStorage.getItem('baseurl')) {
return true;
} else {
return false;
}
}
componentDidMount() {
if (localStorage.getItem("login")) {
this.getSavedSession();
this.setState({
foundSavedLogin: true
})
this.getSavedSession();
this.checkForToken();
}
}
checkForToken() {
let location = window.location.href;
if (location.includes("?code=")) {
let code = parseUrl(location).query.code as string;
this.setState({ authority: true });
let loginData = localStorage.getItem("login");
if (loginData) {
let clientLoginSession: SaveClientSession = JSON.parse(loginData);
console.log(clientLoginSession);
Mastodon.fetchAccessToken(
clientLoginSession.clientId,
clientLoginSession.clientSecret,
code,
(localStorage.getItem("baseurl") as string),
`https://${window.location.host}`,
).then((tokenData: any) => {
localStorage.setItem("access_token", tokenData.access_token);
window.location.href=`https://${window.location.host}/#/`;
}).catch((err: Error) => {
console.log(err.message);
})
}
getSavedSession() {
let loginData = localStorage.getItem("login");
if (loginData) {
let session: SaveClientSession = JSON.parse(loginData);
this.setState({
clientId: session.clientId,
clientSecret: session.clientSecret,
authUrl: session.authUrl,
emergencyMode: session.emergency
})
}
}
updateUserInfo(user: string) {
this.setState({ user });
startEmergencyLogin() {
if (!this.state.emergencyMode) {
this.createEmergencyLogin();
};
this.toggleAuthDialog();
}
startRegistration() {
if (this.state.registerBase) {
return "https://" + this.state.registerBase + "/auth/sign_up";
} else {
return "https://joinmastodon.org/#getting-started";
}
}
getLoginUser(user: string) {
@ -116,14 +145,6 @@ class WelcomePage extends Component<any, IWelcomeState> {
}
}
startRegistration() {
if (this.state.registerBase) {
return "https://" + this.state.registerBase + "/auth/sign_up";
} else {
return "https://joinmastodon.org/#getting-started";
}
}
startLogin() {
let error = this.checkForErrors();
if (!error) {
@ -134,7 +155,8 @@ class WelcomePage extends Component<any, IWelcomeState> {
let saveSessionForCrashing: SaveClientSession = {
clientId: resp.clientId,
clientSecret: resp.clientSecret,
authUrl: resp.url
authUrl: resp.url,
emergency: false
}
localStorage.setItem("login", JSON.stringify(saveSessionForCrashing));
this.setState({
@ -149,6 +171,30 @@ class WelcomePage extends Component<any, IWelcomeState> {
}
}
createEmergencyLogin() {
console.log("Creating an emergency login...")
const scopes = "read write follow";
const baseurl = localStorage.getItem('baseurl') || this.getLoginUser(this.state.user);
createHyperspaceApp(scopes, baseurl, "urn:ietf:wg:oauth:2.0:oob").then((resp: any) => {
let saveSessionForCrashing: SaveClientSession = {
clientId: resp.clientId,
clientSecret: resp.clientSecret,
authUrl: resp.url,
emergency: true
};
localStorage.setItem("login", JSON.stringify(saveSessionForCrashing));
this.setState({
clientId: resp.clientId,
clientSecret: resp.clientSecret,
authUrl: resp.url
});
})
}
authorizeEmergencyLogin() {
window.location.href = `/?code=${this.state.authCode}#/`;
}
resumeLogin() {
let loginData = localStorage.getItem("login");
if (loginData) {
@ -157,23 +203,12 @@ class WelcomePage extends Component<any, IWelcomeState> {
clientId: session.clientId,
clientSecret: session.clientSecret,
authUrl: session.authUrl,
emergencyMode: session.emergency,
wantsToLogin: true
})
}
}
getSavedSession() {
let loginData = localStorage.getItem("login");
if (loginData) {
let session: SaveClientSession = JSON.parse(loginData);
this.setState({
clientId: session.clientId,
clientSecret: session.clientSecret,
authUrl: session.authUrl
})
}
}
checkForErrors(): boolean {
let userInputError = false;
let userInputErrorMessage = "";
@ -201,11 +236,32 @@ class WelcomePage extends Component<any, IWelcomeState> {
}
readyForAuth() {
if (localStorage.getItem('baseurl')) {
return true;
} else {
return false;
checkForToken() {
let location = window.location.href;
if (location.includes("?code=")) {
let code = parseUrl(location).query.code as string;
this.setState({ authority: true });
let loginData = localStorage.getItem("login");
if (loginData) {
let clientLoginSession: SaveClientSession = JSON.parse(loginData);
Mastodon.fetchAccessToken(
clientLoginSession.clientId,
clientLoginSession.clientSecret,
code,
(localStorage.getItem("baseurl") as string),
this.state.emergencyMode?
undefined:
clientLoginSession.authUrl.includes("urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob")?
undefined:
`https://${window.location.host}`,
).then((tokenData: any) => {
localStorage.setItem("access_token", tokenData.access_token);
window.location.href=`https://${window.location.host}/#/`;
}).catch((err: Error) => {
this.props.enqueueSnackbar("Couldn't authorize Hyperspace: " + err.name, {variant: 'error'});
console.error(err.message);
})
}
}
}
@ -280,10 +336,51 @@ class WelcomePage extends Component<any, IWelcomeState> {
<div className={classes.flexGrow}/>
</div>
<div className={classes.middlePadding}/>
<Typography>Having trouble signing in? <Link onClick={() => this.startEmergencyLogin()}>Sign in with a code.</Link></Typography>
</div>
);
}
showAuthDialog() {
const {classes} = this.props;
return (
<Dialog
open={this.state.openAuthDialog}
disableBackdropClick
disableEscapeKeyDown
maxWidth="sm"
fullWidth={true}
>
<DialogTitle>
Authorize with a code
</DialogTitle>
<DialogContent>
<Typography paragraph>
If you're having trouble authorizing Hyperspace, you can manually request for an authorization code. Click 'Request Code' and then paste the code in the authorization code box to continue.
</Typography>
<Button
color="primary"
variant="contained"
href={this.state.authUrl? this.state.authUrl: ""}
target="_blank"
rel="noopener noreferrer"
>Request Code</Button>
<br/><br/>
<TextField
variant="outlined"
label="Authorization code"
fullWidth
onChange={(event) => this.updateAuthCode(event.target.value)}
></TextField>
</DialogContent>
<DialogActions>
<Button onClick={() => this.toggleAuthDialog()}>Cancel</Button>
<Button color="secondary" onClick={() => this.authorizeEmergencyLogin()}>Authorize</Button>
</DialogActions>
</Dialog>
);
}
showAuthority() {
const { classes } = this.props;
return (
@ -325,9 +422,10 @@ class WelcomePage extends Component<any, IWelcomeState> {
{ this.state.repo? <span><Link href={this.state.repo? this.state.repo: "https://github.com/hyperspacedev"} target="_blank" rel="noreferrer">Source code</Link> | </span>: null}<Link href={this.state.license? this.state.license: "https://www.apache.org/licenses/LICENSE-2.0"} target="_blank" rel="noreferrer">License</Link> | <Link href="https://github.com/hyperspacedev/hyperspace/issues/new" target="_blank" rel="noreferrer">File an Issue</Link>
</Typography>
</Paper>
{this.showAuthDialog()}
</div>
);
}
}
export default withStyles(styles)(WelcomePage);
export default withStyles(styles)(withSnackbar(WelcomePage));

View File

@ -2,4 +2,5 @@ export type SaveClientSession = {
clientId: string;
clientSecret: string;
authUrl: string;
emergency: boolean;
}