[KnackSteem API] - New Functions and some fix

in #utopian-io6 years ago

Repository & Pull Requests

https://github.com/knacksteem/knacksteem-api/
https://github.com/knacksteem/knacksteem-api/pull/14
https://github.com/knacksteem/knacksteem-api/pull/15

What is KnackSteem?

"Do you have any talent? If yes! then KnackSteem is for you."
"Rewards people with talents, it can be any talent, anything you know how to do best is highly welcome on the platform. "
Source: Discord Channel :D

Screen Shot 2018-07-21 at 11.27.49 PM.png

Changes Made

Endpoint to edit post tags (on backend only)

We use tags to improve our posts search functionality. This point will allow the post owner to edit the tags of this post if a mistake was made. This endpoint will require prior authentification before using it.

Related code:

/**
 * Method to update the tags of a post
 * @param {Object} req: url params
 * @param {Function} res: Express.js response callback
 * @param {Function} next: Express.js middleware callback
 * @author Jayser Mendez
 * @public
 */
exports.updateTags = async (req, res, next) => {
  try {
    const { permlink, tags } = req.body;
    const { username } = res.locals;

    const post = await Post.findOne({ permlink });

    if (post.author !== username) {
      return next({
        status: httpStatus.UNAUTHORIZED,
        message: 'You cannot edit someone else post',
      });
    }

    await Post.update({ permlink }, { tags });

    return res.status(httpStatus.OK).send({
      status: httpStatus.OK,
      message: 'Post edited correctly',
    });
  } catch (err) {
    console.log(err);
    return next({
      status: httpStatus.INTERNAL_SERVER_ERROR,
      message: 'Opps! Something is wrong in our server. Please report it to the administrator.',
      error: err,
    });
  }
};
Refactor fields in stats endpoints

By default, stats endpoints were not showing if the current user has voted the current loaded post. Indeed, there was an inconsistency in the returned fields in comparison with other endpoints. Also, this was leading to errors in client-side since it is re-using components for the posts. To solve this issue, I replaced the username field (used to get posts by the user) to author and used the username field to confirm is the current user has voted this post. The isVoted field was added to the response to make it identically to the rest.

Related code (coded was truncated to improve visibility):

let isVoted = false;

// Check if there is a user provided in the params.
 // If so, determine if this user has voted the post.
if (username) {
   isVoted = helper.isVoted(response.active_votes, username);
}
Allow all CORS method in Development mode

Even I was not facing this issue, the frontend developer told me that CORS were denying the PUT method at his end. To solve this issue, we decided to allow all methods in development mode (and we've confirmed that it works properly in production mode).

Related code:

app.use((req, res, next) => {
    res.header('Access-Control-Allow-Origin', '*');
    res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
    res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
    next();
});
Categories model

Categories were loaded directly from the client side. As an enhancement, I decided to load them dynamically from the server side since we may need to add or remove some categories in the future. to avoid a re-deploy of the client-side, those should be loaded from the backend.

Related code:

const mongoose = require('mongoose');

/**
 * Category Schema
 * @author Jayser Mendez
 * @private
 */
const categorySchema = new mongoose.Schema({
  key: {
    type: String,
    required: true,
    trim: true,
    lowercase: true,
    unique: true,
  },
  name: {
    type: String,
    required: true,
    trim: true,
  },
});

// Declare index in category schema for faster query.
categorySchema.index({
  key: 1,
  name: 1,
}, { name: 'category_index' });

/**
 * @typedef Category
 */
module.exports = mongoose.model('Category', categorySchema);
Endpoint to get all categories

As explained above, categories are now dynamically loaded. Hence, an endpoint is needed to consume them. The endpoint will return a response in the exact way it was in the client side so not too much changes are needed.

Related code:

/**
 * Get all the categories in database
 * @param {Object} req: url params
 * @param {Function} res: Express.js response callback
 * @param {Function} next: Express.js middleware callback
 * @public
 * @author Jayser Mendez
 */
exports.getCategories = async (req, res, next) => {
  try {
    const categoriesList = await Category.find({}, { __v: 0, _id: 0 });

    return res.status(httpStatus.OK).send({
      status: httpStatus.OK,
      results: categoriesList,
      count: categoriesList.length,
    });
  } catch (err) {
    return next({
      status: httpStatus.INTERNAL_SERVER_ERROR,
      message: 'Opps! Something is wrong in our server. Please report it to the administrator.',
      error: err,
    });
  }
};
Endpoint to add category

Since now categories are dynamic, a supervisor may be able to create categories. So, this endpoint was created with this functionality in mind.

Related code:

/**
 * Create a new category in database
 * @param {Object} req: url params
 * @param {Function} res: Express.js response callback
 * @param {Function} next: Express.js middleware callback
 * @public
 * @author Jayser Mendez
 */
exports.createCategory = async (req, res, next) => {
  try {
    const { name } = req.body;
    // Strip all the empty spaces and special characters and convert to lower case
    const key = name.replace(/[^A-Z0-9]+/ig, '').toLowerCase();

    const newCategory = await new Category({ key, name });

    await Category.create(newCategory);

    return res.status(httpStatus.CREATED).send({
      status: httpStatus.CREATED,
      message: 'Category was correctly created',
    });
  } catch (err) {
    // Return exact error if there is a collision in the key
    if (err.message.includes('E11000')) {
      return next({
        status: httpStatus.NOT_ACCEPTABLE,
        message: 'Opps! A category with this name already exists.',
        error: err,
      });
    }
    return next({
      status: httpStatus.INTERNAL_SERVER_ERROR,
      message: 'Opps! Something is wrong in our server. Please report it to the administrator.',
      error: err,
    });
  }
};
Seed method to insert default categories

A set of default categories should be added when the server run for the first time. To do so, I created a seed method to insert a batch of data in the database if the categories collection is empty.

Related code:

const Category = require('../models/category.model');

// Batch of initial categories
const initialCategories = [
  { key: 'vlog', name: 'VLog' },
  { key: 'graphics', name: 'Graphics' },
  { key: 'art', name: 'Art' },
  { key: 'knack', name: 'Knack' },
  { key: 'onealtruism', name: 'One Altruism' },
  { key: 'music', name: 'Music' },
  { key: 'humor', name: 'Joke/Humor' },
  { key: 'inspiring', name: 'Inspiring' },
  { key: 'visibility', name: 'Visibility' },
  { key: 'news', name: 'News' },
  { key: 'quotes', name: 'Quotes' },
  { key: 'techtrends', name: 'Tech Trends' },
  { key: 'blogposts', name: 'Blog Posts' },
];

/**
 * Method to insert the initial batch of categories in the backend
 * @public
 * @author Jayser Mendez
 */
exports.seedCategories = async () => {
  try {
    const count = await Category.count();
    // If this is the first time running, insert the categories
    if (count === 0) {
      initialCategories.map(async (category) => {
        const newCategory = await new Category({
          key: category.key,
          name: category.name,
        });
        await Category.create(newCategory);
      });

      return true;
    }
    return false;
  } catch (err) {
    return false;
  }
};

Contributors

Feel free to contact @knowledges :)

Sort:  

Hey! I'm pleased to see this project grow.

Let's go for the review:

Overall this is great work! Congratulations :)

See you for another contribution

Your contribution has been evaluated according to Utopian policies and guidelines, as well as a predefined set of questions pertaining to the category.

To view those questions and the relevant answers related to your post, click here.


Need help? Write a ticket on https://support.utopian.io/.
Chat with us on Discord.
[utopian-moderator]

Hey @gregory.latinier
Here's a tip for your valuable feedback! @Utopian-io loves and incentivises informative comments.

Contributing on Utopian
Learn how to contribute on our website.

Want to chat? Join us on Discord https://discord.gg/h52nFrV.

Vote for Utopian Witness!

Hey @jaysermendez
Thanks for contributing on Utopian.
We’re already looking forward to your next contribution!

Want to chat? Join us on Discord https://discord.gg/h52nFrV.

Vote for Utopian Witness!

Congratulations @jaysermendez! You have completed the following achievement on Steemit and have been rewarded with new badge(s) :

Award for the number of upvotes received

Click on the badge to view your Board of Honor.
If you no longer want to receive notifications, reply to this comment with the word STOP

To support your work, I also upvoted your post!

Do not miss the last post from @steemitboard:
SteemitBoard World Cup Contest - The results, the winners and the prizes

Do you like SteemitBoard's project? Then Vote for its witness and get one more award!

Congratulations @jaysermendez! You have completed the following achievement on Steemit and have been rewarded with new badge(s) :

Award for the number of upvotes

Click on the badge to view your Board of Honor.
If you no longer want to receive notifications, reply to this comment with the word STOP

Do you like SteemitBoard's project? Then Vote for its witness and get one more award!

Congratulations @jaysermendez! You have completed the following achievement on the Steem blockchain and have been rewarded with new badge(s) :

Award for the number of upvotes

Click on the badge to view your Board of Honor.
If you no longer want to receive notifications, reply to this comment with the word STOP

Do not miss the last post from @steemitboard:

SteemFest³ - SteemitBoard support the Travel Reimbursement Fund.

Support SteemitBoard's project! Vote for its witness and get one more award!

Congratulations @jaysermendez! You have completed the following achievement on the Steem blockchain and have been rewarded with new badge(s) :

You made more than 8000 upvotes. Your next target is to reach 9000 upvotes.

Click here to view your Board of Honor
If you no longer want to receive notifications, reply to this comment with the word STOP

Do not miss the last post from @steemitboard:

The Meet the Steemians Contest is over - Results are coming soon ...

Support SteemitBoard's project! Vote for its witness and get one more award!

Congratulations @jaysermendez! You received a personal award!

1 Year on Steemit

Click here to view your Board

Do not miss the last post from @steemitboard:

Christmas Challenge - The party continues

Support SteemitBoard's project! Vote for its witness and get one more award!

Dear @jaysermendez

I just decided to visit your profile and check out your latest content only to notice that you didn't blog in quite a while already.

Hope you didn't give up completely on Steemit?

Cheers, Piotr