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
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