matching package

Subpackages

Submodules

matching.admin module

matching.apps module

class matching.apps.MatchingConfig(app_name, app_module)[source]

Bases: AppConfig

default_auto_field = 'django_mongodb_backend.fields.ObjectIdAutoField'
name = 'matching'
ready()[source]

Import signals when app loads. Note: Added noqa so linter won’t remove the function. https://docs.djangoproject.com/en/dev/ref/applications/#django.apps.AppConfig.ready https://stackoverflow.com/questions/58362534/i-m-confused-about-the-ready-function-used-inside-app-py

matching.models module

class matching.models.Score(*args, **kwargs)[source]

Bases: Model

Stores the computed compatibility score between a mentee and a mentor.

Each row represents a unique mentee–mentor pairing. Scores are used by the matching algorithm to rank and assign mentors to mentees. The (mentee_email, mentor_email) pair is enforced as unique at the database level.

mentee_email

Email address of the mentee in the pairing.

Type:

EmailField

mentor_email

Email address of the mentor in the pairing.

Type:

EmailField

score

Computed compatibility score for this pairing.

Type:

FloatField

created_at

Timestamp when the score was first calculated.

Type:

DateTimeField

updated_at

Timestamp of the most recent score update.

Type:

DateTimeField

mentee_email

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

mentor_email

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

score

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

created_at

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

updated_at

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

property mentee

Retrieve the User instance for the mentee.

Performs a live database lookup by mentee_email on every access.

Returns:

The User record whose email matches mentee_email.

Return type:

users.models.User

Raises:

users.models.User.DoesNotExist – If no user with mentee_email exists in the database.

Example:

>>> score.mentee.firstName
'Jane'
property mentor

Retrieve the User instance for the mentor.

Performs a live database lookup by mentor_email on every access.

Returns:

The User record whose email matches mentor_email.

Return type:

users.models.User

Raises:

users.models.User.DoesNotExist – If no user with mentor_email exists in the database.

Example:

>>> score.mentor.firstName
'John'
exception DoesNotExist

Bases: ObjectDoesNotExist

exception MultipleObjectsReturned

Bases: MultipleObjectsReturned

exception NotUpdated

Bases: ObjectNotUpdated, DatabaseError

get_next_by_created_at(*, field=<django.db.models.fields.DateTimeField: created_at>, is_next=True, **kwargs)
get_next_by_updated_at(*, field=<django.db.models.fields.DateTimeField: updated_at>, is_next=True, **kwargs)
get_previous_by_created_at(*, field=<django.db.models.fields.DateTimeField: created_at>, is_next=False, **kwargs)
get_previous_by_updated_at(*, field=<django.db.models.fields.DateTimeField: updated_at>, is_next=False, **kwargs)
id

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

objects = <django.db.models.manager.Manager object>

matching.scoring module

matching.scoring.get_embedding_model()[source]

Return the shared SentenceTransformer instance, loading it on first call.

Uses a module-level singleton (_embedding_model) to avoid reloading the 'all-MiniLM-L6-v2' model on every scoring request. The model is approximately 80 MB and takes several seconds to initialise, so lazy loading defers that cost until the first actual score calculation rather than at import time.

Returns:

The loaded SentenceTransformer model instance.

Return type:

sentence_transformers.SentenceTransformer

matching.scoring.build_profile_text(user)[source]

Concatenate a user’s semantic profile fields into a single text block.

Combining all fields into one string before encoding gives the embedding model full context and produces richer, more discriminative embeddings than encoding each field in isolation. Fields that are empty or falsy are omitted entirely so they do not dilute the representation.

Parameters:

user (users.models.User) – The user whose profile fields are being combined.

Returns:

A newline-separated string of labelled profile fields, or an empty string if all fields are blank.

Return type:

str

Example:

>>> build_profile_text(user)
'Major: Computer Science\nHobbies and interests: chess, hiking\nGoals: SWE internship'
matching.scoring.calculate_match_score(mentee, mentor)[source]

Compute a compatibility score between a mentee and a mentor.

Combines three weighted sub-scores:

  1. Profile text similarity (up to 70 points) — cosine similarity of sentence embeddings built from build_profile_text(), scaled to the 0–70 range.

  2. Year compatibility (up to 10 points) — gap-based scoring from calculate_year_compatibility().

  3. Special category overlap (up to 20 points) — 5 points per shared background category (international, commuter, firstgen, outofstate, transfer), capped at 20.

Parameters:
  • mentee (users.models.User) – The mentee side of the pairing.

  • mentor (users.models.User) – The mentor side of the pairing.

Returns:

Total compatibility score rounded to two decimal places, in the range [0.0, 100.0].

Return type:

float

Example:

>>> calculate_match_score(mentee_user, mentor_user)
73.45
matching.scoring.calculate_year_compatibility(mentee_year, mentor_year)[source]

Score the academic-year gap between a mentee and a mentor.

Rewards pairings where the mentor is 2–3 years ahead of the mentee, reflecting the expectation that a slightly senior mentor provides the most relevant guidance. Both year values are normalized via _parse_year() before comparison; a value of 0 (unparseable or missing) causes the function to return a neutral mid-range score of 5.0.

Scoring table:

Condition

Points

Year 1 mentee / Year 3

10.0

Year 1 mentee / Year 4

9.0

Gap ≥ 3 years

9.0

Gap = 2 years

8.0

Gap = 1 year

6.0

Same year (gap = 0)

3.0

Mentor is junior

1.0

Either year unknown

5.0

Parameters:
  • mentee_year (int or str) – Academic year of the mentee (integer or string).

  • mentor_year (int or str) – Academic year of the mentor (integer or string).

Returns:

Year-compatibility sub-score in the range [1.0, 10.0].

Return type:

float

Example:

>>> calculate_year_compatibility(1, 3)
10.0
>>> calculate_year_compatibility(2, 2)
3.0

matching.serializers module

matching.serializers.SPECIAL_CATEGORY_FIELDS = {'commuter': 'commuter', 'firstgen': 'firstgen', 'international': 'international', 'outofstate': 'outofstate', 'transfer': 'transfer'}

Maps User boolean background fields to the label returned in API responses under specialCategories. Add, remove, or rename entries here to control which flags are exposed and how they are labelled without touching serializer logic.

matching.serializers.MAX_MENTEES = 2

Maximum number of mentees a single mentor may be assigned. Mirrors users.models.MAX_MENTEES and is re-exported here so that matching serializers and services can import from a single location.

matching.serializers.serialize_mentor(mentor, score=None)[source]

Serialize a mentor User instance into an API-ready dictionary.

Includes profile fields, available roster capacity, and an optional compatibility score. The score field is included in the output only when explicitly supplied, keeping the schema consistent between match-listing responses (which need a score) and plain profile lookups (which do not).

Parameters:
  • mentor (users.models.User) – The mentor user instance to serialize.

  • score (float or None) – Compatibility score for this mentor relative to a specific mentee. Pass None (default) to omit the field from the response.

Returns:

Dictionary of serialized mentor data. When score is provided the dict includes a 'score' key; otherwise it is absent.

Return type:

dict

Example — match listing (with score):

>>> serialize_mentor(mentor_user, score=0.87)
{
    'email': 'mentor@ucla.edu',
    'name': 'John Smith',
    'score': 0.87,
    'available_slots': 1,
    ...
}

Example — profile lookup (without score):

>>> serialize_mentor(mentor_user)
{
    'email': 'mentor@ucla.edu',
    'name': 'John Smith',
    'available_slots': 2,
    ...
}
matching.serializers.serialize_mentee(mentee)[source]

Serialize a mentee User instance into an API-ready dictionary.

Returns core profile fields and background category labels. Does not include matching metadata such as isMatched or matchedMentorEmail — those are considered internal state and are not exposed through this serializer.

Parameters:

mentee (users.models.User) – The mentee user instance to serialize.

Returns:

Dictionary of serialized mentee data.

Return type:

dict

Example:

>>> serialize_mentee(mentee_user)
{
    'email': 'mentee@g.ucla.edu',
    'name': 'Jane Doe',
    'major': ['Biology'],
    'minor': [],
    'year': 1,
    'hobbies': 'hiking',
    'clubs': 'Pre-Med Society',
    'goals': 'Become a doctor',
    'specialCategories': ['firstgen', 'transfer']
}
matching.serializers.full_name(user)[source]

Derive a display name from a user’s firstName and lastName fields.

Strips whitespace from each component before joining. Falls back to 'Not provided' if both fields are blank or absent, ensuring the return value is always a non-empty string suitable for display.

Parameters:

user (users.models.User) – The user whose name is being formatted.

Returns:

Full name string, or 'Not provided' if both name fields are empty.

Return type:

str

Example:

>>> full_name(user)          # both fields set
'Jane Doe'
>>> full_name(empty_user)    # both fields blank
'Not provided'
matching.serializers.special_categories(user)[source]

Return a list of background category labels that apply to the given user.

Iterates over SPECIAL_CATEGORY_FIELDS and includes the label for each field whose value is truthy on the user instance. Fields absent from the user object are treated as False via getattr default.

To add or remove a category from API responses, update SPECIAL_CATEGORY_FIELDS — no changes to this function are needed.

Parameters:

user (users.models.User) – The user whose background flags are being evaluated.

Returns:

List of label strings for all truthy background fields. Returns an empty list if no flags are set.

Return type:

list[str]

Example:

>>> special_categories(user)   # firstgen and transfer flags set
['firstgen', 'transfer']
>>> special_categories(user)   # no flags set
[]

matching.services module

exception matching.services.MatchingError(message, status=400)[source]

Bases: Exception

Base exception for all matching-layer errors.

Carries an HTTP status code alongside the message so that views can return the appropriate response status without additional branching logic.

Parameters:
  • message (str) – Human-readable description of the error.

  • status (int) – HTTP status code to return to the client. Defaults to 400.

Example:

raise MatchingError('Something went wrong', status=400)
exception matching.services.NotFound(message)[source]

Bases: MatchingError

Raised when a required resource (user, mentor, mentee) cannot be found.

Specialization of MatchingError that always sets status=404.

Parameters:

message (str) – Human-readable description of the missing resource.

Example:

raise NotFound('Mentor not found')
exception matching.services.Conflict(message)[source]

Bases: MatchingError

Raised when a matching operation conflicts with the current system state.

Specialization of MatchingError that always sets status=409. Typical use case: attempting to add a mentee to a mentor who is already at full capacity.

Parameters:

message (str) – Human-readable description of the conflict.

Example:

raise Conflict('This mentor already has two mentees.')
exception matching.services.Forbidden(message)[source]

Bases: MatchingError

Raised when a user attempts an action they are not authorized to perform.

Specialization of MatchingError that always sets status=403.

Parameters:

message (str) – Human-readable description of the authorization failure.

Example:

raise Forbidden('You do not have permission to perform this action.')
matching.services.get_ranked_matches(mentee)[source]

Return a ranked list of compatible mentors for the given mentee.

Queries all Score rows for the mentee, resolves each to a User, and filters out:

  • Mentors on the mentee’s blacklisted_mentors list.

  • Mentors whose current_mentees roster is already at capacity (>= MAX_MENTEES).

  • Score rows whose mentor_email no longer corresponds to an existing user (silently skipped).

The remaining mentors are sorted primary by score descending, secondary by date_joined ascending as a tiebreaker (earlier joiners are preferred).

Parameters:

mentee (users.models.User) – The mentee user for whom matches are being retrieved.

Returns:

List of serialized mentor dicts, each including a score field, ordered from best to worst match.

Return type:

list[dict]

Example:

>>> matches = get_ranked_matches(mentee_user)
>>> matches[0]['score']
0.92
matching.services.select_mentor(mentee, mentor_email)[source]

Match a mentee with their chosen mentor.

Validates that the mentee is not already matched, that the target user exists and holds the MENTOR role, and that the mentor’s roster is not full. On success, updates isMatched and matchedMentorEmail on the mentee and appends the mentee’s email to the mentor’s current_mentees.

Parameters:
  • mentee (users.models.User) – The mentee initiating the match request.

  • mentor_email (str) – Email address of the mentor to match with.

Returns:

The mentor User instance after the match is recorded.

Return type:

users.models.User

Raises:
  • MatchingError – If the mentee is already matched (HTTP 400), or if the resolved user is not a mentor (HTTP 400).

  • NotFound – If no user exists for mentor_email (HTTP 404).

  • Conflict – If the mentor’s roster is already at capacity (HTTP 409).

Example:

>>> mentor = select_mentor(mentee_user, 'mentor@ucla.edu')
matching.services.mentee_unmatch(mentee, mentor_email)[source]

Remove the match between a mentee and their current mentor.

Performs the following operations in order:

  1. Verifies the mentor exists and is the mentee’s current match.

  2. Clears isMatched and matchedMentorEmail on the mentee.

  3. Removes the mentee from the mentor’s current_mentees roster.

  4. Blacklists the mentor on the mentee’s account via blacklist_mentor() to prevent re-matching.

  5. Hard-deletes all chat messages between the pair via _delete_messages_between().

Parameters:
  • mentee (users.models.User) – The mentee requesting the unmatch.

  • mentor_email (str) – Email address of the mentor to unmatch from.

Raises:
  • MatchingError – If the mentee is not currently matched with the specified mentor (HTTP 400).

  • NotFound – If no user exists for mentor_email (HTTP 404).

Example:

>>> mentee_unmatch(mentee_user, 'mentor@ucla.edu')
matching.services.mentor_unmatch(mentor, mentee_email)[source]

Remove a specific mentee from a mentor’s active roster.

Performs the following operations in order:

  1. Verifies the mentee exists and is on the mentor’s current roster.

  2. Delegates roster cleanup to remove_mentee(), which handles the database update and in-memory refresh internally.

  3. Clears isMatched and matchedMentorEmail on the mentee.

  4. Blacklists the mentor on the mentee’s account via blacklist_mentor() to prevent re-matching.

  5. Hard-deletes all chat messages between the pair via _delete_messages_between().

Parameters:
  • mentor (users.models.User) – The mentor initiating the unmatch.

  • mentee_email (str) – Email address of the mentee to remove.

Raises:
  • MatchingError – If the specified mentee is not on the mentor’s current roster (HTTP 400).

  • NotFound – If no user exists for mentee_email (HTTP 404).

Example:

>>> mentor_unmatch(mentor_user, 'mentee@g.ucla.edu')

matching.signals module

matching.signals.calculate_and_store_scores_for_user(user)[source]
matching.signals.recalculate_scores_for_user(user)[source]
matching.signals.handle_user_profile_completion(sender, instance, created, **kwargs)[source]

matching.test_scoring module

matching.test_scoring.make_user(hobbies='', goals='', clubs='', major=None, minor=None, year='1', international=False, commuter=False, firstgen=False, outofstate=False, transfer=False)[source]
class matching.test_scoring.TestYearCompatibility(methodName='runTest')[source]

Bases: TestCase

setUp()[source]

Hook method for setting up the test fixture before exercising it.

test_optimal_pairing_1st_3rd()[source]
test_strong_pairing_1st_4th()[source]
test_large_gap_pairing()[source]
test_two_year_gap()[source]
test_one_year_gap()[source]
test_same_year()[source]
test_negative_gap()[source]
test_5_plus_year_parsing()[source]
test_missing_year_data()[source]
test_invalid_year_strings()[source]
class matching.test_scoring.TestMatchScoring(methodName='runTest')[source]

Bases: TestCase

setUp()[source]

Hook method for setting up the test fixture before exercising it.

test_high_similarity_cs_match()[source]
test_cross_discipline_mismatch()[source]
test_same_field_different_focus()[source]
test_interdisciplinary_match()[source]
test_special_category_boost()[source]
test_identical_profiles()[source]
test_missing_data_handling()[source]
test_empty_strings_handling()[source]
test_score_range_validation()[source]
test_generic_vs_specific()[source]
class matching.test_scoring.TestEdgeCases(methodName='runTest')[source]

Bases: TestCase

setUp()[source]

Hook method for setting up the test fixture before exercising it.

test_year_boundary_values()[source]
test_build_profile_text_empty()[source]
test_build_profile_text_full()[source]
test_single_word_vs_paragraph()[source]
test_similar_meaning_different_words()[source]
test_completely_unrelated_profiles()[source]
test_unicode_and_special_characters()[source]

matching.test_scoring_advanced module

Advanced real-world integration tests for the combined-text scoring algorithm.

class matching.test_scoring_advanced.Profile(hobbies='', goals='', clubs='', major=None, minor=None, year='1', international=False, commuter=False, firstgen=False, outofstate=False, transfer=False)[source]

Bases: object

Profile object matching the current User schema.

class matching.test_scoring_advanced.TestRealWorldScenarios(methodName='runTest')[source]

Bases: TestCase

setUp()[source]

Hook method for setting up the test fixture before exercising it.

test_cs_freshman_seeking_startup_mentor()[source]
test_pre_med_mentorship()[source]
test_engineering_to_consulting_mismatch()[source]
test_international_student_pairing()[source]
test_women_in_stem_mentorship()[source]
test_career_switcher_scenario()[source]
test_graduate_school_prep()[source]
class matching.test_scoring_advanced.TestFieldSpecificScenarios(methodName='runTest')[source]

Bases: TestCase

setUp()[source]

Hook method for setting up the test fixture before exercising it.

test_frontend_vs_backend_developer()[source]
test_theoretical_vs_applied_math()[source]
test_creative_writing_vs_journalism()[source]
class matching.test_scoring_advanced.TestEdgeCaseProfiles(methodName='runTest')[source]

Bases: TestCase

setUp()[source]

Hook method for setting up the test fixture before exercising it.

test_very_brief_vs_detailed_profiles()[source]
test_interdisciplinary_double_major()[source]
test_all_generic_interests()[source]
test_special_category_max_cap()[source]

4 shared categories should add exactly 20 points.

test_minor_field_included_in_profile_text()[source]

Minor should appear in the combined profile text.

matching.tests module

class matching.tests.MatchingAPITests(methodName='runTest')[source]

Bases: TestCase

setUp()[source]

Hook method for setting up the test fixture before exercising it.

test_get_mentor_matches_ranked()[source]

Ensures mentee receives mentors sorted by high score first

test_select_mentor_success()[source]

Ensures a mentee can successfully match with a mentor

test_mentor_capacity_limit()[source]

Ensures a mentor with 2 mentees is rejected

test_unauthorized_role_blocked()[source]

Ensures a mentor cannot access mentee-only matching endpoints

test_incomplete_profile_no_matches()[source]

Ensures users without major/year see 0 matches

test_unmatch_lifecycle()[source]

Verifies unmatching clears state and blacklists the mentor

test_deleted_user_cannot_match()[source]

Ensures users pending deletion are blocked from matching

test_rematch_endpoint_logic()[source]

Verifies the rematch endpoint returns the same ranked data

matching.urls module

matching.utils module

matching.utils.get_top_matches_for_mentee(mentee, limit=10)[source]

Return the highest-scoring Score rows for a mentee.

Results are ordered by score descending and sliced to limit rows. No filtering for blacklisted or full mentors is applied here — this is a raw score lookup intended for administrative or diagnostic use. For the filtered, serialized match list used in the matching UI, see matching.services.get_ranked_matches().

Parameters:
  • mentee (users.models.User) – The mentee whose scores are being queried.

  • limit (int) – Maximum number of score rows to return. Defaults to 10.

Returns:

Queryset of Score instances ordered by score descending, sliced to limit.

Return type:

django.db.models.QuerySet

Example:

>>> get_top_matches_for_mentee(mentee_user, limit=5)
<QuerySet [<Score: mentee@g.ucla.edu - mentor@ucla.edu: 0.91>, ...]>
matching.utils.get_top_matches_for_mentor(mentor, limit=10)[source]

Return the highest-scoring Score rows for a mentor.

Results are ordered by score descending and sliced to limit rows. Intended for administrative or diagnostic use; does not apply blacklist or capacity filtering.

Parameters:
  • mentor (users.models.User) – The mentor whose scores are being queried.

  • limit (int) – Maximum number of score rows to return. Defaults to 10.

Returns:

Queryset of Score instances ordered by score descending, sliced to limit.

Return type:

django.db.models.QuerySet

Example:

>>> get_top_matches_for_mentor(mentor_user, limit=5)
<QuerySet [<Score: mentee@g.ucla.edu - mentor@ucla.edu: 0.91>, ...]>
matching.utils.recalculate_all_scores()[source]

Rebuild the entire Score table from scratch.

Deletes all existing score rows, then computes a fresh calculate_match_score() for every eligible mentee–mentor pair and bulk-inserts the results in batches of 1 000 within a single database transaction.

Users on either side who do not pass _has_enough_profile_data() are excluded from the calculation entirely.

Warning

This function performs a full table wipe before re-inserting. It is intended for scheduled background jobs or admin-triggered resets, not for request-cycle use. For incremental updates triggered by a profile change, use recalculate_scores_for_mentee() instead.

Returns:

None. Prints the number of score records created to stdout.

Example:

>>> recalculate_all_scores()
Created 240 score records
matching.utils.UNMATCH_CONFIRMATION = 'I would like to unmatch'

Exact confirmation string a user must submit to complete an unmatch request. Referenced by require_confirmation() and surfaced in error messages so the frontend can display the expected phrase to the user.

matching.utils.require_auth(request)[source]

Guard helper that rejects unauthenticated requests.

Intended to be called at the top of matching views using the walrus operator pattern:

if err := require_auth(request):
    return err
Parameters:

request (django.http.HttpRequest) – The incoming HTTP request.

Returns:

A JsonResponse with HTTP 401 if the user is not authenticated, or None if the check passes.

Return type:

django.http.JsonResponse or None

matching.utils.require_role(request, role)[source]

Guard helper that rejects requests from users who do not hold a specific role.

Intended to be called at the top of matching views using the walrus operator pattern:

if err := require_role(request, 'MENTEE'):
    return err
Parameters:
  • request (django.http.HttpRequest) – The incoming HTTP request.

  • role (str) – The required role string, e.g. 'MENTEE' or 'MENTOR'.

Returns:

A JsonResponse with HTTP 403 if the user’s role does not match, or None if the check passes.

Return type:

django.http.JsonResponse or None

matching.utils.require_confirmation(data, expected='I would like to unmatch')[source]

Guard helper that validates a user-supplied confirmation string.

Prevents destructive unmatch operations from being triggered accidentally by requiring the caller to echo back the exact phrase defined in UNMATCH_CONFIRMATION. The comparison is performed after stripping leading and trailing whitespace.

Intended to be called in views using the walrus operator pattern:

if err := require_confirmation(data):
    return err
Parameters:
  • data (dict) – Parsed JSON body of the request, expected to contain a 'confirmation' key.

  • expected (str) – The exact string the 'confirmation' value must match. Defaults to UNMATCH_CONFIRMATION.

Returns:

A JsonResponse with HTTP 400 and an instructional error message if the confirmation does not match, or None if it passes.

Return type:

django.http.JsonResponse or None

matching.utils.recalculate_scores_for_mentee(mentee)[source]

Incrementally refresh compatibility scores between one mentee and all eligible mentors.

Uses update_or_create to upsert a Score row for every mentor who passes _has_enough_profile_data(), preserving scores for existing pairs while creating rows for any new mentors. If the mentee themselves does not have enough profile data the function returns immediately without writing anything.

Intended to be called after a mentee updates their profile so that the match dashboard reflects their latest information without requiring a full table rebuild. For a complete reset of all scores, use recalculate_all_scores() instead.

Parameters:

mentee (users.models.User) – The mentee whose scores should be refreshed.

Returns:

None. Returns early without side effects if the mentee’s profile is incomplete.

Example:

>>> recalculate_scores_for_mentee(mentee_user)
matching.utils.require_not_deleted(request)[source]

Guard helper that rejects requests from accounts pending deletion.

Prevents soft-deleted users from accessing matching features while their account is in the grace period. Intended to be called at the top of matching views using the walrus operator pattern:

if err := require_not_deleted(request):
    return err
Parameters:

request (django.http.HttpRequest) – The incoming HTTP request.

Returns:

A JsonResponse with HTTP 403 and a cancellation prompt if the account is soft-deleted, or None if the check passes.

Return type:

django.http.JsonResponse or None

matching.views module

matching.views.get_mentor_matches(request)[source]

Return a ranked list of compatible mentors for the authenticated mentee.

Delegates to services.get_ranked_matches() to compute and sort mentor candidates based on pre-calculated compatibility scores.

Parameters:

request (django.http.HttpRequest) – The incoming HTTP GET request. Must belong to an authenticated, non-deleted user with the MENTEE role.

Returns:

  • HTTP 200 with matches (list of serialized mentor objects) and total (count) on success.

  • HTTP 401 if the request is unauthenticated.

  • HTTP 403 if the user does not have the MENTEE role.

  • HTTP 404 if the account is pending deletion.

Return type:

django.http.JsonResponse

Success response (HTTP 200):

{
    "matches": [ { ...mentor fields... }, ... ],
    "total": 5
}
matching.views.rematch(request)[source]

Re-fetch the ranked mentor list for the authenticated mentee.

Thin wrapper around get_mentor_matches() kept as a distinct endpoint for semantic clarity in the URL configuration (e.g. /matching/rematch/ vs /matching/matches/).

Parameters:

request (django.http.HttpRequest) – The incoming HTTP GET request. Must belong to an authenticated, non-deleted user with the MENTEE role.

Returns:

Identical response to get_mentor_matches().

Return type:

django.http.JsonResponse

matching.views.select_mentor(request)[source]

Match the authenticated mentee with a chosen mentor.

Delegates to services.select_mentor(), which validates capacity, blacklist rules, and existing match state before creating the pairing.

Parameters:

request (django.http.HttpRequest) – The incoming HTTP POST request containing a JSON body with mentor_email. Must belong to an authenticated, non-deleted user with the MENTEE role.

Returns:

  • HTTP 200 with success, message, and serialized mentor data on success.

  • HTTP 400 if the request body is invalid JSON or mentor_email is absent.

  • HTTP 401 if the request is unauthenticated.

  • HTTP 403 if the user does not have the MENTEE role.

  • HTTP 404 if the account is pending deletion.

  • Appropriate error status from MatchingError if the pairing is not permitted.

Return type:

django.http.JsonResponse

Raises:

MatchingError – Caught internally; returns the error message and its associated HTTP status code.

Request body (JSON):

{
    "mentor_email": "mentor@ucla.edu"
}

Success response (HTTP 200):

{
    "success": true,
    "message": "Successfully matched with mentor",
    "mentor": { ...mentor fields... }
}
matching.views.get_my_mentor(request)[source]

Return the mentor currently matched to the authenticated mentee.

Reads matchedMentorEmail from the session user and fetches the corresponding User record via the internal service helper.

Parameters:

request (django.http.HttpRequest) – The incoming HTTP GET request. Must belong to an authenticated, non-deleted user with the MENTEE role who is currently matched.

Returns:

  • HTTP 200 with a serialized mentor object on success.

  • HTTP 400 if isMatched is False.

  • HTTP 401 if the request is unauthenticated.

  • HTTP 403 if the user does not have the MENTEE role.

  • HTTP 404 if matchedMentorEmail is absent or the mentor record no longer exists.

Return type:

django.http.JsonResponse

Raises:

MatchingError – Caught internally; returns the error message and its associated HTTP status code.

Success response (HTTP 200):

{
    "mentor": { ...mentor fields... }
}
matching.views.get_my_mentees(request)[source]

Return all mentees currently assigned to the authenticated mentor.

Iterates over current_mentees on the session user, fetches each User record, and silently skips any email addresses that no longer correspond to an existing account.

Parameters:

request (django.http.HttpRequest) – The incoming HTTP GET request. Must belong to an authenticated, non-deleted user with the MENTOR role.

Returns:

  • HTTP 200 with mentees (list of serialized mentee objects) and total (count) on success. The list may be empty if the mentor has no current mentees.

  • HTTP 401 if the request is unauthenticated.

  • HTTP 403 if the user does not have the MENTOR role.

  • HTTP 404 if the account is pending deletion.

Return type:

django.http.JsonResponse

Success response (HTTP 200):

{
    "mentees": [ { ...mentee fields... }, ... ],
    "total": 2
}
matching.views.unmatch(request)[source]

Remove an existing match between the authenticated user and a counterpart.

Behaviour differs by role:

  • MENTEE — requires mentor_email in the body; delegates to services.mentee_unmatch().

  • MENTOR — requires mentee_email in the body; delegates to services.mentor_unmatch().

A confirmation string must be present in the request body (validated by require_confirmation()) before any unmatching logic is executed.

Parameters:

request (django.http.HttpRequest) – The incoming HTTP POST request containing a JSON body with a confirmation field and either mentor_email or mentee_email depending on the caller’s role. Must belong to an authenticated, non-deleted user.

Returns:

  • HTTP 200 with 'Successfully unmatched' on success.

  • HTTP 400 if the request body is invalid JSON, the required email field is absent, or the confirmation check fails.

  • HTTP 401 if the request is unauthenticated.

  • HTTP 403 if the user’s role is neither MENTEE nor MENTOR.

  • HTTP 404 if the account is pending deletion.

  • Appropriate error status from MatchingError if the unmatch operation is not permitted.

Return type:

django.http.JsonResponse

Raises:

MatchingError – Caught internally; returns the error message and its associated HTTP status code.

Request body — mentee caller (JSON):

{
    "confirmation": "unmatch",
    "mentor_email": "mentor@ucla.edu"
}

Request body — mentor caller (JSON):

{
    "confirmation": "unmatch",
    "mentee_email": "mentee@g.ucla.edu"
}
matching.views.update_profile(request)[source]

Update the authenticated user’s profile and refresh match scores if applicable.

Applies the supplied field updates via User.update_profile(). If the caller is a MENTEE, compatibility scores against all available mentors are immediately recalculated via recalculate_scores_for_mentee() so that the match dashboard reflects the latest profile state.

Parameters:

request (django.http.HttpRequest) – The incoming HTTP PUT request containing a JSON body with one or more profile field key-value pairs. Must belong to an authenticated user.

Returns:

  • HTTP 200 with a success message on update.

  • HTTP 400 if the request body is not valid JSON.

  • HTTP 401 if the request is unauthenticated.

Return type:

django.http.JsonResponse

Request body (JSON):

{
    "firstName": "Jane",
    "year": 3,
    "hobbies": "hiking, chess"
}

Module contents

show-inheritance:

undoc-members: