added whatwg-fetch and fixed publish validation

This commit is contained in:
bill bittner 2018-01-25 13:37:59 -08:00
parent 1f78a50b48
commit 8945707d0f
11 changed files with 93 additions and 68 deletions

View file

@ -54,6 +54,7 @@
"sequelize-cli": "^3.0.0-3", "sequelize-cli": "^3.0.0-3",
"sleep": "^5.1.1", "sleep": "^5.1.1",
"universal-analytics": "^0.4.13", "universal-analytics": "^0.4.13",
"whatwg-fetch": "^2.0.3",
"winston": "^2.3.1", "winston": "^2.3.1",
"winston-slack-webhook": "billbitt/winston-slack-webhook" "winston-slack-webhook": "billbitt/winston-slack-webhook"
}, },

View file

@ -21,9 +21,6 @@ const validationFunctions = {
isChannelNameAvailable: function (name) { isChannelNameAvailable: function (name) {
return this.isNameAvailable(name, '/api/channel-is-available/'); return this.isNameAvailable(name, '/api/channel-is-available/');
}, },
isClaimNameAvailable: function (name) {
return this.isNameAvailable(name, '/api/claim-is-available/')
},
isNameAvailable: function (name, apiUrl) { isNameAvailable: function (name, apiUrl) {
console.log('isNameAvailable?', name); console.log('isNameAvailable?', name);
const url = apiUrl + name; const url = apiUrl + name;

View file

@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import ProgressBar from 'components/ProgressBar'; import ProgressBar from 'components/ProgressBar';
import { makeGetRequest, makePostRequest } from 'utils/xhr'; import request from 'utils/request';
class ChannelCreateForm extends React.Component { class ChannelCreateForm extends React.Component {
constructor (props) { constructor (props) {
@ -43,7 +43,7 @@ class ChannelCreateForm extends React.Component {
updateIsChannelAvailable (channel) { updateIsChannelAvailable (channel) {
const that = this; const that = this;
const channelWithAtSymbol = `@${channel}`; const channelWithAtSymbol = `@${channel}`;
makeGetRequest(`/api/channel-is-available/${channelWithAtSymbol}`) request(`/api/channel-is-available/${channelWithAtSymbol}`)
.then(isAvailable => { .then(isAvailable => {
if (isAvailable) { if (isAvailable) {
that.setState({'error': null}); that.setState({'error': null});
@ -58,7 +58,7 @@ class ChannelCreateForm extends React.Component {
checkIsChannelAvailable (channel) { checkIsChannelAvailable (channel) {
const channelWithAtSymbol = `@${channel}`; const channelWithAtSymbol = `@${channel}`;
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
makeGetRequest(`/api/channel-is-available/${channelWithAtSymbol}`) request(`/api/channel-is-available/${channelWithAtSymbol}`)
.then(isAvailable => { .then(isAvailable => {
console.log('checkIsChannelAvailable result:', isAvailable); console.log('checkIsChannelAvailable result:', isAvailable);
if (!isAvailable) { if (!isAvailable) {
@ -82,10 +82,17 @@ class ChannelCreateForm extends React.Component {
resolve(); resolve();
}); });
} }
makePublishChannelRequest (channel, password) { makePublishChannelRequest (username, password) {
const params = `username=${channel}&password=${password}`; const params = {
method : 'POST',
body : JSON.stringify({username, password}),
headers: new Headers({
'Content-Type': 'application/json',
}),
credentials: 'include',
};
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
makePostRequest('/signup', params) request('/signup', params)
.then(result => { .then(result => {
console.log('makePublishChannelRequest result:', result); console.log('makePublishChannelRequest result:', result);
return resolve(result); return resolve(result);

View file

@ -1,5 +1,5 @@
import React from 'react'; import React from 'react';
import { makePostRequest } from 'utils/xhr'; import request from 'utils/request';
class ChannelLoginForm extends React.Component { class ChannelLoginForm extends React.Component {
constructor (props) { constructor (props) {
@ -19,15 +19,22 @@ class ChannelLoginForm extends React.Component {
} }
loginToChannel (event) { loginToChannel (event) {
event.preventDefault(); event.preventDefault();
const params = `username=${this.state.name}&password=${this.state.password}`; const params = {
method : 'POST',
body : JSON.stringify({username: this.state.name, password: this.state.password}),
headers: new Headers({
'Content-Type': 'application/json',
}),
credentials: 'include',
}
const that = this; const that = this;
makePostRequest('login', params) request('login', params)
.then(result => { .then(({success, channelName, shortChannelId, channelClaimId, message}) => {
console.log('loginToChannel result:', result); console.log('loginToChannel success:', success);
if (result.success) { if (success) {
that.props.onChannelLogin(result.channelName, result.shortChannelId, result.channelClaimId); that.props.onChannelLogin(channelName, shortChannelId, channelClaimId);
} else { } else {
that.setState({'error': result.message}); that.setState({'error': message});
}; };
}) })
.catch(error => { .catch(error => {

View file

@ -1,5 +1,5 @@
import React from 'react'; import React from 'react';
import { authenticateUser } from 'utils/auth'; import request from 'utils/request';
import Logo from 'components/Logo'; import Logo from 'components/Logo';
import NavBarChannelDropdown from 'components/NavBarChannelOptionsDropdown'; import NavBarChannelDropdown from 'components/NavBarChannelOptionsDropdown';
@ -19,7 +19,10 @@ class NavBar extends React.Component {
} }
checkForLoggedInUser () { checkForLoggedInUser () {
// check for whether a channel is already logged in // check for whether a channel is already logged in
authenticateUser() const params = {
credentials: 'include',
}
request('/user', params)
.then(({success, message}) => { .then(({success, message}) => {
if (success) { if (success) {
this.props.onChannelLogin(message.channelName, message.shortChannelId, message.channelClaimId); this.props.onChannelLogin(message.channelName, message.shortChannelId, message.channelClaimId);

View file

@ -16,18 +16,21 @@ class PublishForm extends React.Component {
this.publish = this.publish.bind(this); this.publish = this.publish.bind(this);
} }
validateChannelSelection () { validateChannelSelection () {
console.log('validating channel selection');
// make sure all required data is provided // make sure all required data is provided
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
// if publishInChannel is true, is a channel selected & logged in? // if publishInChannel is true, is a channel selected & logged in?
if (this.props.publishInChannel && (this.props.selectedChannel !== this.props.loggedInChannel.name)) { if (this.props.publishInChannel && (this.props.selectedChannel !== this.props.loggedInChannel.name)) {
// update state with error // update state with error
this.props.onChannelSelectionError('Select a channel or Anonymous'); this.props.onChannelSelectionError('Log in to a channel or select Anonymous"');
// reject this promise // reject this promise
return reject(new Error('Fix the channel')); return reject(new Error('Fix the channel'));
} }
resolve();
}); });
} }
validatePublishParams () { validatePublishParams () {
console.log('validating publish params');
// make sure all required data is provided // make sure all required data is provided
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
// is there a file? // is there a file?
@ -41,11 +44,11 @@ class PublishForm extends React.Component {
if (this.props.urlError) { if (this.props.urlError) {
return reject(new Error('Fix the url')); return reject(new Error('Fix the url'));
} }
// is the claim available?
resolve(); resolve();
}); });
} }
makePublishRequest (file, metadata) { makePublishRequest (file, metadata) {
console.log('making publish request');
const uri = '/api/claim-publish'; const uri = '/api/claim-publish';
const xhr = new XMLHttpRequest(); const xhr = new XMLHttpRequest();
const fd = this.appendDataToFormData(file, metadata); const fd = this.appendDataToFormData(file, metadata);
@ -84,6 +87,7 @@ class PublishForm extends React.Component {
xhr.send(fd); xhr.send(fd);
} }
createMetadata () { createMetadata () {
console.log('creating metadata');
let metadata = { let metadata = {
name : this.props.claim, name : this.props.claim,
title : this.props.title, title : this.props.title,
@ -103,18 +107,19 @@ class PublishForm extends React.Component {
fd.append('file', file); fd.append('file', file);
for (var key in metadata) { for (var key in metadata) {
if (metadata.hasOwnProperty(key)) { if (metadata.hasOwnProperty(key)) {
console.log(key, metadata[key]); console.log('adding form data', key, metadata[key]);
fd.append(key, metadata[key]); fd.append(key, metadata[key]);
} }
} }
return fd; return fd;
} }
publish () { publish () {
console.log('publishing file');
// publish the asset // publish the asset
const that = this; const that = this;
this.validateChannelSelection() this.validateChannelSelection()
.then(() => { .then(() => {
return that.validatePublishRequest(); return that.validatePublishParams();
}) })
.then(() => { .then(() => {
const metadata = that.createMetadata(); const metadata = that.createMetadata();

View file

@ -1,5 +1,5 @@
import React from 'react'; import React from 'react';
import {makeGetRequest} from 'utils/xhr'; import request from 'utils/request';
import UrlMiddle from 'components/PublishUrlMiddleDisplay'; import UrlMiddle from 'components/PublishUrlMiddleDisplay';
class PublishUrlInput extends React.Component { class PublishUrlInput extends React.Component {
@ -41,10 +41,10 @@ class PublishUrlInput extends React.Component {
} }
checkClaimIsAvailable (claim) { checkClaimIsAvailable (claim) {
const that = this; const that = this;
makeGetRequest(`/api/claim-is-available/${claim}`) request(`/api/claim-is-available/${claim}`)
.then(response => { .then(isAvailable => {
console.log('makeGetRequest response:', response); // console.log('checkClaimIsAvailable request response:', isAvailable);
if (response) { if (isAvailable) {
that.props.onUrlError(null); that.props.onUrlError(null);
} else { } else {
that.props.onUrlError('That url has already been claimed'); that.props.onUrlError('That url has already been claimed');

View file

@ -1,8 +0,0 @@
import {makeGetRequest} from 'utils/xhr';
module.exports = {
authenticateUser () {
// send request to server & receive the user info back
return makeGetRequest('/user');
},
};

44
react/utils/request.js Normal file
View file

@ -0,0 +1,44 @@
/**
* Parses the JSON returned by a network request
*
* @param {object} response A response from a network request
*
* @return {object} The parsed JSON from the request
*/
function parseJSON (response) {
if (response.status === 204 || response.status === 205) {
return null;
}
return response.json();
}
/**
* Checks if a network request came back fine, and throws an error if not
*
* @param {object} response A response from a network request
*
* @return {object|undefined} Returns either the response, or throws an error
*/
function checkStatus (response) {
if (response.status >= 200 && response.status < 300) {
return response;
}
const error = new Error(response.statusText);
error.response = response;
throw error;
}
/**
* Requests a URL, returning a promise
*
* @param {string} url The URL we want to request
* @param {object} [options] The options we want to pass to "fetch"
*
* @return {object} The response data
*/
export default function request (url, options) {
return fetch(url, options)
.then(checkStatus)
.then(parseJSON);
}

View file

@ -1,31 +0,0 @@
module.exports = {
makeGetRequest (url) {
return new Promise((resolve, reject) => {
let xhttp = new XMLHttpRequest();
xhttp.open('GET', url, true);
xhttp.responseType = 'json';
xhttp.onreadystatechange = () => {
if (xhttp.readyState === 4) {
console.log('makeGetRequest response:', xhttp.response);
resolve(xhttp.response);
};
};
xhttp.send();
});
},
makePostRequest (url, params) {
return new Promise((resolve, reject) => {
let xhttp = new XMLHttpRequest();
xhttp.open('POST', url, true);
xhttp.responseType = 'json';
xhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xhttp.onreadystatechange = () => {
if (xhttp.readyState === 4) {
console.log('makePostRequest response:', xhttp.response);
resolve(xhttp.response);
};
};
xhttp.send(params);
});
},
}

View file

@ -3,7 +3,7 @@ const Path = require('path');
const REACT_ROOT = Path.resolve(__dirname, 'react/'); const REACT_ROOT = Path.resolve(__dirname, 'react/');
module.exports = { module.exports = {
entry : './react/app.js', entry : ['whatwg-fetch', './react/app.js'],
output: { output: {
path : Path.join(__dirname, '/public/bundle/'), path : Path.join(__dirname, '/public/bundle/'),
filename: 'bundle.js', filename: 'bundle.js',