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>')
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}
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}
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")
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}
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}
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}
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')
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")
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}
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}
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)
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}
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)
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>')
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)