Esempio n. 1
0
def patch_topic_link(request: Request, link: str) -> dict:
    """Edit a topic's link with Intercooler."""
    topic = request.context

    if link == topic.link:
        return IC_NOOP

    request.db_session.add(
        LogTopic(
            LogEventType.TOPIC_LINK_EDIT,
            request,
            topic,
            info={
                "old": topic.link,
                "new": link
            },
        ))

    # Wipe any old metadata from scrapers so we don't leave behind remnants
    # (this probably really shouldn't be done here, but it's fine for now)
    (request.query(Topic).filter(Topic.topic_id == topic.topic_id).update(
        {
            "content_metadata":
            Topic.content_metadata.op("-")(  # type: ignore
                cast(METADATA_KEYS, ARRAY(Text)))
        },
        synchronize_session=False,
    ))

    topic.link = link

    return Response(f'<a href="{topic.link}">{topic.link}</a>')
Esempio n. 2
0
def put_topic_vote(request: Request) -> Response:
    """Vote on a topic with Intercooler."""
    topic = request.context

    savepoint = request.tm.savepoint()

    new_vote = TopicVote(request.user, topic)
    request.db_session.add(new_vote)

    request.db_session.add(LogTopic(LogEventType.TOPIC_VOTE, request, topic))

    try:
        # manually flush before attempting to commit, to avoid having all objects
        # detached from the session in case of an error
        request.db_session.flush()
        request.tm.commit()
    except IntegrityError:
        # the user has already voted on this topic
        savepoint.rollback()

    # re-query the topic to get complete data
    topic = (request.query(Topic).join_all_relationships().filter_by(
        topic_id=topic.topic_id).one())

    return {"topic": topic}
Esempio n. 3
0
def tag_topic(request: Request, tags: str) -> dict:
    """Apply tags to a topic with Intercooler."""
    topic = request.context

    if tags:
        # split the tag string on commas
        new_tags = tags.split(',')
    else:
        new_tags = []

    old_tags = topic.tags

    try:
        topic.tags = new_tags
    except ValidationError:
        raise ValidationError({'tags': ['Invalid tags']})

    # if tags weren't changed, don't add a log entry or update page
    if set(topic.tags) == set(old_tags):
        return IC_NOOP

    request.db_session.add(
        LogTopic(
            LogEventType.TOPIC_TAG,
            request,
            topic,
            info={
                'old': old_tags,
                'new': topic.tags
            },
        ), )

    return {'topic': topic}
Esempio n. 4
0
def patch_move_topic(request: Request, path: str) -> dict:
    """Move a topic to a different group with Intercooler."""
    topic = request.context

    new_group = request.query(Group).filter(Group.path == path).one_or_none()
    if not new_group:
        raise HTTPNotFound("Group not found")

    old_group = topic.group

    if new_group == old_group:
        return IC_NOOP

    topic.group = new_group

    request.db_session.add(
        LogTopic(
            LogEventType.TOPIC_MOVE,
            request,
            topic,
            info={
                "old": str(old_group.path),
                "new": str(topic.group.path)
            },
        ))

    return Response("Moved")
Esempio n. 5
0
def delete_topic_lock(request: Request) -> dict:
    """Unlock a topic with Intercooler."""
    topic = request.context

    topic.is_locked = False
    request.db_session.add(LogTopic(LogEventType.TOPIC_UNLOCK, request, topic))

    return {"name": "lock", "subject": topic, "is_toggled": False}
Esempio n. 6
0
def put_topic_lock(request: Request) -> dict:
    """Lock a topic with Intercooler."""
    topic = request.context

    topic.is_locked = True
    request.db_session.add(LogTopic(LogEventType.TOPIC_LOCK, request, topic))

    return {"name": "lock", "subject": topic, "is_toggled": True}
Esempio n. 7
0
def put_topic_remove(request: Request) -> dict:
    """Remove a topic with Intercooler."""
    topic = request.context

    topic.is_removed = True
    request.db_session.add(LogTopic(LogEventType.TOPIC_REMOVE, request, topic))

    return {"name": "remove", "subject": topic, "is_toggled": True}
Esempio n. 8
0
def unlock_topic(request: Request) -> Response:
    """Unlock a topic with Intercooler."""
    topic = request.context

    topic.is_locked = False
    request.db_session.add(LogTopic(LogEventType.TOPIC_UNLOCK, request, topic))

    return Response('Unlocked')
Esempio n. 9
0
def pin_topic(request: Request) -> Response:
    """Pin a topic with Intercooler."""
    topic = request.context

    topic.is_pinned = True
    request.db_session.add(LogTopic(LogEventType.TOPIC_PINNED, request, topic))

    return Response("Pinned")
Esempio n. 10
0
def delete_topic_remove(request: Request) -> dict:
    """Un-remove a topic with Intercooler."""
    topic = request.context

    topic.is_removed = False
    request.db_session.add(
        LogTopic(LogEventType.TOPIC_UNREMOVE, request, topic))

    return {"name": "remove", "subject": topic, "is_toggled": False}
Esempio n. 11
0
def put_tag_topic(request: Request, tags: str, conflict_check: str) -> dict:
    """Apply tags to a topic with Intercooler."""
    topic = request.context

    # check for edit conflict by verifying tags didn't change after they loaded the form
    if conflict_check:
        conflict_check_tags = conflict_check.split(",")
    else:
        conflict_check_tags = []

    if conflict_check_tags != topic.tags:
        raise ValidationError({
            "tags":
            ["Someone else edited simultaneously, please cancel and retry"]
        })

    if tags:
        # split the tag string on commas
        new_tags = tags.split(",")
    else:
        new_tags = []

    old_tags = topic.tags

    try:
        topic.tags = new_tags
    except ValidationError:
        raise ValidationError({"tags": ["Invalid tags"]})

    # if tags weren't changed, don't add a log entry or update page
    if set(topic.tags) == set(old_tags):
        return IC_NOOP

    request.db_session.add(
        LogTopic(
            LogEventType.TOPIC_TAG,
            request,
            topic,
            info={
                "old": old_tags,
                "new": topic.tags
            },
        ))

    # show the tag field by default in the future when the tagger is posting a new topic
    if not request.user.show_tags_on_new_topic:
        request.user.show_tags_on_new_topic = True
        request.db_session.add(request.user)

    return {"topic": topic}
Esempio n. 12
0
def post_group_topics(
    request: Request,
    title: str,
    markdown: str,
    link: str,
    tags: str,
) -> HTTPFound:
    """Post a new topic to a group."""
    if link:
        new_topic = Topic.create_link_topic(
            group=request.context,
            author=request.user,
            title=title,
            link=link,
        )

        # if they specified both a link and markdown, use the markdown to post
        # an initial comment on the topic
        if markdown:
            new_comment = Comment(
                topic=new_topic,
                author=request.user,
                markdown=markdown,
            )
            request.db_session.add(new_comment)
    else:
        new_topic = Topic.create_text_topic(
            group=request.context,
            author=request.user,
            title=title,
            markdown=markdown,
        )

    try:
        new_topic.tags = tags.split(',')
    except ValidationError:
        raise ValidationError({'tags': ['Invalid tags']})

    request.db_session.add(new_topic)

    request.db_session.add(
        LogTopic(LogEventType.TOPIC_POST, request, new_topic))

    # flush the changes to the database so the new topic's ID is generated
    request.db_session.flush()

    raise HTTPFound(location=new_topic.permalink)
Esempio n. 13
0
def delete_topic_vote(request: Request) -> Response:
    """Remove the user's vote from a topic with Intercooler."""
    topic = request.context

    request.query(TopicVote).filter(
        TopicVote.topic == topic,
        TopicVote.user == request.user).delete(synchronize_session=False)

    request.db_session.add(LogTopic(LogEventType.TOPIC_UNVOTE, request, topic))

    # manually commit the transaction so triggers will execute
    request.tm.commit()

    # re-query the topic to get complete data
    topic = (request.query(Topic).join_all_relationships().filter_by(
        topic_id=topic.topic_id).one())

    return {"topic": topic}
Esempio n. 14
0
def edit_topic_title(request: Request, title: str) -> dict:
    """Edit a topic's title with Intercooler."""
    topic = request.context

    if title == topic.title:
        return IC_NOOP

    request.db_session.add(
        LogTopic(LogEventType.TOPIC_TITLE_EDIT,
                 request,
                 topic,
                 info={
                     'old': topic.title,
                     'new': title
                 }), )

    topic.title = title

    return Response(topic.title)
Esempio n. 15
0
def patch_topic_link(request: Request, link: str) -> dict:
    """Edit a topic's link with Intercooler."""
    topic = request.context

    if link == topic.link:
        return IC_NOOP

    request.db_session.add(
        LogTopic(
            LogEventType.TOPIC_LINK_EDIT,
            request,
            topic,
            info={
                "old": topic.link,
                "new": link
            },
        ))

    topic.link = link
    topic.content_metadata = None

    return Response(f'<a href="{topic.link}">{topic.link}</a>')
Esempio n. 16
0
def post_group_topics(
    request: Request,
    title: str,
    markdown: str,
    link: str,
    tags: str,
    confirm_repost: bool,
) -> Union[HTTPFound, Response]:
    """Post a new topic to a group."""
    group = request.context

    if link:
        # check to see if this link has been posted before
        previous_topics = (request.query(Topic).filter(
            Topic.link == link).order_by(desc(
                Topic.created_time)).limit(5).all())

        if previous_topics and not confirm_repost:
            # Render partial form for Intercooler.js request, whole page for normal POST
            # (I don't like this much, there must be a better way to handle this)
            if "X-IC-Request" in request.headers:
                template = "tildes:templates/includes/new_topic_form.jinja2"
            else:
                template = "tildes:templates/new_topic.jinja2"

            return render_to_response(
                template,
                {
                    "group": group,
                    "title": title,
                    "link": link,
                    "markdown": markdown,
                    "tags": tags,
                    "previous_topics": previous_topics,
                },
                request=request,
            )

        new_topic = Topic.create_link_topic(group=group,
                                            author=request.user,
                                            title=title,
                                            link=link)

        # if they specified both a link and markdown, use the markdown to post an
        # initial comment on the topic
        if markdown:
            new_comment = Comment(topic=new_topic,
                                  author=request.user,
                                  markdown=markdown)
            request.db_session.add(new_comment)

            request.db_session.add(
                LogComment(LogEventType.COMMENT_POST, request, new_comment))
    else:
        new_topic = Topic.create_text_topic(group=group,
                                            author=request.user,
                                            title=title,
                                            markdown=markdown)

    try:
        new_topic.tags = tags.split(",")
    except ValidationError:
        raise ValidationError({"tags": ["Invalid tags"]})

    # remove any tag that's the same as the group's name
    new_topic.tags = [tag for tag in new_topic.tags if tag != str(group.path)]

    request.apply_rate_limit("topic_post")

    request.db_session.add(new_topic)

    request.db_session.add(
        LogTopic(LogEventType.TOPIC_POST, request, new_topic))

    # if the user added tags to the topic, show the field by default in the future
    if tags and not request.user.show_tags_on_new_topic:
        request.user.show_tags_on_new_topic = True
        request.db_session.add(request.user)

    # flush the changes to the database so the new topic's ID is generated
    request.db_session.flush()

    raise HTTPFound(location=new_topic.permalink)