def test_notifications_for_new_post(self):
        ws = self.portal['workspaces']['workspace-1']
        people = self.portal['people']
        self.mailhost.messages = []
        login(self.portal, 'test_user_1')

        post = helpers.create_post(ws, 'new-post', title=u"New Post",
            text=richtextify(u"<p>test</p><p>test</p>123"))

        self.assertEqual(len(self.mailhost.messages), 0)

        helpers.publish_post(post)

        self.assertEqual(len(self.mailhost.messages), 2)

        recipients = [unicode(m['To']) for m in self.mailhost.messages]
        expected_recipients = []
        for uid in ws.getMemberIds():
            name = getattr(people.get(uid, None), 'title', uid)
            email = getattr(people.get(uid, None), 'emailAddress', None)
            if not email:
                continue
            expected_recipients.append('{0} <{1}>'.format(name, email))
        self.assertEqual(recipients, expected_recipients)

        for message in self.mailhost.messages:
            self.assertEqual(unicode(message['Subject']), u"[Plone site] " +
                u"New post: “New Post” by Test User in Workspace 1")

            msg_text = quopri.decodestring(message.get_payload())
            expected_msg_text = u"test\n\ntest\n123"
            self.assertEqual(msg_text, expected_msg_text)
    def test_notifications_for_new_reply(self):
        ws = self.portal['workspaces']['workspace-1']
        people = self.portal['people']
        post = ws['post-2']
        self.mailhost.messages = []
        login(self.portal, 'test_user_1')
        helpers.create_reply(post, 'new-reply',
            text=richtextify(u"<p>test</p><p>test</p>123"))

        self.assertEqual(len(self.mailhost.messages), 2)

        recipients = [unicode(m['To']) for m in self.mailhost.messages]
        expected_recipients = []
        for uid in ['test_user_1', 'test_user_2']:
            name = getattr(people.get(uid, None), 'title', uid)
            email = getattr(people.get(uid, None), 'emailAddress', None)
            expected_recipients.append('{0} <{1}>'.format(name, email))
        self.assertEqual(recipients, expected_recipients)

        for message in self.mailhost.messages:
            self.assertEqual(unicode(message['Subject']), u"[Plone site] " +
                u"Test User replied to “Post 2” in Workspace 1")

            msg_text = quopri.decodestring(message.get_payload())
            expected_msg_text = u"test\n\ntest\n123"
            self.assertEqual(msg_text, expected_msg_text)
    def setUpContent(self):
        pat.login(self.portal, testing.MANAGER)

        self.project = helpers.create_project(
            self.workspaces, 'project',
            title=u"Prøjėçt",
            description=u"A lengthy but interesting description",
            goals=u"Lorem ipsum. Add goals here.")
        ws_helpers.do_action_for(self.project, 'publish')
        self.ws = ws_helpers.create_workspace(self.workspaces,
            "project-workspace", title=u"Project Workspace")
        self.project.add_workspace(self.ws)

        self.post_text = richtextify(
            u"<p>" + 40*u"<a href="">Rich</a> Text " + u"</p>")
        self.project.invokeFactory(
            'ixds.Post', "post-in-project", project_featured=True,
            title="Post in project",
            text=self.post_text)
        self.project_post = self.project["post-in-project"]
        ws_helpers.do_action_for(self.project_post, 'publish')
        self.ws.invokeFactory(
            'ixds.Post', "post-in-workspace", project_featured=True,
            title="Post in workspace",
            text=self.post_text)
        self.workspace_post = self.ws["post-in-workspace"]
        ws_helpers.do_action_for(self.workspace_post, 'publish')

        self.project.invokeFactory(
            'ixds.Post', "local-project-post", project_featured=False,
            title="Local Project-Post",
            text=self.post_text)
        self.local_project_post = self.project["local-project-post"]
        ws_helpers.do_action_for(self.local_project_post, 'publish')

        self.workspace_post.invokeFactory(
            'ixds.Reply', "reply-in-workspace",
            title="Reply in workspace",
            text=self.post_text)

        pat.logout()
def create_test_content(site):
    catalog = getToolByName(site, 'portal_catalog')
    portal_workflow = getToolByName(site, 'portal_workflow')

    print '### Creating test content on "%s" ###' % site

    print "creating challenges..."

    challenges = [
        {
            'portal_type': 'cnrd.Challenge',
            'title': u'Challenge 1',
            'description': u'Interesting description.',
            'icon': named_image(150, 150),
            'publish': False,
            'finalize': [challenge_finalizer],
        },
        {
            'portal_type': 'cnrd.Challenge',
            'title': u'Challenge 2',
            'description': u'Another interesting description.',
            'icon': named_image(150, 150),
            'publish': False,
            'finalize': [challenge_finalizer],
        },
    ]

    stats = build(challenges, site['challenges'])
    print '  %i created, %i modified, %i skipped, %i recursions.' % stats

    print "creating universities..."

    universities = [
        {
            'portal_type': 'cnrd.University',
            'title': u'University of Roma',
            'text': richtextify(u'<p>Some nice words.</p>'),
            'picture': named_image(150, 150),
            'location': 'Roma',
            'publish': True,
            'finalize': [university_finalizer],
        },
        {
            'portal_type': 'cnrd.University',
            'title': u'University of Helsinki',
            'text': richtextify(u'<p>Some nice words.</p>'),
            'picture': named_image(150, 150),
            'location': 'Helsinki',
            'publish': True,
            'finalize': [university_finalizer],
        },
    ]

    stats = build(universities, site['universities'])
    print '  %i created, %i modified, %i skipped, %i recursions.' % stats

    print "creating members..."

    members = [
        {
            'portal_type': 'cnrd.Member',
            'id': 'test_user_1',
            'title': u'Test User',
            'emailAddress': '*****@*****.**',
            'description': u'What are you lookin\' at?',
            'portrait': named_blob_image(150, 300, filename=u"member_img.png"),
            'university': relatify(site['universities'][utilities.find_possible_id(
                'University of Helsinki')]),
            'role': 'student',
            'publish': False,
            'finalize': [
                (covalent_utilities.add_plone_member, {'password': '******'}),
                covalent_utilities.activate_member_object],
        },
        {
            'portal_type': 'cnrd.Member',
            'id': 'test_user_2',
            'title': u'Karl Heinz',
            'emailAddress': '*****@*****.**',
            'description': u'What are you lookin\' at?',
            'portrait': named_blob_image(300, 150, filename=u"member_img.png"),
            'university': relatify(site['universities'][utilities.find_possible_id(
                'University of Helsinki')]),
            'role': 'student',
            'publish': False,
            'finalize': [
                (covalent_utilities.add_plone_member, {'password': '******'}),
                covalent_utilities.activate_member_object],
        },
        {
            'portal_type': 'cnrd.Member',
            'id': 'new-student',
            'title': u'New Student',
            'emailAddress': '*****@*****.**',
            'description': u'What are you lookin\' at?',
            'portrait': named_blob_image(300, 150, filename=u"member_img.png"),
            'university': relatify(site['universities'][utilities.find_possible_id(
                'University of Helsinki')]),
            'role': 'student',
            'as_user': '******',
            'publish': False,
        },
        {
            'portal_type': 'cnrd.Member',
            'id': 'rejected-student',
            'title': u'Rejected Student',
            'emailAddress': '*****@*****.**',
            'description': u'What are you lookin\' at?',
            'portrait': named_blob_image(300, 150, filename=u"member_img.png"),
            'university': relatify(site['universities'][utilities.find_possible_id(
                'University of Helsinki')]),
            'role': 'student',
            'as_user': '******',
            'publish': False,
            'finalize': [
                setToRejected],
        },
        {
            'portal_type': 'cnrd.Member',
            'id': 'pending-student',
            'title': u'Pending Student',
            'emailAddress': '*****@*****.**',
            'description': u'What are you lookin\' at?',
            'portrait': named_blob_image(300, 150, filename=u"member_img.png"),
            'university': relatify(site['universities'][utilities.find_possible_id(
                'University of Helsinki')]),
            'role': 'student',
            'publish': False,
        },
        {
            'portal_type': 'cnrd.Member',
            'id': 'expired-student',
            'title': u'Expired Student',
            'emailAddress': '*****@*****.**',
            'description': u'What are you lookin\' at?',
            'portrait': named_blob_image(300, 150, filename=u"member_img.png"),
            'university': relatify(site['universities'][utilities.find_possible_id(
                'University of Helsinki')]),
            'role': 'student',
            'publish': False,
            'finalize': [
                setToExpired],
        },
        {
            'portal_type': 'cnrd.Member',
            'id': 'active-student',
            'title': u'Active Student',
            'emailAddress': '*****@*****.**',
            'description': u'What are you lookin\' at?',
            'portrait': named_blob_image(300, 150, filename=u"member_img.png"),
            'university': relatify(site['universities'][utilities.find_possible_id(
                'University of Helsinki')]),
            'role': 'student',
            'publish': False,
            'finalize': [
                (covalent_utilities.add_plone_member, {'password': '******'}),
                covalent_utilities.activate_member_object],
        },
        {
            'portal_type': 'cnrd.Member',
            'id': 'inactive-student',
            'title': u'Inactive Student',
            'emailAddress': '*****@*****.**',
            'description': u'What are you lookin\' at?',
            'portrait': named_blob_image(300, 150, filename=u"member_img.png"),
            'university': relatify(site['universities'][utilities.find_possible_id(
                'University of Helsinki')]),
            'role': 'student',
            'publish': False,
            'finalize': [
                (covalent_utilities.add_plone_member, {'password': '******'}),
                covalent_utilities.activate_member_object,
                (portal_workflow.doActionFor, {'action': 'deactivate'})],
        },
        {
            'portal_type': 'cnrd.Member',
            'id': 'new_test_student_1',
            'title': u'New Test Student 1',
            'emailAddress': '*****@*****.**',
            'description': u'What are you lookin\' at?',
            'portrait': named_blob_image(300, 150, filename=u"member_img.png"),
            'university': relatify(site['universities'][utilities.find_possible_id(
                'University of Helsinki')]),
            'role': 'student',
            'as_user': '******',
            'publish': False,
            'finalize': [],
        },
        {
            'portal_type': 'cnrd.Member',
            'id': 'new_test_student_2',
            'title': u'New Test Student 2',
            'emailAddress': '*****@*****.**',
            'description': u'What are you lookin\' at?',
            'portrait': named_blob_image(300, 150, filename=u"member_img.png"),
            'university': relatify(site['universities'][utilities.find_possible_id(
                'University of Helsinki')]),
            'role': 'student',
            'as_user': '******',
            'publish': False,
            'finalize': [],
        },
        {
            'portal_type': 'cnrd.Member',
            'id': 'new_test_teacher',
            'title': u'New Test Teacher',
            'emailAddress': '*****@*****.**',
            'description': u'What are you lookin\' at?',
            'portrait': named_blob_image(300, 150, filename=u"member_img.png"),
            'university': relatify(site['universities'][utilities.find_possible_id(
                'University of Helsinki')]),
            'role': 'teacher',
            'as_user': '******',
            'publish': False,
            'finalize': [],
        },
    ]
    stats = build(members, site['people'])
    print '  %i created, %i modified, %i skipped, %i recursions.' % stats

    addSiteAdminsToAdminGroup(site)

    print "creating workspaces..."
    workspaces = [
        {
            'portal_type': 'ixds.Workspace',
            'title': u'My Workspace Draft',
            'description': u'Interesting description.',
            'challenges': [
                relatify(site['challenges']['challenge-1']),
            ],
            'members': set(),
            'previouslyEdited': True,
            'publish': False,
            'finalize': [
                (set_dates, {'date': DateTime() - 1})],
        },
        {
            'portal_type': 'ixds.Workspace',
            'title': u'Workspace 1',
            'description': u'Interesting description.',
            'challenges': [
                relatify(site['challenges']['challenge-1']),
            ],
            'members': set(['test_user_1', 'test_user_2', ]),
            'images': [named_image(150, 150), ],
            'previouslyEdited': True,
            'finalize': [
                update_workspace_image_fields,
                (set_dates, {'date': DateTime() - 80})],
        },
        {
            'portal_type': 'ixds.Workspace',
            'title': u'Workspace 2',
            'description': u'Another interesting description.',
            'challenges': [
                relatify(site['challenges']['challenge-2']),
            ],
            'members': set(['test_user_1', ]),
            'images': [named_image(150, 150), ],
            'previouslyEdited': True,
            'finalize': [
                update_workspace_image_fields,
                (set_dates, {'date': DateTime() - 70})],
        },
        {
            'portal_type': 'ixds.Workspace',
            'title': u'Empty workspace',
            'description': u'There is nothing in here, trust me.',
            'challenges': [
                relatify(site['challenges']['challenge-2']),
            ],
            'members': set(['test_user_1', ]),
            'images': [named_image(150, 150), ],
            'previouslyEdited': True,
            'finalize': [
                update_workspace_image_fields,
                (set_dates, {'date': DateTime() - 70})],
        },
        {
            'portal_type': 'ixds.Workspace',
            'title': u'Workspace with many posts',
            'description': u'This workspace certainly has a lot of posts.',
            'challenges': [
                relatify(site['challenges']['challenge-2']),
            ],
            'members': set(['test_user_1', ]),
            'images': [named_image(150, 150), ],
            'previouslyEdited': True,
            'finalize': [
                update_workspace_image_fields,
                (set_dates, {'date': DateTime() - 14})],
        },
        {
            'portal_type': 'ixds.Workspace',
            'title': u'Workspace with tasks',
            'description': u'',
            'challenges': [
                relatify(site['challenges']['challenge-2']),
            ],
            'members': set(['test_user_1', ]),
            'images': [named_image(150, 150), ],
            'previouslyEdited': True,
            'finalize': [
                update_workspace_image_fields,
                (set_dates, {'date': DateTime() - 14})],
        },
        {
            'portal_type': 'ixds.Workspace',
            'title': u'Workspace with polls',
            'description': u'',
            'challenges': [
                relatify(site['challenges']['challenge-2']),
            ],
            'members': set(['test_user_1', ]),
            'images': [named_image(150, 150), ],
            'previouslyEdited': True,
            'finalize': [
                update_workspace_image_fields,
                (set_dates, {'date': DateTime() - 14})],
        },
        {
            'portal_type': 'ixds.Workspace',
            'title': u'Workspace with files',
            'description': u'',
            'challenges': [
                relatify(site['challenges']['challenge-2']),
            ],
            'members': set(['test_user_2', ]),
            'images': [named_image(150, 150), ],
            'previouslyEdited': True,
            'finalize': [
                update_workspace_image_fields,
                (set_dates, {'date': DateTime() - 14})],
        },
    ]

    stats = build(workspaces, site['workspaces'])
    print '  %i created, %i modified, %i skipped, %i recursions.' % stats

    print "creating posts and files..."
    posts = [
        {
            'portal_type': 'ixds.Post',
            'title': u'Post 1',
            'text': richtextify(u'<p>This is text.</p>'),
            'parent': site['workspaces']['workspace-1'],
            'as_user': '******',
        },
        {
            'portal_type': 'ixds.Post',
            'title': u'Post 2',
            'text': richtextify(u'<p>This is more text.</p>'
                u'<p>More text, again.</p>'),
            'parent': site['workspaces']['workspace-1'],
            'as_user': '******',
            'items': [
                {
                    'portal_type': 'ixds.Reply',
                    'title': u'Reply 1',
                    'text': richtextify(u'<p>That\'s obvious.</p>'),
                    'as_user': '******',
                    'publish': False,
                    'finalize': [notify_form_completed],
                },
                {
                    'portal_type': 'ixds.Reply',
                    'title': u'Reply 2',
                    'text': richtextify(u'<p>Indeed.</p>'),
                    'as_user': '******',
                    'publish': False,
                    'finalize': [notify_form_completed],
                },
            ],
        },
        # tasks:
        {
            'portal_type': 'ixds.Task',
            'title': u'Task in the future',
            'text': richtextify(u'<p>This is fresh text.</p>'),
            'parent': site['workspaces']['workspace-with-tasks'],
            'date': DateTime() + 7,
            'finalize': [(covalent_utilities.set_owner_and_creator, {'userid': 'test_user_2'})],
        },
        {
            'portal_type': 'ixds.Task',
            'title': u'Task in the past',
            'text': richtextify(u'<p>This is text from long ago.</p>'),
            'parent': site['workspaces']['workspace-with-tasks'],
            'date': DateTime() - 7,
            'finalize': [(covalent_utilities.set_owner_and_creator, {'userid': 'test_user_2'})],
        },
        # polls and ratings:
        {
            'portal_type': 'ixds.Poll',
            'pollOrRating': 'poll',
            'options': set(['the one', 'the other']),
            'title': u'The poll from the past',
            'text': richtextify(u'<p>This is text from long ago.</p>'),
            'parent': site['workspaces']['workspace-with-polls'],
            'date': DateTime() - 7,
            'deadline': datetime.now() - timedelta(days=3),
            'finalize': [(covalent_utilities.set_owner_and_creator, {'userid': 'test_user_2'}),
                poll.initialize],
        },
        {
            'portal_type': 'ixds.Poll',
            'pollOrRating': 'rating',
            'options': set(range(1, 6)),
            'title': u'The rating from the past',
            'text': richtextify(u'<p>This is text from long ago.</p>'),
            'parent': site['workspaces']['workspace-with-polls'],
            'date': DateTime() - 6,
            'deadline': datetime.now() - timedelta(days=4),
            'finalize': [(covalent_utilities.set_owner_and_creator, {'userid': 'test_user_2'}),
                poll.initialize],
        },
        {
            'portal_type': 'ixds.Poll',
            'pollOrRating': 'poll',
            'options': set(['the one', 'the other']),
            'title': u'The poll',
            'text': richtextify(u'<p>This is text.</p>'),
            'parent': site['workspaces']['workspace-with-polls'],
            'date': DateTime() - 1,
            'deadline': datetime.now() + timedelta(days=7),
            'finalize': [(covalent_utilities.set_owner_and_creator, {'userid': 'test_user_2'}),
                poll.initialize],
        },
        {
            'portal_type': 'ixds.Poll',
            'pollOrRating': 'rating',
            'options': set(range(1, 6)),
            'title': u'The rating',
            'text': richtextify(u'<p>This is text.</p>'),
            'parent': site['workspaces']['workspace-with-polls'],
            'date': DateTime() - 2,
            'deadline': datetime.now() + timedelta(days=6),
            'finalize': [(covalent_utilities.set_owner_and_creator, {'userid': 'test_user_2'}),
                poll.initialize],
        },
        # (posts with) files:
        {
            'portal_type': 'ixds.Post',
            'title': u'Post with attached files',
            'text': richtextify(u'<p>This is text.</p>'),
            'parent': site['workspaces']['workspace-with-files'],
            'publish': False,
            'as_user': '******',
            'items': [
                {
                    'portal_type': 'RichFile',
                    'title': u'File with meta-data',
                    'rmMediaType': 'images',
                    'rmAuthor': u'Peter Müller',
                    'rmTags': ['scientific', 'handout'],
                    'public': True,
                    'fileData': namedfile.NamedBlobFile(dummy_image(50, 50),
                        filename=u"some_image.png"),
                    'publish': False,
                    'as_user': '******',
                    'finalize': [
                        notify_form_completed],
                },
                {
                    'portal_type': 'RichFile',
                    'title': u'Another File with meta-data',
                    'rmMediaType': 'images',
                    'rmAuthor': u'Peter Müller',
                    'rmTags': ['bachelor'],
                    'public': True,
                    'fileData': namedfile.NamedBlobFile(dummy_image(50, 50),
                        filename=u"some_other_image.png"),
                    'publish': False,
                    'as_user': '******',
                    'finalize': [
                        notify_form_completed],
                },
            ],
            'finalize_branch': [fileuploadcapable.publish_post],
        },
        {
            'portal_type': 'ixds.Post',
            'title': u'Post with attached file that has no meta-data',
            'text': richtextify(u'<p>This is text.</p>'),
            'parent': site['workspaces']['workspace-with-files'],
            'publish': False,
            'finalize': [(covalent_utilities.set_owner_and_creator, {'userid': 'test_user_2'})],
            'items': [
                {
                    'portal_type': 'RichFile',
                    'id': 'file_without_meta_data',
                    'fileData': namedfile.NamedBlobFile(dummy_image(50, 50),
                        filename=u"file_without_meta_data.png"),
                    'publish': False,
                    'finalize': [
                        (covalent_utilities.set_owner_and_creator, {'userid': 'test_user_2'})],
                },
                {
                    'portal_type': 'RichFile',
                    'id': 'another_file_without_meta_data',
                    'fileData': namedfile.NamedBlobFile(dummy_image(50, 50),
                        filename=u"another_file_without_meta_data.png"),
                    'publish': False,
                    'finalize': [
                        (covalent_utilities.set_owner_and_creator, {'userid': 'test_user_2'})],
                },
            ],
            'finalize_branch': [fileuploadcapable.publish_post],
        },
    ]

    for i in range(1, 25):
        posts.append({
            'portal_type': 'ixds.Post',
            'title': u'Post %d of many' % i,
            'text': richtextify(u'<p>This is text.</p>'),
            'parent': site['workspaces']['workspace-with-many-posts'],
            'finalize': [
                (covalent_utilities.set_owner_and_creator, {'userid': 'test_user_2'}),
                (set_dates, {'date': DateTime() - 25 + i}),
            ],
        })

    stats = build(posts)
    print '  %i created, %i modified, %i skipped, %i recursions.' % stats
    print
    print "reindexing... ",

    catalog.manage_catalogRebuild()

    print "done."
def add_demo_content(
    context,
    minUsers=1,
    maxUsers=1,
    minCallenges=1,
    maxChallenges=1,
    minWorkspacePerChallenge=1,
    maxWorkspacePerChallenge=1,
    minMembersPerWorkspace=1,
    maxMembersPerWorkspace=1,
    minPostPerWorkspace=1,
    maxPostPerWorkspace=1,
):
    site = context
    catalog = getToolByName(site, "portal_catalog")

    print '### Creating demo content on "%s" ###' % site

    # create a 'demo-users'-group
    group_id = "demo-users"
    groups_tool = getToolByName(site, "portal_groups")
    if not group_id in groups_tool.getGroupIds():
        groups_tool.addGroup(group_id)

    # create users and add them to the 'demo-users'-group
    nUsers = random.randint(minUsers, maxUsers)
    for i in range(0, nUsers):
        first = get_word().title()
        last = get_word().title()
        uid = "_".join([first, last]).lower()
        email = "*****@*****.**" % (uid)
        passwd = "secret"
        portrait = None
        if random.choice([True, False]):
            portrait = namedfile.NamedBlobImage(
                random_image(random.randint(150, 300), random.randint(150, 300)), filename=u"%s.jpg" % (get_word())
            )
        add_cnrd_member(site, uid, last, first, email, passwd, portrait)
        groups_tool.addPrincipalToGroup(uid, group_id)
    print "### %i members created. ###" % nUsers

    # create challenges
    nChallenges = random.randint(minCallenges, maxChallenges)
    print "  creating %i challenges..." % (nChallenges)
    challenges = []
    for i in range(0, nChallenges):

        challenges.append(
            {
                "portal_type": "cnrd.Challenge",
                "title": get_words(1, 4),
                "description": get_words(4, 12),
                "icon": namedfile.NamedImage(random_image(150, 150), filename=u"nice_image.jpg"),
                "publish": False,
                "finalize": [challenge_finalizer, mark_as_democontent],
            }
        )

    stats = build(challenges, site["challenges"])
    print "  %i created, %i modified, %i skipped, %i recursions. ###" % stats

    # create workspaces
    workspaces = []
    for c in site["challenges"].listFolderContents():

        # leave this challenge alone if it's not demo-content
        if not IDemoContent.providedBy(c):
            continue

        print "challenge '%s' with %i items" % (c.title, c.getNumWorkspaces())

        nWorkspaces = random.randint(minWorkspacePerChallenge, maxWorkspacePerChallenge)
        print "  creating %i workspaces..." % (nWorkspaces)

        # create some workspaces
        for i in range(0, nWorkspaces):
            usersIds = site["people"].keys()
            nWsMembers = random.randint(
                min(minMembersPerWorkspace, len(usersIds)), min(maxMembersPerWorkspace, len(usersIds))
            )
            date = DateTime() - (nWorkspaces - i) * random.randint(6, 66)

            workspaces.append(
                {
                    "portal_type": "ixds.Workspace",
                    "title": get_words(1, 4),
                    "description": u"",
                    "challenges": [relatify(c)],
                    "members": set(random.sample(usersIds, nWsMembers)),
                    "images": [
                        namedfile.NamedImage(
                            random_image(random.randint(100, 400), random.randint(300, 800)),
                            filename=u"%s.jpg" % (get_word()),
                        )
                        for ii in range(0, random.randint(1, 2))
                    ],
                    "previouslyEdited": True,
                    "finalize": [update_workspace_image_fields, (set_dates, {"date": date}), mark_as_democontent],
                }
            )

    stats = build(workspaces, site["workspaces"])
    print "  %i created, %i modified, %i skipped, %i recursions. ###" % stats

    # create posts
    posts = []
    for ws in site["workspaces"].listFolderContents():

        # leave this workspace alone if it's not demo-content
        if not IDemoContent.providedBy(ws):
            continue

        print "workspace '%s' with %i entries" % (ws.title, ws.getNumEntries())

        nPosts = random.randint(minPostPerWorkspace, maxPostPerWorkspace)
        print "  creating %i posts..." % (nPosts)

        for i in range(0, nPosts):
            nParagraphs = random.randint(1, 2)
            text = u"".join((u"<p>%s</p>" % p for p in get_paragraphs(nParagraphs)))

            delta = DateTime() - ws.created()
            date = ws.created() + delta * random.random()

            posts.append(
                {
                    "portal_type": "ixds.Post",
                    "title": get_words(1, 6),
                    "text": richtextify(text),
                    "parent": ws,
                    "finalize": [
                        (set_dates, {"date": date}),
                        (set_owner_and_creator, {"userid": random.choice(list(ws.getMemberIds()))}),
                    ],
                }
            )

    stats = build(posts)
    print "  %i created, %i modified, %i skipped, %i recursions. ###" % stats
    print
    print "reindexing... ",

    catalog.manage_catalogRebuild()

    print "done."