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
11 changes: 11 additions & 0 deletions app/api/api_v1/endpoints/flatmates.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
list_incoming_likes,
list_matches,
list_messages,
list_outgoing_likes,
mark_all_flatmates_notifications_read,
mark_conversation_read,
mark_flatmates_notification_read,
Expand Down Expand Up @@ -192,6 +193,16 @@ async def get_incoming_likes(
return await list_incoming_likes(db, current_user.id, limit=limit, offset=offset)


@router.get("/outgoing-likes", response_model=list[IncomingLikeSummary])
Comment thread
RaviSahu1520 marked this conversation as resolved.
async def get_outgoing_likes(
limit: int = Query(default=20, ge=1, le=100),
offset: int = Query(default=0, ge=0),
current_user: UserSchema = Depends(get_current_active_user),
db: AsyncSession = Depends(get_db),
):
return await list_outgoing_likes(db, current_user.id, limit=limit, offset=offset)


@router.post("/profile-views", response_model=ProfileViewEventOut)
async def record_profile_view(
payload: ProfileViewEventCreate,
Expand Down
8 changes: 4 additions & 4 deletions app/core/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,10 @@ def _secret_key_not_default_in_production(cls, value: str, info: ValidationInfo)
REDIS_URL: str = "redis://localhost:6379"

# Main pool (HTTP/MCP request traffic)
DB_POOL_SIZE: int = 3
DB_MAX_OVERFLOW: int = 3
DB_POOL_TIMEOUT: int = 10
DB_POOL_RECYCLE: int = 300
DB_POOL_SIZE: int = 5
DB_MAX_OVERFLOW: int = 5
DB_POOL_TIMEOUT: int = 15
DB_POOL_RECYCLE: int = 180
# Background pool (schedulers, scrapers, long-running tasks)
DB_BG_POOL_SIZE: int = 2
DB_BG_MAX_OVERFLOW: int = 2
Expand Down
2 changes: 2 additions & 0 deletions app/services/flatmates/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from app.services.flatmates.matching import (
list_incoming_likes,
list_matches,
list_outgoing_likes,
record_swipe,
unmatch_match,
unmatch_user_pair,
Expand Down Expand Up @@ -60,6 +61,7 @@
# matching
"record_swipe",
"list_incoming_likes",
"list_outgoing_likes",
"list_matches",
"unmatch_user_pair",
"unmatch_match",
Expand Down
51 changes: 50 additions & 1 deletion app/services/flatmates/matching.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
UserMatchStatus,
)
from app.models.properties import Property
from app.models.social import FlatmateSuperLikeUsage, UserConversation, UserMatch
from app.models.social import FlatmateSuperLikeUsage, UserBlock, UserConversation, UserMatch
from app.models.users import User, UserSwipe
from app.schemas.flatmates import SwipeRequest
from app.services.flatmates.conversations import _ensure_conversation
Expand Down Expand Up @@ -308,6 +308,55 @@ async def list_incoming_likes(
return items


async def list_outgoing_likes(
db: AsyncSession,
user_id: int,
*,
limit: int = 20,
offset: int = 0,
) -> list[dict[str, Any]]:
"""Return profiles the current user has liked (outgoing likes)."""
current_user = await db.get(User, user_id)
stmt = (
select(UserSwipe)
.options(selectinload(UserSwipe.target_user), selectinload(UserSwipe.context_property))
.where(
UserSwipe.user_id == user_id,
UserSwipe.target_type == SwipeTargetType.user.value,
UserSwipe.is_liked.is_(True),
UserSwipe.target_user_id.is_not(None),
)
.order_by(UserSwipe.created_at.desc())
.limit(limit)
.offset(offset)
)
outgoing_swipes = list((await db.execute(stmt)).scalars().all())

blocked_ids_stmt = select(UserBlock.blocked_user_id).where(
UserBlock.blocker_user_id == user_id,
)
blocker_ids_stmt = select(UserBlock.blocker_user_id).where(
UserBlock.blocked_user_id == user_id,
)
blocked_ids = set((await db.execute(blocked_ids_stmt)).scalars().all())
blocker_ids = set((await db.execute(blocker_ids_stmt)).scalars().all())
excluded_ids = blocked_ids | blocker_ids

items: list[dict[str, Any]] = []
for swipe in outgoing_swipes:
if swipe.target_user is None or swipe.target_user_id in excluded_ids:
continue
Comment thread
qodo-code-review[bot] marked this conversation as resolved.
items.append(
{
"id": swipe.id,
"peer": _build_peer_payload(swipe.target_user, current_user),
"context_property": _build_property_context(swipe.context_property),
"created_at": swipe.created_at,
}
)
return items


async def list_matches(db: AsyncSession, user_id: int) -> list[dict[str, Any]]:
current_user = await db.get(User, user_id)
stmt = (
Expand Down
10 changes: 9 additions & 1 deletion app/services/flatmates/profiles.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@
FlatmatesProfileStatus,
PropertyPurpose,
PropertyType,
SwipeTargetType,
)
from app.models.properties import Property
from app.models.social import AppCatalog, UserConversation, UserMessage
from app.models.users import User
from app.models.users import User, UserSwipe
from app.schemas.flatmates import FlatmatesProfileUpdate
from app.services.flatmates.helpers import (
_build_peer_payload,
Expand Down Expand Up @@ -77,6 +78,12 @@ async def list_discoverable_profiles(
blocker_ids = list((await db.execute(blocker_stmt)).scalars().all())
excluded = {user_id, *blocked_ids, *blocker_ids}

swiped_subq = select(UserSwipe.target_user_id).where(
UserSwipe.user_id == user_id,
UserSwipe.target_type == SwipeTargetType.user.value,
UserSwipe.target_user_id.is_not(None),
)
Comment thread
RaviSahu1520 marked this conversation as resolved.

# --- Deal-breaker (non-negotiables) filtering (P0-4) ---
requesting_user = await db.get(User, user_id)
non_negotiables: list[str] = []
Expand All @@ -89,6 +96,7 @@ async def list_discoverable_profiles(

filters = [
User.id.notin_(excluded),
User.id.notin_(swiped_subq),
User.flatmates_onboarding_completed.is_(True),
User.flatmates_profile_status == FlatmatesProfileStatus.active,
]
Expand Down
28 changes: 17 additions & 11 deletions app/services/property/search.py
Original file line number Diff line number Diff line change
Expand Up @@ -589,17 +589,23 @@ async def get_unified_properties_optimized(
if has_additional_columns:
rows = result.all()
for row in rows:
mapping = row._mapping if hasattr(row, "_mapping") else {}
prop = mapping.get("Property") or mapping.get(Property)
if prop is None:
prop = row[0] if isinstance(row, tuple) and len(row) > 0 else row
if mapping and prop:
if "distance_km" in mapping and mapping["distance_km"] is not None:
prop.distance_km = mapping["distance_km"]
if "vector_distance" in mapping and mapping["vector_distance"] is not None:
prop.vector_distance = mapping["vector_distance"]
if "relevance_score" in mapping and mapping["relevance_score"] is not None:
prop.relevance_score = mapping["relevance_score"]
prop = row[0]
if not isinstance(prop, Property):
mapping = row._mapping if hasattr(row, "_mapping") else {}
prop = mapping.get("Property") or mapping.get(Property)
if prop is None:
prop = row[0] if isinstance(row, tuple) and len(row) > 0 else row
if isinstance(prop, Property):
try:
mapping = row._mapping if hasattr(row, "_mapping") else {}
if "distance_km" in mapping and mapping["distance_km"] is not None:
prop.distance_km = float(mapping["distance_km"])
if "vector_distance" in mapping and mapping["vector_distance"] is not None:
prop.vector_distance = float(mapping["vector_distance"])
if "relevance_score" in mapping and mapping["relevance_score"] is not None:
prop.relevance_score = float(mapping["relevance_score"])
except (TypeError, ValueError, KeyError) as exc:
logger.debug("Failed to cast property score fields: %s", exc)
if prop:
properties.append(cast(Property, prop)) # type: ignore[arg-type]
Comment thread
RaviSahu1520 marked this conversation as resolved.
else:
Expand Down
Loading