More changes for db migration

This commit is contained in:
Jonathan Cremin 2016-08-07 14:38:05 +01:00
parent de0284e48a
commit 889dc02945
33 changed files with 740 additions and 100 deletions

View file

@ -5,6 +5,7 @@ import StatsD from 'statsy';
import auth from './lib/auth';
import * as user from './routes/user';
import * as file from './routes/file';
import * as pro from './routes/pro';
import debugname from 'debug';
const debug = debugname('hostr-api');
@ -64,10 +65,11 @@ router.get('/user/token', auth, user.token);
router.get('/token', auth, user.token);
router.get('/user/transaction', auth, user.transaction);
router.post('/user/settings', auth, user.settings);
router.post('/user/pro', auth, pro.create);
router.delete('/user/pro', auth, pro.cancel);
router.get('/file', auth, file.list);
router.post('/file', auth, file.post);
router.get('/file/:id', file.get);
router.put('/file/:id', auth, file.put);
router.delete('/file/:id', auth, file.del);
router.delete('/file/:id', auth, file.del);

View file

@ -31,7 +31,7 @@ export default function* (next) {
ip: remoteIp,
successful: false,
createdAt: {
$gt: new Date(Math.ceil(Date.now()) - 600000),
$gt: new Date(Date.now() - 600000),
},
},
});
@ -71,7 +71,7 @@ export default function* (next) {
where: {
userId: user.id,
createdAt: {
$gt: Math.ceil(Date.now() / 1000) - 86400,
$gt: Date.now() - 86400000,
},
},
});

View file

@ -54,7 +54,7 @@ export function* list() {
const files = yield models.file.findAll({
where: {
userId: this.user.id,
status: 'active',
processed: true,
},
order: '"createdAt" DESC',
offset,
@ -70,9 +70,6 @@ export function* get() {
const file = yield models.file.findOne({
where: {
id: this.params.id,
status: {
$in: ['active', 'uploading'],
},
},
});
this.assert(file, 404, '{"error": {"message": "File not found", "code": 604}}');
@ -83,20 +80,6 @@ export function* get() {
}
export function* put() {
if (this.request.body.trashed) {
const file = yield models.file.findOne({
where: {
id: this.params.id,
userId: this.user.id,
},
});
file.status = this.request.body.trashed ? 'trashed' : 'active';
yield file.save();
}
}
export function* del() {
const file = yield models.file.findOne({
where: {
@ -105,8 +88,7 @@ export function* del() {
},
});
this.assert(file, 401, '{"error": {"message": "File not found", "code": 604}}');
file.status = 'deleted';
yield file.save();
yield file.destroy();
const event = { type: 'file-deleted', data: { id: this.params.id } };
yield this.redis.publish(`/file/${this.params.id}`, JSON.stringify(event));
yield this.redis.publish(`/user/${this.user.id}`, JSON.stringify(event));

85
api/routes/pro.js Normal file
View file

@ -0,0 +1,85 @@
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);
import models from '../../models';
const from = process.env.EMAIL_FROM;
const fromname = process.env.EMAIL_NAME;
export function* create() {
const stripeToken = this.request.body.stripeToken;
const ip = this.request.headers['x-real-ip'] || this.req.connection.remoteAddress;
const createCustomer = {
card: stripeToken.id,
plan: 'usd_monthly',
email: this.user.email,
};
const customer = yield stripe.customers.create(createCustomer);
this.assert(customer.subscription.status === 'active', 400, '{"status": "error"}');
delete customer.subscriptions;
const user = yield models.user.findById(this.user.id);
user.plan = 'Pro';
yield user.save();
const transaction = yield models.transaction.create({
userId: this.user.id,
amount: customer.subscription.plan.amount,
description: customer.subscription.plan.name,
data: customer,
type: 'direct',
ip,
});
yield transaction.save();
this.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.user.email,
subject: 'Hostr Pro',
from,
fromname,
html,
text,
});
mail.addCategory('pro-upgrade');
sendgrid.send(mail);
}
export function* cancel() {
const user = yield models.user.findById(this.user.id);
const transactions = yield user.getTransactions();
const transaction = transactions[0];
yield stripe.customers.cancelSubscription(
transaction.data.id,
transaction.data.subscription.id,
{ at_period_end: false }
);
user.plan = 'Free';
yield user.save();
this.user.plan = 'Free';
this.body = { status: 'inactive' };
}

View file

@ -20,7 +20,11 @@ export function* token() {
}
export function* transaction() {
const transactions = yield models.transaction.findAll({ userId: this.user.id });
const transactions = yield models.transaction.findAll({
where: {
userId: this.user.id,
},
});
this.body = transactions.map((item) => {
return {

View file

@ -0,0 +1,101 @@
<!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>

56
api/views/email/pro.html Normal file
View file

@ -0,0 +1,56 @@
<!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">
&mdash; 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>

271
api/views/email/style.css Normal file
View file

@ -0,0 +1,271 @@
/* -------------------------------------
GLOBAL
A very basic CSS reset
------------------------------------- */
* {
margin: 0;
padding: 0;
font-family: "Helvetica Neue", "Helvetica", Helvetica, Arial, sans-serif;
box-sizing: border-box;
font-size: 14px;
}
img {
max-width: 100%;
}
body {
-webkit-font-smoothing: antialiased;
-webkit-text-size-adjust: none;
width: 100% !important;
height: 100%;
line-height: 1.6;
}
/* Let's make sure all tables have defaults */
table td {
vertical-align: top;
}
/* -------------------------------------
BODY & CONTAINER
------------------------------------- */
body {
background-color: #f6f6f6;
}
.body-wrap {
background-color: #f6f6f6;
width: 100%;
}
.container {
display: block !important;
max-width: 600px !important;
margin: 0 auto !important;
/* makes it centered */
clear: both !important;
}
.content {
max-width: 600px;
margin: 0 auto;
display: block;
padding: 20px;
}
/* -------------------------------------
HEADER, FOOTER, MAIN
------------------------------------- */
.main {
background: #fff;
border: 1px solid #e9e9e9;
border-radius: 3px;
}
.content-wrap {
padding: 20px;
}
.content-block {
padding: 0 0 20px;
}
.header {
width: 100%;
margin-bottom: 20px;
}
.logo {
margin-top: 40px;
margin-bottom: 20px;
}
.footer {
width: 100%;
clear: both;
color: #999;
padding: 20px;
}
.footer a {
color: #999;
}
.footer p, .footer a, .footer unsubscribe, .footer td {
font-size: 12px;
}
/* -------------------------------------
TYPOGRAPHY
------------------------------------- */
h1, h2, h3 {
font-family: "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
color: #000;
margin: 40px 0 0;
line-height: 1.2;
font-weight: 400;
}
h1 {
font-size: 32px;
font-weight: 500;
}
h2 {
font-size: 24px;
}
h3 {
font-size: 18px;
}
h4 {
font-size: 14px;
font-weight: 600;
}
p, ul, ol {
margin-bottom: 10px;
font-weight: normal;
}
p li, ul li, ol li {
margin-left: 5px;
list-style-position: inside;
}
/* -------------------------------------
LINKS & BUTTONS
------------------------------------- */
a {
color: #456470;
text-decoration: underline;
}
.btn-primary {
text-decoration: none;
color: #FFF;
background-color: #456470;
border: solid #456470;
/* seems to be a bug stopping this from being applied above */
border-color: #456470;
border-width: 10px 20px;
line-height: 2;
font-weight: bold;
text-align: center;
cursor: pointer;
display: inline-block;
border-radius: 5px;
text-transform: capitalize;
}
/* -------------------------------------
OTHER STYLES THAT MIGHT BE USEFUL
------------------------------------- */
.last {
margin-bottom: 0;
}
.first {
margin-top: 0;
}
.aligncenter {
text-align: center;
}
.alignright {
text-align: right;
}
.alignleft {
text-align: left;
}
.clear {
clear: both;
}
/* -------------------------------------
ALERTS
Change the class depending on warning email, good email or bad email
------------------------------------- */
.alert {
font-size: 16px;
color: #fff;
font-weight: 500;
padding: 20px;
text-align: center;
border-radius: 3px 3px 0 0;
}
.alert a {
color: #fff;
text-decoration: none;
font-weight: 500;
font-size: 16px;
}
.alert.alert-warning {
background: #ff9f00;
}
.alert.alert-bad {
background: #d0021b;
}
.alert.alert-good {
background: #68b90f;
}
/* -------------------------------------
INVOICE
Styles for the billing table
------------------------------------- */
.invoice {
margin: 40px auto;
text-align: left;
width: 80%;
}
.invoice td {
padding: 5px 0;
}
.invoice .invoice-items {
width: 100%;
}
.invoice .invoice-items td {
border-top: #eee 1px solid;
}
.invoice .invoice-items .total td {
border-top: 2px solid #333;
border-bottom: 2px solid #333;
font-weight: 700;
}
/* -------------------------------------
RESPONSIVE AND MOBILE FRIENDLY STYLES
------------------------------------- */
@media only screen and (max-width: 640px) {
h1, h2, h3, 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, .content-wrapper {
padding: 10px !important;
}
.invoice {
width: 100% !important;
}
}