Skip to content

Commit 2f8ff74

Browse files
authored
Merge pull request #340 from Seluj78/feature/randomonlineusers
2 parents af54996 + a0e3107 commit 2f8ff74

File tree

7 files changed

+61
-55
lines changed

7 files changed

+61
-55
lines changed

backend/PyMatcha/__init__.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -195,15 +195,17 @@ def expired_token_callback(expired_token):
195195
@jwt.user_loader_callback_loader
196196
def jwt_user_callback(identity):
197197
try:
198-
u = get_user(identity["id"])
198+
user = get_user(identity["id"])
199199
except NotFoundError:
200200
# The user who the server issues the token for was deleted in the db.
201201
return None
202202

203203
with configure_scope() as scope:
204-
scope.user = {"email": u.email, "id": u.id, "username": u.username}
205-
redis.set("online_user:" + str(identity["id"]), datetime.datetime.utcnow().timestamp())
206-
return u
204+
scope.user = {"email": user.email, "id": user.id, "username": user.username}
205+
user.is_online = True
206+
user.date_lastseen = datetime.datetime.utcnow()
207+
user.save()
208+
return user
207209

208210

209211
@jwt.token_in_blacklist_loader

backend/PyMatcha/models/user.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
from PyMatcha.utils.errors import NotFoundError
4040
from PyMatcha.utils.orm import Field
4141
from PyMatcha.utils.orm import Model
42+
from timeago import format as timeago_format
4243

4344

4445
class User(Model):
@@ -194,6 +195,7 @@ def to_dict(self) -> Dict:
194195
returned_dict["likes"] = {"sent": [], "received": []}
195196
returned_dict["likes"]["sent"] = [like.to_dict() for like in self.get_likes_sent()]
196197
returned_dict["likes"]["received"] = [like.to_dict() for like in self.get_likes_received()]
198+
returned_dict["last_seen"] = timeago_format(self.date_lastseen, datetime.datetime.utcnow())
197199
returned_dict.pop("password")
198200
returned_dict.pop("previous_reset_token")
199201

backend/PyMatcha/routes/api/auth/login.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,9 @@ def auth_login():
7272
redis.set("is_revoked_jti:" + refresh_jti, "false", REFRESH_TOKEN_EXPIRES * 1.2)
7373

7474
current_app.logger.debug("/auth/login -> Returning access token for user {}".format(username))
75-
redis.set("online_user:" + str(u.id), datetime.datetime.utcnow().timestamp())
75+
u.is_online = True
76+
u.date_lastseen = datetime.datetime.utcnow()
77+
u.save()
7678
ret = {"access_token": access_token, "refresh_token": refresh_token, "is_profile_completed": u.is_profile_completed}
7779
return SuccessOutput("return", ret)
7880

backend/PyMatcha/routes/api/user.py

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
from flask import current_app
2121
from flask import jsonify
2222
from flask_jwt_extended import jwt_required
23-
from PyMatcha import redis
2423
from PyMatcha.models.user import get_user
2524
from PyMatcha.models.user import User
2625
from PyMatcha.utils.errors import NotFoundError
@@ -56,11 +55,7 @@ def get_one_user(uid):
5655
@user_bp.route("/users/online", methods=["GET"])
5756
@jwt_required
5857
def get_all_online_users():
59-
user_id = None # noqa
60-
date_lastseen = None # noqa
6158
online_user_list = []
62-
for key in redis.scan_iter("online_user:*"):
63-
user_id = str(key).split(":")[1]
64-
date_lastseen = float(redis.get(key))
65-
online_user_list.append({"id": user_id, "date_lastseen": date_lastseen})
59+
for user in User.get_multis(is_online=True):
60+
online_user_list.append(user.to_dict())
6661
return jsonify(online_user_list)

backend/PyMatcha/utils/orm/_model.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,25 @@ def select_all(cls):
372372
for item in data:
373373
yield cls(item)
374374

375+
@classmethod
376+
def select_random(cls, count):
377+
logging.debug(f"Getting {count} random entries from {cls.table_name}")
378+
temp = cls()
379+
with temp.db.cursor() as c:
380+
c.execute(
381+
"""
382+
SELECT * FROM {}
383+
ORDER BY RAND()
384+
LIMIT {}
385+
""".format(
386+
temp.table_name, count
387+
)
388+
)
389+
data = c.fetchall()
390+
c.close()
391+
for item in data:
392+
yield cls(item)
393+
375394
@classmethod
376395
def drop_table(cls):
377396
logging.warning("Dropping table {}".format(cls.table_name))

backend/PyMatcha/utils/tasks.py

Lines changed: 26 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import datetime
22
import json
3-
import logging
43
from math import ceil
54

65
from PyMatcha import celery
@@ -20,9 +19,10 @@
2019

2120
@celery.on_after_configure.connect
2221
def setup_periodic_tasks(sender, **kwargs):
23-
sender.add_periodic_task(60, update_offline_users.s(), name="Update online users every minute")
22+
sender.add_periodic_task(60, take_users_offline.s(), name="Update online users every minute")
2423
sender.add_periodic_task(3600, update_heat_scores.s(), name="Update heat scores every hour")
2524
sender.add_periodic_task(60, update_user_recommendations.s(), name="Update user recommendations every minute")
25+
sender.add_periodic_task(30, take_random_users_online.s(), name="Set 100 random users online every 30 seconds")
2626
sender.add_periodic_task(
2727
600, calc_search_min_max.s(), name="Update Minimum and Maximum scores and ages for search every 10 minutes"
2828
)
@@ -60,47 +60,19 @@ def update_heat_scores():
6060

6161

6262
@celery.task
63-
def update_offline_users():
64-
logging.debug("Updating offline users")
65-
# Get the last login deadline
66-
login_deadline_timestamp = float(datetime.datetime.utcnow().timestamp()) - 120
67-
count = 0
68-
online_count = 0
69-
offline_count = 0
70-
# For all user keys
71-
for key in redis.scan_iter("online_user:*"):
72-
# Get the user id
73-
user_id = str(key).split(":")[1]
74-
date_lastseen = float(redis.get(key))
75-
# If the user has passed the deadline
76-
if date_lastseen < login_deadline_timestamp:
77-
u = User.get(id=user_id)
78-
if u:
79-
u.date_lastseen = datetime.datetime.fromtimestamp(date_lastseen)
80-
u.is_online = False
81-
u.save()
82-
offline_count += 1
83-
# delete the key in redis, setting the user as offline in redis
84-
redis.delete(key)
85-
count += 1
63+
def take_users_offline():
64+
went_offline_count = 0
65+
stayed_online_count = 0
66+
for user in User.get_multis(is_online=True):
67+
if user.date_lastseen + datetime.timedelta(minutes=2) < datetime.datetime.utcnow():
68+
user.is_online = False
69+
user.save()
70+
went_offline_count += 1
8671
else:
87-
u = User.get(id=user_id)
88-
if not u:
89-
# Edge case where the user has been deleted from DB while he was still online
90-
redis.delete(key)
91-
else:
92-
u.date_lastseen = datetime.datetime.fromtimestamp(date_lastseen)
93-
u.is_online = True
94-
u.save()
95-
online_count += 1
96-
count += 1
97-
logging.debug(
98-
"Updated online status for {} users. {} passed offline and {} passed or stayed online.".format(
99-
count, offline_count, online_count
100-
)
101-
)
102-
return "Updated online status for {} users. {} passed offline and {} passed or stayed online.".format(
103-
count, offline_count, online_count
72+
stayed_online_count += 1
73+
return (
74+
f"{stayed_online_count} stayed online and "
75+
f"{went_offline_count} went offline for {went_offline_count + stayed_online_count} users"
10476
)
10577

10678

@@ -143,3 +115,15 @@ def calc_search_min_max():
143115
minmax = {"min_score": min_score, "max_score": max_score, "min_age": min_age, "max_age": max_age}
144116
redis.set("search_minmax", json.dumps(minmax))
145117
return "Successfully updated min and max ages and scores"
118+
119+
120+
@celery.task
121+
def take_random_users_online():
122+
for user in User.select_random(100):
123+
if not user.skip_recommendations:
124+
# User isn't a bot, so skip him
125+
continue
126+
user.is_online = True
127+
user.date_lastseen = datetime.datetime.utcnow()
128+
user.save()
129+
return "Successfully set 100 users online"

backend/requirements.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,6 @@ sentry-sdk==0.18.0
3737

3838
randomuser==1.6
3939
pyimgur==0.6.0
40-
Pillow==7.2.0
40+
Pillow==7.2.0
41+
42+
timeago==1.0.14

0 commit comments

Comments
 (0)