Skip to content

Commit 940e8c6

Browse files
authored
Merge pull request #299 from Seluj78/294-recommendations
Recommendations + Search
2 parents ce0824b + 92102ca commit 940e8c6

37 files changed

+1083
-68
lines changed

PyMatcha.postman_collection.json

Lines changed: 60 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2616,7 +2616,7 @@
26162616
" pm.response.to.have.status(200);",
26172617
"});",
26182618
"",
2619-
"tests[\"Is geohash correct\"] = response.geohash == \"spb8kg12wgw3\""
2619+
"tests[\"Is geohash correct\"] = response.geohash == \"gbqc2cm8zj0h\""
26202620
],
26212621
"type": "text/javascript"
26222622
}
@@ -5817,6 +5817,44 @@
58175817
}
58185818
},
58195819
"response": []
5820+
},
5821+
{
5822+
"name": "{{host}}/search/values",
5823+
"event": [
5824+
{
5825+
"listen": "test",
5826+
"script": {
5827+
"id": "800e378b-5cbb-46c3-94b3-1a25db03a846",
5828+
"exec": [
5829+
"var response = JSON.parse(responseBody);",
5830+
"",
5831+
"",
5832+
"pm.test(\"Status code is 200\", function () {",
5833+
" pm.response.to.have.status(200);",
5834+
"});",
5835+
"",
5836+
"tests[\"Success is true\"] = response.success == true",
5837+
""
5838+
],
5839+
"type": "text/javascript"
5840+
}
5841+
}
5842+
],
5843+
"request": {
5844+
"method": "GET",
5845+
"header": [],
5846+
"url": {
5847+
"raw": "{{host}}/search/values",
5848+
"host": [
5849+
"{{host}}"
5850+
],
5851+
"path": [
5852+
"search",
5853+
"values"
5854+
]
5855+
}
5856+
},
5857+
"response": []
58205858
}
58215859
],
58225860
"protocolProfileBehavior": {}
@@ -6012,107 +6050,107 @@
60126050
],
60136051
"variable": [
60146052
{
6015-
"id": "1c6f53dc-e42f-4454-9bc3-ed7efc324c5e",
6053+
"id": "1422b800-5b00-4e83-b384-b0a2335ce1f6",
60166054
"key": "host",
60176055
"value": "http://127.0.0.1:5000"
60186056
},
60196057
{
6020-
"id": "795d11f0-db2d-4e43-bcce-51e4dd7d403e",
6058+
"id": "45b4ac16-259f-4039-9f45-9e687dde7c56",
60216059
"key": "user_id",
60226060
"value": ""
60236061
},
60246062
{
6025-
"id": "c10e1323-93da-441c-a4aa-ab8a56d127fa",
6063+
"id": "9bcded74-14bb-43ec-96a6-ddbace075f06",
60266064
"key": "user_email",
60276065
"value": "foo@example.org"
60286066
},
60296067
{
6030-
"id": "4e4339d4-037b-4a47-a940-af44ceba7702",
6068+
"id": "caaaaaa8-3409-4c18-bb84-8f7413b74119",
60316069
"key": "user_username",
60326070
"value": "foo"
60336071
},
60346072
{
6035-
"id": "200e3227-ae76-482b-8806-afdf11e4a946",
6073+
"id": "0c2a62b7-cae4-4b2e-861a-d18d8852cd3a",
60366074
"key": "user_password",
60376075
"value": "admin"
60386076
},
60396077
{
6040-
"id": "6c1cbef8-de33-45b3-8e95-0b2c42bfba72",
6078+
"id": "87dc2468-5256-468f-82d5-2ac67426c9c2",
60416079
"key": "user_firstname",
60426080
"value": "Foo"
60436081
},
60446082
{
6045-
"id": "220b0df3-d386-4dae-9439-77361ed5397f",
6083+
"id": "a991a290-b276-4ec3-b728-5545bdb0f865",
60466084
"key": "user_lastname",
60476085
"value": "Bar"
60486086
},
60496087
{
6050-
"id": "2740c551-4c1a-4fd4-b14c-437c2e5b176d",
6088+
"id": "50fcf6ff-9a13-4ac4-bd55-f62f208213fd",
60516089
"key": "debug_token",
60526090
"value": "xX69jules69Xx"
60536091
},
60546092
{
6055-
"id": "558a8390-adec-4afb-9414-5c305ce932e2",
6093+
"id": "cbcf5b56-8099-433e-9f44-729df553e8f4",
60566094
"key": "user_access_token",
60576095
"value": ""
60586096
},
60596097
{
6060-
"id": "19668937-3689-4bb3-97e4-ad0262b20779",
6098+
"id": "19085103-b960-4e72-9ddb-c6f496f731af",
60616099
"key": "user_refresh_token",
60626100
"value": ""
60636101
},
60646102
{
6065-
"id": "922cef0c-ac18-4509-9f08-7240f04a9634",
6103+
"id": "56764f2f-ab0d-46fc-8690-2dacb95006e2",
60666104
"key": "expired_token",
60676105
"value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1OTAyNDIyNjQsIm5iZiI6MTU5MDI0MjI2NCwianRpIjoiNTM0ZGI5NzQtOWE4Ni00MGViLWE1NDEtMDg3N2ZmNzQ3NDVhIiwiZXhwIjoxNTkwMjQyMzI0LCJpZGVudGl0eSI6eyJpZCI6NTEyLCJlbWFpbCI6ImZvb0BleGFtcGxlLm9yZyIsInVzZXJuYW1lIjoiYmFyIiwiaXNfb25saW5lIjp0cnVlLCJkYXRlX2xhc3RzZWVuIjoiU2F0LCAyMyBNYXkgMjAyMCAxMzo1Nzo0NCBHTVQifSwiZnJlc2giOnRydWUsInR5cGUiOiJhY2Nlc3MifQ.NTp2P0WNkXDwzuzrcNIQdeAfizQ57HQgkzBLSvY1yHU"
60686106
},
60696107
{
6070-
"id": "425325f9-1bd7-4f0c-9863-f3f44a0546e1",
6108+
"id": "4f2dc328-0d84-455e-b539-3eedb52ad509",
60716109
"key": "user_orientation",
60726110
"value": "heterosexual"
60736111
},
60746112
{
6075-
"id": "cb3e3a95-1cef-4b63-a0c1-41bea9ac7abe",
6113+
"id": "c1c3b0d9-d693-4c3e-bfe1-790246f36975",
60766114
"key": "user_bio",
60776115
"value": "Lorem Ipsum is the single greatest threat. We are not - we are not keeping up with other websites. Lorem Ipsum best not make any more threats to your website. It will be met with fire and fury like the world has never seen. Does everybody know that pig named Lorem Ipsum? An ‘extremely credible source’ has called my office and told me that Barack Obama’s placeholder text is a fraud."
60786116
},
60796117
{
6080-
"id": "5595875e-6866-4d62-94a5-e24ea59e40d7",
6118+
"id": "22247a60-3b04-4cf3-b71e-020be5e5af2b",
60816119
"key": "user_gender",
60826120
"value": "male"
60836121
},
60846122
{
6085-
"id": "4f00c819-d5a2-4ffa-9841-927a584a73ad",
6123+
"id": "73131f55-444b-435c-a1a2-3d8dac1757e9",
60866124
"key": "user_birthdate",
60876125
"value": "06/04/1998"
60886126
},
60896127
{
6090-
"id": "ae73bd61-998f-4741-98d2-3a9c832e5d3b",
6128+
"id": "d5f365e6-94c6-4e8c-b26b-71e29927db28",
60916129
"key": "user_lat",
60926130
"value": "44.8404"
60936131
},
60946132
{
6095-
"id": "05660d8f-92d8-492d-bda0-a1e5f0d76dee",
6133+
"id": "1e75fc16-8889-4c28-8749-f2d8fd4f5012",
60966134
"key": "user_lng",
60976135
"value": "-0.5805"
60986136
},
60996137
{
6100-
"id": "62c639b4-dd0c-435f-b00c-139ef0e6d334",
6138+
"id": "32238ac7-ecee-43bb-822d-e58cee7f4d75",
61016139
"key": "user_ip",
61026140
"value": "77.205.46.181"
61036141
},
61046142
{
6105-
"id": "d7d84d53-5ce3-48a5-9171-5177c9f4bd29",
6143+
"id": "2918a794-4b28-4b66-9ff1-277bfe8173a7",
61066144
"key": "user_username2",
61076145
"value": "FooBar"
61086146
},
61096147
{
6110-
"id": "b5b77a26-ee98-445b-9fc9-efd9a5421d4e",
6148+
"id": "7ebb04be-74e9-4823-9b4e-8b658e59194d",
61116149
"key": "user_email2",
61126150
"value": "bar@example.org"
61136151
},
61146152
{
6115-
"id": "0112646c-3f47-431b-a92c-179babdf271f",
6153+
"id": "24f73465-8c81-47f1-ba70-7bead50632dc",
61166154
"key": "user_password2",
61176155
"value": "dolphin2"
61186156
}

backend/PyMatcha/models/user.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ class User(Model):
6363
is_confirmed = Field(bool)
6464
confirmed_on = Field(datetime.datetime, fmt="%Y-%m-%d %H:%M:%S")
6565
previous_reset_token = Field(str)
66+
skip_recommendations = Field(bool)
6667

6768
@staticmethod
6869
def create(
@@ -83,6 +84,7 @@ def create(
8384
is_profile_completed: bool = False,
8485
is_confirmed: bool = False,
8586
confirmed_on: datetime.datetime = None,
87+
skip_recommendations: bool = False,
8688
) -> User:
8789
# Check email availability
8890
if User.get(email=email):
@@ -136,6 +138,7 @@ def create(
136138
is_confirmed=is_confirmed,
137139
confirmed_on=confirmed_on,
138140
previous_reset_token=None,
141+
skip_recommendations=skip_recommendations,
139142
)
140143
new_user.save()
141144
logging.debug("New user {} created".format(new_user.email))
@@ -175,6 +178,7 @@ def register(email: str, username: str, password: str, first_name: str, last_nam
175178
is_confirmed=False,
176179
confirmed_on=None,
177180
previous_reset_token=None,
181+
skip_recommendations=False,
178182
)
179183
new_user.save()
180184
logging.debug("New user {} created".format(new_user.email))

backend/PyMatcha/routes/api/profile/edit.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@
1919
import datetime
2020

2121
import Geohash
22+
import requests
2223
from flask import Blueprint
2324
from flask import render_template
2425
from flask import request
2526
from flask_jwt_extended import current_user
2627
from flask_jwt_extended import jwt_required
27-
from ip2geotools.databases.noncommercial import DbIpCity
2828
from PyMatcha.models.user import get_user
2929
from PyMatcha.utils import hash_password
3030
from PyMatcha.utils.confirm_token import generate_confirmation_token
@@ -156,9 +156,11 @@ def edit_geolocation():
156156
if lat and lng:
157157
current_user.geohash = Geohash.encode(lat, lng)
158158
else:
159-
response = DbIpCity.get(ip, api_key="free")
160-
lat = response.latitude
161-
lng = response.longitude
159+
response = requests.get(
160+
f"http://api.ipstack.com/{ip}?access_key=b5f9be2253823006b478da121d1c855b&format=1"
161+
).json()
162+
lat = response["latitude"]
163+
lng = response["longitude"]
162164
current_user.geohash = Geohash.encode(lat, lng)
163165
current_user.save()
164166
return Success("New location sucessfully saved.")

backend/PyMatcha/routes/api/search.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,13 @@ def search():
7878
if max_distance != -1:
7979
raise BadRequestError("user needs to sets his location first")
8080

81-
user_tags = [t.name for t in user.get_tags()]
82-
common_tags = _get_common_tags(tags, user_tags)
83-
if not common_tags:
84-
common_tags = []
85-
if tags:
81+
common_tags = []
82+
if tags:
83+
user_tags = [t.name for t in user.get_tags()]
84+
common_tags = _get_common_tags(tags, user_tags)
85+
if not common_tags:
86+
# No tags has been found
87+
common_tags = []
8688
continue
8789

8890
user_dict = user.to_dict()

backend/PyMatcha/utils/match_score.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ def _get_common_tags(tag_list_1: list, tag_list_2: list) -> List[str]:
2222
common_tags = []
2323
for tag_1 in tag_list_1:
2424
for tag_2 in tag_list_2:
25-
if fuzz.partial_ratio(tag_1, tag_2) >= 70:
25+
if fuzz.partial_ratio(tag_1, tag_2) >= 90:
2626
common_tags.append(tag_1 if len(tag_1) > len(tag_2) else tag_2)
2727
return list(set(common_tags))
2828

backend/PyMatcha/utils/populate_database.py

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,14 @@
1414
from PyMatcha.models.user import User
1515
from PyMatcha.utils.errors import ConflictError
1616
from randomuser import RandomUser
17+
from tqdm import tqdm
1718

1819
FRANCE_GEOHASH_START = ("u0", "gb", "ez", "sp")
1920
NATIONALITIES_PARAMS = {"nat": "fr"}
2021

22+
# LATVIA_GEOHASH_START = ("d0", "d1", "d4", "d4")
23+
# NATIONALITIES_PARAMS = {"nat": "lv"}
24+
2125

2226
def gen_datetime(min_year: int = 1900, max_year: int = datetime.datetime.now().year) -> datetime.datetime:
2327
# generate a datetime in format yyyy-mm-dd hh:mm:ss.000000
@@ -27,6 +31,19 @@ def gen_datetime(min_year: int = 1900, max_year: int = datetime.datetime.now().y
2731
return start + (end - start) * random.random()
2832

2933

34+
def get_unsplash_image(gender):
35+
link = None
36+
while True:
37+
r = requests.get(f"https://source.unsplash.com/featured/?{gender}")
38+
if r.status_code == 403:
39+
sleep(1)
40+
continue
41+
link = r.url
42+
if not Image.get(link=link):
43+
break
44+
return link
45+
46+
3047
def populate_users(amount=150, drop_user_table=False):
3148
if drop_user_table:
3249
User.drop_table()
@@ -36,7 +53,7 @@ def populate_users(amount=150, drop_user_table=False):
3653
except HTTPError:
3754
sleep(10)
3855
users = RandomUser.generate_users(amount=amount, get_params=NATIONALITIES_PARAMS)
39-
for user in users:
56+
for user in tqdm(users):
4057
gender = random.choice(["male", "female", "other"])
4158
if gender != "other":
4259
if gender == user.get_gender():
@@ -87,7 +104,14 @@ def populate_users(amount=150, drop_user_table=False):
87104

88105
for tag in tags:
89106
Tag.create(name=tag, user_id=u.id)
90-
image_url = requests.get(f"https://picsum.photos/seed/{username}/1000/1000").url
107+
108+
if gender == "other":
109+
# Change the gender because the profile picture needs to be of a person
110+
gender = random.choice(["male", "female"])
111+
image_url = get_unsplash_image("man" if gender == "male" else "woman")
112+
if not image_url:
113+
raise ValueError("ERROR ON GETTING IMAGE FROM UNSPLASH")
114+
91115
Image.create(user_id=u.id, link=image_url, is_primary=True)
92116
except ConflictError:
93117
pass # Pass on the conflict error, this user wont be created because the username is taken. Who cares ?

backend/PyMatcha/utils/tables.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ def _create_user_table(db):
4848
is_online BOOLEAN DEFAULT (FALSE),
4949
is_profile_completed BOOLEAN DEFAULT (FALSE),
5050
is_confirmed BOOLEAN DEFAULT (FALSE),
51-
confirmed_on DATETIME DEFAULT NULL
51+
confirmed_on DATETIME DEFAULT NULL,
52+
skip_recommendations BOOLEAN DEFAULT (FALSE)
5253
) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci ;
5354
"""
5455
)

backend/PyMatcha/utils/tasks.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,9 @@ def update_offline_users():
107107
@celery.task
108108
def update_user_recommendations():
109109
count = 0
110-
for user_to_update in User.select_all():
110+
for user_to_update in User.get_multis(skip_recommendations=False):
111111
create_user_recommendations(user_to_update)
112+
count += 1
112113
return f"Successfully updated recommendations for {count} users."
113114

114115

backend/requirements.txt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,7 @@ pre-commit==2.7.1
2626

2727
lorem==0.1.1
2828
future==0.18.2
29-
ip2geotools==0.1.5
30-
29+
requests==2.24.0
3130
argon2-cffi==20.1.0
3231

3332
geopy==2.0.0

frontend/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
"axios": "^0.20.0",
1515
"core-js": "^3.6.5",
1616
"jwt-decode": "^3.0.0-beta.2",
17+
"nouislider": "^14.6.2",
1718
"secure-ls": "^1.2.6",
1819
"tailwindcss": "^1.8.10",
1920
"vee-validate": "^3.3.11",

0 commit comments

Comments
 (0)