Esempio n. 1
0
class AnswerList:
    """
	AnswerList provides an interface between AnswerListScreen and the database

	AnswerList queries the database to get answers for AnswerListScreen
	"""
    client = pymongo.MongoClient('localhost', int(Terminal.getPort()))
    db = client[Terminal.getDBName()]

    def getAnswers(question):
        """
		Grabs answers if their parent ID matches the selected questions ID

		Parameters:
			question:
				A Dictionary object representing a question from the database
		Returns:
			A Dictionary of dictionaries representing various answers to the question
		"""
        answers = {}
        collection = AnswerList.db['Posts']
        query = {'$and': [{'ParentId': question['Id']}, {'PostTypeId': '2'}]}
        results = collection.find(query)
        for result in results:
            answers[result['Id']] = result
        return answers
    def printScreen(self):
        """
		Provides the main functionality of SearchQuestionMenu
		Prints various posts and prompts the user for input
		checks said input before returning the post selected

		Returns:
			A Dictionary object representing a post from the database
		"""
        continueRunning = True
        index = 0
        while continueRunning:
            self.printMenu(index)
            userInput = input("Enter Selection: ")
            if userInput.upper() == "EXIT" or userInput.upper() == "QUIT":
                return None
            elif userInput.upper() == "NEXT":
                if index + SearchQuestionMenu.POSTS_PER_PAGE < len(
                        self.__menuItems__):
                    index += SearchQuestionMenu.POSTS_PER_PAGE
                else:
                    print("You are currently on the last page!")
                    input("Type Enter to Continue: ")
            elif userInput.upper() == "PREV":
                if index >= SearchQuestionMenu.POSTS_PER_PAGE:
                    index += SearchQuestionMenu.POSTS_PER_PAGE
                else:
                    print("You are currently on the first page!")
                    input("Press Enter to Continue: ")
            else:
                try:
                    userInput = int(userInput)
                    if (userInput < 1
                            or userInput > SearchQuestionMenu.POSTS_PER_PAGE
                            or userInput > len(self.__menuItems__[index:])):
                        print("Input is out of range")
                    else:
                        continueRunning = False
                except Exception:
                    print("Entered input is invalid!")
                finally:
                    input("Press Enter to Continue: ")

        userInput += -1 + index

        selectedPost = self.__menuItems__[userInput]

        client = pymongo.MongoClient('localhost', int(Terminal.getPort()))
        db = client[Terminal.getDBName()]
        collection = SearchForQuestions.db["Posts"]

        updatedViewCount = selectedPost.Post['ViewCount'] + 1
        updateQuery = {'$set': {'ViewCount': updatedViewCount}}

        collection.update_one(selectedPost.Post, updateQuery)

        return selectedPost.Post
Esempio n. 3
0
    def report(self, uid):
        #TODO: print the user report out
        """
		(1) the number of questions owned and the average score for those questions
		(2) the number of answers owned and the average score for those answers
		(3) the number of votes registered for the user.
		"""
        client = pymongo.MongoClient('localhost', int(Terminal.getPort()))
        db = client[Terminal.getDBName()]

        posts = db.Posts
        votes = db.Votes

        #PART 1

        #all of the questions
        num_questions = 0
        total_score = 0

        questions = posts.find({"OwnerUserId": uid, "PostTypeId": "1"})

        for dictionary in questions:
            num_questions += 1
            total_score += dictionary["Score"]

        try:
            qavg_score = total_score / num_questions
        except ZeroDivisionError:
            qavg_score = 0
        #print("Number of questions: {}. Average score: {}.".format(num_questions, qavg_score))

        #PART 2
        num_answers = 0
        total_score = 0

        answers = posts.find({"OwnerUserId": uid, "PostTypeId": "2"})

        for dictionary in answers:
            num_answers += 1
            total_score += dictionary["Score"]

        try:
            aavg_score = total_score / num_answers
        except ZeroDivisionError:
            aavg_score = 0
        #PART 3

        num_votes = votes.count_documents({"UserId": uid})

        return {
            "num_questions": num_questions,
            "num_answers": num_answers,
            "qavg_score": qavg_score,
            "aavg_score": aavg_score,
            "num_votes": num_votes
        }
class Vote:
	"""
	Vote is an Interface which allows the user to interact with posts
	
	Vote allows the user to upvote posts and handles database updating
	to represent that
	"""
	client = pymongo.MongoClient('localhost', int(Terminal.getPort()))
	db = client[Terminal.getDBName()]
	def makeVote(post, userID=None):
		"""
		Provides the main functionality of Vote
		Creates a dictionary object representing a vote before inserting it
		into the vote collection. It then updates the post collections by increasing
		the number of votes on the given post

		Parameters:
			post:
				A Dictionary object representing the selected post from the database
			userID:
				A String object whose default value is none which represents the current
				users ID
		Returns:
			A Boolean object representing whether the vote was successfully added to the database
		"""
		postCollection = Vote.db['Posts']
		votesCollection = Vote.db['Votes']

		
		postID = post['Id']
		voteTypeID = '2'
		creationDate = str(datetime.datetime.utcnow().isoformat())
		
		if userID:
			if (not Vote.userVoted(votesCollection, post, userID)):
				voteID = Vote.getUniqueID(votesCollection)
				voteDict = {'Id' : voteID, 'PostId' : postID, 'VoteTypeId' : voteTypeID, 'UserId' : userID, 'CreationDate' : creationDate}
			else:
				print("You have already voted on this post!")
				input("Press Enter to Continue: ")
				return False
		else:
			voteID = Vote.getUniqueID(votesCollection)
			voteDict = {'Id' : voteID, 'PostId' : postID, 'VoteTypeId' : voteTypeID, 'CreationDate' : creationDate}
		
		votesCollection.insert_one(voteDict)
		Vote.updatePostVotes(post, postCollection)
		print("Vote Successfully added!")
		input("Press Enter to Continue: ")
		return True


	def getUniqueID(collection):
		"""
		Gets a unique ID for the vote being created by querying the database for all votes
		iterating to the last Dictionary object (representing a vote) grabbing it's id and incrementing
		by one

		Parameters:
			collection:
				A pymongo Collection Reference representing the current collection with which
				we are finding the unique ID for

		Returns:
			A String object representing a unique ID
		"""
		"""
		maxId = 0
		results = collection.find();
		for result in results:
			if int(result['Id']) > maxId:
				maxId = int(result['Id'])
		return str(maxId + 1)
		"""
		def findMaxAndMin(collection):
			maxNum = 1
			minNum = 1
			while  collection.find_one({'Id': str(maxNum)}) is not None:
				minNum = maxNum
				maxNum *= 2
			
			return [minNum, maxNum]
			
		votes = collection
		nums = findMaxAndMin(votes)
		minNum = nums[0]
		maxNum = nums[1]
		
		"""TESTING
		print(minNum, maxNum)
		print(type(minNum), type(maxNum))
		print("+++++++++++\n")
		"""

		while True:
			num = (minNum + maxNum) // 2
			
			search = votes.find_one({'Id': str(num)})
			
			try:
				if int(search["Id"]) >= minNum:
					minNum = num
				else:
					maxNum = num
			except:
				maxNum = num
				
			"""TESTING
			print("Min:", minNum)
			print("Max:", maxNum)
			print("Middle:", num)
			"""
				
			if minNum == maxNum or minNum+1 == maxNum:
				num = maxNum
				
				break
				
		#print("Final:", num)
		return str(num)


	def userVoted(collection, post, userID):
		"""
		Checks if the current user has voted on this post

		Parameters:
			collection:
				A pymongo Collection Reference representing the current collection with which
				we are finding the unique ID for
			post:
				A Dictionary object representing a post currently being voted on
			userID:
				A String object representing the current user's ID

		Returns:
			A Boolean representing whether the current user has voted
		"""
		query = {'$and' : 
						[{ 'UserId' : userID},
						{ 'PostId' : post['Id']}] 
				}
		return collection.find_one(query) is not None

	def updatePostVotes(post, collection): 		
		updatedScore = post['Score'] + 1
		updateQuery = { '$inc' : { 'Score' : 1 } }
		collection.update_one({'Id' : post['Id']}, updateQuery)
class SearchForQuestions:
    """
	SearchForQuestions serves as an interface between SearchForQuestionsScreen
	and the database

	SearchForQuestions allows SearchForQuestionsScreen to query the database through
	it's methods
	"""
    client = pymongo.MongoClient('localhost', int(Terminal.getPort()))
    db = client[Terminal.getDBName()]

    def getQuestions(searchKeys):
        """
		getQuestions fetches any posts matching the searchKeys
		by calling various methods

		Parameters:
			searchKeys:
				A List of String objects representing search terms entered by
				the user
		Returns:
			A Dictionary object of dictionaries representing posts that match the search
			terms
		"""
        posts = {}
        posts = SearchForQuestions.getMatchingTitle(searchKeys, posts)
        posts = SearchForQuestions.getMatchingBody(searchKeys, posts)
        posts = SearchForQuestions.getMatchingTag(searchKeys, posts)
        return posts

    def getMatchingTitle(searchKeys, posts):
        """
		Fetches any posts whose title matches one of the
		searchTerms

		Parameters:
			searchKeys:
				A List of String objects representing search terms entered by
				the user
			posts:
				A Dictionary object of Dictionaries to append any posts
				retrieved through the query
		Returns:
			A Dictionary object of dictionaries representing posts that match the search
		"""
        collection = SearchForQuestions.db["Posts"]

        for keyWord in searchKeys:
            searchQuery = {
                '$and': [{
                    'Title': {
                        '$regex': keyWord,
                        '$options': 'i'
                    }
                }, {
                    'PostTypeId': '1'
                }]
            }

            queryResults = collection.find(searchQuery)
            for result in queryResults:
                posts[result['Id']] = result

        return posts

    def getMatchingBody(searchKeys, posts):
        """
		Fetches any posts whose body matches one of the searchTerms

		Parameters:
			searchKeys:
				A List of String objects representing search terms entered by
				the user
			posts: A Dictionary object of dictionaries representing posts that match the search
			terms

		Returns:
			A Dictionary object of dictionaries representing posts that match the search
			terms
		"""
        collection = SearchForQuestions.db["Posts"]

        for keyWord in searchKeys:
            searchQuery = {
                '$and': [{
                    'Body': {
                        '$regex': keyWord,
                        '$options': 'i'
                    }
                }, {
                    'PostTypeId': '1'
                }]
            }

            queryResults = collection.find(searchQuery)
            for result in queryResults:
                posts[result['Id']] = result

        return posts

    def getMatchingTag(searchKeys, posts):
        """
		Fetches any posts whose tags match one of the searchTerms

		Parameters:
			searchKeys:
				A List of String objects representing search terms entered by
				the user
			posts: A Dictionary object of dictionaries representing posts that match the search
			terms

		Returns:
			A Dictionary object of dictionaries representing posts that match the search
			terms
		"""
        searchKeys = SearchForQuestions.processSearchKeysForTags(searchKeys)
        collection = SearchForQuestions.db["Posts"]

        for keyWord in searchKeys:
            searchQuery = {
                '$and': [{
                    'Tags': {
                        '$regex': keyWord,
                        '$options': 'i'
                    }
                }, {
                    'PostTypeId': '1'
                }]
            }

            queryResults = collection.find(searchQuery)
            for result in queryResults:
                posts[result['Id']] = result

        return posts

    def processSearchKeysForTags(searchKeys):
        for i, searchKey in enumerate(searchKeys):
            searchKeys[i] = searchKey.replace(' ', '-')
        return searchKeys