Files
zeekayandHanzo Dev 841ea1c0da no hogs: products and insights
716 files rewritten, 30 renamed, same family mapping as the frontend pass.

Held back, and each for a reason rather than by oversight:

  db_table values          insights_hogfunction, insights_hogflow,
                           insights_hogfunctiontemplate, hogflow_templates.
                           Renaming a table is ALTER TABLE, so it ships as a
                           migration with the raw SQL in nodejs that names it.
  hog_invocation_results   a Datastore table with Kafka engine tables on it
  products/review_hog      the module path is the Django app path; moving it
                           moves app_label and every migration is recorded under
                           (app_label, name). That is the same history break as
                           renaming a migration file, one level up.
  */migrations/*           five files, untouched
  whogho                   an integration vendor

Checked: 395 of 397 changed Python files compile. The two that do not —
insightsql/database/database.py and temporal/schedule.py — fail identically at
origin/main under the same interpreter, because they use `type X = ...` and
`except*`, which need the 3.13 this repo pins and not the 3.9 doing the check.
Running the check against the original is what told those apart from a real
break.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-09 09:16:43 -07:00

84 lines
2.9 KiB
Python

from typing import Any
from django.db.models import QuerySet
import structlog
from rest_framework import serializers, viewsets
from rest_framework.permissions import IsAuthenticated
from rest_framework.request import Request
from rest_framework.response import Response
from insights.api.routing import TeamAndOrgViewSetMixin
from insights.api.shared import UserBasicSerializer
from insights.models.team.team import Team
from products.links.backend.models import Link
logger = structlog.get_logger(__name__)
class LinkSerializer(serializers.ModelSerializer):
created_by = UserBasicSerializer(read_only=True)
short_code = serializers.CharField(required=True, allow_null=False)
_create_in_folder = serializers.CharField(required=False, allow_blank=True, write_only=True)
class Meta:
model = Link
fields = [
"id",
"redirect_url",
"short_link_domain",
"short_code",
"description",
"created_at",
"updated_at",
"created_by",
"_create_in_folder",
]
read_only_fields = ["id", "created_at", "updated_at"]
def create(self, validated_data: dict[str, Any]) -> Link:
team = Team.objects.get(id=self.context["team_id"])
if validated_data.get("short_link_domain") != "pscript.gg":
raise serializers.ValidationError({"short_link_domain": "Only pscript.gg is allowed as a short link domain"})
link = Link.objects.create(
team=team,
created_by=self.context["request"].user,
**validated_data,
)
logger.info("link_created", id=link.id, team_id=team.id)
return link
class LinkViewSet(TeamAndOrgViewSetMixin, viewsets.ModelViewSet):
"""
Create, read, update, and delete links.
"""
scope_object = "link"
queryset = Link.objects.all()
serializer_class = LinkSerializer
lookup_field = "id"
permission_classes = [IsAuthenticated]
# Use the team from the user's current context when not in a team-specific route
param_derived_from_user_current_team = "team_id"
def safely_get_queryset(self, queryset: QuerySet) -> QuerySet:
return queryset.filter(team_id=self.team_id).order_by("-created_at")
# TODO: Call the /invalidate route on the Rust service
def update(self, request: Request, *args: Any, **kwargs: Any) -> Response:
return super().update(request, *args, **kwargs)
# TODO: Call the /invalidate route on the Rust service
# and wait for confirmation before we delete this link
#
# TODO: Consider implementing "archiving" rather than deletion
def destroy(self, request: Request, *args: Any, **kwargs: Any) -> Response:
instance = self.get_object()
logger.info("link_deleted", id=instance.id, team_id=self.team_id)
return super().destroy(request, *args, **kwargs)