finished basic loop for channel creation

This commit is contained in:
bill bittner 2017-09-19 18:50:25 -07:00
parent 86a2c6fe03
commit 0dd8e19a26
15 changed files with 158 additions and 32 deletions

View file

@ -6,7 +6,7 @@ module.exports = {
'UserId',
{
type : Sequelize.STRING,
allowNull: false,
allowNull: true,
}
);
},

View file

@ -0,0 +1,20 @@
module.exports = {
up: (queryInterface, Sequelize) => {
// logic for transforming into the new state
return queryInterface.removeColumn(
'User',
'Email'
);
},
down: (queryInterface, Sequelize) => {
// logic for reverting the changes
return queryInterface.addColumn(
'User',
'Email',
{
type : Sequelize.STRING,
allowNull: true,
}
);
},
};

View file

@ -14,10 +14,6 @@ module.exports = (sequelize, { STRING }) => {
type : STRING,
allowNull: false,
},
email: {
type : STRING,
allowNull: false,
},
address: {
type : STRING,
allowNull: false,

View file

@ -10,6 +10,7 @@ module.exports = new PassportLocalStrategy(
passReqToCallback: true,
},
(req, username, password, done) => {
username = `@${username}`;
return db.User
.findOne({where: {channelName: username}})
.then(user => {

View file

@ -2,6 +2,7 @@ const db = require('../models');
const PassportLocalStrategy = require('passport-local').Strategy;
const lbryApi = require('../helpers/lbryApi.js');
const logger = require('winston');
const config = require('config');
module.exports = new PassportLocalStrategy(
{
@ -11,20 +12,34 @@ module.exports = new PassportLocalStrategy(
passReqToCallback: true, // we want to be able to read the post body message parameters in the callback
},
(req, username, password, done) => {
console.log('inside local-signup');
logger.debug('new channel signup request');
const address = config.get('WalletConfig.LbryClaimAddress');
// validate raw inputs (username, password)
username = '@' + username;
// create the channel and retrieve the metadata
lbryApi.createChannel(username)
.then(channelInfo => {
// define an object that contains all the user data
return lbryApi.createChannel(username)
.then(channelTx => {
// create certificate record
const certificateData = {
address,
claimId: channelTx.claim_id,
name : username,
};
logger.debug('certificateData >', certificateData);
return db.Certificate.create(certificateData);
})
.then(certificate => {
logger.debug('certificate result >', certificate.dataValues);
logger.debug('Certificate record was created successfully');
// define an object that contains all the user data
const userData = {
channelName : username,
channelClaimId: channelInfo.claim_id,
channelClaimId: certificate.claimId,
password : password,
email : 'test email', // req.body.email.trim(),
address,
};
return db.User.create(userData);
})
.then(user => {
}).then(user => {
logger.debug('User record was created successfully');
return done(null, user); // user.datavalues?
})

View file

@ -0,0 +1,26 @@
function sendSignupRequest (channelName, password) {
return new Promise(function(resolve, reject) {
// make sure the claim name is still available
let xhttp;
const params = `username=${channelName}&password=${password}`;
console.log(params);
xhttp = new XMLHttpRequest();
xhttp.open('POST', '/api/signup', true);
xhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xhttp.responseType = 'json';
xhttp.onreadystatechange = function() {
if (this.readyState == 4 ) {
if ( this.status == 200) {
if (this.response == true) {
resolve();
} else {
reject( new NameError("Your request could not be completed"));
}
} else {
reject("createChannel request failed with status:" + this.status);
};
}
};
xhttp.send(params);
});
}

View file

@ -40,6 +40,26 @@ function validateClaimName (name) {
}
}
function validateChannelName (name) {
name = name.substring(name.indexOf('@') + 1);
console.log(name);
// ensure a name was entered
if (name.length < 1) {
throw new ChannelError("You must enter a name for your channel");
}
// validate the characters in the 'name' field
const invalidCharacters = /[^A-Za-z0-9,-,@]/g.exec(name);
if (invalidCharacters) {
throw new ChannelError('"' + invalidCharacters + '" characters are not allowed in the channel name.');
}
}
function validatePassword (password) {
if (password.length < 1) {
throw new ChannelError("You must enter a password for you channel");
}
}
function cleanseClaimName(name) {
name = name.replace(/\s+/g, '-'); // replace spaces with dashes
name = name.replace(/[^A-Za-z0-9-]/g, ''); // remove all characters that are not A-Z, a-z, 0-9, or '-'
@ -92,10 +112,10 @@ function hideSuccess (successElement) {
successElement.innerHTML = "";
}
function checkAvailability(name, successDisplayElement, errorDisplayElement, isNameAvailable, apiUrl) {
function checkAvailability(name, successDisplayElement, errorDisplayElement, validateName, isNameAvailable, apiUrl) {
try {
// check to make sure the characters are valid
validateClaimName(name);
validateName(name);
// check to make sure it is available
isNameAvailable(name, apiUrl)
.then(function() {
@ -115,13 +135,14 @@ function checkAvailability(name, successDisplayElement, errorDisplayElement, isN
function checkClaimName(name){
const successDisplayElement = document.getElementById('input-success-claim-name');
const errorDisplayElement = document.getElementById('input-error-claim-name');
checkAvailability(name, successDisplayElement, errorDisplayElement, isNameAvailable, '/api/isClaimAvailable/');
checkAvailability(name, successDisplayElement, errorDisplayElement, validateClaimName, isNameAvailable, '/api/isClaimAvailable/');
}
function checkChannelName(name){
const successDisplayElement = document.getElementById('input-success-channel-name');
const errorDisplayElement = document.getElementById('input-error-channel-name');
checkAvailability(name, successDisplayElement, errorDisplayElement, isNameAvailable, '/api/isChannelAvailable/');
name = `@${name}`;
checkAvailability(name, successDisplayElement, errorDisplayElement, validateChannelName, isNameAvailable, '/api/isChannelAvailable/');
}
// validation function which checks all aspects of the publish submission
@ -158,4 +179,4 @@ function validateSubmission(stagedFiles, claimName, channelName){
reject(error);
});
});
}
}

View file

@ -6,8 +6,18 @@ const { getClaimList, resolveUri } = require('../helpers/lbryApi.js');
const { createPublishParams, validateFile, checkClaimNameAvailability, checkChannelAvailability } = require('../helpers/publishHelpers.js');
const errorHandlers = require('../helpers/errorHandlers.js');
const { postToStats, sendGoogleAnalytics } = require('../controllers/statsController.js');
const passport = require('passport');
module.exports = (app, hostedContentPath) => {
// route for auth
app.post('/api/signup', passport.authenticate('local-signup'), (req, res) => {
logger.debug('successful signup');
res.status(200).json(true);
});
app.post('/api/login', passport.authenticate('local-login'), (req, res) => {
logger.debug('successful login');
res.status(200).json(true);
});
// route to run a claim_list request on the daemon
app.get('/api/claim_list/:name', ({ headers, ip, originalUrl, params }, res) => {
// google analytics

View file

@ -9,13 +9,13 @@ module.exports = (app) => {
logger.debug('redirecting to user channel');
// If this function gets called, signup was successful.
// `req.user` contains the authenticated user.
res.redirect('/@' + req.user.channelName);
res.redirect(`/${req.user.channelName}`);
});
app.post('/login', passport.authenticate('local-login'), (req, res) => {
logger.debug('redirecting to user channel');
// If this function gets called, login was successful.
// `req.user` contains the authenticated user.
res.redirect('/@' + req.user.channelName);
res.redirect(`/${req.user.channelName}`);
});
// route to log out
app.get('/logout', (req, res) => {
@ -26,7 +26,7 @@ module.exports = (app) => {
// route to display login page
app.get('/login', (req, res) => {
if (req.user) {
res.status(200).redirect(`/@${req.user.channelName}`);
res.status(200).redirect(`/${req.user.channelName}`);
} else {
res.status(200).render('login');
}

View file

@ -31,6 +31,7 @@ app.use(bodyParser.urlencoded({ extended: true })); // 'body parser' for parsing
app.use(siofu.router); // 'socketio-file-upload' router for uploading with socket.io
app.use((req, res, next) => { // custom logging middleware to log all incoming http requests
logger.verbose(`Request on ${req.originalUrl} from ${req.ip}`);
logger.debug(req.body);
next();
});
@ -75,6 +76,7 @@ app.use((req, res, next) => {
}
next();
});
// start the server
db.sequelize
.sync() // sync sequelize

View file

@ -64,5 +64,4 @@
document.getElementById('publish-active-area').innerHTML = publishResults;
window.location.href = showUrl;
});
</script>

View file

@ -3,7 +3,7 @@
<div class="full">
<h2>Log In</h2>
<p>Log in to an existing channel</p>
<p>Log in to an existing channel:</p>
<form id="login-form" action="/login" method="post">
<div>
<label>Username:</label>
@ -19,21 +19,56 @@
</form>
<h2>Create New</h2>
<p>Create a brand new channel</p>
<form action="/signup" method="post">
<p>Create a brand new channel:</p>
<span id="input-error-channel-name" class="info-message info-message--failure"></span><br/>
<form id="signup-form" action="/signup" method="post">
<div>
<label>Channel name:</label>
@ <input type="text" name="username" class="input-text input-text--primary"/>
@ <input type="text" name="username" value="" id="new-channel-name" class="input-text input-text--primary" oninput="checkChannelName(event.target.value)"/>
<span id="input-success-channel-name" class="info-message info-message--success"></span>
</div>
<div>
<span id="input-error-password" class="info-message info-message--failure"></span><br/>
<label>Password:</label>
<input type="password" name="password" class="input-text input-text--primary"/>
<input type="password" name="password" value="" id="new-channel-password" class="input-text input-text--primary"/>
</div>
<div>
<input type="submit" value="Create"/>
<input type="submit" value="Create" onclick="submitNewChannelRequest(event)"/>
</div>
</form>
</div>
{{> footer}}
</div>
<script src="/assets/js/generalFunctions.js"></script>
<script src="/assets/js/validationFunctions.js"></script>
<script src="/assets/js/channelFunctions.js"></script>
<script type="text/javascript">
function submitNewChannelRequest (event) {
const channelName = document.getElementById('new-channel-name').value;
const password = document.getElementById('new-channel-password').value;
// prevent default so this script can handle submission
event.preventDefault();
// validate channel name
// validate password
try {
validatePassword(password);
} catch (error) {
showError(document.getElementById('input-error-password'), error.message)
return;
}
// post request
sendSignupRequest(channelName, password)
.then(() => {
console.log('success');
document.getElementById('signup-form').innerHTML = '<p>Your channel has been successfully created! Redirecting you now...</p>';
window.location.href = '/channelName';
})
.catch(error => {
console.log(error);
})
}
</script>

View file

@ -4,7 +4,7 @@
<label for="channel-name-select">Channel:</label>
<select type="text" id="channel-name-select" name="channel" value="channel" onclick="check(event)">
{{#if user}}
<option value="@{{user.channelName}}" >@{{user.channelName}}</option>
<option value="{{user.channelName}}" >{{user.channelName}}</option>
{{/if}}
<option value="@speech" >Anonymous</option>
<option value="new" >New</option>
@ -15,7 +15,7 @@
<span id="input-error-channel-name" class="info-message info-message--failure"></span>
<p>
<label for="channelName">Channel Name: </label>
@<input type="text" id="channel-name-input" class="input-text input-text--primary" placeholder="exampleChannel" value=""; oninput="checkChannelName(event.target.value)">
@<input type="text" id="channel-name-input" class="input-text input-text--primary" placeholder="exampleChannel" value="" oninput="checkChannelName(event.target.value)">
<span id="input-success-channel-name" class="info-message info-message--success"></span>
<br/>

View file

@ -25,4 +25,5 @@
<td><input type="checkbox" id="publish-nsfw"></td>
</tr>
</table>
</div>
</div>

View file

@ -6,7 +6,7 @@
<a href="/about" class="top-bar-right">help</a>
{{#if user}}
<a href="/@{{user.channelName}}" class="top-bar-right">@{{user.channelName}}</a>
<a href="/{{user.channelName}}" class="top-bar-right">{{user.channelName}}</a>
<a href="/logout" class="top-bar-right">logout</a>
{{else}}
<a href="/login" class="top-bar-right">login</a>