Ejemplo n.º 1
0
    def get(self, **kwargs):
        """"Adds the study to the user's wish list.

        Establishes a wish lists relationship between a study and a user.

        Args:
            token (String): A tokenized identifier for the user wish listing the study, tokenization is done with
                            a flask GET HTTP request using the crypto blueprint and formatted like this.
                            ('/token/generate', data={'user_id': 'VALID_USER_IN_DATABASE'})
                            
            study_id (int): The identifier for the study the user is trying to wish list.

        Returns:
            JSON: {"Success": True}
        """
        # obtain parameters
        parser = reqparse.RequestParser(bundle_errors=True)
        #parser.add_argument("user_id", type=str, required=True, help="The user ID of the wish lister is a String.")
        parser.add_argument(
            "study_id",
            type=int,
            required=True,
            help="The study ID of the study being wish listed is an integer.")
        returned_args = parser.parse_args()
        user_id = kwargs["user_id"]  #returned_args.get("user_id", None)
        study_id = returned_args.get("study_id", None)

        # update the user data
        Auxiliary.addWishlist(user_id, study_id)
        # return success
        return jsonify({"Success": True})
Ejemplo n.º 2
0
    def get(self,**kwargs):
        """"Returns the user ID associated with the token.

        Also creates a new user in the database if not already present.
        This function is intended to complement /token/generate,
        given that that endpoint will not be accessible to the GUI.
        It must be called prior to any other user-related endpoints
        to ensure the user is properly initialized.
        The output is in JSON form, rather than a simple String,
        so that other information can be returned if it is added to the token.
        
        Args:
            token (String): A tokenized identifier of a user, tokenization is done with
                            a flask GET HTTP request using the crypto blueprint and formatted like this.
                            ('/token/generate', data={'user_id': 'VALID_USER_IN_DATABASE'})

        Returns:
            JSON: {"user_id": user_id, "new": N} where N is true if a new user was created in the database. (If not, N is false.)
        """
        # obtain parameters
        user_id = kwargs["user_id"]
        # auxiliary function does all the work
        user_is_new = Auxiliary.createUser(f5user(user_id))
        if user_is_new:
            Auxiliary.addNotification(user_id, "Welcome!", "Thank you for visiting the FindingFive Study Store.", "Welcome")
        # return converted output
        return jsonify({"user_id": user_id, "new": user_is_new})
Ejemplo n.º 3
0
    def get(self, **kwargs):
        """"Returns the list of .studies owned by a user.

        Returns all studies owned by a user.

        Args:
            token (String): A tokenized identifier of a user, tokenization is done with
                            a flask GET HTTP request using the crypto blueprint and formatted like this.
                            ('/token/generate', data={'user_id': 'VALID_USER_IN_DATABASE'})

        Returns:
            JSON: The list of owned studies.
        """

        parser = reqparse.RequestParser(bundle_errors=True)
        #parser.add_argument("user_id", type=str, required=True, help="The user ID of the owner is a String.")
        returned_args = parser.parse_args()
        user_id = kwargs["user_id"]  #returned_args.get("user_id", None)
        # print(returned_args)
        user = Auxiliary.getUser(user_id)
        search = user.get_ownedStudies()
        params = {"Study_id": {"$in": search}}
        studyList = Auxiliary.getStudies(params)
        # convert output
        out = Auxiliary.studyListToDictList(studyList)
        # return converted output
        return jsonify(out)
Ejemplo n.º 4
0
    def get(self, **kwargs):
        """"Returns the study template.

            Returns the template of the indicated study only if the indicated user owns that study.

            Args:
                token (String): A tokenized identifier of a user, tokenization is done with
                                a flask GET HTTP request using the crypto blueprint and formatted like this.
                                ('/token/generate', data={'user_id': 'VALID_USER_IN_DATABASE'})
                                
                study_id (int): The identifier for the study the user is trying to download.

            Returns:
                JSON: The desired study template, or an error message.
            """
        # obtain parameters
        parser = reqparse.RequestParser(bundle_errors=True)
        #parser.add_argument("user_id", type=str, required=True, help="The user ID of the owner is a String.")
        parser.add_argument(
            "study_id",
            type=int,
            required=True,
            help="The study ID of the owned study is an integer.")
        returned_args = parser.parse_args()
        user_id = kwargs["user_id"]  #returned_args.get("user_id", None)
        study_id = returned_args.get("study_id", None)
        # return the study template only if owned
        if Auxiliary.isOwned(user_id, study_id):
            return Auxiliary.getTemplate(study_id)
        else:
            return jsonify({"error": "user does not own study"})
Ejemplo n.º 5
0
    def get(self, **kwargs):
        """"Establishes an owns relationship between a study and a user.

            Establishes the owns relationship only if the user has sufficient credits and doesn't already own the study.

            Args:
            
                token (String): A tokenized identifier of a user, tokenization is done with
                                a flask GET HTTP request using the crypto blueprint and formatted like this.
                                ('/token/generate', data={'user_id': 'VALID_USER_IN_DATABASE'})
                                
                study_id (int): The identifier for the study the user is trying to purchase.
                
                credits_available (int): The current credit balance for the user. Overrides any stored balance.

            Returns:
                JSON: The cost of the study, or an error message.
            """
        # obtain parameters
        parser = reqparse.RequestParser(bundle_errors=True)
        #parser.add_argument("user_id", type=str, required=True, help="The user ID of the customer is a String.")
        parser.add_argument(
            "study_id",
            type=int,
            required=True,
            help="The study ID of the study being purchased is an integer.")
        parser.add_argument(
            "credits_available",
            type=int,
            required=True,
            help="The credit balance available to the customer is an integer.")
        returned_args = parser.parse_args()
        user_id = kwargs["user_id"]  #returned_args.get("user_id", None)
        study_id = returned_args.get("study_id", None)
        credits_available = returned_args.get("credits_available", None)
        # verify the parameters exist - now handled by add_argument
        # if user_id == None or study_id == None or credits_available == None:
        #    return jsonify({"error": "missing parameter"})
        # get the necessary data from the database
        user = Auxiliary.getUser(user_id)
        # check for ownership first, because credits won't matter if already owned
        if study_id in user.get_ownedStudies():
            return jsonify({"cost": 0})
        study = Auxiliary.getStudy(study_id)
        cost = study.get_costInCredits()
        # check for sufficient credits and not already owning the study
        if cost > credits_available:
            return jsonify({"error": "insufficient credits"})
        # update the user data
        Auxiliary.addOwned(user_id, study_id, cost)
        # return the cost
        return jsonify({"cost": cost})
Ejemplo n.º 6
0
    def get(self, **kwargs):
        """"Provides the full details for a study from the database.

            Provides a study, in JSON format, with all fields of data, given the ID of the study.
            Intended for use in administrative review.
            For normal previewing, use GetPreview.get().

            Args:
                study_id (Integer): The identifier of the study to be reviewed.


            Returns:
                JSON: The study with its template.
            """
        # obtain parameters
        parser = reqparse.RequestParser(bundle_errors=True)
        parser.add_argument("study_id",
                            type=int,
                            required=True,
                            help="Specify a study for details.")

        # the second parameter to each method call is purely for consistency,
        # they don't actually do anything. They should match the defaults above.
        returned_args = parser.parse_args()
        study_id = returned_args.get("study_id", None)

        # query database
        study = Auxiliary.getStudy(study_id)

        # return converted output
        return jsonify(study.build_dict())
Ejemplo n.º 7
0
    def get(self,**kwargs):
        """"Returns the wish list status of the study.

            Returns true only if the indicated user wishes for the indicated study,
            otherwise returns false.

            Args:
                token (String): A tokenized identifier of a user, tokenization is done with
                                a flask GET HTTP request using the crypto blueprint and formatted like this.
                                ('/token/generate', data={'user_id': 'VALID_USER_IN_DATABASE'})
                                
                study_id (int): The identifier for the study the user may wish for.

            Returns:
                JSON: true, false, or an error message.
            """
        # obtain parameters
        parser = reqparse.RequestParser(bundle_errors=True)
        #parser.add_argument("user_id", type=str, required=True, help="The user ID of the potential owner is a String.")
        parser.add_argument("study_id", type=int, required=True, help="The study ID of the potentially owned study is an integer.")
        returned_args = parser.parse_args()
        user_id = kwargs["user_id"]  #returned_args.get("user_id", None)
        study_id = returned_args.get("study_id", None)
        # let the helper method handle the database call
        return jsonify(Auxiliary.isWishlisted(user_id, study_id))
Ejemplo n.º 8
0
    def get(self, **kwargs):
        """"Provides a list of pending studies from the database.

            Provides a list of studies, in JSON format, that have been neither approved nor denied.
            Excludes studies authored by the accessing user.
            If limit is given, no more than limit studies will be returned.

            Args:
                token (String): A tokenized identifier of a user, tokenization is done with
                                a flask GET HTTP request using the crypto blueprint and formatted like this.
                                ('/token/generate', data={'user_id': 'VALID_USER_IN_DATABASE'})
                                
                limit (Integer): The maximum number of studies to return. Defaults to unlimited when missing or negative.


            Returns:
                JSON: The list of pending studies.
            """
        # obtain parameters
        parser = reqparse.RequestParser(bundle_errors=True)
        parser.add_argument("limit", type=int, default=-1)

        # the second parameter to each method call is purely for consistency,
        # they don't actually do anything. They should match the defaults above.
        returned_args = parser.parse_args()
        limit = returned_args.get("limit", -1)
        user_id = kwargs["user_id"]

        # build search parameters
        params = {
            "Author_id": {
                "$ne": user_id
            },
            "Approved": {
                "$exists": False
            },
            "Denied": {
                "$exists": False
            }
        }

        # query database
        studyList = Auxiliary.getStudies(params, limit)
        # convert output
        out = Auxiliary.studyListToDictList(studyList)
        # return converted output
        return jsonify(out)
Ejemplo n.º 9
0
    def post(self,**kwargs):
        """Rates a study.

        If the user is submitting a duplicate review (same study), the previous review will be overwritten.
        Fails, modifying nothing, if the user is the author of the study.

        Args:
            study_id (Integer): The identifier of the study being rated.
            user_id (String): The identifier of the user rating the study.
            name (String): The name of the user, as it will be displayed for this review.
            rating (Integer): The rating the user is apllying to the study, from the range [0-5]
            comment (String): The comment the user is making about the study for this review.

        Returns:
            JSON: {Success: True} if the rating was made successfully.
        """
        # obtain parameters
        parser = reqparse.RequestParser(bundle_errors=True)
        parser.add_argument("study_id", type=int, required=True, help="The integer identifier of the study to rate.")
        parser.add_argument("name", type=str, required=True, help="The name to be displayed for this review.")
        parser.add_argument("rating", type=int, required=True, choices=(0, 1, 2, 3, 4, 5),
                            help="The integer [0-5] rating being given to the study.")
        parser.add_argument("comment", type=str, required=True, help="The comment to be displayed for this review")

        returned_args = parser.parse_args()

        study_id = returned_args.get("study_id", None)
        name = returned_args.get("name", None)
        rating = returned_args.get("rating", None)
        comment = returned_args.get("comment", None)
        user_id = kwargs["user_id"]

        # check for author
        user = Auxiliary.getUser(user_id)
        if study_id in user.get_authorList():
            return jsonify({"Success": False, "Reason": "User is Author."})

        ratingsys(study_id, user_id, name, rating, comment)

        return jsonify({"Success": True})
Ejemplo n.º 10
0
    def post(self,**kwargs):
        """Uploads a new study to the database.

        Uploaded studies are not visible in the store's search results until they are approved by an administrator.
        Adds the new study to the author's author list and owned list.
        Note the difference between author and author_id:
        author is intended to be displayed to other users,
        while author_id is used for internal referencing.
        They can be the same, but security may be improved by not displaying other user's IDs.

        Args:
            title (String): The title of the study.
            author (String): The author of the study, as it should be displayed.
            costInCredits (Integer): The cost of the study in credits. Negative values are possible, but will not be
                                     returned when filtering by price.
            purpose (String): The purpose of the study.
            references (String): The reference that others should use when referencing this study.
            categories (List of Strings): The main categories that the study belongs to.
            subcategories (List of Strings): The subcategories that the study belongs to.
            keywords (List of Strings): The keywords associated with a study.
            num_stimuli (Integer): The number of stimuli that the study uses.
            num_responses (Integer): The number of responses that the study uses.
            num_trials (Integer): The number of trials that the study uses.
            randomize (Boolean): Whether the study uses randomization.
            duration (Integer): The expected duration, in minutes, of the study.
            institution (String): The institution associated with the author or study.
            template (String): The JSON study template from FindingFive.
            images (List of Strings): The images for display when previewing the study.
                                      May be references to external images, or may be base64 encoded images.
            abstract (String): The abstract of the study. Acts as a description.
            author_id (String): The user ID of the author.


        Returns:
            JSON: {"study_id": id}, where id is the generated study ID for this study.
        """
        # obtain parameters
        parser = reqparse.RequestParser(bundle_errors=True)
        parser.add_argument("title", type=str, required=True,
                            help="Title should be a String.", nullable=False)
        parser.add_argument("author", type=str, required=True,
                            help="Author should be a String.", nullable=False)
        parser.add_argument("costInCredits", type=int, required=True,
                            help="Cost should be an integer.", nullable=False)
        parser.add_argument("purpose", type=str, required=True,
                            help="Purpose should be a String.", nullable=False)
        parser.add_argument("references", type=str, required=True,
                            help="References should be a String.", nullable=False)
        parser.add_argument("categories", type=str, action='append', required=True,
                            help="Category should be a list of Strings.", nullable=False)
        parser.add_argument("subcategories", type=str, action='append', required=True,
                            help="Subcategories should be a list of Strings.", nullable=False)
        parser.add_argument("keywords", type=str, action='append', required=True,
                            help="Keywords should be a list of Strings.", nullable=False)
        parser.add_argument("num_stimuli", type=int, required=True,
                            help="The number of stimuli should be an integer.", nullable=False)
        parser.add_argument("num_responses", type=int, required=True,
                            help="The number of responses should be an integer.", nullable=False)
        parser.add_argument("num_trials", type=int, required=True,
                            help="The number of trials should be an integer.", nullable=False)
        parser.add_argument("randomize", type=inputs.boolean, required=True,
                            help="Randomization of trials should be a boolean.", nullable=False)
        parser.add_argument("duration", type=int, required=True,
                            help="Duration should be an integer.", nullable=False)
        parser.add_argument("institution", type=str, required=True,
                            help="Institution should be a String.", nullable=False)
        parser.add_argument("template", type=str, required=True,
                            help="Template should be a JSON in String form.", nullable=False)
        parser.add_argument("images", type=str, action="append",
                            required=True, help="Images should be a list of base64-encoded Strings.", nullable=False)
        parser.add_argument("abstract", type=str, required=True,
                            help="Abstract should be a String.", nullable=False)
        #parser.add_argument("author_id", type=str, required=True, help="The author_id is the user_id of the uploading user.")

        returned_args = parser.parse_args()

        constants = DbConnection.connector()["Constants"]
        counter = constants.find_one_and_update({"Next_ID": {"$exists": True}}, {"$inc": {"Next_ID": 1}})
        study_id = counter["Next_ID"]
        title = returned_args.get("title", None)
        author = returned_args.get("author", None)
        costInCredits = returned_args.get("costInCredits", None)
        purpose = returned_args.get("purpose", None)

        # todo: check to ensure that the lists are coming back with proper values
        references = returned_args.get("references", None)
        categories = returned_args.get("categories", None)
        subcategories = returned_args.get("subcategories", None)
        keywords = returned_args.get("keywords", None)
        num_stimuli = returned_args.get("num_stimuli", None)
        num_responses = returned_args.get("num_responses", None)
        num_trials = returned_args.get("num_trials", None)
        randomize = returned_args.get("randomize", None)
        duration = returned_args.get("duration", None)
        institution = returned_args.get("institution", None)
        template = returned_args.get("template", None)
        images = returned_args.get("images", None)
        abstract = returned_args.get("abstract", None)
        author_id = kwargs["user_id"]  #returned_args.get("author_id", None)
        # the miscelaneous-looking 0 is the initial rating.
        study = FindingFiveStudyStoreStudy(study_id, title, author, costInCredits, purpose, references, categories,
                                           subcategories, keywords, num_stimuli, num_responses, randomize,
                                           duration, num_trials, 0, institution, template, images, abstract, author_id)
        # connect = DbConnection.connector()["Studies"]
        study_dict = study.build_database_doc()

        # using update_one so that we can use update operations to establish the upload date.
        DbConnection.connector()["Studies"].update_one({"Study_id": study_id}, study_dict, upsert=True)

        # update the author and ownenship information of the uploading user
        Auxiliary.addAuthored(author_id, study_id)
        # tq=task_queue.TaskQueue()
        # tq.add_function(prefix_cache.SearchCache.add_new_word,full=title)

        return jsonify({"study_id": study_id})
Ejemplo n.º 11
0
    def get(self,**kwargs):
        """"Provides a list of studies from the database.

            Provides a list of studies, in JSON format, that meet some specified requirements.
            All parameters are optional, except for the token required for authentication.
            Providing none of the optional parameters will result in all studies being returned,
            but may result in a connection time out.
            If title is given, return only studies with that title.
            If keywords are given, return only studies with all of those keywords.
            If keyword_all is false, each study need only have one or more keywords, not necessarily all of them.
            If searchInput is given, return studies with that title OR any keyword in searchInput,
            splitting by a comma with an optional space after it.
            Specifying title or keywords with searchInput will require each individual parameter to be satisfied.
            If limit is given, no more than limit studies will be returned.
            If price_min is given, return only studies at that price or higher.
            If price_max is given, return only studies at that price or lower.
            If price_min is greater than price_max, ignore price_max.
            For the purposes of this method, the price of a study may not be negative,
            so all negative values of price_min and price_max will be ignored.
            If duration_min is given, return only studies at that duration or higher.
            If duration_max is given, return only studies at that duration or lower.
            If duration_min is greater than duration_max, ignore duration_max.
            For the purposes of this method, the duration of a study may not be negative,
            so all negative values of duration_min and duration_max will be ignored.
            If rating_min is given, return only studies with that rating or higher.
            If rating_max is given, return only studies with that rating or lower.
            If rating_min is greater than or equal to rating_max, ignore rating_max.
            The valid options for rating_min and rating_max are 0, 1, 2, 3, 4, and 5.
            If category is given, return only studies with that category.
            If sub_category is given, return only studies with that sub category.
            If institution is given, return only studies with that institution.
            If max_days_since_upload is given, return only studies that have been uploaded within that number of days.

            Args:
                title (String): The title that a study must have..
                keywords (List<String>): Contains all the keywords that a study must have.
                keyword_all (Boolean): If false, any non-empty subset of the keywords is sufficient to match.
                searchInput (String): The title or comma-seperated keyword set that a study must have at least one of.
                limit (Integer): The maximum number of studies to return. Defaults to unlimited when missing or negative.
                price_min (Integer): The minimum price, in credits, that a study may have.
                price_max (Integer): The maximum price, in credits, that a study may have.
                duration_min (Integer): The minimum duration, in minutes, that a study may have.
                duration_max (Integer): The maximum duration, in minutes, that a study may have.
                rating_min (Integer): The minimum rating that a study may have. Must be in the range [0, 5].
                rating_max (Integer): The maximum rating that a study may have. Must be in the range [0, 5].
                category (String): The category that a study must have.
                sub_category (String): The sub category that a study must have.
                institution (String): The institution that a study must have.
                max_days_since_upload (Integer): The maximum days after upload that a study may be.


            Returns:
                JSON: The list of studies that meet the specified requirements.
            """
        # obtain parameters
        parser = reqparse.RequestParser(bundle_errors=True)
        parser.add_argument("title", type=str)
        parser.add_argument("keywords", type=str, action="append")
        parser.add_argument("keyword_all", type=inputs.boolean, default=True)
        parser.add_argument("searchInput", type=str)
        parser.add_argument("limit", type=int, default=-1)
        parser.add_argument("price_min", type=int, default=0)
        parser.add_argument("price_max", type=int, default=-1)
        parser.add_argument("duration_min", type=int, default=0)
        parser.add_argument("duration_max", type=int, default=-1)
        parser.add_argument("rating_min", type=int, default=0, choices=(0, 1, 2, 3, 4, 5))
        parser.add_argument("rating_max", type=int, default=5, choices=(0, 1, 2, 3, 4, 5))
        parser.add_argument("category", type=str)
        parser.add_argument("sub_category", type=str)
        parser.add_argument("institution", type=str)
        parser.add_argument("max_days_since_upload", type=int)

        # the second parameter to each method call is purely for consistency,
        # they don't actually do anything. They should match the defaults above.
        returned_args = parser.parse_args()
        title = returned_args.get("title", None)
        keywords = returned_args.get("keywords", None)
        keyword_all = returned_args.get("keyword_all", True)
        searchInput = returned_args.get("searchInput", None)
        limit = returned_args.get("limit", -1)
        price_min = returned_args.get("price_min", 0)
        price_max = returned_args.get("price_max", -1)
        duration_min = returned_args.get("duration_min", 0)
        duration_max = returned_args.get("duration_max", -1)
        rating_min = returned_args.get("rating_min", 0)
        rating_max = returned_args.get("rating_max", 5)
        category = returned_args.get("category", None)
        sub_category = returned_args.get("sub_category", None)
        institution = returned_args.get("institution", None)
        max_days_since_upload = returned_args.get("max_days_since_upload", None)

        # build search parameters
        params = {"Approved": {"$exists": True}, "Denied": {"$exists": False}}
        if title is not None:
            params["Title"] = title
        if keywords is not None:
            # intersection/and
            if keyword_all is True:
                params["Keywords"] = {"$all": keywords}
            # union/or
            else:
                params["Keywords"] = {"$in": keywords}
        if searchInput is not None:
            splitSearch = re.split(r', ?', searchInput)
            params["$or"] = [{"Title": searchInput}, {"Keywords": {"$in": splitSearch}}]
        self.addRange(params, price_min, price_max, "CostinCredits")
        self.addRange(params, duration_min, duration_max, "Duration")
        self.addRange(params, rating_min, rating_max, "Rating")
        if category is not None:
            # using $in so that we can make Categories an array or string without breaking this code
            params["Categories"] = {"$in": [category]}
        if sub_category is not None:
            # using $in so that we can make Sub_Categories an array or string without breaking this code
            params["Sub_Categories"] = {"$in": [sub_category]}
        if institution is not None:
            params["Institution"] = institution
        if max_days_since_upload is not None:
            max_millis = max_days_since_upload * 86400000  #24 * 60 * 60 * 1000
            params["$expr"] = {"$lt": [{"$subtract": ["$$NOW", "$Timestamp"]}, max_millis]}
        # query database
        studyList = Auxiliary.getStudies(params, limit)
        # convert output
        out = Auxiliary.studyListToDictList(studyList)
        for d in out:
            d["reviews"] = []
        # return converted output
        return jsonify(out)
Ejemplo n.º 12
0
    def get(self, **kwargs):
        """"Reviews a pending study.

            Approves or denies a given study.
            Creates a notification to alert the user, based on the parameters.
            If an optional parameter is not given, that field is assumed to be acceptable.
            Fails, modifying nothing, if the user is the author of the study.

            Args:
                user_id (String): The identifier of the user approving or denying the study, required.
                study_id (Integer): The identifier of the study being reviewed, required.
                approved (Boolean): Whether to approve or deny this study. When true, ignore all following paramaters.
                title (String): The comment on what was wrong with the title.
                reference (String): The comment on what was wrong with the references.
                purpose (String): The comment on what was wrong with the purpose.
                categories (String): The comment on what was wrong with the categories.
                subcategories (String): The comment on what was wrong with the subcategories.
                keywords (String): The comment on what was wrong with the keywords.
                abstract (String): The comment on what was wrong with the abstract.
                num_stimuli (String): The comment on what was wrong with the number of stimuli.
                duration (String): The comment on what was wrong with the duration of the study.
                num_responses (String): The comment on what was wrong with the number of responses.
                num_trials (String): The comment on what was wrong with the number of trials.
                randomized (String): The comment on what was wrong with the randomization of the study.
                images (String): The comment on what was wrong with the images.
                template (String): The comment on what was wrong with the JSON template.


            Returns:
                JSON: {"Success":True} unless the review failed.
            """
        # establish parameters
        parser = reqparse.RequestParser(bundle_errors=True)
        parser.add_argument("study_id", type=int, required=True)
        parser.add_argument("approved", type=inputs.boolean, default=False)
        parser.add_argument("title", type=str)
        parser.add_argument("reference", type=str)
        parser.add_argument("purpose", type=str)
        parser.add_argument("categories", type=str)
        parser.add_argument("subcategories", type=str)
        parser.add_argument("keywords", type=str)
        parser.add_argument("abstract", type=str)
        parser.add_argument("num_stimuli", type=str)
        parser.add_argument("duration", type=str)
        parser.add_argument("num_responses", type=str)
        parser.add_argument("num_trials", type=str)
        parser.add_argument("randomized", type=str)
        parser.add_argument("images", type=str)
        parser.add_argument("template", type=str)

        # obtain first parameters
        returned_args = parser.parse_args()
        study_id = returned_args.get("study_id", -1)
        user_id = kwargs["user_id"]
        approved = returned_args.get("approved", None)

        # check for author
        user = Auxiliary.getUser(user_id)
        if study_id in user.get_authorList():
            return jsonify({"Success": False, "Reason": "User is Author."})

        # check for non-existent study, storing the title for later
        study_title = Auxiliary.getTitle(study_id)
        if study_title is None:
            return jsonify({"Success": False, "Reason": "No such study."})

        # check for approval
        if approved is True:
            user_id = Auxiliary.timestampAndGetAuthor(study_id, "Approved")
            body = "Your study, " + study_title + ", was approved and is now visible in the Study Store."
            Auxiliary.addNotification(user_id, "Study approved.", body,
                                      "Approval")
            return jsonify({"Success": True})

        # otherwise we need all the other parameters
        title = returned_args.get("title", None)
        reference = returned_args.get("reference", None)
        purpose = returned_args.get("purpose", None)
        categories = returned_args.get("categories", None)
        subcategories = returned_args.get("subcategories", None)
        keywords = returned_args.get("keywords", None)
        abstract = returned_args.get("abstract", None)
        num_stimuli = returned_args.get("num_stimuli", None)
        duration = returned_args.get("duration", None)
        num_responses = returned_args.get("num_responses", None)
        num_trials = returned_args.get("num_trials", None)
        randomized = returned_args.get("randomized", None)
        images = returned_args.get("images", None)
        template = returned_args.get("template", None)

        # build response body
        body_string = "Your study, " + study_title + ", has been denied."
        body_string += "Problems with the title: " + str(title) + "\n"
        body_string += "Problems with the reference: " + str(reference) + "\n"
        body_string += "Problems with the purpose: " + str(purpose) + "\n"
        body_string += "Problems with the categories: " + str(
            categories) + "\n"
        body_string += "Problems with the subcategories: " + str(
            subcategories) + "\n"
        body_string += "Problems with the keywords: " + str(keywords) + "\n"
        body_string += "Problems with the abstract: " + str(abstract) + "\n"
        body_string += "Problems with the number of stimuli: " + str(
            num_stimuli) + "\n"
        body_string += "Problems with the duration of the study: " + str(
            duration) + "\n"
        body_string += "Problems with the number of responses: " + str(
            num_responses) + "\n"
        body_string += "Problems with the number of trials: " + str(
            num_trials) + "\n"
        body_string += "Problems with the randomization: " + str(
            randomized) + "\n"
        body_string += "Problems with the images: " + str(images) + "\n"
        body_string += "Problems with the template: " + str(template) + "\n"

        # mark the study and post the notification
        user_id = Auxiliary.timestampAndGetAuthor(study_id, "Denied")
        Auxiliary.addNotification(user_id, "Study denied.", body_string,
                                  "Denial")
        return jsonify({"Success": True})