コード例 #1
0
    def mutate(root, args, context, info):
        cls = models.VoteProposal
        require_cls_permission(CrudPermissions.CREATE, cls, context)
        vote_session_id = args.get('vote_session_id')
        vote_session_id = int(Node.from_global_id(vote_session_id)[1])
        vote_session = models.VoteSession.get(vote_session_id)
        title_entries = args.get('title_entries')
        description_entries = args.get('description_entries')
        discussion_id = context.matchdict['discussion_id']
        discussion = models.Discussion.get(discussion_id)

        with cls.default_db.no_autoflush as db:
            title_ls = langstring_from_input_entries(title_entries)
            description_ls = langstring_from_input_entries(description_entries)
            if vote_session is None:
                raise Exception(
                    "A vote session is required before creating a proposal")
            idea = vote_session.idea
            proposal = cls(discussion_id=discussion_id,
                           discussion=discussion,
                           title=title_ls,
                           description=description_ls)
            db.add(proposal)
            order = len(idea.get_children()) + 1.0
            db.add(
                models.IdeaLink(source=idea,
                                target=proposal,
                                order=args.get('order', order)))
            db.flush()

        return CreateProposal(proposal=proposal)
コード例 #2
0
ファイル: vote_session.py プロジェクト: pierre56/assembl
    def mutate(root, args, context, info):
        cls = models.Idea
        require_cls_permission(CrudPermissions.CREATE, cls, context)
        vote_session_id = args.get('vote_session_id')
        vote_session_id = int(Node.from_global_id(vote_session_id)[1])
        vote_session = models.VoteSession.get(vote_session_id)
        title_entries = args.get('title_entries')
        description_entries = args.get('description_entries')
        discussion_id = context.matchdict['discussion_id']
        discussion = models.Discussion.get(discussion_id)

        with cls.default_db.no_autoflush as db:
            title_ls = langstring_from_input_entries(title_entries)
            description_ls = langstring_from_input_entries(description_entries)
            proposal = cls(discussion_id=discussion_id,
                           discussion=discussion,
                           title=title_ls,
                           description=description_ls)
            db.add(proposal)
            phase = vote_session.discussion_phase
            root_thematic = get_root_thematic_for_phase(phase)
            if root_thematic is None:
                raise Exception(
                    "There is no root thematic for this vote session.")

            order = len(root_thematic.get_children()) + 1.0
            db.add(
                models.IdeaLink(source=root_thematic,
                                target=proposal,
                                order=args.get('order', order)))
            db.flush()

        return CreateProposal(proposal=proposal)
コード例 #3
0
ファイル: test_graphql.py プロジェクト: n0izn0iz/assembl
def test_get_thematics_no_video(discussion, graphql_request, test_session):
    title = u"Comprendre les dynamiques et les enjeux"
    title = models.LangString.create(title, locale_code="fr")
    root_thematic = create_root_thematic(discussion, "survey")
    thematic = models.Thematic(discussion_id=discussion.id,
                               title=title,
                               identifier="survey")
    test_session.add(
        models.IdeaLink(source=root_thematic, target=thematic, order=1.0))
    test_session.commit()
    thematic_gid = to_global_id('Thematic', thematic.id)

    res = schema.execute(
        u'query { thematics(identifier:"survey") { id, title, description, numPosts, numContributors, questions { title }, video {title, descriptionTop, descriptionBottom, descriptionSide, htmlCode} } }',
        context_value=graphql_request)
    assert json.loads(json.dumps(res.data)) == {
        u'thematics': [{
            u'description': None,
            u'id': thematic_gid,
            u'numContributors': 0,
            u'numPosts': 0,
            u'questions': [],
            u'title': u'Comprendre les dynamiques et les enjeux',
            u'video': None
        }]
    }
コード例 #4
0
ファイル: test_graphql.py プロジェクト: n0izn0iz/assembl
def test_get_thematics_with_video(discussion, graphql_request, test_session):
    title = u"Comprendre les dynamiques et les enjeux"
    title = models.LangString.create(title, locale_code="fr")
    video_title = models.LangString.create(
        u"Laurent Alexandre, chirurgien et expert en intelligence artificielle nous livre ses prédictions pour le 21e siècle.",
        locale_code="fr")
    video_desc_top = models.LangString.create(
        u"Personne ne veut d'un monde où on pourrait manipuler nos cerveaux et où les états pourraient les bidouiller",
        locale_code="fr")
    video_desc_bottom = models.LangString.create(u"Calise de tabarnak",
                                                 locale_code="fr")
    video_desc_side = models.LangString.create(u"Putain", locale_code="fr")
    root_thematic = create_root_thematic(discussion, "survey")
    thematic = models.Thematic(
        discussion_id=discussion.id,
        title=title,
        identifier="survey",
        video_title=video_title,
        video_description_top=video_desc_top,
        video_description_bottom=video_desc_bottom,
        video_description_side=video_desc_side,
        video_html_code=u"<object>....</object>",
    )
    test_session.add(
        models.IdeaLink(source=root_thematic, target=thematic, order=1.0))
    test_session.commit()
    thematic_gid = to_global_id('Thematic', thematic.id)

    res = schema.execute(
        u'query { thematics(identifier:"survey") { id, title, description, numPosts, numContributors, questions { title }, video {title, descriptionTop, descriptionBottom, descriptionSide, htmlCode} } }',
        context_value=graphql_request)
    assert json.loads(json.dumps(res.data)) == {
        u'thematics': [{
            u'description': None,
            u'id': thematic_gid,
            u'numContributors': 0,
            u'numPosts': 0,
            u'questions': [],
            u'title': u'Comprendre les dynamiques et les enjeux',
            u'video': {
                u'title':
                u"Laurent Alexandre, chirurgien et expert en intelligence artificielle nous livre ses prédictions pour le 21e siècle.",
                u'descriptionTop':
                u"Personne ne veut d'un monde où on pourrait manipuler nos cerveaux et où les états pourraient les bidouiller",
                u'descriptionBottom': u"Calise de tabarnak",
                u'descriptionSide': u"Putain",
                u'htmlCode': u"<object>....</object>",
            }
        }]
    }
コード例 #5
0
    def mutate(root, args, context, info):
        EMBED_ATTACHMENT = models.AttachmentPurpose.EMBED_ATTACHMENT.value
        cls = models.Thematic
        discussion_id = context.matchdict['discussion_id']
        discussion = models.Discussion.get(discussion_id)
        user_id = context.authenticated_userid or Everyone

        thematic_id = args.get('id')
        id_ = int(Node.from_global_id(thematic_id)[1])
        thematic = cls.get(id_)

        permissions = get_permissions(user_id, discussion_id)
        allowed = thematic.user_can(user_id, CrudPermissions.UPDATE,
                                    permissions)
        if not allowed:
            raise HTTPUnauthorized()

        with cls.default_db.no_autoflush:
            # introducing history at every step, including thematics + questions  # noqa: E501
            thematic.copy(tombstone=True)
            title_entries = args.get('title_entries')
            if title_entries is not None and len(title_entries) == 0:
                raise Exception(
                    'Thematic titleEntries needs at least one entry')
                # Better to have this message than
                # 'NoneType' object has no attribute 'owner_object'
                # when creating the saobj below if title=None

            update_langstring_from_input_entries(thematic, 'title',
                                                 title_entries)
            update_langstring_from_input_entries(
                thematic, 'description', args.get('description_entries'))
            kwargs = {}
            video = args.get('video', None)
            if video is not None:
                update_langstring_from_input_entries(
                    thematic, 'video_title', video.get('title_entries', []))
                update_langstring_from_input_entries(
                    thematic, 'video_description_top',
                    video.get('description_entries_top', []))
                update_langstring_from_input_entries(
                    thematic, 'video_description_bottom',
                    video.get('description_entries_bottom', []))
                update_langstring_from_input_entries(
                    thematic, 'video_description_side',
                    video.get('description_entries_side', []))
                kwargs['video_html_code'] = video.get('html_code', None)

            if args.get('identifier') is not None:
                kwargs['identifier'] = args.get('identifier')

            for attr, value in kwargs.items():
                setattr(thematic, attr, value)

            db = thematic.db

            # change order if needed
            order = args.get('order')
            if order:
                thematic.source_links[0].order = order

            # add uploaded image as an attachment to the idea
            image = args.get('image')
            if image is not None:
                if image == 'TO_DELETE' and thematic.attachments:
                    # delete the image
                    attachment = thematic.attachments[0]
                    attachment.document.delete_file()
                    db.delete(attachment.document)
                    db.delete(attachment)
                    thematic.attachments.remove(attachment)
                else:
                    filename = os.path.basename(context.POST[image].filename)
                    mime_type = context.POST[image].type
                    document = models.File(discussion=discussion,
                                           mime_type=mime_type,
                                           title=filename)
                    document.add_file_data(context.POST[image].file)
                    # if there is already an attachment, remove it with the
                    # associated document (image)
                    if thematic.attachments:
                        thematic.attachments[0].document.delete_file()
                        db.delete(thematic.attachments[0].document)
                        thematic.attachments.remove(thematic.attachments[0])

                    attachment = models.IdeaAttachment(
                        document=document,
                        discussion=discussion,
                        creator_id=context.authenticated_userid,
                        title=filename,
                        attachmentPurpose=EMBED_ATTACHMENT)
                    thematic.attachments.append(attachment)
            db.flush()

            questions_input = args.get('questions')
            existing_questions = {
                question.id: question
                for question in thematic.get_children()
            }
            updated_questions = set()
            if questions_input is not None:
                for idx, question_input in enumerate(questions_input):
                    if question_input.get('id', None) is not None:
                        id_ = int(Node.from_global_id(question_input['id'])[1])
                        updated_questions.add(id_)
                        question = models.Question.get(id_)
                        # archive the question
                        question.copy(tombstone=True)
                        update_langstring_from_input_entries(
                            question, 'title', question_input['title_entries'])
                        # modify question order
                        question.source_links[0].order = idx + 1.0
                    else:
                        title_ls = langstring_from_input_entries(
                            question_input['title_entries'])
                        question = models.Question(title=title_ls,
                                                   discussion_id=discussion_id)
                        db.add(
                            models.IdeaLink(source=thematic,
                                            target=question,
                                            order=idx + 1.0))

                # remove question (tombstone) that are not in questions_input
                for question_id in set(existing_questions.keys()).difference(
                        updated_questions):
                    existing_questions[question_id].is_tombstone = True

            db.flush()

        return UpdateThematic(thematic=thematic)
コード例 #6
0
    def mutate(root, args, context, info):
        EMBED_ATTACHMENT = models.AttachmentPurpose.EMBED_ATTACHMENT.value
        cls = models.Thematic
        discussion_id = context.matchdict['discussion_id']
        discussion = models.Discussion.get(discussion_id)
        user_id = context.authenticated_userid or Everyone

        permissions = get_permissions(user_id, discussion_id)
        allowed = cls.user_can_cls(user_id, CrudPermissions.CREATE,
                                   permissions)
        if not allowed or (allowed == IF_OWNED and user_id == Everyone):
            raise HTTPUnauthorized()

        identifier = args.get('identifier')
        with cls.default_db.no_autoflush:
            title_entries = args.get('title_entries')
            if len(title_entries) == 0:
                raise Exception(
                    'Thematic titleEntries needs at least one entry')
                # Better to have this message than
                # 'NoneType' object has no attribute 'owner_object'
                # when creating the saobj below if title=None

            title_langstring = langstring_from_input_entries(title_entries)
            description_langstring = langstring_from_input_entries(
                args.get('description_entries'))
            kwargs = {}
            if description_langstring is not None:
                kwargs['description'] = description_langstring

            video = args.get('video')
            if video is not None:
                video_title = langstring_from_input_entries(
                    video.get('title_entries', None))
                if video_title is not None:
                    kwargs['video_title'] = video_title

                video_description_top = langstring_from_input_entries(
                    video.get('description_entries_top', None))
                if video_description_top is not None:
                    kwargs['video_description_top'] = video_description_top

                video_description_bottom = langstring_from_input_entries(
                    video.get('description_entries_bottom', None))
                if video_description_bottom is not None:
                    kwargs[
                        'video_description_bottom'] = video_description_bottom

                video_description_side = langstring_from_input_entries(
                    video.get('description_entries_side', None))
                if video_description_side is not None:
                    kwargs['video_description_side'] = video_description_side

                video_html_code = video.get('html_code', None)
                if video_html_code is not None:
                    kwargs['video_html_code'] = video_html_code

            # Our thematic, because it inherits from Idea, needs to be
            # associated to the root idea of the discussion.
            # We create a hidden root thematic, corresponding to the
            # `identifier` phase, child of the root idea,
            # and add our thematic as a child of this root thematic.
            root_thematic = get_root_thematic_for_phase(discussion, identifier)
            if root_thematic is None:
                root_thematic = create_root_thematic(discussion, identifier)

            saobj = cls(discussion_id=discussion_id,
                        title=title_langstring,
                        identifier=identifier,
                        **kwargs)
            db = saobj.db
            db.add(saobj)
            order = len(root_thematic.get_children()) + 1.0
            db.add(
                models.IdeaLink(source=root_thematic,
                                target=saobj,
                                order=args.get('order', order)))

            # add uploaded image as an attachment to the idea
            image = args.get('image')
            if image is not None:
                filename = os.path.basename(context.POST[image].filename)
                mime_type = context.POST[image].type
                document = models.File(discussion=discussion,
                                       mime_type=mime_type,
                                       title=filename)
                document.add_file_data(context.POST[image].file)
                db.add(
                    models.IdeaAttachment(
                        document=document,
                        idea=saobj,
                        discussion=discussion,
                        creator_id=context.authenticated_userid,
                        title=filename,
                        attachmentPurpose=EMBED_ATTACHMENT))

            db.flush()

            questions_input = args.get('questions')
            if questions_input is not None:
                for idx, question_input in enumerate(questions_input):
                    title_ls = langstring_from_input_entries(
                        question_input['title_entries'])
                    question = models.Question(title=title_ls,
                                               discussion_id=discussion_id)
                    db.add(
                        models.IdeaLink(source=saobj,
                                        target=question,
                                        order=idx + 1.0))
                db.flush()

        return CreateThematic(thematic=saobj)
コード例 #7
0
    def mutate(root, args, context, info):
        EMBED_ATTACHMENT = models.AttachmentPurpose.EMBED_ATTACHMENT.value
        cls = models.Idea
        discussion_id = context.matchdict['discussion_id']
        discussion = models.Discussion.get(discussion_id)
        user_id = context.authenticated_userid or Everyone

        permissions = get_permissions(user_id, discussion_id)
        allowed = cls.user_can_cls(user_id, CrudPermissions.CREATE,
                                   permissions)
        if not allowed or (allowed == IF_OWNED and user_id == Everyone):
            raise HTTPUnauthorized()

        with cls.default_db.no_autoflush:
            title_entries = args.get('title_entries')
            if len(title_entries) == 0:
                raise Exception('Idea titleEntries needs at least one entry')
                # Better to have this message than
                # 'NoneType' object has no attribute 'owner_object'
                # when creating the saobj below if title=None

            title_langstring = langstring_from_input_entries(title_entries)
            description_langstring = langstring_from_input_entries(
                args.get('description_entries'))
            kwargs = {}
            if description_langstring is not None:
                kwargs['description'] = description_langstring

            parent_idea_id = args.get('parent_id')
            if parent_idea_id:
                parent_idea_id = int(Node.from_global_id(parent_idea_id)[1])
                if parent_idea_id:
                    parent_idea = models.Idea.get(parent_idea_id)
                    if not parent_idea:
                        raise Exception('Parent Idea not found')
                    if parent_idea.discussion != discussion:
                        # No cross-debate references are allowed,
                        # for security reasons
                        raise Exception(
                            'Parent Idea does not belong to this discussion'
                        )  # noqa: E501
                else:
                    raise Exception('Parent Idea not found')
            if not parent_idea_id:
                parent_idea = discussion.root_idea

            saobj = cls(discussion_id=discussion_id,
                        title=title_langstring,
                        **kwargs)
            db = saobj.db
            db.add(saobj)
            order = len(parent_idea.get_children()) + 1.0
            db.add(
                models.IdeaLink(source=parent_idea,
                                target=saobj,
                                order=args.get('order', order)))

            # add uploaded image as an attachment to the idea
            image = args.get('image')
            if image is not None:
                filename = os.path.basename(context.POST[image].filename)
                mime_type = context.POST[image].type
                document = models.File(discussion=discussion,
                                       mime_type=mime_type,
                                       title=filename)
                document.add_file_data(context.POST[image].file)
                db.add(
                    models.IdeaAttachment(
                        document=document,
                        idea=saobj,
                        discussion=discussion,
                        creator_id=context.authenticated_userid,
                        title=filename,
                        attachmentPurpose=EMBED_ATTACHMENT))

            db.flush()

        return CreateIdea(idea=saobj)
コード例 #8
0
ファイル: idea.py プロジェクト: magarrigue/assembl
    def mutate(root, args, context, info):
        EMBED_ATTACHMENT = models.AttachmentPurpose.EMBED_ATTACHMENT.value
        MEDIA_ATTACHMENT = models.AttachmentPurpose.MEDIA_ATTACHMENT.value
        cls = models.Idea
        discussion_id = context.matchdict['discussion_id']
        discussion = models.Discussion.get(discussion_id)
        user_id = context.authenticated_userid or Everyone

        thematic_id = args.get('id')
        id_ = int(Node.from_global_id(thematic_id)[1])
        thematic = cls.get(id_)

        permissions = get_permissions(user_id, discussion_id)
        allowed = thematic.user_can(user_id, CrudPermissions.UPDATE,
                                    permissions)
        if not allowed:
            raise HTTPUnauthorized()

        with cls.default_db.no_autoflush as db:
            # introducing history at every step, including thematics + questions  # noqa: E501
            thematic.copy(tombstone=True)
            title_entries = args.get('title_entries')
            if title_entries is not None and len(title_entries) == 0:
                raise Exception(
                    'Thematic titleEntries needs at least one entry')
                # Better to have this message than
                # 'NoneType' object has no attribute 'owner_object'
                # when creating the saobj below if title=None

            update_langstring_from_input_entries(thematic, 'title',
                                                 title_entries)
            update_langstring_from_input_entries(
                thematic, 'description', args.get('description_entries'))
            kwargs = {}
            video = args.get('video', None)
            if video is not None:
                update_langstring_from_input_entries(
                    thematic, 'video_title', video.get('title_entries', []))
                update_langstring_from_input_entries(
                    thematic, 'video_description_top',
                    video.get('description_entries_top', []))
                update_langstring_from_input_entries(
                    thematic, 'video_description_bottom',
                    video.get('description_entries_bottom', []))
                update_langstring_from_input_entries(
                    thematic, 'video_description_side',
                    video.get('description_entries_side', []))
                kwargs['video_html_code'] = video.get('html_code', None)

                video_media = video.get('media_file', None)
                if video_media:
                    update_attachment(discussion, models.IdeaAttachment,
                                      video_media, thematic.attachments,
                                      MEDIA_ATTACHMENT, db, context)

            kwargs['message_view_override'] = args.get('message_view_override')

            for attr, value in kwargs.items():
                setattr(thematic, attr, value)

            # change order if needed
            order = args.get('order')
            if order:
                thematic.source_links[0].order = order

            # add uploaded image as an attachment to the idea
            image = args.get('image')
            if image is not None:
                update_attachment(discussion, models.IdeaAttachment, image,
                                  thematic.attachments, EMBED_ATTACHMENT, db,
                                  context)

            # Create the idea announcement object which corresponds to the instructions
            announcement = args.get('announcement')
            if announcement is not None:
                announcement_title_entries = announcement.get('title_entries')
                if len(announcement_title_entries) == 0:
                    raise Exception(
                        'Announcement titleEntries needs at least one entry')

                announcement_title_langstring = langstring_from_input_entries(
                    announcement_title_entries)
                announcement_body_langstring = langstring_from_input_entries(
                    announcement.get('body_entries', None))
                saobj2 = create_idea_announcement(
                    user_id, discussion, thematic,
                    announcement_title_langstring,
                    announcement_body_langstring)
                db.add(saobj2)

            questions_input = args.get('questions')
            existing_questions = {
                question.id: question
                for question in thematic.get_children()
            }
            updated_questions = set()
            if questions_input is not None:
                for idx, question_input in enumerate(questions_input):
                    if question_input.get('id', None) is not None:
                        id_ = int(Node.from_global_id(question_input['id'])[1])
                        updated_questions.add(id_)
                        question = models.Question.get(id_)
                        # archive the question
                        question.copy(tombstone=True)
                        update_langstring_from_input_entries(
                            question, 'title', question_input['title_entries'])
                        # modify question order
                        question.source_links[0].order = idx + 1.0
                    else:
                        title_ls = langstring_from_input_entries(
                            question_input['title_entries'])
                        question = models.Question(title=title_ls,
                                                   discussion_id=discussion_id)
                        db.add(
                            models.IdeaLink(source=thematic,
                                            target=question,
                                            order=idx + 1.0))

                # remove question (tombstone) that are not in questions_input
                for question_id in set(existing_questions.keys()).difference(
                        updated_questions):
                    existing_questions[question_id].is_tombstone = True

            db.flush()

        return UpdateThematic(thematic=thematic)
コード例 #9
0
ファイル: idea.py プロジェクト: magarrigue/assembl
    def mutate(root, args, context, info):
        EMBED_ATTACHMENT = models.AttachmentPurpose.EMBED_ATTACHMENT.value
        MEDIA_ATTACHMENT = models.AttachmentPurpose.MEDIA_ATTACHMENT.value
        cls = models.Idea
        phase_identifier = args.get('identifier')
        if phase_identifier == Phases.survey.value:
            cls = models.Thematic

        discussion_id = context.matchdict['discussion_id']
        discussion = models.Discussion.get(discussion_id)
        user_id = context.authenticated_userid or Everyone

        permissions = get_permissions(user_id, discussion_id)
        allowed = cls.user_can_cls(user_id, CrudPermissions.CREATE,
                                   permissions)
        if not allowed or (allowed == IF_OWNED and user_id == Everyone):
            raise HTTPUnauthorized()

        with cls.default_db.no_autoflush as db:
            title_entries = args.get('title_entries')
            if len(title_entries) == 0:
                raise Exception(
                    'Thematic titleEntries needs at least one entry')
                # Better to have this message than
                # 'NoneType' object has no attribute 'owner_object'
                # when creating the saobj below if title=None

            title_langstring = langstring_from_input_entries(title_entries)
            description_langstring = langstring_from_input_entries(
                args.get('description_entries'))
            kwargs = {}
            if description_langstring is not None:
                kwargs['description'] = description_langstring

            kwargs['message_view_override'] = args.get('message_view_override')

            video = args.get('video')
            video_media = None
            if video is not None:
                video_title = langstring_from_input_entries(
                    video.get('title_entries', None))
                if video_title is not None:
                    kwargs['video_title'] = video_title

                video_description_top = langstring_from_input_entries(
                    video.get('description_entries_top', None))
                if video_description_top is not None:
                    kwargs['video_description_top'] = video_description_top

                video_description_bottom = langstring_from_input_entries(
                    video.get('description_entries_bottom', None))
                if video_description_bottom is not None:
                    kwargs[
                        'video_description_bottom'] = video_description_bottom

                video_description_side = langstring_from_input_entries(
                    video.get('description_entries_side', None))
                if video_description_side is not None:
                    kwargs['video_description_side'] = video_description_side

                video_html_code = video.get('html_code', None)
                if video_html_code is not None:
                    kwargs['video_html_code'] = video_html_code

                video_media = video.get('media_file', None)

            parent_idea_id = args.get('parent_id')
            if parent_idea_id:
                parent_idea_id = int(Node.from_global_id(parent_idea_id)[1])
                parent_idea = models.Idea.get(parent_idea_id)
                if not parent_idea:
                    raise Exception('Parent Idea not found')
                if parent_idea.discussion != discussion:
                    # No cross-debate references are allowed,
                    # for security reasons
                    raise Exception(
                        'Parent Idea does not belong to this discussion'
                    )  # noqa: E501
            else:
                if phase_identifier in (Phases.thread.value,
                                        Phases.multiColumns.value):
                    parent_idea = discussion.root_idea
                else:
                    # Our thematic, because it inherits from Idea, needs to be
                    # associated to the root idea of the discussion.
                    # We create a hidden root thematic, corresponding to the
                    # `identifier` phase, child of the root idea,
                    # and add our thematic as a child of this root thematic.
                    parent_idea = get_root_thematic_for_phase(
                        discussion, phase_identifier)
                    if parent_idea is None:
                        parent_idea = create_root_thematic(
                            discussion, phase_identifier)

            saobj = cls(discussion_id=discussion_id,
                        title=title_langstring,
                        **kwargs)
            if cls == models.Thematic:
                saobj.identifier = phase_identifier  # I don't think this is really used

            db.add(saobj)
            order = len(parent_idea.get_children()) + 1.0
            db.add(
                models.IdeaLink(source=parent_idea,
                                target=saobj,
                                order=args.get('order', order)))

            # Create the idea announcement object which corresponds to the instructions
            announcement = args.get('announcement')
            if announcement is not None:
                announcement_title_entries = announcement.get('title_entries')
                if len(announcement_title_entries) == 0:
                    raise Exception(
                        'Announcement titleEntries needs at least one entry')

                announcement_title_langstring = langstring_from_input_entries(
                    announcement_title_entries)
                announcement_body_langstring = langstring_from_input_entries(
                    announcement.get('body_entries', None))
                saobj2 = create_idea_announcement(
                    user_id, discussion, saobj, announcement_title_langstring,
                    announcement_body_langstring)
                db.add(saobj2)

            # add uploaded image as an attachment to the idea
            image = args.get('image')
            if image is not None:
                new_attachment = create_attachment(discussion,
                                                   models.IdeaAttachment,
                                                   image, EMBED_ATTACHMENT,
                                                   context)
                new_attachment.idea = saobj
                db.add(new_attachment)

            # add uploaded image as an attachment to the idea
            if video_media is not None:
                new_attachment = create_attachment(discussion,
                                                   models.IdeaAttachment,
                                                   video_media,
                                                   MEDIA_ATTACHMENT, context)
                new_attachment.idea = saobj
                db.add(new_attachment)

            questions_input = args.get('questions')
            if questions_input is not None:
                for idx, question_input in enumerate(questions_input):
                    title_ls = langstring_from_input_entries(
                        question_input['title_entries'])
                    question = models.Question(title=title_ls,
                                               discussion_id=discussion_id)
                    db.add(
                        models.IdeaLink(source=saobj,
                                        target=question,
                                        order=idx + 1.0))

        db.flush()
        return CreateThematic(thematic=saobj)