Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backend/feature/user search mega issue #4992

Open
wants to merge 26 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
9566dfe
added fluency criteria, search age
Krishnag09 Oct 1, 2024
0e16df7
Merge branch 'develop' of github.com:Couchers-org/couchers into backe…
Krishnag09 Oct 1, 2024
285f87d
initial commit with test
Krishnag09 Oct 9, 2024
3def65b
format and typo fixes
Krishnag09 Oct 14, 2024
486153d
test without errors
Krishnag09 Oct 14, 2024
eb95f21
fluency code missing
Krishnag09 Oct 15, 2024
c150539
passing test
Krishnag09 Oct 15, 2024
732478b
final changes
Krishnag09 Oct 15, 2024
42e36a9
ruff reformat
Krishnag09 Oct 15, 2024
ac6b5e3
age filter correction
Krishnag09 Oct 16, 2024
1d55b0b
review comment changes
Krishnag09 Oct 26, 2024
04b4399
removed unussed proto message
Krishnag09 Oct 26, 2024
1a49850
test_review_comments
Krishnag09 Oct 28, 2024
d66da41
Update app/backend/src/couchers/servicers/search.py
Krishnag09 Nov 13, 2024
af9f067
review comments changes 2
Krishnag09 Nov 13, 2024
a7305ed
Merge branch 'backend/feature/user_search_mega_issue' of github.com:C…
Krishnag09 Nov 13, 2024
c3f7ef8
review comments
Krishnag09 Nov 17, 2024
7a9d59a
review_comments_3
Krishnag09 Nov 26, 2024
a86fd07
Merge branch 'develop' of github.com:Couchers-org/couchers into backe…
Krishnag09 Nov 26, 2024
89dd3ba
merge+ added Q to readme
Krishnag09 Nov 26, 2024
db7c624
ruff fixes
Krishnag09 Nov 26, 2024
efb9462
text fix
Krishnag09 Nov 27, 2024
3dd6235
use correct proto
Krishnag09 Nov 27, 2024
51ee756
adding conversions
Krishnag09 Nov 27, 2024
cae3a3f
query_refactor
Krishnag09 Nov 27, 2024
71194e8
add levels tetsing
Krishnag09 Nov 28, 2024
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
8 changes: 4 additions & 4 deletions app/backend/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

[Here is information for debugging the backend inside VS Code](/docs/backend-in-vscode.md)

You can run the whole thing through Docker and docker-compose (see the readme in the `app/` folder).
You can run the whole thing through Docker and docker compose (see the readme in the `app/` folder).

## Running tests in docker

Expand All @@ -16,7 +16,7 @@ docker compose -f docker-compose.test.yml up --build

1. If you haven't already, run the first two steps from the [readme in the `app/` folder](https://github.com/Couchers-org/couchers/blob/develop/app/readme.md).

**Remember** that if you've made changes to any *.proto files, you may need to re-compile the protocol buffers (step 2).
**Remember** that if you've made changes to any \*.proto files, you may need to re-compile the protocol buffers (step 2).

2. Make sure the postgres_tests container is running:

Expand Down Expand Up @@ -45,7 +45,7 @@ export DATABASE_CONNECTION_STRING=postgresql://postgres:06b3890acd2c235c41be0bbf
6. Run `pytest` in the `app/backend/src/` folder.

```sh
cd src
cd src
pytest
```

Expand All @@ -57,4 +57,4 @@ A: Doublecheck that your DB test container is running. Then make sure the DATABA

Q: I can't connect to the DB!

A: First doublecheck what port the DB is listening on - run `docker-compose up postgres` and it should say something like `listening on IPv6 address "::", port 6545`. Then doublecheck you have the right password. There are TWO passwords - one for the test db and one for the normal db! See app/postgres.dev.env and app/postgres.test.env
A: First doublecheck what port the DB is listening on - run `docker compose up postgres` and it should say something like `listening on IPv6 address "::", port 6545`. Then doublecheck you have the right password. There are TWO passwords - one for the test db and one for the normal db! See app/postgres.dev.env and app/postgres.test.env
33 changes: 32 additions & 1 deletion app/backend/src/couchers/servicers/search.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
EventOccurrenceAttendee,
EventOrganizer,
EventSubscription,
LanguageAbility,
Node,
Page,
PageType,
Expand All @@ -26,6 +27,7 @@
)
from couchers.servicers.account import has_strong_verification
from couchers.servicers.api import (
fluency2sql,
hostingstatus2sql,
meetupstatus2sql,
parkingdetails2sql,
Expand All @@ -46,7 +48,7 @@
now,
to_aware_datetime,
)
from proto import search_pb2, search_pb2_grpc
from proto import api_pb2, search_pb2, search_pb2_grpc

# searches are a bit expensive, we'd rather send back a bunch of results at once than lots of small pages
MAX_PAGINATION_LENGTH = 100
Expand All @@ -55,6 +57,11 @@
TRI_SIMILARITY_THRESHOLD = 0.6
TRI_SIMILARITY_WEIGHT = 5

conversational_fluent_filter_values = [
Krishnag09 marked this conversation as resolved.
Show resolved Hide resolved
fluency2sql[api_pb2.LanguageAbility.Fluency.FLUENCY_CONVERSATIONAL],
fluency2sql[api_pb2.LanguageAbility.Fluency.FLUENCY_FLUENT],
Krishnag09 marked this conversation as resolved.
Show resolved Hide resolved
]

Krishnag09 marked this conversation as resolved.
Show resolved Hide resolved

def _join_with_space(coalesces):
# the objects in coalesces are not strings, so we can't do " ".join(coalesces). They're SQLAlchemy magic.
Expand Down Expand Up @@ -410,6 +417,7 @@ def UserSearch(self, request, context, session):
)
)

# add interests in profile and as filter.
if request.HasField("last_active"):
raw_dt = to_aware_datetime(request.last_active)
statement = statement.where(User.last_active >= last_active_coarsen(raw_dt))
Expand Down Expand Up @@ -444,6 +452,29 @@ def UserSearch(self, request, context, session):
statement = statement.where(
User.parking_details.in_([parkingdetails2sql[det] for det in request.parking_details_filter])
)
# limits/default could be handled on the front end as well
min_age = request.age_min.value if request.HasField("age_min") else 18
max_age = request.age_max.value if request.HasField("age_max") else 200

statement = statement.where((User.age >= min_age) & (User.age <= max_age))
aapeliv marked this conversation as resolved.
Show resolved Hide resolved


# return results with by language code as only input
# fluency in conversational or fluent

if len(request.language_ability_filter) > 0:
for ability_filter in request.language_ability_filter:
fluency_sql_value = fluency2sql.get(ability_filter.fluency)

if fluency_sql_value is None:
continue

statement = statement.where(
User.language_abilities.any(
(LanguageAbility.language_code == ability_filter.code)
& (LanguageAbility.fluency.in_(conversational_fluent_filter_values))
Krishnag09 marked this conversation as resolved.
Show resolved Hide resolved
)
)
if request.HasField("profile_completed"):
statement = statement.where(User.has_completed_profile == request.profile_completed.value)
if request.HasField("guests"):
Expand Down
43 changes: 42 additions & 1 deletion app/backend/src/tests/test_search.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from google.protobuf import wrappers_pb2

from couchers.db import session_scope
from couchers.models import EventOccurrence, MeetupStatus
from couchers.models import EventOccurrence, Language, LanguageAbility, LanguageFluency, MeetupStatus
from couchers.utils import Timestamp_from_datetime, create_coordinate, millis_from_dt, now
from proto import api_pb2, communities_pb2, events_pb2, search_pb2
from tests.test_communities import create_community, testing_communities # noqa
Expand All @@ -14,7 +14,9 @@
events_session,
generate_user,
search_session,
session_scope,
testconfig,
recreate_database,
)


Expand Down Expand Up @@ -158,6 +160,45 @@ def test_user_filter_meetup_status(db):
assert [result.user.user_id for result in res.results] == [user_does_not_want_to_meet.id]


def test_user_filter_language(db):
"""
Make sure the language filter returns the rigth profiles
"""
recreate_database()
Krishnag09 marked this conversation as resolved.
Show resolved Hide resolved
user_with_german_fluent, token11 = generate_user()
user_with_japanese_conversational, token12 = generate_user()

with session_scope() as session:

session.add(
LanguageAbility(user_id=user_with_german_fluent.id, language_code="deu", fluency=LanguageFluency.fluent)
)
session.add(
LanguageAbility(
user_id=user_with_japanese_conversational.id, language_code="jpn", fluency=LanguageFluency.conversational
)
)

with search_session(token11) as api:
search_request_1 = search_pb2.UserSearchReq(
language_ability_filter=[
api_pb2.LanguageAbility(code="deu", fluency=api_pb2.LanguageAbility.Fluency.FLUENCY_FLUENT)
]
)
with search_session(token12) as api:
search_request_2 = search_pb2.UserSearchReq(
language_ability_filter=[
api_pb2.LanguageAbility(code="jpn", fluency=api_pb2.LanguageAbility.Fluency.FLUENCY_CONVERSATIONAL)
]
)

result_1 = api.UserSearch(search_request_1)
result_2 = api.UserSearch(search_request_2)

assert [result.user.user_id for result in result_1.results] == [user_with_german_fluent.id]
assert [result.user.user_id for result in result_2.results] == [user_with_japanese_conversational.id]

Krishnag09 marked this conversation as resolved.
Show resolved Hide resolved

@pytest.fixture
def sample_event_data() -> dict:
"""Dummy data for creating events."""
Expand Down
1 change: 0 additions & 1 deletion app/proto/api.proto
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ package org.couchers.api.core;
import "google/protobuf/empty.proto";
import "google/protobuf/timestamp.proto";
import "google/protobuf/wrappers.proto";

import "annotations.proto";

service API {
Expand Down
19 changes: 15 additions & 4 deletions app/proto/search.proto
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,14 @@ message SearchRes {
string next_page_token = 2;
}


message LanguageAbility {
int64 user_id = 1; // Corresponds to the user ID (optional, may not be needed for search)
string language_code = 2; // ISO code for the language (e.g., "dan" for Danish)
org.couchers.api.core.LanguageAbility.Fluency fluency = 3; // The language fluency level
}
Krishnag09 marked this conversation as resolved.
Show resolved Hide resolved


message UserSearchReq {
google.protobuf.StringValue query = 3;
// whether the query (if any) should only search through username and display name
Expand All @@ -123,17 +131,19 @@ message UserSearchReq {
repeated org.couchers.api.core.SleepingArrangement sleeping_arrangement_filter = 7;
repeated org.couchers.api.core.ParkingDetails parking_details_filter = 8;
repeated org.couchers.api.core.MeetupStatus meetup_status_filter = 32;
repeated org.couchers.api.core.LanguageAbility language_ability_filter = 34;
repeated org.couchers.api.core.LanguageAbility.Fluency fluency = 35;
Krishnag09 marked this conversation as resolved.
Show resolved Hide resolved



repeated string gender = 9;
google.protobuf.UInt32Value guests = 10;
// google.protobuf.StringValue language = 11;
bool only_with_references = 12;

// bool friends_only = 13;

// google.protobuf.UInt32Value age_min = 14;
// google.protobuf.UInt32Value age_max = 15;
google.protobuf.UInt32Value age_min = 14;
google.protobuf.UInt32Value age_max = 15;

google.protobuf.BoolValue last_minute = 16;
google.protobuf.BoolValue has_pets = 17;
Expand Down Expand Up @@ -205,3 +215,4 @@ message EventSearchRes {

string next_page_token = 2;
}