def post(self, request):
        r_id = get_request_body_param(request, 'recipe_id', None)
        r_step_num = get_request_body_param(request, 'step_num', 0)
        r_instr_text = get_request_body_param(request, 'instruction', None)
        r_dur_min = get_request_body_param(request, 'duration_minute', 0)
        r_dur_hour = get_request_body_param(request, 'duration_hour', 0)

        recipe = RecipeUtils.get_recipe_or_404(r_id)
        RecipeUtils.raise_401_if_recipe_not_belong_user(recipe, request)

        if r_step_num <= 0:
            return Response(
                {'detail': 'Step number must be greater or equal to 1'},
                status=status.HTTP_400_BAD_REQUEST)
        if not r_instr_text:
            return Response(
                {'detail': 'Instruction for recipe must not be empty'},
                status=status.HTTP_400_BAD_REQUEST)

        r_dur_min = r_dur_min if isinstance(r_dur_min, int) else 0
        r_dur_hour = int(r_dur_hour) if isinstance(r_dur_hour, int) else 0
        r_duration = timedelta(hours=r_dur_hour, minutes=r_dur_min)

        ri = RecipeInstruction.objects.create(recipe=recipe,
                                              step_num=r_step_num,
                                              instruction=r_instr_text,
                                              time_required=r_duration)
        return Response({
            "success": True,
            "instruction_id": ri.id
        },
                        status=status.HTTP_201_CREATED)
    def post(self, request):
        """
        Create an empty recipe

        @body str name: recipe name
        @body str description: recipe description
        @body int difficulty: difficulty level from 1 - 5
        """
        recipe_name = get_request_body_param(request, 'name', '').strip()
        recipe_desc = get_request_body_param(request, 'description',
                                             '').strip()
        recipe_diff = get_request_body_param(request, 'difficulty', 0)

        if recipe_name == "":
            return Response({'detail': 'recipe name must not be empty'},
                            status=status.HTTP_400_BAD_REQUEST)
        if recipe_desc == "":
            return Response({'detail': 'recipe desc must not be empty'},
                            status=status.HTTP_400_BAD_REQUEST)

        recipe_diff = recipe_diff if isinstance(recipe_diff, int) else 0

        upload_user = request.user

        recipe = Recipe.objects.create(name=recipe_name,
                                       description=recipe_desc,
                                       difficulty_level=recipe_diff,
                                       upload_by_user=upload_user)

        return Response({
            "success": True,
            "recipe_id": recipe.id
        },
                        status=status.HTTP_201_CREATED)
    def post(self, request):
        """
        Sign up a user

        @body email: user comment on the recipe
        @body username: user comment on the recipe
        @body password: user comment on the recipe

        @return: http status of query
        @raise HTTP_400_BAD_REQUEST: signup details must not be empty
        """

        email = get_request_body_param(request, 'email', '')
        password = get_request_body_param(request, 'password', '')
        username = get_request_body_param(request, 'username', '')

        if email == "":
            return Response({'detail': 'email must not be empty'},
                            status=status.HTTP_400_BAD_REQUEST)
        if username == "":
            return Response({'detail': 'username must not be empty'},
                            status=status.HTTP_400_BAD_REQUEST)
        if password == "":
            return Response({'detail': 'password must not be empty'},
                            status=status.HTTP_400_BAD_REQUEST)

        try:
            User.objects.create_user(username, email, password)
        except:
            return self.response_with_400(
                "The username entered already exists")
        return Response({"success": True}, status=status.HTTP_201_CREATED)
    def post(self, request):

        username = get_request_body_param(request, 'email', '')
        password = get_request_body_param(request, 'password', '')

        if not (username and password):
            return Response({"detail": "credentials not entered"},
                            status.HTTP_400_BAD_REQUEST)

        email_regex_pattern = '^([\w\.]+)@((?:[\w]+\.)+)([a-zA-Z]{2,4})$'
        if re.search(email_regex_pattern, username) is not None:
            try:
                username = User.objects.get(email=username).username
            except User.DoesNotExist:
                username = None

        user = authenticate(username=username, password=password)
        if user is None:
            return Response(
                {
                    "non_field_errors":
                    ["Unable to log in with provided credentials."]
                }, status.HTTP_400_BAD_REQUEST)

        token = Token.objects.get(user=user)
        return Response({"token": token.key}, status.HTTP_200_OK)
    def delete(self, request):
        r_id = get_request_body_param(request, 'recipe_id', None)
        r_instr_id = get_request_body_param(request, 'instruction_id', 0)

        recipe = RecipeUtils.get_recipe_or_404(r_id)
        instr = RecipeUtils.get_recipe_instruction_or_404(r_instr_id)

        affected_instr_step = recipe.instructions.filter(
            step_num__gt=instr.step_num)

        instr.delete()
        affected_instr_step.update(step_num=F('step_num') - 1)

        return Response({"success": True}, status=status.HTTP_200_OK)
    def post(self, request, pk):
        """
        Login user comment on a recipe by id

        @body comment: user comment on the recipe
        @return: http status of query
        @raise HTTP_401_UNAUTHORIZED: user must be login
        @raise HTTP_404_NOT_FOUND: must be a valid recipe id
        @raise HTTP_400_BAD_REQUEST: recipe comment must not be empty
        """

        comment = get_request_body_param(request, 'comment', '').strip()
        if not comment:
            return Response({'detail': 'recipe comment must not be empty'},
                            status=status.HTTP_400_BAD_REQUEST)

        recipe = RecipeUtils.get_recipe_or_404(pk)
        comment_user = request.user

        RecipeUtils.add_recipe_comments(recipe, comment_user, comment)

        ActivityTimeline.objects.create(
            user=comment_user,
            target_user=recipe.upload_by_user,
            main_object_image=comment_user.userprofile.avatar,
            target_object_image=recipe.image,
            summary_text="{0} commented on {1} recipe")

        return Response({"success": True}, status=status.HTTP_201_CREATED)
    def post(self, request, pk):
        """
        Add tags to a recipe

        @body int[] tag_ids: list of tag id
        @raise HTTP_401_UNAUTHORIZED: only creator of recipe can add tag to recipe
        """

        recipe = RecipeUtils.get_recipe_or_404(pk)
        RecipeUtils.raise_401_if_recipe_not_belong_user(recipe, request)

        tag_ids = get_request_body_param(request, 'tag_ids', [])

        tag_ids_added = []
        for tag_id in tag_ids:
            tag = RecipeUtils.get_recipe_tag_or_none(tag_id)
            if tag is not None:
                RecipeTagTable.objects.create(recipe=recipe, tag=tag)
                tag_ids_added.append(tag_id)

        response_data = {
            'tag_ids_added': tag_ids_added,
            'tag_ids_not_added': list(set(tag_ids) - set(tag_ids_added))
        }

        return Response({'data': response_data},
                        status=status.HTTP_201_CREATED)
    def put(self, request, pk):

        recipe = RecipeUtils.get_recipe_or_404(pk)
        RecipeUtils.raise_401_if_recipe_not_belong_user(recipe, request)

        r_name = get_request_body_param(request, 'name', None)
        r_desc = get_request_body_param(request, 'description', None)
        r_diff_level = get_request_body_param(request, 'difficulty_level',
                                              None)

        if r_name is not None:
            recipe.name = r_name

        if r_desc is not None:
            recipe.description = r_desc

        if r_diff_level is not None:
            recipe.difficulty_level = r_diff_level

        recipe.save()
        return Response({'success': True}, status=status.HTTP_200_OK)
    def post(self, request, pk):
        """
        Add ingredient to recipe
        """
        serving_size = get_request_body_param(request, 'serving_size',
                                              '').strip()
        ingredient_name = get_request_body_param(request, 'ingredient_name',
                                                 '').strip()
        if not serving_size:
            return Response(
                {'detail': 'serving size of ingredient must not be empty'},
                status=status.HTTP_400_BAD_REQUEST)

        if not ingredient_name:
            return Response({'detail': 'ingredient name must not be empty'},
                            status=status.HTTP_400_BAD_REQUEST)

        recipe = RecipeUtils.get_recipe_or_404(pk)
        RecipeUtils.raise_401_if_recipe_not_belong_user(recipe, request)

        ingredient = Ingredient.objects.filter(
            name__iexact=ingredient_name).first()
        if not ingredient:
            return Response(
                {
                    'detail':
                    'ingredient with name %s could not be found' %
                    ingredient_name
                },
                status=status.HTTP_400_BAD_REQUEST)

        RecipeIngredient.objects.create(recipe=recipe,
                                        ingredient=ingredient,
                                        serving_size=serving_size)

        return Response({"success": True}, status=status.HTTP_201_CREATED)
    def post(self, request, rpk, ipk):
        """
        Add ingredient to recipe
        """
        serving_size = get_request_body_param(request, 'serving_size',
                                              '').strip()
        if not serving_size:
            return Response(
                {'detail': 'serving size of ingredient must not be empty'},
                status=status.HTTP_400_BAD_REQUEST)

        recipe = RecipeUtils.get_recipe_or_404(rpk)
        RecipeUtils.raise_401_if_recipe_not_belong_user(recipe, request)

        ingredient = RecipeUtils.get_ingredient_or_404(ipk)
        RecipeIngredient.objects.create(recipe=recipe,
                                        ingredient=ingredient,
                                        serving_size=serving_size)

        return Response({"success": True}, status=status.HTTP_201_CREATED)