More changes for db migration
This commit is contained in:
parent
de0284e48a
commit
889dc02945
33 changed files with 740 additions and 100 deletions
|
@ -8,7 +8,6 @@ import errors from 'koa-error';
|
|||
import * as redis from '../lib/redis';
|
||||
import * as index from './routes/index';
|
||||
import * as file from './routes/file';
|
||||
import * as pro from './routes/pro';
|
||||
import * as user from './routes/user';
|
||||
|
||||
const router = new Router();
|
||||
|
@ -67,9 +66,6 @@ router.get('/pricing', index.staticPage);
|
|||
router.get('/apps', index.staticPage);
|
||||
router.get('/stats', index.staticPage);
|
||||
|
||||
router.post('/pro/create', pro.create);
|
||||
router.post('/pro/cancel', pro.cancel);
|
||||
|
||||
router.get('/:id', file.landing);
|
||||
router.get('/file/:id/:name', file.get);
|
||||
router.get('/file/:size/:id/:name', file.get);
|
||||
|
|
|
@ -25,7 +25,7 @@ export function* authenticate(email, password) {
|
|||
ip: remoteIp,
|
||||
successful: false,
|
||||
createdAt: {
|
||||
$gt: Math.ceil(Date.now() / 1000) - 600,
|
||||
$gt: Math.ceil(Date.now()) - 600000,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -35,26 +35,30 @@ export function* authenticate(email, password) {
|
|||
return new Error('Invalid login details');
|
||||
}
|
||||
const user = yield models.user.findOne({
|
||||
email: email.toLowerCase(),
|
||||
activated: 'true',
|
||||
where: {
|
||||
email: email.toLowerCase(),
|
||||
activated: true,
|
||||
},
|
||||
});
|
||||
debug(user);
|
||||
const login = yield models.login.create({
|
||||
ip: remoteIp,
|
||||
successful: false,
|
||||
});
|
||||
|
||||
if (user) {
|
||||
if (user && user.password) {
|
||||
if (yield passwords.verify(password, user.password)) {
|
||||
debug('Password verified');
|
||||
login.successful = true;
|
||||
yield login.save();
|
||||
debug(user);
|
||||
return user;
|
||||
}
|
||||
debug('Password invalid');
|
||||
login.userId = user.id;
|
||||
}
|
||||
yield login.save();
|
||||
return new Error('Invalid login details');
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -93,7 +97,12 @@ export function* setupSession(user) {
|
|||
|
||||
|
||||
export function* signup(email, password, ip) {
|
||||
const existingUser = yield models.user.findOne({ where: { email, activated: true } });
|
||||
const existingUser = yield models.user.findOne({
|
||||
where: {
|
||||
email,
|
||||
activated: true,
|
||||
},
|
||||
});
|
||||
if (existingUser) {
|
||||
debug('Email already in use.');
|
||||
throw new Error('Email already in use.');
|
||||
|
@ -102,8 +111,8 @@ export function* signup(email, password, ip) {
|
|||
const user = yield models.user.create({
|
||||
email,
|
||||
password: cryptedPassword,
|
||||
created: Math.round(new Date().getTime() / 1000),
|
||||
ip,
|
||||
plan: 'Free',
|
||||
activation: {
|
||||
id: uuid(),
|
||||
email,
|
||||
|
@ -138,7 +147,11 @@ ${process.env.WEB_BASE_URL}/activate/${user.activation.id}
|
|||
|
||||
|
||||
export function* sendResetToken(email) {
|
||||
const user = yield models.user.findOne({ email });
|
||||
const user = yield models.user.findOne({
|
||||
where: {
|
||||
email,
|
||||
},
|
||||
});
|
||||
if (user) {
|
||||
const reset = yield models.reset.create({
|
||||
id: uuid.v4(),
|
||||
|
@ -168,18 +181,18 @@ Visit ${process.env.WEB_BASE_URL}/forgot/${reset.id} to set a new one.
|
|||
|
||||
export function* fromToken(token) {
|
||||
const userId = yield this.redis.get(token);
|
||||
return yield models.user.findbyId(userId);
|
||||
return yield models.user.findById(userId);
|
||||
}
|
||||
|
||||
|
||||
export function* fromCookie(rememberId) {
|
||||
const userId = yield models.remember.findById(rememberId);
|
||||
return yield models.user.findbyId(userId);
|
||||
return yield models.user.findById(userId);
|
||||
}
|
||||
|
||||
|
||||
export function* validateResetToken(resetId) {
|
||||
return yield models.reset.findbyId(resetId);
|
||||
return yield models.reset.findById(resetId);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ export class ProController {
|
|||
$scope.user = UserService.get();
|
||||
$scope.header = 'full';
|
||||
$scope.cancel = () => {
|
||||
$http.post('/pro/cancel').success(() => {
|
||||
$http.delete(window.settings.apiURL + '/user/pro').success(() => {
|
||||
window.location.reload(true);
|
||||
}).error((data) => {
|
||||
console.error(new Error(data));
|
||||
|
|
|
@ -69,7 +69,7 @@ export function stripeSubscribe($http) {
|
|||
key: window.settings.stripePublic,
|
||||
image: '/images/stripe-128.png',
|
||||
token: (token) => {
|
||||
$http.post('/pro/create', {
|
||||
$http.post(window.settings.apiURL + '/user/pro', {
|
||||
stripeToken: token,
|
||||
})
|
||||
.success((data) => {
|
||||
|
|
|
@ -37,7 +37,6 @@ export function* get() {
|
|||
where: {
|
||||
id: this.params.id,
|
||||
name: this.params.name,
|
||||
status: 'active',
|
||||
},
|
||||
});
|
||||
this.assert(file, 404);
|
||||
|
@ -104,7 +103,6 @@ export function* landing() {
|
|||
const file = yield models.file.findOne({
|
||||
where: {
|
||||
id: this.params.id,
|
||||
status: 'active',
|
||||
},
|
||||
});
|
||||
this.assert(file, 404);
|
||||
|
|
|
@ -1,80 +0,0 @@
|
|||
import path from 'path';
|
||||
import views from 'co-views';
|
||||
const render = views(path.join(__dirname, '/../views'), { default: 'ejs' });
|
||||
import Stripe from 'stripe';
|
||||
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
|
||||
import sendgridInit from 'sendgrid';
|
||||
const sendgrid = sendgridInit(process.env.SENDGRID_KEY);
|
||||
|
||||
const from = process.env.EMAIL_FROM;
|
||||
const fromname = process.env.EMAIL_NAME;
|
||||
|
||||
export function* create() {
|
||||
const Users = this.db.Users;
|
||||
const Transactions = this.db.Transactions;
|
||||
const stripeToken = this.request.body.stripeToken;
|
||||
|
||||
const createCustomer = {
|
||||
card: stripeToken.id,
|
||||
plan: 'usd_monthly',
|
||||
email: this.session.email,
|
||||
};
|
||||
|
||||
const customer = yield stripe.customers.create(createCustomer);
|
||||
|
||||
this.assert(customer.subscription.status === 'active', 400, '{"status": "error"}');
|
||||
|
||||
delete customer.subscriptions;
|
||||
|
||||
yield Users.updateOne({ _id: this.session.user.id },
|
||||
{ $set: { stripe_customer: customer, type: 'Pro' } });
|
||||
|
||||
const transaction = {
|
||||
user_id: this.session.user.id,
|
||||
amount: customer.subscription.plan.amount,
|
||||
desc: customer.subscription.plan.name,
|
||||
date: new Date(customer.subscription.plan.created * 1000),
|
||||
};
|
||||
|
||||
yield Transactions.insertOne(transaction);
|
||||
|
||||
this.session.user.plan = 'Pro';
|
||||
this.body = { status: 'active' };
|
||||
|
||||
const html = yield render('email/inlined/pro');
|
||||
const text = `Hey, thanks for upgrading to Hostr Pro!
|
||||
|
||||
You've signed up for Hostr Pro Monthly at $6/Month.
|
||||
|
||||
— Jonathan Cremin, Hostr Founder
|
||||
`;
|
||||
|
||||
const mail = new sendgrid.Email({
|
||||
to: this.session.user.email,
|
||||
subject: 'Hostr Pro',
|
||||
from,
|
||||
fromname,
|
||||
html,
|
||||
text,
|
||||
});
|
||||
mail.addCategory('pro-upgrade');
|
||||
sendgrid.send(mail);
|
||||
}
|
||||
|
||||
export function* cancel() {
|
||||
this.assertCSRF();
|
||||
const Users = this.db.Users;
|
||||
const user = yield Users.findOne({ _id: this.session.user.id });
|
||||
|
||||
const confirmation = yield stripe.customers.cancelSubscription(
|
||||
user.stripe_customer.id,
|
||||
user.stripe_customer.subscription.id,
|
||||
{ at_period_end: true }
|
||||
);
|
||||
|
||||
yield Users.updateOne({ _id: this.session.user.id },
|
||||
{ $set: { 'stripe_customer.subscription': confirmation, type: 'Free' } });
|
||||
|
||||
this.session.user.plan = 'Pro';
|
||||
this.body = { status: 'inactive' };
|
||||
}
|
|
@ -15,13 +15,14 @@ export function* signin() {
|
|||
this.statsd.incr('auth.attempt', 1);
|
||||
this.assertCSRF(this.request.body);
|
||||
const user = yield authenticate.call(this, this.request.body.email, this.request.body.password);
|
||||
|
||||
if (!user) {
|
||||
this.statsd.incr('auth.failure', 1);
|
||||
yield this.render('signin', { error: 'Invalid login details', csrf: this.csrf });
|
||||
return;
|
||||
} else if (user.activationCode) {
|
||||
yield this.render('signin', {
|
||||
error: 'Your account hasn\'t been activated yet. Check your for an activation email.',
|
||||
error: 'Your account hasn\'t been activated yet. Check for an activation email.',
|
||||
csrf: this.csrf,
|
||||
});
|
||||
return;
|
||||
|
@ -83,11 +84,14 @@ export function* forgot() {
|
|||
}
|
||||
this.assertCSRF(this.request.body);
|
||||
const user = yield validateResetToken(token);
|
||||
yield updatePassword(user.id, this.request.body.password);
|
||||
yield models.reset.deleteById(token);
|
||||
yield setupSession(this, user);
|
||||
this.statsd.incr('auth.reset.success', 1);
|
||||
this.redirect('/');
|
||||
if (user) {
|
||||
yield updatePassword(user.userId, this.request.body.password);
|
||||
const reset = yield models.reset.findById(token);
|
||||
//reset.destroy();
|
||||
yield setupSession.call(this, user);
|
||||
this.statsd.incr('auth.reset.success', 1);
|
||||
this.redirect('/');
|
||||
}
|
||||
} else if (token) {
|
||||
const tokenUser = yield validateResetToken(token);
|
||||
if (!tokenUser) {
|
||||
|
|
|
@ -1,101 +0,0 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns="http://www.w3.org/1999/xhtml" style="box-sizing: border-box; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-size: 14px; margin: 0; padding: 0">
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<title>Hostr Pro</title>
|
||||
|
||||
</head>
|
||||
|
||||
<body style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; background: #f6f6f6; box-sizing: border-box; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-size: 14px; height: 100%; line-height: 1.6; margin: 0; padding: 0; width: 100% !important" bgcolor="#f6f6f6"><style type="text/css">
|
||||
img {
|
||||
max-width: 100%;
|
||||
}
|
||||
body {
|
||||
-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; width: 100% !important; height: 100%; line-height: 1.6;
|
||||
}
|
||||
body {
|
||||
background-color: #f6f6f6;
|
||||
}
|
||||
@media only screen and (max-width: 640px) {
|
||||
h1 {
|
||||
font-weight: 600 !important; margin: 20px 0 5px !important;
|
||||
}
|
||||
h2 {
|
||||
font-weight: 600 !important; margin: 20px 0 5px !important;
|
||||
}
|
||||
h3 {
|
||||
font-weight: 600 !important; margin: 20px 0 5px !important;
|
||||
}
|
||||
h4 {
|
||||
font-weight: 600 !important; margin: 20px 0 5px !important;
|
||||
}
|
||||
h1 {
|
||||
font-size: 22px !important;
|
||||
}
|
||||
h2 {
|
||||
font-size: 18px !important;
|
||||
}
|
||||
h3 {
|
||||
font-size: 16px !important;
|
||||
}
|
||||
.container {
|
||||
width: 100% !important;
|
||||
}
|
||||
.content {
|
||||
padding: 10px !important;
|
||||
}
|
||||
.content-wrapper {
|
||||
padding: 10px !important;
|
||||
}
|
||||
.invoice {
|
||||
width: 100% !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<table class="body-wrap" style="background: #f6f6f6; box-sizing: border-box; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-size: 14px; margin: 0; padding: 0; width: 100%" bgcolor="#f6f6f6">
|
||||
<tr style="box-sizing: border-box; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-size: 14px; margin: 0; padding: 0">
|
||||
<td align="center" width="100%" colspan="2" style="box-sizing: border-box; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-size: 14px; margin: 0; padding: 0; vertical-align: top" valign="top"><img src="https://hostr.co/images/logo-dark-r.png" height="22" width="26" class="logo" style="box-sizing: border-box; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-size: 14px; margin: 40px 0 20px; max-width: 100%; padding: 0" /></td>
|
||||
</tr>
|
||||
<tr style="box-sizing: border-box; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-size: 14px; margin: 0; padding: 0">
|
||||
<td style="box-sizing: border-box; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-size: 14px; margin: 0; padding: 0; vertical-align: top" valign="top"></td>
|
||||
<td class="container" width="600" style="box-sizing: border-box; clear: both !important; display: block !important; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-size: 14px; margin: 0 auto; max-width: 600px !important; padding: 0; vertical-align: top" valign="top">
|
||||
<div class="content" style="box-sizing: border-box; display: block; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-size: 14px; margin: 0 auto; max-width: 600px; padding: 20px">
|
||||
<table class="main" width="100%" cellpadding="0" cellspacing="0" style="background: #fff; border-radius: 3px; border: 1px solid #e9e9e9; box-sizing: border-box; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-size: 14px; margin: 0; padding: 0" bgcolor="#fff">
|
||||
<tr style="box-sizing: border-box; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-size: 14px; margin: 0; padding: 0">
|
||||
<td class="content-wrap" style="box-sizing: border-box; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-size: 14px; margin: 0; padding: 20px; vertical-align: top" valign="top">
|
||||
<table width="100%" cellpadding="0" cellspacing="0" style="box-sizing: border-box; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-size: 14px; margin: 0; padding: 0">
|
||||
<tr style="box-sizing: border-box; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-size: 14px; margin: 0; padding: 0">
|
||||
<td class="content-block" style="box-sizing: border-box; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-size: 14px; margin: 0; padding: 0 0 20px; vertical-align: top" valign="top">
|
||||
Thanks for upgrading to Hostr Pro!
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="box-sizing: border-box; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-size: 14px; margin: 0; padding: 0">
|
||||
<td class="content-block" style="box-sizing: border-box; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-size: 14px; margin: 0; padding: 0 0 20px; vertical-align: top" valign="top">
|
||||
You've signed up for Hostr Pro Monthly at $6/month
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="box-sizing: border-box; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-size: 14px; margin: 0; padding: 0">
|
||||
<td class="content-block" style="box-sizing: border-box; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-size: 14px; margin: 0; padding: 0 0 20px; vertical-align: top" valign="top">
|
||||
— Jonathan Cremin, Hostr Founder
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div class="footer" style="box-sizing: border-box; clear: both; color: #999; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-size: 14px; margin: 0; padding: 20px; width: 100%">
|
||||
<table width="100%" style="box-sizing: border-box; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-size: 14px; margin: 0; padding: 0">
|
||||
<tr style="box-sizing: border-box; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-size: 14px; margin: 0; padding: 0">
|
||||
<td class="aligncenter content-block" style="box-sizing: border-box; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-size: 12px; margin: 0; padding: 0 0 20px; text-align: center; vertical-align: top" align="center" valign="top">Follow <a href="http://twitter.com/gethostr" style="box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-size: 12px; margin: 0; padding: 0; text-decoration: underline">@gethostr</a> on Twitter.</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div></div>
|
||||
</td>
|
||||
<td style="box-sizing: border-box; font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-size: 14px; margin: 0; padding: 0; vertical-align: top" valign="top"></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -1,56 +0,0 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<title>Hostr Pro</title>
|
||||
<link href="style.css" media="all" rel="stylesheet" type="text/css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<table class="body-wrap">
|
||||
<tr>
|
||||
<td align="center" width="100%" colspan="2"><img src="https://hostr.co/images/logo-dark-r.png" height="22" width="26" class="logo" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td class="container" width="600">
|
||||
<div class="content">
|
||||
<table class="main" width="100%" cellpadding="0" cellspacing="0">
|
||||
<tr>
|
||||
<td class="content-wrap">
|
||||
<table width="100%" cellpadding="0" cellspacing="0">
|
||||
<tr>
|
||||
<td class="content-block">
|
||||
Thanks for upgrading to Hostr Pro!
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="content-block">
|
||||
You've signed up for Hostr Pro Monthly at $6/month
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="content-block">
|
||||
— Jonathan Cremin, Hostr Founder
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div class="footer">
|
||||
<table width="100%">
|
||||
<tr>
|
||||
<td class="aligncenter content-block">Follow <a href="http://twitter.com/gethostr">@gethostr</a> on Twitter.</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div></div>
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</body>
|
||||
</html>
|
Loading…
Add table
Add a link
Reference in a new issue