Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
"""Create anonymous_annotation_name

Revision ID: dfb64594049f
Revises: 1d3398f9cd8a
Create Date: 2025-12-05 17:21:35.134935

"""
from typing import Sequence, Union

from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects.postgresql import UUID

from src.util.alembic_helpers import created_at_column

# revision identifiers, used by Alembic.
revision: str = 'dfb64594049f'
down_revision: Union[str, None] = '1d3398f9cd8a'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def upgrade() -> None:

Check warning on line 23 in alembic/versions/2025_12_05_1721-dfb64594049f_create_anonymous_annotation_name.py

View workflow job for this annotation

GitHub Actions / flake8

[flake8] alembic/versions/2025_12_05_1721-dfb64594049f_create_anonymous_annotation_name.py#L23 <103>

Missing docstring in public function
Raw output
./alembic/versions/2025_12_05_1721-dfb64594049f_create_anonymous_annotation_name.py:23:1: D103 Missing docstring in public function
op.create_table(
"link__anonymous_sessions__name_suggestions",
sa.Column(
"session_id",
UUID,
sa.ForeignKey("anonymous_sessions.id"),
nullable=False
),
sa.Column(
"suggestion_id",
sa.Integer(),
sa.ForeignKey("url_name_suggestions.id"),
nullable=False,
),
created_at_column(),
sa.PrimaryKeyConstraint(
"session_id",
"suggestion_id"
)
)


def downgrade() -> None:

Check warning on line 46 in alembic/versions/2025_12_05_1721-dfb64594049f_create_anonymous_annotation_name.py

View workflow job for this annotation

GitHub Actions / flake8

[flake8] alembic/versions/2025_12_05_1721-dfb64594049f_create_anonymous_annotation_name.py#L46 <103>

Missing docstring in public function
Raw output
./alembic/versions/2025_12_05_1721-dfb64594049f_create_anonymous_annotation_name.py:46:1: D103 Missing docstring in public function
pass
25 changes: 25 additions & 0 deletions src/api/endpoints/annotate/anonymous/post/query.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
from uuid import UUID

Check warning on line 1 in src/api/endpoints/annotate/anonymous/post/query.py

View workflow job for this annotation

GitHub Actions / flake8

[flake8] src/api/endpoints/annotate/anonymous/post/query.py#L1 <100>

Missing docstring in public module
Raw output
./src/api/endpoints/annotate/anonymous/post/query.py:1:1: D100 Missing docstring in public module

from sqlalchemy.ext.asyncio import AsyncSession

from src.api.endpoints.annotate.all.post.models.request import AllAnnotationPostInfo
from src.db.models.impl.link.anonymous_sessions__name_suggestion import LinkAnonymousSessionNameSuggestion
from src.db.models.impl.url.suggestion.anonymous.agency.sqlalchemy import AnonymousAnnotationAgency
from src.db.models.impl.url.suggestion.anonymous.location.sqlalchemy import AnonymousAnnotationLocation
from src.db.models.impl.url.suggestion.anonymous.record_type.sqlalchemy import AnonymousAnnotationRecordType
from src.db.models.impl.url.suggestion.anonymous.url_type.sqlalchemy import AnonymousAnnotationURLType
from src.db.models.impl.url.suggestion.name.enums import NameSuggestionSource
from src.db.models.impl.url.suggestion.name.sqlalchemy import URLNameSuggestion
from src.db.queries.base.builder import QueryBuilderBase


Expand All @@ -31,6 +34,28 @@
)
session.add(url_type_suggestion)

name_id: int | None
if self.post_info.name_info.new_name is not None:
name_suggestion = URLNameSuggestion(
url_id=self.url_id,
suggestion=self.post_info.name_info.new_name,
source=NameSuggestionSource.USER
)
session.add(name_suggestion)
await session.flush()
name_id = name_suggestion.id
elif self.post_info.name_info.existing_name_id is not None:
name_id = self.post_info.name_info.existing_name_id
else:
name_id = None

if name_id is not None:
name_suggestion = LinkAnonymousSessionNameSuggestion(
suggestion_id=name_id,
session_id=self.session_id
)
session.add(name_suggestion)

if self.post_info.record_type is not None:
record_type_suggestion = AnonymousAnnotationRecordType(
url_id=self.url_id,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,76 @@
from sqlalchemy import select, func

from src.core.tasks.url.operators.validate.queries.ctes.counts.core import ValidatedCountsCTEContainer
from src.db.models.impl.link.anonymous_sessions__name_suggestion import LinkAnonymousSessionNameSuggestion
from src.db.models.impl.link.user_name_suggestion.sqlalchemy import LinkUserNameSuggestion
from src.db.models.impl.url.suggestion.name.sqlalchemy import URLNameSuggestion
from src.db.models.views.unvalidated_url import UnvalidatedURL

_user_counts = (
select(
URLNameSuggestion.url_id,
URLNameSuggestion.suggestion.label("entity"),
func.count().label("votes")
)
.join(
LinkUserNameSuggestion,
LinkUserNameSuggestion.suggestion_id == URLNameSuggestion.id
)
.group_by(
URLNameSuggestion.url_id,
URLNameSuggestion.suggestion
)
.cte("user_counts")
)

_anon_counts = (
select(
URLNameSuggestion.url_id,
URLNameSuggestion.suggestion.label("entity"),
func.count().label("votes")
)
.join(
LinkAnonymousSessionNameSuggestion,
LinkAnonymousSessionNameSuggestion.suggestion_id == URLNameSuggestion.id
)
.group_by(
URLNameSuggestion.url_id,
URLNameSuggestion.suggestion
)
.cte("anon_counts")
)

_union_counts = (
select(
_user_counts.c.url_id,
_user_counts.c.entity,
_user_counts.c.votes
)
.union_all(
select(
_anon_counts.c.url_id,
_anon_counts.c.entity,
_anon_counts.c.votes
)
)
.cte("counts_name_union")
)


NAME_VALIDATION_COUNTS_CTE = ValidatedCountsCTEContainer(
(
select(
URLNameSuggestion.url_id,
URLNameSuggestion.suggestion.label("entity"),
func.count().label("votes")
_union_counts.c.url_id,
_union_counts.c.entity,
func.sum(_union_counts.c.votes).label("votes")
)
.join(
UnvalidatedURL,
URLNameSuggestion.url_id == UnvalidatedURL.url_id
)
.join(
LinkUserNameSuggestion,
LinkUserNameSuggestion.suggestion_id == URLNameSuggestion.id
_union_counts.c.url_id == UnvalidatedURL.url_id
)
.group_by(
URLNameSuggestion.url_id,
URLNameSuggestion.suggestion
_union_counts.c.url_id,
_union_counts.c.entity,
)
).cte("counts_name")
)
24 changes: 24 additions & 0 deletions src/db/models/impl/link/anonymous_sessions__name_suggestion.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from sqlalchemy import PrimaryKeyConstraint, ForeignKey, Integer, Column

Check warning on line 1 in src/db/models/impl/link/anonymous_sessions__name_suggestion.py

View workflow job for this annotation

GitHub Actions / flake8

[flake8] src/db/models/impl/link/anonymous_sessions__name_suggestion.py#L1 <100>

Missing docstring in public module
Raw output
./src/db/models/impl/link/anonymous_sessions__name_suggestion.py:1:1: D100 Missing docstring in public module

from src.db.models.mixins import CreatedAtMixin, AnonymousSessionMixin
from src.db.models.templates_.base import Base


class LinkAnonymousSessionNameSuggestion(

Check warning on line 7 in src/db/models/impl/link/anonymous_sessions__name_suggestion.py

View workflow job for this annotation

GitHub Actions / flake8

[flake8] src/db/models/impl/link/anonymous_sessions__name_suggestion.py#L7 <101>

Missing docstring in public class
Raw output
./src/db/models/impl/link/anonymous_sessions__name_suggestion.py:7:1: D101 Missing docstring in public class
Base,
AnonymousSessionMixin,
CreatedAtMixin
):
__tablename__ = "link__anonymous_sessions__name_suggestions"
suggestion_id = Column(
Integer,
ForeignKey("url_name_suggestions.id"),
primary_key=True,
nullable=False,
)
__table_args__ = (
PrimaryKeyConstraint(
"session_id",
"suggestion_id"
),
)

Check warning on line 24 in src/db/models/impl/link/anonymous_sessions__name_suggestion.py

View workflow job for this annotation

GitHub Actions / flake8

[flake8] src/db/models/impl/link/anonymous_sessions__name_suggestion.py#L24 <292>

no newline at end of file
Raw output
./src/db/models/impl/link/anonymous_sessions__name_suggestion.py:24:6: W292 no newline at end of file
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import pytest

from src.api.endpoints.annotate.all.get.models.name import NameAnnotationSuggestion
from src.api.endpoints.annotate.all.get.models.response import GetNextURLForAllAnnotationResponse
from src.api.endpoints.annotate.all.post.models.agency import AnnotationPostAgencyInfo
from src.api.endpoints.annotate.all.post.models.location import AnnotationPostLocationInfo
from src.api.endpoints.annotate.all.post.models.name import AnnotationPostNameInfo
Expand All @@ -12,10 +11,12 @@
from src.core.enums import RecordType
from src.db.dtos.url.mapping_.simple import SimpleURLMapping
from src.db.models.impl.flag.url_validated.enums import URLType
from src.db.models.impl.link.anonymous_sessions__name_suggestion import LinkAnonymousSessionNameSuggestion
from src.db.models.impl.url.suggestion.anonymous.agency.sqlalchemy import AnonymousAnnotationAgency
from src.db.models.impl.url.suggestion.anonymous.location.sqlalchemy import AnonymousAnnotationLocation
from src.db.models.impl.url.suggestion.anonymous.record_type.sqlalchemy import AnonymousAnnotationRecordType
from src.db.models.impl.url.suggestion.anonymous.url_type.sqlalchemy import AnonymousAnnotationURLType
from src.db.models.impl.url.suggestion.name.sqlalchemy import URLNameSuggestion
from src.db.models.mixins import URLDependentMixin
from tests.automated.integration.api.annotate.anonymous.helper import get_next_url_for_anonymous_annotation, \
post_and_get_next_url_for_anonymous_annotation
Expand Down Expand Up @@ -90,6 +91,16 @@ async def test_annotate_anonymous(
instance: model = instances[0]
assert instance.url_id == get_response_1.next_annotation.url_info.url_id

# Check for existence of name suggestion (2 were added by setup)
name_suggestions: list[URLNameSuggestion] = await ddc.adb_client.get_all(URLNameSuggestion)
assert len(name_suggestions) == 3

# Check for existence of link
link_instances: list[LinkAnonymousSessionNameSuggestion] = await ddc.adb_client.get_all(LinkAnonymousSessionNameSuggestion)
assert len(link_instances) == 1
link_instance: LinkAnonymousSessionNameSuggestion = link_instances[0]
assert link_instance.session_id == session_id

# Run again without giving session ID, confirm original URL returned
get_response_2: GetNextURLForAnonymousAnnotationResponse = await get_next_url_for_anonymous_annotation(rv)
assert get_response_2.session_id != session_id
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ async def add_record_type_suggestions(
async def add_name_suggestion(
self,
count: int = 1,
) -> str:
) -> int:
name = f"Test Validate Task Name"
suggestion_id: int = await self.db_data_creator.name_suggestion(
url_id=self.url_id,
Expand All @@ -144,7 +144,7 @@ async def add_name_suggestion(
suggestion_id=suggestion_id,
user_id=next_int(),
)
return name
return suggestion_id

async def check_name(self) -> None:
urls: list[URL] = await self.adb_client.get_all(URL)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from src.core.enums import RecordType
from src.core.tasks.url.operators.validate.core import AutoValidateURLTaskOperator
from src.db.models.impl.flag.url_validated.enums import URLType
from src.db.models.impl.link.anonymous_sessions__name_suggestion import LinkAnonymousSessionNameSuggestion
from src.db.models.impl.url.suggestion.anonymous.agency.sqlalchemy import AnonymousAnnotationAgency
from src.db.models.impl.url.suggestion.anonymous.location.sqlalchemy import AnonymousAnnotationLocation
from src.db.models.impl.url.suggestion.anonymous.record_type.sqlalchemy import AnonymousAnnotationRecordType
Expand Down Expand Up @@ -45,7 +46,7 @@ async def test_data_source(

assert not await operator.meets_task_prerequisites()

await helper.add_name_suggestion(count=2)
suggestion_id: int = await helper.add_name_suggestion(count=1)

assert not await operator.meets_task_prerequisites()

Expand Down Expand Up @@ -74,11 +75,16 @@ async def test_data_source(
session_id=session_id,
url_id=helper.url_id
)
anon_name_link = LinkAnonymousSessionNameSuggestion(
suggestion_id=suggestion_id,
session_id=session_id
)
for model in [
anon_url_type,
anon_record_type,
anon_location,
anon_agency
anon_agency,
anon_name_link
]:
await helper.adb_client.add(model)

Expand Down
Loading