diff --git a/api/messages/messages_service.py b/api/messages/messages_service.py index 439c5e5..add3a5a 100644 --- a/api/messages/messages_service.py +++ b/api/messages/messages_service.py @@ -1,6 +1,6 @@ from common.utils import safe_get_env_var from common.utils.slack import send_slack_audit, create_slack_channel, send_slack, invite_user_to_channel -from common.utils.firebase import get_hackathon_by_event_id, upsert_news +from common.utils.firebase import get_hackathon_by_event_id, upsert_news, upsert_praise, get_github_contributions_for_user from common.utils.openai_api import generate_and_save_image_to_cdn from common.utils.github import create_github_repo from api.messages.message import Message @@ -30,7 +30,8 @@ logger = logging.getLogger("myapp") -logger.setLevel(logging.INFO) +logger.setLevel(logging.DEBUG) +logger.setLevel(logging.DEBUG) google_recaptcha_key = safe_get_env_var("GOOGLE_CAPTCHA_SECRET_KEY") @@ -1235,6 +1236,26 @@ def save_news(json): return Message("Saved News") +def save_praise(json): + logger.debug(f"Attempting to save the praise with the json object {json}") + # Take in Slack message and summarize it using GPT-3.5 + # Make sure these fields exist praise_receiver, praise_channel, praise_message + check_fields = ["praise_receiver", "praise_channel", "praise_message"] + for field in check_fields: + if field not in json: + logger.error(f"Missing field {field} in {json}") + return Message("Missing field") + + logger.debug(f"Detected required fields, attempting to save praise") + upsert_praise(json) + + logger.info("Updated praise successfully") + + #get_news.cache_clear() + #logger.info("Cleared cache for get_news") + + return Message("Saved praise") + async def save_lead(json): token = json["token"] @@ -1713,6 +1734,16 @@ def get_problem_statement_list_old(): logger.debug(results) return { "problem_statements": results } +@cached(cache=TTLCache(maxsize=100, ttl=600)) +@limits(calls=100, period=ONE_MINUTE) +def get_github_profile(github_username): + logger.debug(f"Getting Github Profile for {github_username}") + + return { + "github_history": get_github_contributions_for_user(github_username) + } + + # -------------------- User functions to be deleted ---------------------------------------- # # 10 minute cache for 100 objects LRU @@ -1816,6 +1847,8 @@ def get_history_old(db_id): "expertise": res["expertise"] if "expertise" in res else "", "education": res["education"] if "education" in res else "", "shirt_size": res["shirt_size"] if "shirt_size" in res else "", + "linkedin_url": res["linkedin_url"] if "linkedin_url" in res else "", + "instagram_url": res["instagram_url"] if "instagram_url" in res else "", "github": res["github"] if "github" in res else "", "why": res["why"] if "why" in res else "", "role": res["role"] if "role" in res else "", @@ -1907,7 +1940,7 @@ def save_profile_metadata_old(propel_id, json): logger.info(f"User exists: {user.id}") # Only update metadata that is in the json - metadataList = ["role", "expertise", "education", "company", "why", "shirt_size", "github"] + metadataList = ["role", "expertise", "education", "company", "why", "shirt_size", "github", "linkedin_url", "instagram_url"] d = {} @@ -1944,3 +1977,70 @@ def get_user_by_id_old(id): logger.debug(f"Get User By ID Result: {res}") return res + +@limits(calls=50, period=ONE_MINUTE) +def save_feedback(propel_user_id, json): + db = get_db() + logger.info("Saving Feedback") + send_slack_audit(action="save_feedback", message="Saving", payload=json) + + slack_user = get_slack_user_from_propel_user_id(propel_user_id) + user_db_id = get_user_from_slack_id(slack_user["sub"]).id + feedback_giver_id = slack_user["sub"] + + doc_id = uuid.uuid1().hex + feedback_receiver_id = json.get("feedback_receiver_id") + relationship = json.get("relationship") + duration = json.get("duration") + confidence_level = json.get("confidence_level") + is_anonymous = json.get("is_anonymous", False) + feedback_data = json.get("feedback", {}) + + collection = db.collection('feedback') + + insert_res = collection.document(doc_id).set({ + "feedback_giver_slack_id": feedback_giver_id, + "feedback_giver_id": user_db_id, + "feedback_receiver_id": feedback_receiver_id, + "relationship": relationship, + "duration": duration, + "confidence_level": confidence_level, + "is_anonymous": is_anonymous, + "feedback": feedback_data, + "timestamp": datetime.now().isoformat() + }) + + logger.info(f"Insert Result: {insert_res}") + + # Notify the feedback receiver + notify_feedback_receiver(feedback_receiver_id) + + # Clear cache + get_user_feedback.cache_clear() + + return Message("Feedback saved successfully") + +def notify_feedback_receiver(feedback_receiver_id): + # Implement notification logic here + # This could be sending an email, a Slack message, or updating a notification field in the user's document + pass + +@cached(cache=TTLCache(maxsize=100, ttl=600)) +@limits(calls=100, period=ONE_MINUTE) +def get_user_feedback(propel_user_id): + logger.info(f"Getting feedback for propel_user_id: {propel_user_id}") + db = get_db() + + slack_user = get_slack_user_from_propel_user_id(propel_user_id) + db_user_id = get_user_from_slack_id(slack_user["sub"]).id + + feedback_docs = db.collection('feedback').where("feedback_receiver_id", "==", db_user_id).stream() + + feedback_list = [] + for doc in feedback_docs: + feedback = doc.to_dict() + if feedback.get("is_anonymous", False): + feedback.pop("feedback_giver_id", None) + feedback_list.append(feedback) + + return {"feedback": feedback_list} \ No newline at end of file diff --git a/api/messages/messages_views.py b/api/messages/messages_views.py index 2136bf9..552241b 100644 --- a/api/messages/messages_views.py +++ b/api/messages/messages_views.py @@ -1,5 +1,6 @@ import os - +import logging +import json from common.auth import auth, auth_user from flask import ( @@ -42,10 +43,15 @@ get_all_profiles, save_npo_application, get_npo_applications, - update_npo_application + update_npo_application, + get_github_profile, + save_praise, + save_feedback, + get_user_feedback ) - +logger = logging.getLogger("myapp") +logger.setLevel(logging.DEBUG) bp_name = 'api-messages' @@ -261,6 +267,27 @@ async def store_lead(): else: return "OK", 200 +# -------------------- Praises routes begin here --------------------------- # +@bp.route("/praise", methods=["POST"]) +def store_praise(): + # Check header for token + # if token is valid, store news + # else return 401 + + token = request.headers.get("X-Api-Key") + + # Check BACKEND_NEWS_TOKEN + if token == None or token != os.getenv("BACKEND_PRAISE_TOKEN"): + return "Unauthorized", 401 + else: + logger.debug(f"Hre is the request object {request.get_json()}") + # try: + # logger.debug(f"Here is the request object: {request.get_json()}") + # except Exception as e: + # logger.error(f"Error logging request object: {e}") + return vars(save_praise(request.get_json())) + +# -------------------- Praises routes end here --------------------------- # # -------------------- Problem Statement routes to be deleted --------------------------- # @auth.require_user @@ -316,6 +343,10 @@ def save_profile(): else: return None +@bp.route("/profile/github/", methods=["GET"]) +def get_github_profile_api(username): + return get_github_profile(username) + # Get user profile by user id @bp.route("/profile/", methods=["GET"]) def get_profile_by_id(id): @@ -329,3 +360,21 @@ def all_profiles(): return get_all_profiles() +@bp.route("/feedback", methods=["POST"]) +@auth.require_user +def submit_feedback(): + if auth_user and auth_user.user_id: + return vars(save_feedback(auth_user.user_id, request.get_json())) + else: + return {"error": "Unauthorized"}, 401 + +@bp.route("/feedback", methods=["GET"]) +@auth.require_user +def get_feedback(): + """ + Get feedback for a user - note that you can only get this for the current logged in user + """ + if auth_user and auth_user.user_id: + return get_user_feedback(auth_user.user_id) + else: + return {"error": "Unauthorized"}, 401 \ No newline at end of file diff --git a/common/utils/firebase.py b/common/utils/firebase.py index 03739f0..2490252 100644 --- a/common/utils/firebase.py +++ b/common/utils/firebase.py @@ -16,9 +16,9 @@ # add logger import logging -logger = logging.getLogger(__name__) +logger = logging.getLogger("myapp") # set log level -logger.setLevel(logging.INFO) +logger.setLevel(logging.DEBUG) def get_db(): @@ -88,6 +88,34 @@ def get_user_by_email(email_address): return adict +def get_github_contributions_for_user(login): + logger.info(f"Getting github contributions for user {login}") + + db = get_db() # this connects to our Firestore database + + # Use a collection group query to search across all contributor subcollections + contributors_ref = db.collection_group('github_contributors').where("login", "==", login) + + docs = contributors_ref.stream() + + github_history = [] + for doc in docs: + contribution = doc.to_dict() + # Add document ID + contribution["id"] = doc.id + # Add organization and repository information + repo_ref = doc.reference.parent.parent + org_ref = repo_ref.parent.parent + contribution["repo_name"] = repo_ref.id + contribution["org_name"] = org_ref.id + github_history.append(contribution) + + logger.info(f"Found {len(github_history)} contributions for user {login}") + + return github_history + + + def create_user(name, email_address, slack_id): db = get_db() # this connects to our Firestore database logger.info(f"Creating user {name} {email_address}") @@ -1017,3 +1045,17 @@ def upsert_news(news): logger.info("news does not exist") db.collection("news").add(news) + +def upsert_praise(praise): + db = get_db() # this connects to our Firestore database + logger.info(f"Adding praise {praise}") + + #Check if the vibe field exists. + if "praise_gif" not in praise: + logger.info("vibe field not found, setting praise['vibe'] to None") + praise["praise_gif"] = None + + logger.info(f"Adding refined praise {praise} into the database") + + db.collection("praises").add(praise) + logger.info("praise successfully saved") diff --git a/model/user.py b/model/user.py index a13e878..36db4e2 100644 --- a/model/user.py +++ b/model/user.py @@ -1,4 +1,4 @@ -metadata_list = ["role", "expertise", "education", "company", "why", "shirt_size", "github", "volunteering"] +metadata_list = ["role", "expertise", "education", "company", "why", "shirt_size", "github", "volunteering", "linkedin_url", "instagram_url"] class User: id = None @@ -34,6 +34,8 @@ def deserialize(cls, d): u.expertise = d['expertise'] if 'expertise' in d else '' u.education = d['education'] if 'education' in d else '' u.shirt_size = d['shirt_size'] if 'shirt_size' in d else '' + u.linkedin_url = d['linkedin_url'] if 'linkedin_url' in d else '' + u.instagram_url = d['instagram_url'] if 'instagram_url' in d else '' u.github = d['github'] if 'github' in d else '' u.role = d['role'] if 'role' in d else '' u.company = d['company'] if 'company' in d else ''