]> git.r.bdr.sh - rbdr/dasein/blobdiff - lib/handlers/comments.js
Merge branch 'release/1.0.0'
[rbdr/dasein] / lib / handlers / comments.js
diff --git a/lib/handlers/comments.js b/lib/handlers/comments.js
new file mode 100644 (file)
index 0000000..14bd137
--- /dev/null
@@ -0,0 +1,140 @@
+'use strict';
+
+const Joi = require('joi');
+const Pify = require('pify');
+const Redis = require('redis');
+const UUID = require('uuid/v4');
+
+const internals = {};
+
+internals.kPostsPrefix = 'posts';
+internals.kCommentsPrefix = 'comments';
+internals.kMaxCommentSize = 255;
+
+internals.kCommentsSchema = Joi.object().keys({
+  uuid: Joi.string().required(),
+  content: Joi.string().max(internals.kMaxCommentSize).required(),
+  timestamp: Joi.number().integer().required(),
+  userId: Joi.string().required(),
+  userName: Joi.string().required(),
+  userImage: Joi.string().required()
+});
+
+/**
+ * Handles the HTTP requests for comment related operations
+ *
+ * @class CommentsHandler
+ * @param {Dasein.tConfiguration} config The configuration to
+ * initialize.
+ */
+module.exports = internals.CommentsHandler = class CommentsHandler {
+  constructor(config) {
+
+    this._ttl = config.ttl;
+    this._redis = Redis.createClient(config.redis);
+
+    // Log an error if it happens.
+    this._redis.on('error', (err) => {
+
+      console.error(err);
+    });
+  }
+
+  /**
+   * Fetches all available comments
+   *
+   * @function findAll
+   * @memberof CommentsHandler
+   * @instance
+   * @return {generator} a koa compatible handler generator function
+   */
+  findAll() {
+
+    const self = this;
+
+    return function * (postId) {
+
+      if (!this.state.user) {
+        return this.throw('Unauthorized', 401);
+      }
+
+      const scan = Pify(self._redis.scan.bind(self._redis));
+      const hgetall = Pify(self._redis.hgetall.bind(self._redis));
+
+      const commentsKey = `${internals.kCommentsPrefix}:${postId}:*`;
+      let keys = [];
+      let nextCursor = 0;
+      let currentKeys = null;
+
+      do {
+        [nextCursor, currentKeys] = yield scan(nextCursor || 0, 'MATCH', commentsKey);
+        keys = keys.concat(currentKeys);
+      } while (nextCursor > 0);
+
+      const comments = yield keys.map((key) => hgetall(key));
+
+      this.body = comments.sort((a, b) => a.timestamp - b.timestamp);
+    };
+  }
+
+  /**
+   * Creates a comment
+   *
+   * @function create
+   * @memberof CommentsHandler
+   * @instance
+   * @return {generator} a koa compatible handler generator function
+   */
+  create() {
+
+    const self = this;
+
+    return function * (postId) {
+
+      if (!this.state.user) {
+        return this.throw('Unauthorized', 401);
+      }
+
+      const hmset = Pify(self._redis.hmset.bind(self._redis));
+      const hgetall = Pify(self._redis.hgetall.bind(self._redis));
+      const expire = Pify(self._redis.expire.bind(self._redis));
+
+      const uuid = UUID();
+      const timestamp = Date.now();
+      const user = this.state.user;
+
+      const postKey = `${internals.kPostsPrefix}:${postId}`;
+      const commentKey = `${internals.kCommentsPrefix}:${postId}:${uuid}`;
+
+      const comment = {
+        uuid,
+        content: this.request.body.content,
+        timestamp,
+        userId: user.screen_name,
+        userName: user.name,
+        userImage: user.profile_image_url_https
+      };
+
+      yield self._validate(comment).catch((err) => {
+
+        this.throw(err.message, 422);
+      });
+
+      yield hmset(commentKey, comment);
+      yield expire(commentKey, self._ttl * 100); // this is me being lazy :(
+                                                 // comments will last at most 100 bumps
+                                                 // but will disappear eventually
+      yield expire(postKey, self._ttl); // bumps the parent comment TTL
+
+      this.body = yield hgetall(commentKey);
+    };
+  }
+
+  // Validates the comment schema
+
+  _validate(comment) {
+
+    const validate = Pify(Joi.validate.bind(Joi));
+    return validate(comment, internals.kCommentsSchema);
+  }
+};