From 4c97a5d53dc61145495eb08ccbe584e083408992 Mon Sep 17 00:00:00 2001 From: Muhammad Nadeem Date: Tue, 8 May 2018 19:02:09 +0500 Subject: [PATCH 1/4] LP-935 Initial code --- lms/djangoapps/onboarding/helpers.py | 9 ++++++--- lms/djangoapps/onboarding/views.py | 15 +++++++++------ 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/lms/djangoapps/onboarding/helpers.py b/lms/djangoapps/onboarding/helpers.py index 649ad2d978f4..0db1438986ef 100644 --- a/lms/djangoapps/onboarding/helpers.py +++ b/lms/djangoapps/onboarding/helpers.py @@ -1,7 +1,5 @@ -import operator from datetime import date - -import collections +from difflib import SequenceMatcher COUNTRIES = { 'AD': 'Andorra', @@ -7827,3 +7825,8 @@ def oef_eligible_first_learner(user_extended_profile): """ return user_extended_profile.is_first_signup_in_org and not user_extended_profile.has_submitted_oef() \ and not user_extended_profile.organization.admin + + +def get_str_match_ratio(str1, str2): + """ Return matching percentage of two strings """ + return SequenceMatcher(None, str1, str2).ratio() \ No newline at end of file diff --git a/lms/djangoapps/onboarding/views.py b/lms/djangoapps/onboarding/views.py index ac51e2fe908b..00357325b4dc 100644 --- a/lms/djangoapps/onboarding/views.py +++ b/lms/djangoapps/onboarding/views.py @@ -6,7 +6,6 @@ import logging from datetime import datetime -import os from django.conf import settings from django.contrib import messages from django.contrib.auth import logout @@ -21,13 +20,14 @@ from django.shortcuts import render from django.utils.translation import ugettext_lazy as _, ugettext_noop from django.views.decorators.csrf import csrf_exempt -from path import Path as path from edxmako.shortcuts import render_to_response from lms.djangoapps.onboarding.decorators import can_save_org_data, can_not_update_onboarding_steps, \ can_save_org_details -from lms.djangoapps.onboarding.email_utils import send_admin_activation_email, send_admin_update_confirmation_email, send_admin_update_email -from lms.djangoapps.onboarding.helpers import calculate_age_years, COUNTRIES, LANGUAGES, oef_eligible_first_learner +from lms.djangoapps.onboarding.email_utils import send_admin_activation_email, send_admin_update_confirmation_email, \ + send_admin_update_email +from lms.djangoapps.onboarding.helpers import calculate_age_years, COUNTRIES, LANGUAGES, oef_eligible_first_learner, \ + get_str_match_ratio from lms.djangoapps.onboarding.models import ( Organization, Currency, OrganizationMetric, OrganizationAdminHashKeys, PartnerNetwork) @@ -494,10 +494,13 @@ def get_organizations(request): all_organizations = Organization.objects.filter(label__istartswith=query) for organization in all_organizations: - final_result[organization.label] = { + final_result[organization.label.lower()] = { + 'label': organization.label, 'is_admin_assigned': True if organization.admin else False, 'is_current_user_admin': True if organization.admin == request.user else False, - 'admin_email': organization.admin.email if organization.admin else 'Administrator not assigned yet.' + 'admin_email': organization.admin.email if organization.admin else 'Administrator not assigned yet.', + 'country': COUNTRIES.get(organization.country) if organization.country else '', + 'ratio': get_str_match_ratio(query.lower(), organization.label.lower()) } if request.user.is_authenticated(): From 50d9d16be5c091b48042c54a8baf019f5a5cdad6 Mon Sep 17 00:00:00 2001 From: Muhammad Nadeem Date: Thu, 10 May 2018 16:06:03 +0500 Subject: [PATCH 2/4] LP-935 update query to search org --- lms/djangoapps/onboarding/forms.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lms/djangoapps/onboarding/forms.py b/lms/djangoapps/onboarding/forms.py index 52b22d0145dd..13edbb624644 100644 --- a/lms/djangoapps/onboarding/forms.py +++ b/lms/djangoapps/onboarding/forms.py @@ -658,7 +658,7 @@ def save(self, user=None, commit=True): extended_profile = UserExtendedProfile.objects.create(user=user) if not is_currently_unemployed and organization_name: - organization_to_assign, is_created = Organization.objects.get_or_create(label=organization_name) + organization_to_assign, is_created = Organization.objects.get_or_create(label__iexact=organization_name) extended_profile.organization = organization_to_assign if organization_to_assign.users_count() == 0: @@ -711,7 +711,7 @@ def save(self, user=None, commit=True): extended_profile = UserExtendedProfile.objects.get(user=user) if not is_currently_unemployed and organization_name: - organization_to_assign, is_created = Organization.objects.get_or_create(label=organization_name) + organization_to_assign, is_created = Organization.objects.get_or_create(label__iexact=organization_name) prev_org = extended_profile.organization extended_profile.organization = organization_to_assign From b3f790d251c29b8f274d2e2bc911e182a9559942 Mon Sep 17 00:00:00 2001 From: Muhammad Nadeem Date: Fri, 11 May 2018 13:11:00 +0500 Subject: [PATCH 3/4] LP-935 Fix org autocomplete bugs --- lms/djangoapps/onboarding/forms.py | 10 ++++++++-- lms/djangoapps/onboarding/helpers.py | 28 +++++++++++++++++++++++++++- lms/djangoapps/onboarding/views.py | 27 ++++++++------------------- 3 files changed, 43 insertions(+), 22 deletions(-) diff --git a/lms/djangoapps/onboarding/forms.py b/lms/djangoapps/onboarding/forms.py index 13edbb624644..4621c5284246 100644 --- a/lms/djangoapps/onboarding/forms.py +++ b/lms/djangoapps/onboarding/forms.py @@ -658,7 +658,10 @@ def save(self, user=None, commit=True): extended_profile = UserExtendedProfile.objects.create(user=user) if not is_currently_unemployed and organization_name: - organization_to_assign, is_created = Organization.objects.get_or_create(label__iexact=organization_name) + organization_to_assign = Organization.objects.filter(label__iexact=organization_name).first() + if not organization_to_assign: + organization_to_assign = Organization.objects.create(label=organization_name) + extended_profile.organization = organization_to_assign if organization_to_assign.users_count() == 0: @@ -711,7 +714,10 @@ def save(self, user=None, commit=True): extended_profile = UserExtendedProfile.objects.get(user=user) if not is_currently_unemployed and organization_name: - organization_to_assign, is_created = Organization.objects.get_or_create(label__iexact=organization_name) + organization_to_assign = Organization.objects.filter(label__iexact=organization_name).first() + if not organization_to_assign: + organization_to_assign = Organization.objects.create(label=organization_name) + prev_org = extended_profile.organization extended_profile.organization = organization_to_assign diff --git a/lms/djangoapps/onboarding/helpers.py b/lms/djangoapps/onboarding/helpers.py index 0db1438986ef..3179606d45f4 100644 --- a/lms/djangoapps/onboarding/helpers.py +++ b/lms/djangoapps/onboarding/helpers.py @@ -1,5 +1,7 @@ +import re from datetime import date from difflib import SequenceMatcher +from lms.djangoapps.onboarding.models import Organization COUNTRIES = { 'AD': 'Andorra', @@ -7829,4 +7831,28 @@ def oef_eligible_first_learner(user_extended_profile): def get_str_match_ratio(str1, str2): """ Return matching percentage of two strings """ - return SequenceMatcher(None, str1, str2).ratio() \ No newline at end of file + return SequenceMatcher(None, str1, str2).ratio() + + +def get_close_matching_orgs_with_suggestions(request, query): + """find list of organizations which are very close to a searched string""" + data = {} + + all_organizations = Organization.objects.all() + for organization in all_organizations: + match_ratio = get_str_match_ratio(query.lower(), organization.label.lower()) + is_suggestion = True if re.match(query, organization.label, re.I) else False + is_matched = True if match_ratio >= 0.8 else False + + if is_suggestion or is_matched: + data[organization.label.lower()] = { + 'label': organization.label, + 'is_admin_assigned': True if organization.admin else False, + 'is_current_user_admin': True if organization.admin == request.user else False, + 'admin_email': organization.admin.email if organization.admin else 'Administrator not assigned yet.', + 'country': COUNTRIES.get(organization.country) if organization.country else '', + 'is_matched': is_matched, + 'is_suggestion': is_suggestion, + } + + return data diff --git a/lms/djangoapps/onboarding/views.py b/lms/djangoapps/onboarding/views.py index 00357325b4dc..0e52d2603688 100644 --- a/lms/djangoapps/onboarding/views.py +++ b/lms/djangoapps/onboarding/views.py @@ -27,7 +27,7 @@ from lms.djangoapps.onboarding.email_utils import send_admin_activation_email, send_admin_update_confirmation_email, \ send_admin_update_email from lms.djangoapps.onboarding.helpers import calculate_age_years, COUNTRIES, LANGUAGES, oef_eligible_first_learner, \ - get_str_match_ratio + get_close_matching_orgs_with_suggestions from lms.djangoapps.onboarding.models import ( Organization, Currency, OrganizationMetric, OrganizationAdminHashKeys, PartnerNetwork) @@ -486,32 +486,21 @@ def get_organizations(request): Get organizations """ final_result = {} - org_label = '' - admin_email = '' if request.is_ajax(): query = request.GET.get('term', '') - all_organizations = Organization.objects.filter(label__istartswith=query) - - for organization in all_organizations: - final_result[organization.label.lower()] = { - 'label': organization.label, - 'is_admin_assigned': True if organization.admin else False, - 'is_current_user_admin': True if organization.admin == request.user else False, - 'admin_email': organization.admin.email if organization.admin else 'Administrator not assigned yet.', - 'country': COUNTRIES.get(organization.country) if organization.country else '', - 'ratio': get_str_match_ratio(query.lower(), organization.label.lower()) - } + + final_result = get_close_matching_orgs_with_suggestions(request, query) if request.user.is_authenticated(): user_extended_profile = request.user.extended_profile - organization = user_extended_profile.organization + org = user_extended_profile.organization - if organization: + if org: _result = { - 'org': organization.label, - 'is_poc': True if organization.admin == request.user else False, - 'admin_email': organization.admin.email if organization.admin else '' + 'org': org.label, + 'is_poc': True if org.admin == request.user else False, + 'admin_email': org.admin.email if org.admin else '' } else: _result = { From 4447c879ea774c9997c6601f539d0329f89770f0 Mon Sep 17 00:00:00 2001 From: Muhammad Nadeem Date: Fri, 11 May 2018 15:47:29 +0500 Subject: [PATCH 4/4] LP-935 Remove spaces/special charters for org search matching --- lms/djangoapps/onboarding/helpers.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lms/djangoapps/onboarding/helpers.py b/lms/djangoapps/onboarding/helpers.py index 3179606d45f4..89e05347737b 100644 --- a/lms/djangoapps/onboarding/helpers.py +++ b/lms/djangoapps/onboarding/helpers.py @@ -2,6 +2,7 @@ from datetime import date from difflib import SequenceMatcher from lms.djangoapps.onboarding.models import Organization +from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers COUNTRIES = { 'AD': 'Andorra', @@ -7831,6 +7832,8 @@ def oef_eligible_first_learner(user_extended_profile): def get_str_match_ratio(str1, str2): """ Return matching percentage of two strings """ + str1 = re.sub('[^A-Za-z0-9]+', '', str1) + str2 = re.sub('[^A-Za-z0-9]+', '', str2) return SequenceMatcher(None, str1, str2).ratio() @@ -7842,7 +7845,7 @@ def get_close_matching_orgs_with_suggestions(request, query): for organization in all_organizations: match_ratio = get_str_match_ratio(query.lower(), organization.label.lower()) is_suggestion = True if re.match(query, organization.label, re.I) else False - is_matched = True if match_ratio >= 0.8 else False + is_matched = True if match_ratio >= configuration_helpers.get_value('org_search_ratio', 0) else False if is_suggestion or is_matched: data[organization.label.lower()] = {