diff --git a/tildes/alembic/versions/24014adda7c3_add_topic_link_edit_to_logeventtype.py b/tildes/alembic/versions/24014adda7c3_add_topic_link_edit_to_logeventtype.py new file mode 100644 index 0000000..8230442 --- /dev/null +++ b/tildes/alembic/versions/24014adda7c3_add_topic_link_edit_to_logeventtype.py @@ -0,0 +1,35 @@ +"""Add TOPIC_LINK_EDIT to logeventtype + +Revision ID: 24014adda7c3 +Revises: 7ac1aad64144 +Create Date: 2019-03-14 21:57:27.057187 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = "24014adda7c3" +down_revision = "7ac1aad64144" +branch_labels = None +depends_on = None + + +def upgrade(): + # ALTER TYPE doesn't work from inside a transaction, disable it + connection = None + if not op.get_context().as_sql: + connection = op.get_bind() + connection.execution_options(isolation_level="AUTOCOMMIT") + + op.execute("ALTER TYPE logeventtype ADD VALUE IF NOT EXISTS 'TOPIC_LINK_EDIT'") + + # re-activate the transaction for any future migrations + if connection is not None: + connection.execution_options(isolation_level="READ_COMMITTED") + + +def downgrade(): + # can't remove from enums, do nothing + pass diff --git a/tildes/tildes/enums.py b/tildes/tildes/enums.py index d5c693c..c686521 100644 --- a/tildes/tildes/enums.py +++ b/tildes/tildes/enums.py @@ -74,6 +74,7 @@ class LogEventType(enum.Enum): COMMENT_REMOVE = enum.auto() COMMENT_UNREMOVE = enum.auto() + TOPIC_LINK_EDIT = enum.auto() TOPIC_LOCK = enum.auto() TOPIC_MOVE = enum.auto() TOPIC_POST = enum.auto() diff --git a/tildes/tildes/models/log/log.py b/tildes/tildes/models/log/log.py index 46ca2ed..b5e7a44 100644 --- a/tildes/tildes/models/log/log.py +++ b/tildes/tildes/models/log/log.py @@ -164,6 +164,10 @@ class LogTopic(DatabaseModel, BaseLog): old_title = self.info["old"] new_title = self.info["new"] return f'changed title from "{old_title}" to "{new_title}"' + elif self.event_type == LogEventType.TOPIC_LINK_EDIT: + old_link = self.info["old"] + new_link = self.info["new"] + return f"changed link from {old_link} to {new_link}" return f"performed action {self.event_type.name}" diff --git a/tildes/tildes/models/topic/topic.py b/tildes/tildes/models/topic/topic.py index 9cc8809..1e51902 100644 --- a/tildes/tildes/models/topic/topic.py +++ b/tildes/tildes/models/topic/topic.py @@ -304,6 +304,10 @@ class Topic(DatabaseModel): acl.append((Allow, "admin", "edit_title")) acl.append((Allow, "topic.edit_title", "edit_title")) + if self.is_link_type: + acl.append((Allow, "admin", "edit_link")) + acl.append((Allow, "topic.edit_link", "edit_link")) + # bookmark: # - logged-in users can bookmark topics acl.append((Allow, Authenticated, "bookmark")) diff --git a/tildes/tildes/routes.py b/tildes/tildes/routes.py index 1ad81d1..7b1550a 100644 --- a/tildes/tildes/routes.py +++ b/tildes/tildes/routes.py @@ -115,6 +115,7 @@ def add_intercooler_routes(config: Configurator) -> None: with config.route_prefix_context("/topics/{topic_id36}"): add_ic_route("topic_comments", "/comments", factory=topic_by_id36) add_ic_route("topic_group", "/group", factory=topic_by_id36) + add_ic_route("topic_link", "/link", factory=topic_by_id36) add_ic_route("topic_lock", "/lock", factory=topic_by_id36) add_ic_route("topic_remove", "/remove", factory=topic_by_id36) add_ic_route("topic_title", "/title", factory=topic_by_id36) diff --git a/tildes/tildes/templates/intercooler/topic_link_edit.jinja2 b/tildes/tildes/templates/intercooler/topic_link_edit.jinja2 new file mode 100644 index 0000000..091278c --- /dev/null +++ b/tildes/tildes/templates/intercooler/topic_link_edit.jinja2 @@ -0,0 +1,19 @@ +{# Copyright (c) 2019 Tildes contributors #} +{# SPDX-License-Identifier: AGPL-3.0-or-later #} + +
+ + +
+ + +
+
diff --git a/tildes/tildes/templates/topic.jinja2 b/tildes/tildes/templates/topic.jinja2 index e3a2915..9d58984 100644 --- a/tildes/tildes/templates/topic.jinja2 +++ b/tildes/tildes/templates/topic.jinja2 @@ -66,7 +66,7 @@ {% endif %} {% endif %} -{% if request.has_any_permission(('edit', 'delete', 'tag', 'lock', 'move', 'edit_title', 'remove', 'bookmark'), topic) %} +{% if request.has_any_permission(('edit', 'delete', 'tag', 'lock', 'move', 'edit_link', 'edit_title', 'remove', 'bookmark'), topic) %} {% if request.has_permission('edit', topic) %}
  • {% endif %} + {% if request.has_permission('edit_link', topic) %} +
  • + {% endif %} + {% if request.has_permission('lock', topic) %}
  • {% if not topic.is_locked %} diff --git a/tildes/tildes/views/api/web/topic.py b/tildes/tildes/views/api/web/topic.py index 6a94965..47d0a82 100644 --- a/tildes/tildes/views/api/web/topic.py +++ b/tildes/tildes/views/api/web/topic.py @@ -316,6 +316,45 @@ def patch_topic_title(request: Request, title: str) -> dict: return Response(topic.title) +@ic_view_config( + route_name="topic_link", + request_method="GET", + renderer="topic_link_edit.jinja2", + permission="edit_link", +) +def get_topic_link(request: Request) -> dict: + """Get the form for editing a topic's link with Intercooler.""" + return {"topic": request.context} + + +@ic_view_config( + route_name="topic", + request_param="ic-trigger-name=topic-link-edit", + request_method="PATCH", + permission="edit_link", +) +@use_kwargs(TopicSchema(only=("link",))) +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 + + return Response(f'{topic.link}') + + @ic_view_config( route_name="topic_bookmark", request_method="PUT", permission="bookmark" ) diff --git a/tildes/tildes/views/topic.py b/tildes/tildes/views/topic.py index adcef02..602f522 100644 --- a/tildes/tildes/views/topic.py +++ b/tildes/tildes/views/topic.py @@ -269,6 +269,7 @@ def get_topic(request: Request, comment_order: CommentSortOption) -> dict: # check if there are any items in the log to show visible_events = ( + LogEventType.TOPIC_LINK_EDIT, LogEventType.TOPIC_LOCK, LogEventType.TOPIC_MOVE, LogEventType.TOPIC_REMOVE,