Merge branch 'postgres'

This commit is contained in:
Jonathan Cremin 2016-08-07 19:16:03 +01:00
commit 305dd77f43
36 changed files with 1195 additions and 312 deletions

View file

@ -1,5 +1,6 @@
import redis from 'redis';
import models from '../../models';
import { formatFile } from '../../lib/format';
import Uploader from '../../lib/uploader';
@ -20,7 +21,6 @@ export function* post(next) {
uploader.receive();
yield uploader.save();
yield uploader.promise;
uploader.processingEvent();
@ -30,7 +30,7 @@ export function* post(next) {
yield uploader.finalise();
this.status = 201;
this.body = uploader.toJSON();
this.body = formatFile(uploader.file);
uploader.completeEvent();
uploader.malwareScan();
@ -38,67 +38,56 @@ export function* post(next) {
export function* list() {
const Files = this.db.Files;
let status = 'active';
if (this.request.query.trashed) {
status = 'trashed';
} else if (this.request.query.all) {
status = { $in: ['active', 'trashed'] };
}
let limit = 20;
if (this.request.query.perpage === '0') {
limit = false;
limit = 1000;
} else if (this.request.query.perpage > 0) {
limit = parseInt(this.request.query.perpage / 1, 10);
}
let skip = 0;
let offset = 0;
if (this.request.query.page) {
skip = parseInt(this.request.query.page - 1, 10) * limit;
offset = parseInt(this.request.query.page - 1, 10) * limit;
}
const queryOptions = {
limit, skip, sort: [['time_added', 'desc']],
hint: {
owner: 1, status: 1, time_added: -1,
const files = yield models.file.findAll({
where: {
userId: this.user.id,
processed: true,
},
};
order: '"createdAt" DESC',
offset,
limit,
});
const userFiles = yield Files.find({
owner: this.user.id, status }, queryOptions).toArray();
this.statsd.incr('file.list', 1);
this.body = userFiles.map(formatFile);
this.body = files.map(formatFile);
}
export function* get() {
const Files = this.db.Files;
const Users = this.db.Users;
const file = yield Files.findOne({ _id: this.params.id,
status: { $in: ['active', 'uploading'] } });
const file = yield models.file.findOne({
where: {
id: this.params.id,
},
});
this.assert(file, 404, '{"error": {"message": "File not found", "code": 604}}');
const user = yield Users.findOne({ _id: file.owner });
const user = yield file.getUser();
this.assert(user && !user.banned, 404, '{"error": {"message": "File not found", "code": 604}}');
this.statsd.incr('file.get', 1);
this.body = formatFile(file);
}
export function* put() {
if (this.request.body.trashed) {
const Files = this.db.Files;
const status = this.request.body.trashed ? 'trashed' : 'active';
yield Files.updateOne({ _id: this.params.id, owner: this.user.id },
{ $set: { status } }, { w: 1 });
}
}
export function* del() {
yield this.db.Files.updateOne({ _id: this.params.id, owner: this.db.objectId(this.user.id) },
{ $set: { status: 'deleted' } }, { w: 1 });
const file = yield models.file.findOne({
where: {
id: this.params.id,
userId: this.user.id,
},
});
this.assert(file, 401, '{"error": {"message": "File not found", "code": 604}}');
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

@ -2,6 +2,7 @@ import uuid from 'node-uuid';
import redis from 'redis';
import co from 'co';
import passwords from 'passwords';
import models from '../../models';
import debugname from 'debug';
const debug = debugname('hostr-api:user');
@ -19,17 +20,19 @@ export function* token() {
}
export function* transaction() {
const Transactions = this.db.Transactions;
const transactions = yield Transactions.find({ user_id: this.user.id }).toArray();
const transactions = yield models.transaction.findAll({
where: {
userId: this.user.id,
},
});
this.body = transactions.map((transaction) => { // eslint-disable-line no-shadow
const type = transaction.paypal ? 'paypal' : 'direct';
this.body = transactions.map((item) => {
return {
id: transaction._id,
amount: transaction.paypal ? transaction.amount : transaction.amount / 100,
date: transaction.date,
description: transaction.desc,
type,
id: item.id,
amount: item.amount / 100,
date: item.date,
description: item.description,
type: 'direct',
};
});
}
@ -39,23 +42,18 @@ export function* settings() {
'{"error": {"message": "Current Password required to update account.", "code": 612}}');
this.assert(this.request.body.current_password, 400,
'{"error": {"message": "Current Password required to update account.", "code": 612}}');
const Users = this.db.Users;
const user = yield Users.findOne({ _id: this.user.id });
this.assert(yield passwords.match(this.request.body.current_password, user.salted_password), 400,
const user = yield models.user.findById(this.user.id);
this.assert(yield passwords.match(this.request.body.current_password, user.password), 400,
'{"error": {"message": "Incorrect password", "code": 606}}');
const data = {};
if (this.request.body.email && this.request.body.email !== user.email) {
data.email = this.request.body.email;
if (!user.activated_email) {
data.activated_email = user.email; // eslint-disable-line camelcase
}
user.email = this.request.body.email;
}
if (this.request.body.new_password) {
this.assert(this.request.body.new_password.length >= 7, 400,
'{"error": {"message": "Password must be 7 or more characters long.", "code": 606}}');
data.salted_password = yield passwords.hash(this.request.body.new_password);
user.password = yield passwords.hash(this.request.body.new_password);
}
Users.updateOne({ _id: user._id }, { $set: data });
yield user.save();
this.body = {};
}