mirror of
https://github.com/scratchfoundation/scratch-www.git
synced 2025-02-16 16:19:48 -05:00
Merge pull request #3788 from benjiwheeler/join-endpoint
added /signup/TOKEN route; handle route alongside existing student signup route
This commit is contained in:
commit
ae04860160
4 changed files with 58 additions and 18 deletions
15
src/lib/route.js
Normal file
15
src/lib/route.js
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
module.exports = {};
|
||||||
|
|
||||||
|
// try to extract classroom token from either of two routes
|
||||||
|
module.exports.getURIClassroomToken = uriPathname => {
|
||||||
|
// first try to match /classes/CLASSROOM_ID/register/CLASSROOM_TOKEN
|
||||||
|
const classRegisterRegexp = /^\/?classes\/\d*\/register\/([a-zA-Z0-9]*)\/?$/;
|
||||||
|
const classRegisterMatch = classRegisterRegexp.exec(uriPathname);
|
||||||
|
if (classRegisterMatch) return classRegisterMatch[1];
|
||||||
|
// if regex match failed, try to match /signup/CLASSROOM_TOKEN
|
||||||
|
const signupTokenRegexp = /^\/?signup\/([a-zA-Z0-9]*)\/?$/;
|
||||||
|
const signupTokenMatch = signupTokenRegexp.exec(uriPathname);
|
||||||
|
if (signupTokenMatch) return signupTokenMatch[1];
|
||||||
|
// if neither matched
|
||||||
|
return null;
|
||||||
|
};
|
|
@ -280,6 +280,13 @@
|
||||||
"view": "studentregistration/studentregistration",
|
"view": "studentregistration/studentregistration",
|
||||||
"title": "Class Registration"
|
"title": "Class Registration"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "student-registration-token-only",
|
||||||
|
"pattern": "^/signup/:token",
|
||||||
|
"routeAlias": "/signup/.+)",
|
||||||
|
"view": "studentregistration/studentregistration",
|
||||||
|
"title": "Class Registration"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "teacher-faq",
|
"name": "teacher-faq",
|
||||||
"pattern": "^/educators/faq/?$",
|
"pattern": "^/educators/faq/?$",
|
||||||
|
|
|
@ -6,6 +6,7 @@ const React = require('react');
|
||||||
const api = require('../../lib/api');
|
const api = require('../../lib/api');
|
||||||
const injectIntl = require('../../lib/intl.jsx').injectIntl;
|
const injectIntl = require('../../lib/intl.jsx').injectIntl;
|
||||||
const intlShape = require('../../lib/intl.jsx').intlShape;
|
const intlShape = require('../../lib/intl.jsx').intlShape;
|
||||||
|
const route = require('../../lib/route');
|
||||||
|
|
||||||
const Deck = require('../../components/deck/deck.jsx');
|
const Deck = require('../../components/deck/deck.jsx');
|
||||||
const Progression = require('../../components/progression/progression.jsx');
|
const Progression = require('../../components/progression/progression.jsx');
|
||||||
|
@ -32,11 +33,9 @@ class StudentRegistration extends React.Component {
|
||||||
}
|
}
|
||||||
componentDidMount () {
|
componentDidMount () {
|
||||||
this.setState({waiting: true}); // eslint-disable-line react/no-did-mount-set-state
|
this.setState({waiting: true}); // eslint-disable-line react/no-did-mount-set-state
|
||||||
|
|
||||||
api({
|
api({
|
||||||
uri: `/classrooms/${this.props.classroomId}`,
|
uri: `/classtoken/${this.props.classroomToken}`
|
||||||
params: {
|
|
||||||
token: this.props.classroomToken
|
|
||||||
}
|
|
||||||
}, (err, body, res) => {
|
}, (err, body, res) => {
|
||||||
this.setState({waiting: false});
|
this.setState({waiting: false});
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -46,7 +45,7 @@ class StudentRegistration extends React.Component {
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (res.statusCode === 404) {
|
if (res.statusCode >= 400) {
|
||||||
// TODO: Use react-router for this
|
// TODO: Use react-router for this
|
||||||
window.location = '/404';
|
window.location = '/404';
|
||||||
}
|
}
|
||||||
|
@ -76,7 +75,7 @@ class StudentRegistration extends React.Component {
|
||||||
),
|
),
|
||||||
country: formData.user.country,
|
country: formData.user.country,
|
||||||
is_robot: formData.user.isRobot,
|
is_robot: formData.user.isRobot,
|
||||||
classroom_id: this.props.classroomId,
|
classroom_id: this.state.classroom.id,
|
||||||
classroom_token: this.props.classroomToken
|
classroom_token: this.props.classroomToken
|
||||||
}
|
}
|
||||||
}, (err, body, res) => {
|
}, (err, body, res) => {
|
||||||
|
@ -101,7 +100,7 @@ class StudentRegistration extends React.Component {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
handleGoToClass () {
|
handleGoToClass () {
|
||||||
window.location = `/classes/${this.props.classroomId}/`;
|
window.location = `/classes/${this.state.classroom.id}/`;
|
||||||
}
|
}
|
||||||
render () {
|
render () {
|
||||||
const usernameDescription = this.props.intl.formatMessage({id: 'registration.studentUsernameStepDescription'});
|
const usernameDescription = this.props.intl.formatMessage({id: 'registration.studentUsernameStepDescription'});
|
||||||
|
@ -152,26 +151,19 @@ class StudentRegistration extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
StudentRegistration.propTypes = {
|
StudentRegistration.propTypes = {
|
||||||
classroomId: PropTypes.string.isRequired,
|
|
||||||
classroomToken: PropTypes.string.isRequired,
|
classroomToken: PropTypes.string.isRequired,
|
||||||
intl: intlShape
|
intl: intlShape
|
||||||
};
|
};
|
||||||
|
|
||||||
StudentRegistration.defaultProps = {
|
StudentRegistration.defaultProps = {
|
||||||
classroomId: null,
|
|
||||||
classroomToken: null
|
classroomToken: null
|
||||||
};
|
};
|
||||||
|
|
||||||
const IntlStudentRegistration = injectIntl(StudentRegistration);
|
const IntlStudentRegistration = injectIntl(StudentRegistration);
|
||||||
|
|
||||||
const [classroomId, _, classroomToken] = document.location.pathname.split('/').filter(p => {
|
// parse either format of student registration url:
|
||||||
if (p) {
|
// "class register": http://scratch.mit.edu/classes/3/register/c0256654e1be
|
||||||
return p;
|
// "signup token": http://scratch.mit.edu/signup/c025r54ebe
|
||||||
}
|
const props = {classroomToken: route.getURIClassroomToken(document.location.pathname)};
|
||||||
return null;
|
|
||||||
})
|
|
||||||
.slice(-3);
|
|
||||||
|
|
||||||
const props = {classroomId, classroomToken};
|
|
||||||
|
|
||||||
render(<IntlStudentRegistration {...props} />, document.getElementById('app'));
|
render(<IntlStudentRegistration {...props} />, document.getElementById('app'));
|
||||||
|
|
26
test/unit/lib/route.test.js
Normal file
26
test/unit/lib/route.test.js
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
const route = require('../../../src/lib/route');
|
||||||
|
|
||||||
|
describe('unit test lib/route.js', () => {
|
||||||
|
|
||||||
|
test('getURIClassroomToken exists', () => {
|
||||||
|
expect(typeof route.getURIClassroomToken).toBe('function');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('getURIClassroomToken parses URI paths like /classes/21/register/r9n5f5xk', () => {
|
||||||
|
let response;
|
||||||
|
response = route.getURIClassroomToken('/classes/21/register/r9n5f5xk');
|
||||||
|
expect(response).toEqual('r9n5f5xk');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('getURIClassroomToken parses URI paths like /signup/e2dcfkx95', () => {
|
||||||
|
let response;
|
||||||
|
response = route.getURIClassroomToken('/signup/e2dcfkx95');
|
||||||
|
expect(response).toEqual('e2dcfkx95');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('getURIClassroomToken works with trailing slash', () => {
|
||||||
|
let response;
|
||||||
|
response = route.getURIClassroomToken('/signup/r9n5f5xk/');
|
||||||
|
expect(response).toEqual('r9n5f5xk');
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in a new issue