Spaces:
Sleeping
Sleeping
added a fix to leaderboard
Browse files- app.py +58 -18
- gamification/objects.py +3 -3
- gamification/pointLogic.py +14 -8
- gamification/routes.py +7 -3
app.py
CHANGED
|
@@ -23,7 +23,8 @@ from pydantic import BaseModel
|
|
| 23 |
from datetime import datetime
|
| 24 |
from bson import ObjectId
|
| 25 |
import os
|
| 26 |
-
|
|
|
|
| 27 |
|
| 28 |
|
| 29 |
load_dotenv()
|
|
@@ -439,6 +440,7 @@ def create_leaderboard_ranking( document: LeaderBoardRanking) -> bool:
|
|
| 439 |
collection = db['LeaderBoard']
|
| 440 |
# Insert the document
|
| 441 |
result= collection.find_one_and_replace(filter={"userId":document.userId},replacement=document.model_dump())
|
|
|
|
| 442 |
if result==None:
|
| 443 |
result = collection.insert_one(document.model_dump())
|
| 444 |
print("correctly inserted new document for",document.firstName)
|
|
@@ -484,6 +486,52 @@ def get_user_id_from_docKey(dockId):
|
|
| 484 |
client = MongoClient(MONGO_URI)
|
| 485 |
db = client.crayonics
|
| 486 |
collection = db['Points']
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 487 |
|
| 488 |
# A function to handle changes
|
| 489 |
def handle_change(change=None,new_point=None):
|
|
@@ -494,23 +542,15 @@ def handle_change(change=None,new_point=None):
|
|
| 494 |
if new_point!=None:
|
| 495 |
collections = db.list_collection_names()
|
| 496 |
logger.info(f"Extra info: {new_point}")
|
| 497 |
-
|
| 498 |
-
|
| 499 |
-
|
| 500 |
-
|
| 501 |
-
|
| 502 |
-
|
| 503 |
-
tempDreamJob = get_dream_job(userId=str(user['_id']))
|
| 504 |
-
dreamJob = tempDreamJob if type(tempDreamJob)==str else "IncompleteProfile"
|
| 505 |
-
create_leaderboard_ranking(LeaderBoardRanking(userId=str(user['_id']),firstName=user['first_name'],lastName=user['last_name'],totalpoints=points.totalpoints,lastUpdated=datetime.now(),careerPath=dreamJob,))
|
| 506 |
-
else:
|
| 507 |
-
|
| 508 |
-
user_id =new_point.get('userId')
|
| 509 |
-
leveleduser = get_all_users(userId=user_id)
|
| 510 |
-
points = get_all_simple_points_func(userId=user_id)
|
| 511 |
-
tempDreamJob = get_dream_job(userId=user_id)
|
| 512 |
dreamJob = tempDreamJob if type(tempDreamJob)==str else "IncompleteProfile"
|
| 513 |
-
create_leaderboard_ranking(LeaderBoardRanking(userId=
|
|
|
|
| 514 |
|
| 515 |
|
| 516 |
elif new_point==None and change!=None:
|
|
@@ -553,7 +593,7 @@ def handle_change(change=None,new_point=None):
|
|
| 553 |
create_leaderboard_ranking(LeaderBoardRanking(userId=user_id,firstName=leveleduser['first_name'],lastName=leveleduser['last_name'],totalpoints=points.totalpoints,lastUpdated=datetime.now(),careerPath=dreamJob,))
|
| 554 |
|
| 555 |
|
| 556 |
-
|
| 557 |
|
| 558 |
# Function to run the change stream in a separate thread (non-blocking)
|
| 559 |
def watch_change_stream():
|
|
|
|
| 23 |
from datetime import datetime
|
| 24 |
from bson import ObjectId
|
| 25 |
import os
|
| 26 |
+
from concurrent.futures import ThreadPoolExecutor
|
| 27 |
+
executor = ThreadPoolExecutor(max_workers=5)
|
| 28 |
|
| 29 |
|
| 30 |
load_dotenv()
|
|
|
|
| 440 |
collection = db['LeaderBoard']
|
| 441 |
# Insert the document
|
| 442 |
result= collection.find_one_and_replace(filter={"userId":document.userId},replacement=document.model_dump())
|
| 443 |
+
print(result)
|
| 444 |
if result==None:
|
| 445 |
result = collection.insert_one(document.model_dump())
|
| 446 |
print("correctly inserted new document for",document.firstName)
|
|
|
|
| 486 |
client = MongoClient(MONGO_URI)
|
| 487 |
db = client.crayonics
|
| 488 |
collection = db['Points']
|
| 489 |
+
import logging
|
| 490 |
+
from datetime import datetime
|
| 491 |
+
logging.basicConfig(level=logging.INFO)
|
| 492 |
+
logger = logging.getLogger(__name__)
|
| 493 |
+
|
| 494 |
+
def handle_change2(new_point):
|
| 495 |
+
logger.info(f"Extra info: {new_point}")
|
| 496 |
+
print("No leaderboard so creating one now")
|
| 497 |
+
|
| 498 |
+
users = get_all_users()
|
| 499 |
+
|
| 500 |
+
for user in users:
|
| 501 |
+
user_id = str(user['_id'])
|
| 502 |
+
print("Inserting user", f"User ID: {user_id}")
|
| 503 |
+
|
| 504 |
+
# Handle points retrieval safely
|
| 505 |
+
try:
|
| 506 |
+
points = get_all_simple_points_func(userId=user_id)
|
| 507 |
+
print("Points:", points)
|
| 508 |
+
except Exception as e:
|
| 509 |
+
logger.error(f"Error processing points for user {user_id}: {e}")
|
| 510 |
+
points = None # Default value to prevent errors
|
| 511 |
+
|
| 512 |
+
# Handle dream job retrieval safely
|
| 513 |
+
tempDreamJob = None
|
| 514 |
+
try:
|
| 515 |
+
tempDreamJob = get_dream_job(userId=user_id)
|
| 516 |
+
except Exception as e:
|
| 517 |
+
logger.error(f"Error retrieving dream job for user {user_id}: {e}")
|
| 518 |
+
|
| 519 |
+
# Assign default value if tempDreamJob is invalid
|
| 520 |
+
dreamJob = tempDreamJob if isinstance(tempDreamJob, str) else "IncompleteProfile"
|
| 521 |
+
|
| 522 |
+
# Try inserting into leaderboard
|
| 523 |
+
try:
|
| 524 |
+
create_leaderboard_ranking(LeaderBoardRanking(
|
| 525 |
+
userId=user_id,
|
| 526 |
+
firstName=user.get('first_name', 'Unknown'), # Safer dict access
|
| 527 |
+
lastName=user.get('last_name', 'Unknown'),
|
| 528 |
+
totalpoints=points.totalpoints if points else 0, # Prevent NoneType error
|
| 529 |
+
lastUpdated=datetime.now(),
|
| 530 |
+
careerPath=dreamJob,
|
| 531 |
+
))
|
| 532 |
+
except Exception as e:
|
| 533 |
+
logger.error(f"Error adding user {user_id} to leaderboard: {e}")
|
| 534 |
+
|
| 535 |
|
| 536 |
# A function to handle changes
|
| 537 |
def handle_change(change=None,new_point=None):
|
|
|
|
| 542 |
if new_point!=None:
|
| 543 |
collections = db.list_collection_names()
|
| 544 |
logger.info(f"Extra info: {new_point}")
|
| 545 |
+
print("No leaderboard so creating one now")
|
| 546 |
+
users = get_all_users()
|
| 547 |
+
for user in users:
|
| 548 |
+
print("inserting user",f"user id {user['_id']}")
|
| 549 |
+
points = get_all_simple_points_func(userId=str(user['_id']))
|
| 550 |
+
tempDreamJob = get_dream_job(userId=str(user['_id']))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 551 |
dreamJob = tempDreamJob if type(tempDreamJob)==str else "IncompleteProfile"
|
| 552 |
+
create_leaderboard_ranking(LeaderBoardRanking(userId=str(user['_id']),firstName=user['first_name'],lastName=user['last_name'],totalpoints=points.totalpoints,lastUpdated=datetime.now(),careerPath=dreamJob,))
|
| 553 |
+
|
| 554 |
|
| 555 |
|
| 556 |
elif new_point==None and change!=None:
|
|
|
|
| 593 |
create_leaderboard_ranking(LeaderBoardRanking(userId=user_id,firstName=leveleduser['first_name'],lastName=leveleduser['last_name'],totalpoints=points.totalpoints,lastUpdated=datetime.now(),careerPath=dreamJob,))
|
| 594 |
|
| 595 |
|
| 596 |
+
logger.info(f"Change detected: {dumps(change)}")
|
| 597 |
|
| 598 |
# Function to run the change stream in a separate thread (non-blocking)
|
| 599 |
def watch_change_stream():
|
gamification/objects.py
CHANGED
|
@@ -268,9 +268,9 @@ class IndividualUserLevel(BaseModel):
|
|
| 268 |
|
| 269 |
class SimpleIndividualUserLevel(BaseModel):
|
| 270 |
totalpoints:float
|
| 271 |
-
levelName:str
|
| 272 |
-
maxPoints:float
|
| 273 |
-
minPoints:float
|
| 274 |
|
| 275 |
class Config:
|
| 276 |
json_encoders = {
|
|
|
|
| 268 |
|
| 269 |
class SimpleIndividualUserLevel(BaseModel):
|
| 270 |
totalpoints:float
|
| 271 |
+
levelName:Optional[str]=None
|
| 272 |
+
maxPoints:Optional[float]=None
|
| 273 |
+
minPoints:Optional[float]=None
|
| 274 |
|
| 275 |
class Config:
|
| 276 |
json_encoders = {
|
gamification/pointLogic.py
CHANGED
|
@@ -29,7 +29,6 @@ def get_dream_job(userId):
|
|
| 29 |
|
| 30 |
|
| 31 |
def create_points_func(document:UserPoints)->bool:
|
| 32 |
-
from app import handle_change
|
| 33 |
db_uri = MONGO_URI
|
| 34 |
db_name = "crayonics"
|
| 35 |
collection_name="Points"
|
|
@@ -42,7 +41,7 @@ def create_points_func(document:UserPoints)->bool:
|
|
| 42 |
doc = document.model_dump()
|
| 43 |
doc['earnedAt']=datetime.now()
|
| 44 |
result = collection.insert_one(doc)
|
| 45 |
-
|
| 46 |
return True
|
| 47 |
else:
|
| 48 |
client.close()
|
|
@@ -98,16 +97,23 @@ def get_all_simple_points_func(userId) -> SimpleIndividualUserLevel:
|
|
| 98 |
point_cursor = collection.find({"userId": userId}) # This returns a cursor to the documents
|
| 99 |
|
| 100 |
# Convert the cursor to a list so we can reuse it
|
| 101 |
-
|
|
|
|
| 102 |
|
| 103 |
# Calculate the total points
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
|
| 107 |
|
| 108 |
# Create the IndividualUserLevel object with totalPoints and individualPoints
|
| 109 |
-
|
| 110 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 111 |
return points
|
| 112 |
|
| 113 |
|
|
|
|
| 29 |
|
| 30 |
|
| 31 |
def create_points_func(document:UserPoints)->bool:
|
|
|
|
| 32 |
db_uri = MONGO_URI
|
| 33 |
db_name = "crayonics"
|
| 34 |
collection_name="Points"
|
|
|
|
| 41 |
doc = document.model_dump()
|
| 42 |
doc['earnedAt']=datetime.now()
|
| 43 |
result = collection.insert_one(doc)
|
| 44 |
+
|
| 45 |
return True
|
| 46 |
else:
|
| 47 |
client.close()
|
|
|
|
| 97 |
point_cursor = collection.find({"userId": userId}) # This returns a cursor to the documents
|
| 98 |
|
| 99 |
# Convert the cursor to a list so we can reuse it
|
| 100 |
+
try:
|
| 101 |
+
points_list = list(point_cursor)
|
| 102 |
|
| 103 |
# Calculate the total points
|
| 104 |
+
totalPoints = sum([point['numOfPoints'] for point in points_list])
|
| 105 |
+
particularLevelInfo = get_particular_level(dreamJob=dreamJob,totalPoints=totalPoints)
|
| 106 |
+
# Create the individual points list
|
| 107 |
|
| 108 |
# Create the IndividualUserLevel object with totalPoints and individualPoints
|
| 109 |
+
points = SimpleIndividualUserLevel(totalpoints=totalPoints)
|
| 110 |
+
except:
|
| 111 |
+
totalPoints = 0
|
| 112 |
+
# Create the individual points list
|
| 113 |
+
|
| 114 |
+
# Create the IndividualUserLevel object with totalPoints and individualPoints
|
| 115 |
+
points = SimpleIndividualUserLevel(totalpoints=totalPoints)
|
| 116 |
+
|
| 117 |
return points
|
| 118 |
|
| 119 |
|
gamification/routes.py
CHANGED
|
@@ -124,14 +124,18 @@ def delete_level(levelId):
|
|
| 124 |
except Exception as e:
|
| 125 |
raise HTTPException(status_code=500,detail=f"{e}")
|
| 126 |
|
| 127 |
-
|
| 128 |
@gamification.get("/get-top-30",tags=["user","admin"])
|
| 129 |
-
def get_leaderboard()->List[Ranker]:
|
|
|
|
| 130 |
try:
|
| 131 |
list_of_rankers = []
|
| 132 |
result = get_top_30()
|
|
|
|
|
|
|
|
|
|
| 133 |
list_of_rankers = [Ranker(**ranker) for ranker in result]
|
| 134 |
-
|
| 135 |
return list_of_rankers
|
| 136 |
except Exception as e:
|
| 137 |
raise HTTPException(status_code=500,detail=f"{e}")
|
|
|
|
| 124 |
except Exception as e:
|
| 125 |
raise HTTPException(status_code=500,detail=f"{e}")
|
| 126 |
|
| 127 |
+
from fastapi import BackgroundTasks
|
| 128 |
@gamification.get("/get-top-30",tags=["user","admin"])
|
| 129 |
+
def get_leaderboard(background_tasks: BackgroundTasks)->List[Ranker]:
|
| 130 |
+
from app import handle_change2
|
| 131 |
try:
|
| 132 |
list_of_rankers = []
|
| 133 |
result = get_top_30()
|
| 134 |
+
background_tasks.add_task(handle_change2, 2)
|
| 135 |
+
# executor.submit(handle_change2,2)
|
| 136 |
+
|
| 137 |
list_of_rankers = [Ranker(**ranker) for ranker in result]
|
| 138 |
+
# handle_change(new_point="userId")
|
| 139 |
return list_of_rankers
|
| 140 |
except Exception as e:
|
| 141 |
raise HTTPException(status_code=500,detail=f"{e}")
|