def testCreateComment(self): """ L{createComment} creates a L{Comment} object and the related L{CommentObjectLink} objects. """ commentID = uuid4() target1 = uuid4() target2 = uuid4() createAboutTagValue(target1, u'target1') createAboutTagValue(target2, u'target2') timestamp = datetime.now() createComment(commentID, [target1, target2], u'username', timestamp) result = self.store.find(Comment, Comment.objectID == commentID) comment = result.one() self.assertNotIdentical(None, comment) self.assertEqual(u'username', comment.username) self.assertEqual(timestamp, comment.creationTime) result = self.store.find(CommentObjectLink, CommentObjectLink.commentID == commentID) targets = [relation.objectID for relation in result] self.assertEqual(sorted([target1, target2]), sorted(targets)) comments = [relation.commentID for relation in result] self.assertEqual([commentID, commentID], comments)
def testCreateExistingComment(self): """ L{createComment} with an existent comment ID will remove the old comment and relations before creating a new one. """ commentID = uuid4() target1 = uuid4() target2 = uuid4() createAboutTagValue(target1, u'target1') createAboutTagValue(target2, u'target2') timestamp = datetime.now() createComment(commentID, [target1], u'username', timestamp) createComment(commentID, [target2], u'otheruser', timestamp) result = self.store.find(Comment, Comment.objectID == commentID) comment = result.one() self.assertNotIdentical(None, comment) self.assertEqual(u'otheruser', comment.username) self.assertEqual(timestamp, comment.creationTime) result = self.store.find(CommentObjectLink, CommentObjectLink.commentID == commentID) self.assertEqual([target2], [relation.objectID for relation in result]) comments = [relation.commentID for relation in result] self.assertEqual([commentID], comments)
def testCreateCommentWithoutTimestamp(self): """ L{createComment} uses C{now} if no default creation time is provided. """ commentID = uuid4() target1 = uuid4() target2 = uuid4() createAboutTagValue(target1, u'target1') createAboutTagValue(target2, u'target2') createComment(commentID, [target1, target2], u'username') result = self.store.find(Comment, Comment.objectID == commentID) comment = result.one() self.assertNotIdentical(None, comment) self.assertEqual(u'username', comment.username) self.assertNotIdentical(None, comment.creationTime)
def testDeleteComment(self): """ L{deleteComment} removes a L{Comment} object and its related L{CommentObjectLink} objects. """ commentID = uuid4() target1 = uuid4() target2 = uuid4() createAboutTagValue(target1, u'target1') createAboutTagValue(target2, u'target2') timestamp = datetime.now() createComment(commentID, [target1, target2], u'username', timestamp) self.assertEqual(1, deleteComment(commentID)) # The entry in the comments table must be gone. result = self.store.find(Comment, Comment.objectID == commentID) self.assertTrue(result.is_empty()) # The entries in the comment object link table must be gone. result = self.store.find(CommentObjectLink, CommentObjectLink.commentID == commentID) self.assertTrue(result.is_empty())
def create(self, text, username, about=None, importer=None, when=None, url=None): """Create a new comment. @param text: The C{unicode} comment text. @param username: the C{unicode} username of the commenter. @param about: Optionally, a C{list} of C{unicode} values the comment is about. @param importer: A C{unicode} string giving the name of the importer. @param when: A C{datetime.datetime} instance or C{None} if the current time should be used. @param url: A C{str} URL or C{None} if there is no URL associated with this comment. @raise L{FeatureError}: if (1) the comment text is C{None} or is all whitespace, or (2) if the importer name contains the separator (space) that we use in the about value for comment objects. @return: A C{dict} as follows: { fluidinfo.com/info/about: A C{list} of all the about values (i.e., URLs and hashtags) in the comment text, including the thing the comment was about (if anything). The hashtags are in lowercase. fluidinfo.com/info/timestamp: The C{int} UTC timestamp (seconds since the epoch) the comment was created at. fluidinfo.com/info/url: The C{url}, as received. fluidinfo.com/info/username: The C{username}, as received. } """ if not text or text.strip() == '': raise FeatureError('Comment text non-existent or just whitespace.') if importer: if ' ' in importer: raise FeatureError('Comment importer name contains a space.') else: importer = u'fluidinfo.com' when = when or datetime.utcnow() floatTime = timegm(when.utctimetuple()) + float(when.strftime('0.%f')) isoTime = when.isoformat() if not url: url = 'https://fluidinfo.com/comment/%s/%s/%s' % ( importer, username, isoTime) # Put all the explicit about values into a list called abouts. Items # are stripped and those that are not URLs are lowercased. abouts = [] if about: for item in map(unicode.strip, about): abouts.append(item if URL_REGEX.match(item) else item.lower()) abouts.extend(self._extractAbouts(text)) abouts = uniqueList(abouts) commentObjectAbout = u'%s %s %s' % (importer, username, isoTime) commentID = self._objects.create(commentObjectAbout) values = { u'fluidinfo.com/info/about': abouts, u'fluidinfo.com/info/username': username, u'fluidinfo.com/info/text': text, u'fluidinfo.com/info/url': url, u'fluidinfo.com/info/timestamp': floatTime } self._tagValues.set({commentID: values}) if abouts: # Get all the object IDs of the target objects. If an object does # not exist, create it. result = getAboutTagValues(values=abouts) existingObjects = dict( result.values(AboutTagValue.value, AboutTagValue.objectID)) missingAbouts = set(abouts) - set(existingObjects.iterkeys()) for aboutValue in missingAbouts: existingObjects[aboutValue] = self._objects.create(aboutValue) createComment(commentID, existingObjects.values(), username, when) return values
def create(self, text, username, about=None, importer=None, when=None, url=None): """Create a new comment. @param text: The C{unicode} comment text. @param username: the C{unicode} username of the commenter. @param about: Optionally, a C{list} of C{unicode} values the comment is about. @param importer: A C{unicode} string giving the name of the importer. @param when: A C{datetime.datetime} instance or C{None} if the current time should be used. @param url: A C{str} URL or C{None} if there is no URL associated with this comment. @raise L{FeatureError}: if (1) the comment text is C{None} or is all whitespace, or (2) if the importer name contains the separator (space) that we use in the about value for comment objects. @return: A C{dict} as follows: { fluidinfo.com/info/about: A C{list} of all the about values (i.e., URLs and hashtags) in the comment text, including the thing the comment was about (if anything). The hashtags are in lowercase. fluidinfo.com/info/timestamp: The C{int} UTC timestamp (seconds since the epoch) the comment was created at. fluidinfo.com/info/url: The C{url}, as received. fluidinfo.com/info/username: The C{username}, as received. } """ if not text or text.strip() == '': raise FeatureError('Comment text non-existent or just whitespace.') if importer: if ' ' in importer: raise FeatureError('Comment importer name contains a space.') else: importer = u'fluidinfo.com' when = when or datetime.utcnow() floatTime = timegm(when.utctimetuple()) + float(when.strftime('0.%f')) isoTime = when.isoformat() if not url: url = 'https://fluidinfo.com/comment/%s/%s/%s' % ( importer, username, isoTime) # Put all the explicit about values into a list called abouts. Items # are stripped and those that are not URLs are lowercased. abouts = [] if about: for item in map(unicode.strip, about): abouts.append(item if URL_REGEX.match(item) else item.lower()) abouts.extend(self._extractAbouts(text)) abouts = uniqueList(abouts) commentObjectAbout = u'%s %s %s' % (importer, username, isoTime) commentID = self._objects.create(commentObjectAbout) values = {u'fluidinfo.com/info/about': abouts, u'fluidinfo.com/info/username': username, u'fluidinfo.com/info/text': text, u'fluidinfo.com/info/url': url, u'fluidinfo.com/info/timestamp': floatTime} self._tagValues.set({commentID: values}) if abouts: # Get all the object IDs of the target objects. If an object does # not exist, create it. result = getAboutTagValues(values=abouts) existingObjects = dict(result.values(AboutTagValue.value, AboutTagValue.objectID)) missingAbouts = set(abouts) - set(existingObjects.iterkeys()) for aboutValue in missingAbouts: existingObjects[aboutValue] = self._objects.create(aboutValue) createComment(commentID, existingObjects.values(), username, when) return values