]> git.r.bdr.sh - rbdr/dasein/blobdiff - lib/handlers/posts.js
Merge branch 'release/1.0.0'
[rbdr/dasein] / lib / handlers / posts.js
diff --git a/lib/handlers/posts.js b/lib/handlers/posts.js
new file mode 100644 (file)
index 0000000..b5e4f0e
--- /dev/null
@@ -0,0 +1,179 @@
+'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.kMaxPostSize = 255;
+
+internals.kPostsSchema = Joi.object().keys({
+  uuid: Joi.string().required(),
+  content: Joi.string().max(internals.kMaxPostSize).required(),
+  timestamp: Joi.number().integer().required(),
+  userId: Joi.string().required(),
+  userName: Joi.string().required(),
+  userImage: Joi.string().required()
+});
+
+/**
+ * Handles the HTTP requests for posts related operations
+ *
+ * @class PostsHandler
+ * @param {Dasein.tConfiguration} config The configuration to
+ * initialize.
+ */
+module.exports = internals.PostsHandler = class PostsHandler {
+  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 posts
+   *
+   * @function findAll
+   * @memberof PostsHandler
+   * @instance
+   * @return {generator} a koa compatible handler generator function
+   */
+  findAll() {
+
+    const self = this;
+
+    return function * () {
+
+      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));
+
+      let keys = [];
+      let nextCursor = 0;
+      let currentKeys = null;
+
+      do {
+        [nextCursor, currentKeys] = yield scan(nextCursor || 0, 'MATCH', `${internals.kPostsPrefix}:*`);
+        keys = keys.concat(currentKeys);
+      } while (nextCursor > 0);
+
+      const posts = yield keys.map((key) => hgetall(key));
+
+      this.body = posts.sort((a, b) => b.timestamp - a.timestamp);
+    };
+  }
+
+  /**
+   * Fetches a single post
+   *
+   * @function find
+   * @memberof PostsHandler
+   * @instance
+   * @return {generator} a koa compatible handler generator function
+   */
+  find() {
+
+    const self = this;
+
+    return function * (uuid) {
+
+      if (!this.state.user) {
+        return this.throw('Unauthorized', 401);
+      }
+
+      const hgetall = Pify(self._redis.hgetall.bind(self._redis));
+
+      const postKey = `${internals.kPostsPrefix}:${uuid}`;
+
+      const post = yield hgetall(postKey);
+
+      if (!post) {
+        this.throw('Post not found', 404);
+      }
+
+      this.body = post;
+    };
+  }
+
+  /**
+   * Creates a post
+   *
+   * @function create
+   * @memberof PostsHandler
+   * @instance
+   * @return {generator} a koa compatible handler generator function
+   */
+  create() {
+
+    const self = this;
+
+    return function * () {
+
+      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}:${uuid}`;
+
+      const post = {
+        uuid,
+        content: this.request.body.content,
+        timestamp,
+        userId: user.screen_name,
+        userName: user.name,
+        userImage: user.profile_image_url_https
+      };
+
+      yield self._validate(post).catch((err) => {
+
+        this.throw(err.message, 422);
+      });
+
+      yield hmset(postKey, post);
+      yield expire(postKey, self._ttl);
+
+      this.body = yield hgetall(postKey);
+    };
+  }
+
+  /**
+   * Deletes a post
+   *
+   * @function delete
+   * @memberof PostsHandler
+   * @instance
+   * @return {generator} a koa compatible handler generator function
+   */
+  delete() {
+
+    return function * () {};
+  }
+
+  // Validates the post schema
+
+  _validate(post) {
+
+    const validate = Pify(Joi.validate.bind(Joi));
+    return validate(post, internals.kPostsSchema);
+  }
+};