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)
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)
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 }] }
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>", } }] }
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)
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)
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)
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)
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)