mirror of
https://github.com/scratchfoundation/scratch-www.git
synced 2024-11-27 09:35:56 -05:00
Move api mixin to lib, remove mixin
The mixin doesn't gain us anything except complexity
This commit is contained in:
parent
56e16bc0dc
commit
d7df1e980f
9 changed files with 109 additions and 103 deletions
|
@ -1,7 +1,6 @@
|
|||
var classNames = require('classnames');
|
||||
var React = require('react');
|
||||
|
||||
var Api = require('../../mixins/api.jsx');
|
||||
var jar = require('../../lib/jar.js');
|
||||
var languages = require('../../../languages.json');
|
||||
var Form = require('../forms/form.jsx');
|
||||
|
@ -12,9 +11,6 @@ var Select = require('../forms/select.jsx');
|
|||
*/
|
||||
var LanguageChooser = React.createClass({
|
||||
type: 'LanguageChooser',
|
||||
mixins: [
|
||||
Api
|
||||
],
|
||||
getDefaultProps: function () {
|
||||
return {
|
||||
languages: languages,
|
||||
|
|
|
@ -7,7 +7,7 @@ var injectIntl = ReactIntl.injectIntl;
|
|||
|
||||
var sessionActions = require('../../../redux/session.js');
|
||||
|
||||
var Api = require('../../../mixins/api.jsx');
|
||||
var api = require('../../../lib/api');
|
||||
var Avatar = require('../../avatar/avatar.jsx');
|
||||
var Button = require('../../forms/button.jsx');
|
||||
var Dropdown = require('../../dropdown/dropdown.jsx');
|
||||
|
@ -24,9 +24,6 @@ Modal.setAppElement(document.getElementById('view'));
|
|||
|
||||
var Navigation = React.createClass({
|
||||
type: 'Navigation',
|
||||
mixins: [
|
||||
Api
|
||||
],
|
||||
getInitialState: function () {
|
||||
return {
|
||||
accountNavOpen: false,
|
||||
|
@ -85,7 +82,7 @@ var Navigation = React.createClass({
|
|||
return '/users/' + this.props.session.session.user.username + '/';
|
||||
},
|
||||
getMessageCount: function () {
|
||||
this.api({
|
||||
api({
|
||||
method: 'get',
|
||||
uri: '/users/' + this.props.session.session.user.username + '/messages/count'
|
||||
}, function (err, body) {
|
||||
|
@ -110,7 +107,7 @@ var Navigation = React.createClass({
|
|||
handleLogIn: function (formData, callback) {
|
||||
this.setState({'loginError': null});
|
||||
formData['useMessages'] = true;
|
||||
this.api({
|
||||
api({
|
||||
method: 'post',
|
||||
host: '',
|
||||
uri: '/accounts/login/',
|
||||
|
@ -142,7 +139,7 @@ var Navigation = React.createClass({
|
|||
},
|
||||
handleLogOut: function (e) {
|
||||
e.preventDefault();
|
||||
this.api({
|
||||
api({
|
||||
host: '',
|
||||
method: 'post',
|
||||
uri: '/accounts/logout/',
|
||||
|
|
79
src/lib/api.js
Normal file
79
src/lib/api.js
Normal file
|
@ -0,0 +1,79 @@
|
|||
var defaults = require('lodash.defaults');
|
||||
var xhr = require('xhr');
|
||||
|
||||
var jar = require('./jar');
|
||||
var log = require('./log');
|
||||
var urlParams = require('./url-params');
|
||||
|
||||
/**
|
||||
* Helper method that constructs requests to the scratch api.
|
||||
* Custom arguments:
|
||||
* - useCsrf [boolean] – handles unique csrf token retrieval for POST requests. This prevents
|
||||
* CSRF forgeries (see: https://www.squarefree.com/securitytips/web-developers.html#CSRF)
|
||||
*
|
||||
* It also takes in other arguments specified in the xhr library spec.
|
||||
*/
|
||||
|
||||
module.exports = function (opts, callback) {
|
||||
defaults(opts, {
|
||||
host: process.env.API_HOST,
|
||||
headers: {},
|
||||
json: {},
|
||||
useCsrf: false
|
||||
});
|
||||
|
||||
defaults(opts.headers, {
|
||||
'X-Requested-With': 'XMLHttpRequest'
|
||||
});
|
||||
|
||||
opts.uri = opts.host + opts.uri;
|
||||
|
||||
if (opts.params) {
|
||||
opts.uri = [opts.uri, urlParams(opts.params)]
|
||||
.join(opts.uri.indexOf('?') === -1 ? '?' : '&');
|
||||
}
|
||||
|
||||
var apiRequest = function (opts) {
|
||||
if (opts.host !== '') {
|
||||
// For IE < 10, we must use XDR for cross-domain requests. XDR does not support
|
||||
// custom headers.
|
||||
defaults(opts, {useXDR: true});
|
||||
delete opts.headers;
|
||||
if (opts.authentication) {
|
||||
var authenticationParams = ['x-token=' + opts.authentication];
|
||||
var parts = opts.uri.split('?');
|
||||
var qs = (parts[1] || '').split('&').concat(authenticationParams).join('&');
|
||||
opts.uri = parts[0] + '?' + qs;
|
||||
|
||||
}
|
||||
}
|
||||
xhr(opts, function (err, res, body) {
|
||||
if (err) log.error(err);
|
||||
// Legacy API responses come as lists, and indicate to redirect the client like
|
||||
// [{success: true, redirect: "/location/to/redirect"}]
|
||||
try {
|
||||
if ('redirect' in body[0]) window.location = body[0].redirect;
|
||||
} catch (err) {
|
||||
// do nothing
|
||||
}
|
||||
callback(err, body, res);
|
||||
});
|
||||
}.bind(this);
|
||||
|
||||
if (typeof jar.get('scratchlanguage') !== 'undefined') {
|
||||
opts.headers['Accept-Language'] = jar.get('scratchlanguage') + ', en;q=0.8';
|
||||
}
|
||||
if (opts.authentication) {
|
||||
opts.headers['X-Token'] = opts.authentication;
|
||||
}
|
||||
if (opts.useCsrf) {
|
||||
jar.use('scratchcsrftoken', '/csrf_token/', function (err, csrftoken) {
|
||||
if (err) return log.error('Error while retrieving CSRF token', err);
|
||||
opts.json.csrftoken = csrftoken;
|
||||
opts.headers['X-CSRFToken'] = csrftoken;
|
||||
apiRequest(opts);
|
||||
}.bind(this));
|
||||
} else {
|
||||
apiRequest(opts);
|
||||
}
|
||||
};
|
14
src/lib/url-params.js
Normal file
14
src/lib/url-params.js
Normal file
|
@ -0,0 +1,14 @@
|
|||
/* Turn an object into an url param string
|
||||
* urlParams({a: 1, b: 2, c: 3})
|
||||
* // a=1&b=2&c=3
|
||||
*/
|
||||
module.exports = function urlParams (values) {
|
||||
return Object
|
||||
.keys(values)
|
||||
.map(function (key) {
|
||||
return [key, values[key]]
|
||||
.map(encodeURIComponent)
|
||||
.join('=');
|
||||
})
|
||||
.join('&');
|
||||
};
|
|
@ -1,76 +0,0 @@
|
|||
var defaults = require('lodash.defaults');
|
||||
var xhr = require('xhr');
|
||||
|
||||
var jar = require('../lib/jar.js');
|
||||
var log = require('../lib/log.js');
|
||||
|
||||
/**
|
||||
* Component mixin that constructs requests to the scratch api.
|
||||
* Custom arguments:
|
||||
* - useCsrf [boolean] – handles unique csrf token retrieval for POST requests. This prevents
|
||||
* CSRF forgeries (see: https://www.squarefree.com/securitytips/web-developers.html#CSRF)
|
||||
*
|
||||
* It also takes in other arguments specified in the xhr library spec.
|
||||
*/
|
||||
var Api = {
|
||||
api: function (opts, callback) {
|
||||
defaults(opts, {
|
||||
host: window.env.API_HOST,
|
||||
headers: {},
|
||||
json: {},
|
||||
useCsrf: false
|
||||
});
|
||||
|
||||
defaults(opts.headers, {
|
||||
'X-Requested-With': 'XMLHttpRequest'
|
||||
});
|
||||
|
||||
opts.uri = opts.host + opts.uri;
|
||||
|
||||
var apiRequest = function (opts) {
|
||||
if (opts.host !== '') {
|
||||
// For IE < 10, we must use XDR for cross-domain requests. XDR does not support
|
||||
// custom headers.
|
||||
defaults(opts, {useXDR: true});
|
||||
delete opts.headers;
|
||||
if (opts.authentication) {
|
||||
var authenticationParams = ['x-token=' + opts.authentication];
|
||||
var parts = opts.uri.split('?');
|
||||
var qs = (parts[1] || '').split('&').concat(authenticationParams).join('&');
|
||||
opts.uri = parts[0] + '?' + qs;
|
||||
|
||||
}
|
||||
}
|
||||
xhr(opts, function (err, res, body) {
|
||||
if (err) log.error(err);
|
||||
// Legacy API responses come as lists, and indicate to redirect the client like
|
||||
// [{success: true, redirect: "/location/to/redirect"}]
|
||||
try {
|
||||
if ('redirect' in body[0]) window.location = body[0].redirect;
|
||||
} catch (err) {
|
||||
// do nothing
|
||||
}
|
||||
callback(err, body);
|
||||
});
|
||||
}.bind(this);
|
||||
|
||||
if (typeof jar.get('scratchlanguage') !== 'undefined') {
|
||||
opts.headers['Accept-Language'] = jar.get('scratchlanguage') + ', en;q=0.8';
|
||||
}
|
||||
if (opts.authentication) {
|
||||
opts.headers['X-Token'] = opts.authentication;
|
||||
}
|
||||
if (opts.useCsrf) {
|
||||
jar.use('scratchcsrftoken', '/csrf_token/', function (err, csrftoken) {
|
||||
if (err) return log.error('Error while retrieving CSRF token', err);
|
||||
opts.json.csrftoken = csrftoken;
|
||||
opts.headers['X-CSRFToken'] = csrftoken;
|
||||
apiRequest(opts);
|
||||
}.bind(this));
|
||||
} else {
|
||||
apiRequest(opts);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = Api;
|
|
@ -1,5 +1,5 @@
|
|||
var keyMirror = require('keymirror');
|
||||
var api = require('../mixins/api.jsx').api;
|
||||
var api = require('../lib/api');
|
||||
|
||||
var Types = keyMirror({
|
||||
SET_DETAILS: null,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
var keyMirror = require('keymirror');
|
||||
var api = require('../mixins/api.jsx').api;
|
||||
var api = require('../lib/api');
|
||||
|
||||
var Types = keyMirror({
|
||||
SET_SCHEDULE: null,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
var keyMirror = require('keymirror');
|
||||
var defaults = require('lodash.defaults');
|
||||
|
||||
var api = require('../mixins/api.jsx').api;
|
||||
var api = require('../lib/api');
|
||||
var tokenActions = require('./token.js');
|
||||
|
||||
var Types = keyMirror({
|
||||
|
|
|
@ -2,13 +2,12 @@ var connect = require('react-redux').connect;
|
|||
var injectIntl = require('react-intl').injectIntl;
|
||||
var omit = require('lodash.omit');
|
||||
var React = require('react');
|
||||
var render = require('../../lib/render.jsx');
|
||||
|
||||
var api = require('../../lib/api');
|
||||
var render = require('../../lib/render.jsx');
|
||||
var sessionActions = require('../../redux/session.js');
|
||||
var shuffle = require('../../lib/shuffle.js').shuffle;
|
||||
|
||||
var Api = require('../../mixins/api.jsx');
|
||||
|
||||
var Activity = require('../../components/activity/activity.jsx');
|
||||
var AdminPanel = require('../../components/adminpanel/adminpanel.jsx');
|
||||
var DropdownBanner = require('../../components/dropdown-banner/banner.jsx');
|
||||
|
@ -25,9 +24,6 @@ require('./splash.scss');
|
|||
|
||||
var Splash = injectIntl(React.createClass({
|
||||
type: 'Splash',
|
||||
mixins: [
|
||||
Api
|
||||
],
|
||||
getInitialState: function () {
|
||||
return {
|
||||
projectCount: 14000000, // gets the shared project count
|
||||
|
@ -90,42 +86,42 @@ var Splash = injectIntl(React.createClass({
|
|||
}
|
||||
},
|
||||
getActivity: function () {
|
||||
this.api({
|
||||
api({
|
||||
uri: '/proxy/users/' + this.props.session.session.user.username + '/activity?limit=5'
|
||||
}, function (err, body) {
|
||||
if (!err) this.setState({activity: body});
|
||||
}.bind(this));
|
||||
},
|
||||
getFeaturedGlobal: function () {
|
||||
this.api({
|
||||
api({
|
||||
uri: '/proxy/featured'
|
||||
}, function (err, body) {
|
||||
if (!err) this.setState({featuredGlobal: body});
|
||||
}.bind(this));
|
||||
},
|
||||
getFeaturedCustom: function () {
|
||||
this.api({
|
||||
api({
|
||||
uri: '/proxy/users/' + this.props.session.session.user.id + '/featured'
|
||||
}, function (err, body) {
|
||||
if (!err) this.setState({featuredCustom: body});
|
||||
}.bind(this));
|
||||
},
|
||||
getNews: function () {
|
||||
this.api({
|
||||
api({
|
||||
uri: '/news?limit=3'
|
||||
}, function (err, body) {
|
||||
if (!err) this.setState({news: body});
|
||||
}.bind(this));
|
||||
},
|
||||
getProjectCount: function () {
|
||||
this.api({
|
||||
api({
|
||||
uri: '/projects/count/all'
|
||||
}, function (err, body) {
|
||||
if (!err) this.setState({projectCount: body.count});
|
||||
}.bind(this));
|
||||
},
|
||||
refreshHomepageCache: function () {
|
||||
this.api({
|
||||
api({
|
||||
host: '',
|
||||
uri: '/scratch_admin/homepage/clear-cache/',
|
||||
method: 'post',
|
||||
|
@ -161,7 +157,7 @@ var Splash = injectIntl(React.createClass({
|
|||
this.setState({emailConfirmationModalOpen: false});
|
||||
},
|
||||
handleDismiss: function (cue) {
|
||||
this.api({
|
||||
api({
|
||||
host: '',
|
||||
uri: '/site-api/users/set-template-cue/',
|
||||
method: 'post',
|
||||
|
|
Loading…
Reference in a new issue