Esempio n. 1
0
    def mutate(root, args, context, info):
        EMBED_ATTACHMENT = models.AttachmentPurpose.EMBED_ATTACHMENT.value
        discussion_id = context.matchdict['discussion_id']
        discussion = models.Discussion.get(discussion_id)
        post_id = args.get('post_id')
        post_id = int(Node.from_global_id(post_id)[1])
        post = models.Post.get(post_id)

        cls = models.PostAttachment

        require_cls_permission(CrudPermissions.CREATE, cls, context)

        # add uploaded file as an attachment to the post
        attachment = args.get('file')
        if attachment is not None:
            filename = os.path.basename(context.POST[attachment].filename)
            mime_type = context.POST[attachment].type
            document = models.File(
                discussion=discussion,
                mime_type=mime_type,
                title=filename)
            document.add_file_data(context.POST[attachment].file)

            attachment = models.PostAttachment(
                document=document,
                discussion=discussion,
                creator_id=context.authenticated_userid,
                post=post,
                title=filename,
                attachmentPurpose=EMBED_ATTACHMENT
            )
            post.db.add(attachment)
            post.db.flush()

        return AddPostAttachment(post=post)
Esempio n. 2
0
def upgrade(pyramid_env):
    with context.begin_transaction():
        pass

    # Do stuff with the app's models here.
    from assembl import models as m
    db = m.get_session_maker()()
    with transaction.manager:
        posts = db.query(m.WidgetPost).options(
            sa.orm.joinedload(m.WidgetPost.attachments)).filter(
                m.WidgetPost.metadata_raw.like('%://www.youtube.com/%')).all()
        for post in posts:
            url = post.metadata_json.get("inspiration_url", None)
            if not url:
                continue
            if not (url.startswith("https://www.youtube.com/")
                    or url.startswith("http://www.youtube.com/")):
                # Should not happen, but elsewhere in metadata
                continue
            existing = {att.document.uri_id for att in post.attachments}
            if url in existing:
                continue
            document = db.query(m.Document).filter_by(
                uri_id=url, discussion_id=post.discussion_id).first()
            if not document:
                document = m.Document(uri_id=url,
                                      discussion_id=post.discussion_id)
            attachment = m.PostAttachment(discussion_id=post.discussion_id,
                                          creator_id=post.creator_id,
                                          document=document,
                                          attachmentPurpose='EMBED_ATTACHMENT',
                                          post=post)
            db.add(attachment)
            db.flush()  # so document is available if repeated
Esempio n. 3
0
def fulltext_synthesis_post_with_image(request, discussion, moderator_user,
                                       simple_file, test_session):
    from assembl import models
    synthesis_post = models.SynthesisPost(
        publication_state=models.PublicationStates.DRAFT,
        discussion=discussion,
        creator=moderator_user,
        publishes_synthesis=models.FullTextSynthesis(
            discussion=discussion,
            subject=models.LangString.create(u"a synthesis with image", "en"),
            body=models.LangString.create(u"Lorem ipsum dolor sit amet", "en"),
        ))
    synthesis_post.publishes_synthesis.subject.add_value(
        "une synthèse avec image", "fr")
    synthesis_post.publishes_synthesis.body.add_value(
        "Laurème ipsoume dolaure sitamette", "fr")
    test_session.flush()

    synthesis_image = models.PostAttachment(discussion=discussion,
                                            document=simple_file,
                                            post=synthesis_post,
                                            title=u"Synthesis image",
                                            creator=moderator_user,
                                            attachmentPurpose='IMAGE')
    test_session.add(synthesis_post)
    test_session.flush()

    def fin():
        print("finalizer synthesis post with image")
        test_session.delete(synthesis_image)
        test_session.delete(synthesis_post)
        test_session.flush()

    request.addfinalizer(fin)

    return synthesis_post
Esempio n. 4
0
    def mutate(root, args, context, info):
        EMBED_ATTACHMENT = models.AttachmentPurpose.EMBED_ATTACHMENT.value
        discussion_id = context.matchdict['discussion_id']

        user_id = context.authenticated_userid or Everyone
        discussion = models.Discussion.get(discussion_id)

        post_id = args.get('post_id')
        post_id = int(Node.from_global_id(post_id)[1])
        post = models.Post.get(post_id)
        cls = models.Post

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

        changed = False
        subject = args.get('subject')
        if subject:
            subject = sanitize_text(subject)
        body = args.get('body')
        if body:
            body = sanitize_html(body)
        # TODO: Here, an assumption that the modification uses the same
        # language as the original. May need revisiting.
        original_subject_entry = post.subject.first_original()
        # subject is not required, be careful to not remove it if not specified
        if subject and subject != original_subject_entry.value:
            changed = True
            post.subject.add_value(subject, original_subject_entry.locale_code)
            # Edit subject for all descendants
            children = post.children[:]
            new_subject = u'Re: ' + restrip_pat.sub('', subject).strip()
            while children:
                child = children.pop()
                children.extend(child.children)
                child.subject.add_value(
                    new_subject,
                    child.subject.first_original().locale_code)

        original_body_entry = post.body.first_original()
        if body != original_body_entry.value:
            post.body.add_value(body, original_body_entry.locale_code)
            changed = True

            original_attachments = post.attachments
            original_attachments_doc_ids = []
            if original_attachments:
                original_attachments_doc_ids = [
                    str(a.document_id) for a in original_attachments
                ]

            attachments = args.get('attachments', [])
            for document_id in attachments:
                if document_id not in original_attachments_doc_ids:
                    document = models.Document.get(document_id)
                    models.PostAttachment(
                        document=document,
                        discussion=discussion,
                        creator_id=context.authenticated_userid,
                        post=post,
                        title=document.title,
                        attachmentPurpose=EMBED_ATTACHMENT)

            # delete attachments that has been removed
            documents_to_delete = set(original_attachments_doc_ids) - set(
                attachments)  # noqa: E501
            for document_id in documents_to_delete:
                with cls.default_db.no_autoflush:
                    document = models.Document.get(document_id)
                    post_attachment = post.db.query(
                        models.PostAttachment).filter_by(
                            discussion_id=discussion_id,
                            post_id=post_id,
                            document_id=document_id).first()
                    document.delete_file()
                    post.db.delete(document)
                    post.attachments.remove(post_attachment)
                    post.db.flush()

        publication_state = models.PublicationStates.from_string(
            args.get('publication_state')) if args.get(
                'publication_state') in models.PublicationStates.values(
                ) else None
        if publication_state and publication_state != post.publication_state:
            post.publication_state = publication_state
            changed = True
            # Update the creation date when switching from draft to published
            if post.publication_state == models.PublicationStates.DRAFT and publication_state == models.PublicationStates.PUBLISHED:
                post.creation_date = datetime.utcnow()

        if changed:
            post.modification_date = datetime.utcnow()
            post.body_mime_type = u'text/html'
            post.db.flush()
            post.db.expire(post.subject, ["entries"])
            post.db.expire(post.body, ["entries"])

        return UpdatePost(post=post)
Esempio n. 5
0
    def mutate(root, args, context, info):
        EMBED_ATTACHMENT = models.AttachmentPurpose.EMBED_ATTACHMENT.value
        discussion_id = context.matchdict['discussion_id']

        user_id = context.authenticated_userid or Everyone
        discussion = models.Discussion.get(discussion_id)

        idea_id = args.get('idea_id')
        idea_id = int(Node.from_global_id(idea_id)[1])
        in_reply_to_idea = models.Idea.get(idea_id)

        if isinstance(in_reply_to_idea, models.Question):
            cls = models.PropositionPost
        else:
            cls = models.AssemblPost

        extract_id = args.get('extract_id')
        if extract_id:
            extract_id_global = int(Node.from_global_id(extract_id)[1])
            extract = models.Extract.get(extract_id_global)
            cls = models.ExtractComment

        in_reply_to_post = None
        if (cls == models.AssemblPost) or (cls == models.ExtractComment):
            in_reply_to_post_id = args.get('parent_id')
            if in_reply_to_post_id:
                in_reply_to_post_id = int(
                    Node.from_global_id(in_reply_to_post_id)[1])
                if in_reply_to_post_id:
                    in_reply_to_post = models.Post.get(in_reply_to_post_id)

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

        with cls.default_db.no_autoflush:
            subject = args.get('subject')
            body = args.get('body')
            classifier = args.get('message_classifier', None)
            body = sanitize_html(body)
            body_langstring = models.LangString.create(body)
            publication_state = models.PublicationStates.from_string(
                args.get('publication_state')) if args.get(
                    'publication_state') in models.PublicationStates.values(
                    ) else models.PublicationStates.PUBLISHED

            if subject:
                subject = sanitize_text(subject)
                subject_langstring = models.LangString.create(subject)
            elif issubclass(cls, models.PropositionPost):
                # Specific case first. Respect inheritance. Since we are using
                # a specific value, construct it with localization machinery.
                subject_langstring = models.LangString.create_localized_langstring(  # noqa: E501
                    _('Proposal'), discussion.discussion_locales,
                    {'fr': 'Proposition'})
            else:
                # We apply the same logic than in views/api/post.py::create_post  # noqa: E501
                locale = models.Locale.UNDEFINED
                if in_reply_to_post and in_reply_to_post.get_title():
                    original_subject = in_reply_to_post.get_title(
                    ).first_original()
                    locale = original_subject.locale_code
                    subject = original_subject.value
                elif in_reply_to_idea:
                    # TODO: some ideas have extra langstring titles
                    # we try to guess the locale of the body to use the same locale for post's subject
                    body_lang, data = discussion.translation_service(
                    ).identify(body_langstring.entries[0].value,
                               discussion.discussion_locales)

                    closest_subject = in_reply_to_idea.title.closest_entry(
                        body_lang)
                    if closest_subject:
                        subject = closest_subject.value
                        locale = closest_subject.locale.code
                    else:
                        # rather no subject than one in a random locale
                        subject = u''
                        locale = discussion.main_locale
                else:
                    subject = discussion.topic if discussion.topic else ''
                    locale = discussion.main_locale

                if subject is not None:
                    if in_reply_to_idea and in_reply_to_idea.message_view_override == u'messageColumns':
                        new_subject = subject
                    else:
                        new_subject = u'Re: ' + restrip_pat.sub(
                            '', subject).strip()  # noqa: E501

                    if (in_reply_to_post and new_subject == subject
                            and in_reply_to_post.get_title()):
                        # reuse subject and translations
                        subject_langstring = in_reply_to_post.get_title(
                        ).clone(discussion.db)
                    else:
                        subject_langstring = models.LangString.create(
                            new_subject, locale)

            if cls == models.ExtractComment:
                new_post = cls(discussion=discussion,
                               subject=subject_langstring,
                               body=body_langstring,
                               creator_id=user_id,
                               body_mime_type=u'text/html',
                               message_classifier=classifier,
                               creation_date=datetime.utcnow(),
                               publication_state=publication_state,
                               parent_extract_id=extract.id)
            else:
                new_post = cls(discussion=discussion,
                               subject=subject_langstring,
                               body=body_langstring,
                               creator_id=user_id,
                               body_mime_type=u'text/html',
                               message_classifier=classifier,
                               creation_date=datetime.utcnow(),
                               publication_state=publication_state)

            new_post.guess_languages()
            db = new_post.db
            db.add(new_post)
            db.flush()

            if in_reply_to_post:
                new_post.set_parent(in_reply_to_post)
            elif in_reply_to_idea and cls != models.ExtractComment:
                # don't create IdeaRelatedPostLink when we have both
                # in_reply_to_post and in_reply_to_idea or if it's a comment
                # for an extract
                idea_post_link = models.IdeaRelatedPostLink(
                    creator_id=user_id,
                    content=new_post,
                    idea=in_reply_to_idea)
                db.add(idea_post_link)
            db.flush()

            attachments = args.get('attachments', [])
            for document_id in attachments:
                document = models.Document.get(document_id)
                models.PostAttachment(document=document,
                                      discussion=discussion,
                                      creator_id=context.authenticated_userid,
                                      post=new_post,
                                      title=document.title,
                                      attachmentPurpose=EMBED_ATTACHMENT)

            db.flush()

        return CreatePost(post=new_post)