Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: watch ideas #60

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
watch ideas, first steps
mrkvon committed Apr 2, 2018
commit 9386ea43868b372e920e694de54273f10862b505
3 changes: 3 additions & 0 deletions app.js
Original file line number Diff line number Diff line change
@@ -75,6 +75,9 @@ app.use('/ideas', require('./routes/ideas'));
app.use('/ideas', require('./routes/votes'));
app.use('/comments', require('./routes/votes'));

// watch ideas
app.use('/ideas', require('./routes/watches'));

// following are route factories
// they need to know what is the primary object (i.e. idea, comment, etc.)
app.use('/ideas', require('./routes/primary-comments')('idea'));
13 changes: 13 additions & 0 deletions collections.js
Original file line number Diff line number Diff line change
@@ -130,6 +130,19 @@ module.exports = {
unique: true
}
]
},

watches: {
type: 'edge',
from: ['users'],
to: ['ideas'],
indexes: [
{
type: 'hash',
fields: ['_from', '_to'],
unique: true
}
]
}

};
119 changes: 119 additions & 0 deletions controllers/watches.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
const path = require('path'),
models = require(path.resolve('./models')),
serializers = require(path.resolve('./serializers'));

async function post(req, res, next) {
// read data from request
const { id } = req.params;
const { username } = req.auth;

const primarys = req.baseUrl.substring(1);

try {
const watch = await models.watch.create({ from: username, to: { type: primarys, id } });

const serializedWatch = serializers.serialize.watch(watch);
return res.status(201).json(serializedWatch);
} catch (e) {
return next(e);
}
}

module.exports = { post };
/*
const path = require('path'),
models = require(path.resolve('./models')),
serializers = require(path.resolve('./serializers'));

/**
* Middleware to POST a vote to idea (and other objects in the future)
* /
async function post(req, res, next) {
console.log('&&&&&&&&&&&&&&&&&')

// read data from request
const { id } = req.params;
const { username } = req.auth;

console.log(id);

// what is the type of the object we vote for (i.e. ideas, comments, ...)
const primarys = req.baseUrl.substring(1);
const primary = primarys.slice(0, -1);

try {
console.log(primarys, '***');
// save the vote to database
const vote = await models.vote.create({ from: username, to: { type: primarys, id }, value: 1 });
// respond
const serializedVote = serializers.serialize.vote(vote);
return res.status(201).json(serializedVote);
} catch (e) {
// handle errors
switch (e.code) {
// duplicate vote
case 409: {
return res.status(409).json({
errors: [{
status: 409,
detail: 'duplicate vote'
}]
});
}
// missing idea
case 404: {
console.log('.....');
return res.status(404).json({
errors: [{
status: 404,
detail: `${primary} doesn't exist`
}]
});

}
default: {
return next(e);
}
}
}
}

/**
* Middleware to DELETE a vote from an idea (and other objects in the future).
* /
async function del(req, res, next) {

// read data from request
const { id } = req.params;
const { username } = req.auth;

// what is the type of the object we vote for (i.e. ideas, comments, ...)
const primarys = req.baseUrl.substring(1);
const primary = primarys.slice(0, -1);

try {
// remove the vote from database
await models.vote.remove({ from: username, to: { type: primarys, id } });
// respond
return res.status(204).end();
} catch (e) {
// handle errors
switch (e.code) {
// primary object or vote doesn't exist
case 404: {
return res.status(404).json({
errors: [{
status: 404,
detail: `vote or ${primary} doesn't exist`
}]
});
}
default: {
return next(e);
}
}
}
}

module.exports = { del, post };
*/
5 changes: 3 additions & 2 deletions models/index.js
Original file line number Diff line number Diff line change
@@ -9,7 +9,8 @@ const comment = require('./comment'),
tag = require('./tag'),
user = require('./user'),
userTag = require('./user-tag'),
vote = require('./vote');
vote = require('./vote'),
watch = require('./watch');


const models = {
@@ -22,4 +23,4 @@ const models = {
}
};

module.exports = Object.assign(models, { comment, contact, idea, ideaTag, message, model, tag, user, userTag, vote });
module.exports = Object.assign(models, { comment, contact, idea, ideaTag, message, model, tag, user, userTag, vote, watch });
70 changes: 70 additions & 0 deletions models/watch/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
'use strict';

const path = require('path');

const Model = require(path.resolve('./models/model')),
schema = require('./schema');

class Watch extends Model {

/**
* Create a watch.
* @param {string} from - username of the watch giver
* @param {object} to - receiver object of the watch
* @param {string} to.type - type of the receiver (collection name, i.e. 'ideas')
* @param {string} to.id - id of the receiver
* @returns Promise - the saved watch
*/
static async create({ from: username, to: { type, id } }) {
// generate the watch
const watch = schema({ });

const query = `
FOR u IN users FILTER u.username == @username
FOR i IN @@type FILTER i._key == @id
LET watch = MERGE(@watch, { _from: u._id, _to: i._id })
INSERT watch INTO watches

LET from = MERGE(KEEP(u, 'username'), u.profile)
LET to = MERGE(KEEP(i, 'title', 'detail', 'created'), { id: i._key })
LET savedWatch = MERGE(KEEP(NEW, 'created'), { id: NEW._key }, { from }, { to })
RETURN savedWatch`;
const params = { username, '@type': type, id, watch };
const cursor = await this.db.query(query, params);
const out = await cursor.all();

// when nothing was created, throw error
if (out.length === 0) {
const e = new Error('not found');
e.code = 404;
throw e;
}

// what is the type of the object the watch was given to (important for serialization)
out[0].to.type = type;

return out[0];
}

/**
* Read a watch from user to idea or something.
* @param {string} from - username of the watch giver
* @param {object} to - receiver object of the watch
* @param {string} to.type - type of the receiver (collection name, i.e. 'ideas')
* @param {string} to.id - id of the receiver
* @returns Promise - the found watch or undefined
*/
static async read({ from: username, to: { type, id } }) {
const query = `
FOR u IN users FILTER u.username == @username
FOR i IN @@type FILTER i._key == @id
FOR w IN watches FILTER w._from == u._id && w._to == i._id
RETURN w`;
const params = { username, '@type': type, id };
const cursor = await this.db.query(query, params);

return (await cursor.all())[0];
}
}

module.exports = Watch;
5 changes: 5 additions & 0 deletions models/watch/schema.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
'use strict';

module.exports = function ({ created = Date.now() }) {
return { created };
};
19 changes: 19 additions & 0 deletions routes/watches.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
'use strict';

const express = require('express'),
path = require('path');

const // authorize = require(path.resolve('./controllers/authorize')),
watchControllers = require(path.resolve('./controllers/watches'));
// voteValidators = require(path.resolve('./controllers/validators/votes'));

// create router and controllers
const router = express.Router();

router.route('/:id/watches')
.post(/* authorize.onlyLogged, voteValidators.post,*/ watchControllers.post);

// router.route('/:id/watches/watch')
// .delete(authorize.onlyLogged, voteValidators.del, voteControllers.del);

module.exports = router;
5 changes: 3 additions & 2 deletions serializers/index.js
Original file line number Diff line number Diff line change
@@ -9,7 +9,8 @@ const comments = require('./comments'),
messages = require('./messages'),
tags = require('./tags'),
users = require('./users'),
votes = require('./votes');
votes = require('./votes'),
watches = require('./watches');

// deserializing
const deserializer = new Deserializer({
@@ -44,6 +45,6 @@ function deserialize(req, res, next) {
}

module.exports = {
serialize: Object.assign({ }, comments, contacts, ideas, ideaTags, messages, tags, users, votes),
serialize: Object.assign({ }, comments, contacts, ideas, ideaTags, messages, tags, users, votes, watches),
deserialize
};
2 changes: 1 addition & 1 deletion serializers/votes.js
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@ const Serializer = require('jsonapi-serializer').Serializer;

const voteSerializer = new Serializer('votes', {
id: 'id',
attributes: ['title', 'detail', 'created', 'value', 'from', 'to'],
attributes: ['created', 'value', 'from', 'to'],
keyForAttribute: 'camelCase',
typeForAttribute(attribute, doc) {
if (attribute === 'from') return 'users';
27 changes: 27 additions & 0 deletions serializers/watches.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
'use strict';

const Serializer = require('jsonapi-serializer').Serializer;

const voteSerializer = new Serializer('watches', {
id: 'id',
attributes: ['created', 'from', 'to'],
keyForAttribute: 'camelCase',
typeForAttribute(attribute, doc) {
if (attribute === 'from') return 'users';
if (attribute === 'to') return doc.type;
},
from: {
ref: 'username',
type: 'users'
},
to: {
ref: 'id',
type: 'ideas'
}
});

function watch(data) {
return voteSerializer.serialize(data);
}

module.exports = { watch };
Loading