From 2e5ea7f43a8b159ebf813ed1d38bdc890e90fce3 Mon Sep 17 00:00:00 2001 From: michplunkett <5885605+michplunkett@users.noreply.github.com> Date: Mon, 10 Jul 2023 11:18:50 -0500 Subject: [PATCH 01/29] Small views edits --- OpenOversight/app/main/views.py | 38 +++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/OpenOversight/app/main/views.py b/OpenOversight/app/main/views.py index ee6b8c30a..31ad17f6c 100644 --- a/OpenOversight/app/main/views.py +++ b/OpenOversight/app/main/views.py @@ -246,7 +246,7 @@ def officer_profile(officer_id): except NoResultFound: abort(HTTPStatus.NOT_FOUND) except: # noqa: E722 - exception_type, value, full_tback = sys.exc_info() + exception_type, value, full_traceback = sys.exc_info() current_app.logger.error( "Error finding officer: {}".format( " ".join([str(exception_type), str(value), format_exc()]) @@ -272,7 +272,7 @@ def officer_profile(officer_id): # Add in the placeholder image if no faces are found face_paths = [url_for("static", filename="images/placeholder.png")] except: # noqa: E722 - exception_type, value, full_tback = sys.exc_info() + exception_type, value, full_traceback = sys.exc_info() current_app.logger.error( "Error loading officer profile: {}".format( " ".join([str(exception_type), str(value), format_exc()]) @@ -491,7 +491,7 @@ def classify_submission(image_id, contains_cops): flash("Updated image classification") except: # noqa: E722 flash("Unknown error occurred") - exception_type, value, full_tback = sys.exc_info() + exception_type, value, full_traceback = sys.exc_info() current_app.logger.error( "Error classifying image: {}".format( " ".join([str(exception_type), str(value), format_exc()]) @@ -739,8 +739,9 @@ def list_officer( for officer in officers.items: officer_face = sorted(officer.face, key=lambda x: x.featured, reverse=True) - # could do some extra work to not lazy load images but load them all together - # but we would want to ensure to only load the first picture of each officer + # Could do some extra work to not lazy load images but load them all together. + # To do that properly we would want to ensure to only load the first picture of + # each officer. if officer_face and officer_face[0].image: officer.image = officer_face[0].image.filepath @@ -812,7 +813,8 @@ def get_dept_ranks(department_id=None, is_sworn_officer=None): ranks = ranks.order_by(Job.job_title).all() rank_list = [(rank.id, rank.job_title) for rank in ranks] else: - ranks = Job.query.all() # Not filtering by is_sworn_officer + # Not filtering by is_sworn_officer + ranks = Job.query.all() # Prevent duplicate ranks rank_list = sorted( set((rank.id, rank.job_title) for rank in ranks), @@ -863,11 +865,11 @@ def add_officer(): abort(HTTPStatus.FORBIDDEN) if form.validate_on_submit(): # Work around for WTForms limitation with boolean fields in FieldList - new_formdata = request.form.copy() - for key in new_formdata.keys(): + new_form_data = request.form.copy() + for key in new_form_data.keys(): if re.fullmatch(r"salaries-\d+-is_fiscal_year", key): - new_formdata[key] = "y" - form = AddOfficerForm(new_formdata) + new_form_data[key] = "y" + form = AddOfficerForm(new_form_data) officer = add_officer_profile(form, current_user) flash("New Officer {} added to OpenOversight".format(officer.last_name)) return redirect(url_for("main.submit_officer_images", officer_id=officer.id)) @@ -1025,7 +1027,8 @@ def label_data(department_id=None, image_id=None): department = None if image_id: image = Image.query.filter_by(id=image_id).one() - else: # Select a random untagged image from the entire database + else: + # Select a random untagged image from the entire database image_query = Image.query.filter_by(contains_cops=True).filter_by( is_tagged=False ) @@ -1052,9 +1055,8 @@ def label_data(department_id=None, image_id=None): flash("Invalid officer ID. Please select a valid OpenOversight ID!") elif department and officer_exists.department_id != department_id: flash( - "The officer is not in {}. Are you sure that is the correct OpenOversight ID?".format( - department.name - ) + "The officer is not in {}. Are you sure that is the correct " + "OpenOversight ID?".format(department.name) ) elif not existing_tag: left = form.dataX.data @@ -1389,7 +1391,8 @@ def upload(department_id, officer_id=None): image.contains_cops = True face = Face( officer_id=officer_id, - # Assuming photos uploaded with an officer ID are already cropped, so we set both images to the uploaded one + # Assuming photos uploaded with an officer ID are already cropped, + # we set both images to the uploaded one img_id=image.id, original_image_id=image.id, user_id=current_user.get_id(), @@ -1712,7 +1715,10 @@ def dispatch_request(self, *args, **kwargs): class OfficerLinkApi(ModelView): - """This API only applies to links attached to officer profiles, not links attached to incidents""" + """ + This API only applies to links attached to officer profiles, not links attached to + incidents. + """ model = Link model_name = "link" From d16374a266da01bb733b130f804cbb0cc65acfea Mon Sep 17 00:00:00 2001 From: michplunkett <5885605+michplunkett@users.noreply.github.com> Date: Mon, 10 Jul 2023 11:27:19 -0500 Subject: [PATCH 02/29] Update email_client.py --- OpenOversight/app/email_client.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/OpenOversight/app/email_client.py b/OpenOversight/app/email_client.py index 83568c9ee..9a860135d 100644 --- a/OpenOversight/app/email_client.py +++ b/OpenOversight/app/email_client.py @@ -18,17 +18,15 @@ class EmailClient(object): _instance = None - def __new__(cls, dev=False, testing=False): + def __new__(cls, config=None, dev=False, testing=False): if (testing or dev) and cls._instance is None: cls._instance = {} - if cls._instance is None: + if cls._instance is None and config: credentials = service_account.Credentials.from_service_account_file( SERVICE_ACCOUNT_FILE, scopes=cls.SCOPES ) - delegated_credentials = credentials.with_subject( - current_app.config["OO_SERVICE_EMAIL"] - ) + delegated_credentials = credentials.with_subject(config["OO_SERVICE_EMAIL"]) cls.service = build("gmail", "v1", credentials=delegated_credentials) cls._instance = super(EmailClient, cls).__new__(cls) return cls._instance From e7e2e340e556eaee2b2122251d6e881e354f83e7 Mon Sep 17 00:00:00 2001 From: michplunkett <5885605+michplunkett@users.noreply.github.com> Date: Mon, 10 Jul 2023 11:27:21 -0500 Subject: [PATCH 03/29] Update __init__.py --- OpenOversight/app/__init__.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/OpenOversight/app/__init__.py b/OpenOversight/app/__init__.py index 34cf8abc6..4538914a5 100644 --- a/OpenOversight/app/__init__.py +++ b/OpenOversight/app/__init__.py @@ -48,7 +48,11 @@ def create_app(config_name="default"): # This allows the application to run without creating an email client if it is # in testing or dev mode and the service account file is empty. service_account_file_size = os.path.getsize(SERVICE_ACCOUNT_FILE) - EmailClient(dev=app.debug and service_account_file_size == 0, testing=app.testing) + EmailClient( + config=app.config, + dev=app.debug and service_account_file_size == 0, + testing=app.testing, + ) limiter.init_app(app) login_manager.init_app(app) sitemap.init_app(app) From 2a5113fd0d4bf1d1b8292c2924989bbab18f33fb Mon Sep 17 00:00:00 2001 From: michplunkett <5885605+michplunkett@users.noreply.github.com> Date: Mon, 10 Jul 2023 13:24:15 -0500 Subject: [PATCH 04/29] Update views.py --- OpenOversight/app/main/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenOversight/app/main/views.py b/OpenOversight/app/main/views.py index 31ad17f6c..8972cb5fe 100644 --- a/OpenOversight/app/main/views.py +++ b/OpenOversight/app/main/views.py @@ -147,7 +147,7 @@ def get_officer(): jsloads = ["js/find_officer.js"] form = FindOfficerForm() - depts_dict = [dept_choice.toCustomDict() for dept_choice in dept_choices()] + departments_dict = [dept_choice.toCustomDict() for dept_choice in dept_choices()] if getattr(current_user, "dept_pref_rel", None): set_dynamic_default(form.dept, current_user.dept_pref_rel) @@ -177,7 +177,7 @@ def get_officer(): else: current_app.logger.info(form.errors) return render_template( - "input_find_officer.html", form=form, depts_dict=depts_dict, jsloads=jsloads + "input_find_officer.html", form=form, depts_dict=departments_dict, jsloads=jsloads ) From b35bdb5443665ebf44b637f9df2475fb39c0ed95 Mon Sep 17 00:00:00 2001 From: michplunkett <5885605+michplunkett@users.noreply.github.com> Date: Mon, 10 Jul 2023 13:42:07 -0500 Subject: [PATCH 05/29] Update views.py --- OpenOversight/app/main/views.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/OpenOversight/app/main/views.py b/OpenOversight/app/main/views.py index 8972cb5fe..b9fa0919f 100644 --- a/OpenOversight/app/main/views.py +++ b/OpenOversight/app/main/views.py @@ -177,7 +177,10 @@ def get_officer(): else: current_app.logger.info(form.errors) return render_template( - "input_find_officer.html", form=form, depts_dict=departments_dict, jsloads=jsloads + "input_find_officer.html", + form=form, + depts_dict=departments_dict, + jsloads=jsloads, ) From e368c25aae2ff7490142d22f3b5facd2619a6862 Mon Sep 17 00:00:00 2001 From: michplunkett <5885605+michplunkett@users.noreply.github.com> Date: Mon, 10 Jul 2023 13:45:08 -0500 Subject: [PATCH 06/29] Update list_officer.html --- OpenOversight/app/templates/list_officer.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenOversight/app/templates/list_officer.html b/OpenOversight/app/templates/list_officer.html index 9bdaad382..b2c745488 100644 --- a/OpenOversight/app/templates/list_officer.html +++ b/OpenOversight/app/templates/list_officer.html @@ -163,7 +163,7 @@

Unique ID

{% for officer in officers.items %}
  • -
    +
    {{ officer.full_name() }} From 2dde1bcabb3853326f9b4a8b059a24c88a35ce0a Mon Sep 17 00:00:00 2001 From: michplunkett <5885605+michplunkett@users.noreply.github.com> Date: Mon, 10 Jul 2023 13:49:53 -0500 Subject: [PATCH 07/29] Update openoversight.css --- OpenOversight/app/static/css/openoversight.css | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/OpenOversight/app/static/css/openoversight.css b/OpenOversight/app/static/css/openoversight.css index 66582f205..2db2347bb 100644 --- a/OpenOversight/app/static/css/openoversight.css +++ b/OpenOversight/app/static/css/openoversight.css @@ -114,11 +114,16 @@ a > .tutorial{ max-width:80%; } + .center-text { + text-align: center; + } + /* Carousel base class */ .carousel { min-height: 700px; margin-bottom: 50px; } + /* Since positioning the image, we need to help out the caption */ .carousel-caption { display:block; @@ -500,6 +505,12 @@ tr:hover .row-actions { content: "\e253"; } +@media all and (min-width: 768px) and (max-width: 991px) { + .filter-sidebar > .form > .btn.btn-primary:first-of-type { + margin-bottom: 5px; + } +} + .search-results .list-group-item { border: 0; } @@ -578,8 +589,7 @@ tr:hover .row-actions { } .officer-face { - min-width: 200px; - min-height: 200px; + height: 300px; } .face-wrap { From 87c92c8d9b47864cb44179c4c7e2137b7a55626e Mon Sep 17 00:00:00 2001 From: michplunkett <5885605+michplunkett@users.noreply.github.com> Date: Mon, 10 Jul 2023 14:14:06 -0500 Subject: [PATCH 08/29] Update views.py --- OpenOversight/app/main/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenOversight/app/main/views.py b/OpenOversight/app/main/views.py index b9fa0919f..777cebdc5 100644 --- a/OpenOversight/app/main/views.py +++ b/OpenOversight/app/main/views.py @@ -653,7 +653,7 @@ def list_officer( unit=None, current_job=None, ): - jsloads = ["js/select2.min.js", "js/list_officer.js"] + js_loads = ["js/select2.min.js", "js/list_officer.js"] form = BrowseForm() form.rank.query = ( @@ -797,7 +797,7 @@ def list_officer( choices=choices, next_url=next_url, prev_url=prev_url, - jsloads=jsloads, + jsloads=js_loads, ) From e989bdac2575ddde8f3e42570a2d484d618b0f07 Mon Sep 17 00:00:00 2001 From: michplunkett <5885605+michplunkett@users.noreply.github.com> Date: Mon, 10 Jul 2023 15:02:33 -0500 Subject: [PATCH 09/29] Update forms.py --- OpenOversight/app/utils/forms.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/OpenOversight/app/utils/forms.py b/OpenOversight/app/utils/forms.py index 5c917f13b..1eeba9ed8 100644 --- a/OpenOversight/app/utils/forms.py +++ b/OpenOversight/app/utils/forms.py @@ -345,12 +345,11 @@ def filter_roster(form, officer_query): if "dept" in form and form["dept"]: officer_query = officer_query.filter(Officer.department_id == form["dept"].id) - officer_query = ( + return ( officer_query.outerjoin(Face) .order_by(Face.officer_id.asc()) .order_by(Officer.id.desc()) ) - return officer_query def grab_officers(form): From 0ee8ef79eea993699987c80444982f7460c3daf8 Mon Sep 17 00:00:00 2001 From: michplunkett <5885605+michplunkett@users.noreply.github.com> Date: Mon, 10 Jul 2023 15:36:21 -0500 Subject: [PATCH 10/29] HTML update --- OpenOversight/app/templates/list_officer.html | 31 ++++++++++++++----- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/OpenOversight/app/templates/list_officer.html b/OpenOversight/app/templates/list_officer.html index b2c745488..754167ff5 100644 --- a/OpenOversight/app/templates/list_officer.html +++ b/OpenOversight/app/templates/list_officer.html @@ -35,10 +35,10 @@

    Name

    -
    +

    Badge

    -
    +
    @@ -47,7 +47,7 @@

    Badge

    -
    +

    Race

    @@ -63,7 +63,7 @@

    Race

    -
    +

    Gender

    @@ -79,7 +79,7 @@

    Gender

    -
    +

    Job

    @@ -121,10 +121,10 @@

    Job

    -
    +

    Age range

    -
    +
    @@ -151,6 +151,23 @@

    Unique ID

    +
    +
    +

    Photo

    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    {{ wtf.form_field(form.submit, id="submit", button_map={'submit':'primary'}) }} Clear Filters From fcdd73c5ab564cbbdf0983b492294cb224753b44 Mon Sep 17 00:00:00 2001 From: michplunkett <5885605+michplunkett@users.noreply.github.com> Date: Mon, 10 Jul 2023 15:44:04 -0500 Subject: [PATCH 11/29] Update list_officer.html --- OpenOversight/app/templates/list_officer.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenOversight/app/templates/list_officer.html b/OpenOversight/app/templates/list_officer.html index 754167ff5..a5d78c656 100644 --- a/OpenOversight/app/templates/list_officer.html +++ b/OpenOversight/app/templates/list_officer.html @@ -11,10 +11,10 @@

    {{ department.name|title }} Officers

    -
    +

    Name

    -
    +
    From 27f8ae2d462f22cefdceda723a8f2408278da449 Mon Sep 17 00:00:00 2001 From: michplunkett <5885605+michplunkett@users.noreply.github.com> Date: Mon, 10 Jul 2023 15:56:14 -0500 Subject: [PATCH 12/29] Update views.py --- OpenOversight/app/main/views.py | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/OpenOversight/app/main/views.py b/OpenOversight/app/main/views.py index 777cebdc5..c78018f07 100644 --- a/OpenOversight/app/main/views.py +++ b/OpenOversight/app/main/views.py @@ -652,6 +652,7 @@ def list_officer( unique_internal_identifier=None, unit=None, current_job=None, + require_photo=False, ): js_loads = ["js/select2.min.js", "js/list_officer.js"] @@ -673,6 +674,7 @@ def list_officer( form_data["unit"] = unit or [] form_data["current_job"] = current_job form_data["unique_internal_identifier"] = unique_internal_identifier + form_data["require_photo"] = require_photo department = Department.query.filter_by(id=department_id).first() if not department: @@ -705,15 +707,18 @@ def list_officer( for gender in genders ): form_data["gender"] = genders + if require_photo_arg := request.args.get("require_photo"): + current_app.logger.info("SETTING THE REQUIRE_PHOTO KEY") + form_data["require_photo"] = require_photo_arg - unit_choices = ["Not Sure"] + [ + unit_selections = ["Not Sure"] + [ uc[0] for uc in db.session.query(Unit.descrip) .filter_by(department_id=department_id) .order_by(Unit.descrip.asc()) .all() ] - rank_choices = [ + rank_selections = [ jc[0] for jc in db.session.query(Job.job_title, Job.order) .filter_by(department_id=department_id) @@ -721,11 +726,11 @@ def list_officer( .all() ] if (units := request.args.getlist("unit")) and all( - unit in unit_choices for unit in units + unit in unit_selections for unit in units ): form_data["unit"] = units if (ranks := request.args.getlist("rank")) and all( - rank in rank_choices for rank in ranks + rank in rank_selections for rank in ranks ): form_data["rank"] = ranks if current_job_arg := request.args.get("current_job"): @@ -734,11 +739,18 @@ def list_officer( officers = filter_by_form(form_data, Officer.query, department_id).filter( Officer.department_id == department_id ) - officers = officers.options(selectinload(Officer.face)) + + if form_data["require_photo"]: + officers = officers.join(Face) + else: + officers = officers.options(selectinload(Officer.face)) + officers = officers.order_by(Officer.last_name, Officer.first_name, Officer.id) + officers = officers.paginate( page=page, per_page=current_app.config["OFFICERS_PER_PAGE"], error_out=False ) + for officer in officers.items: officer_face = sorted(officer.face, key=lambda x: x.featured, reverse=True) @@ -751,8 +763,8 @@ def list_officer( choices = { "race": RACE_CHOICES, "gender": GENDER_CHOICES, - "rank": [(rc, rc) for rc in rank_choices], - "unit": [(uc, uc) for uc in unit_choices], + "rank": [(rc, rc) for rc in rank_selections], + "unit": [(uc, uc) for uc in unit_selections], } next_url = url_for( @@ -770,6 +782,7 @@ def list_officer( unique_internal_identifier=form_data["unique_internal_identifier"], unit=form_data["unit"], current_job=form_data["current_job"], + require_photo=form_data["require_photo"], ) prev_url = url_for( "main.list_officer", @@ -786,6 +799,7 @@ def list_officer( unique_internal_identifier=form_data["unique_internal_identifier"], unit=form_data["unit"], current_job=form_data["current_job"], + require_photo=form_data["require_photo"], ) return render_template( From f2c317ae6a6371ff6bfce157abb03c5725bf4afc Mon Sep 17 00:00:00 2001 From: michplunkett <5885605+michplunkett@users.noreply.github.com> Date: Mon, 10 Jul 2023 15:59:15 -0500 Subject: [PATCH 13/29] Update views.py --- OpenOversight/app/main/views.py | 1 + 1 file changed, 1 insertion(+) diff --git a/OpenOversight/app/main/views.py b/OpenOversight/app/main/views.py index c78018f07..9b0cb7d10 100644 --- a/OpenOversight/app/main/views.py +++ b/OpenOversight/app/main/views.py @@ -740,6 +740,7 @@ def list_officer( Officer.department_id == department_id ) + # Filter officers by presence of a photo if form_data["require_photo"]: officers = officers.join(Face) else: From 297c1b176a8bae8707ea9861367be99e3b346691 Mon Sep 17 00:00:00 2001 From: michplunkett <5885605+michplunkett@users.noreply.github.com> Date: Tue, 11 Jul 2023 11:02:20 -0500 Subject: [PATCH 14/29] Formatting using djlint --- OpenOversight/app/templates/list_officer.html | 540 +++++++++++------- 1 file changed, 322 insertions(+), 218 deletions(-) diff --git a/OpenOversight/app/templates/list_officer.html b/OpenOversight/app/templates/list_officer.html index a5d78c656..94923a00b 100644 --- a/OpenOversight/app/templates/list_officer.html +++ b/OpenOversight/app/templates/list_officer.html @@ -1,228 +1,332 @@ {% extends "base.html" %} {% import "bootstrap/wtf.html" as wtf %} {% block title %}Browse {{ department.name|title }} officers - OpenOversight{% endblock %} -{% block meta %}{% endblock %} -{% block head %}{% endblock %} +{% block meta %} + +{% endblock %} +{% block head %} + +{% endblock %} {% block content %} -
    -

    {{ department.name|title }} Officers

    -
    -
    - - -
    -
    -

    Name

    -
    -
    -
    -
    -
    - - -
    -
    - -
    - -
    -
    - - -
    -
    +
    +

    {{ department.name|title }} Officers

    +
    +
    + + +
    +
    +

    Name

    +
    +
    +
    +
    +
    + + +
    +
    +
    +
    +
    + + +
    +
    +
    +
    +
    +
    +
    +

    Badge

    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +

    Race

    +
    +
    +
    +
    + {% for choice in choices['race'] %} + + {% endfor %} +
    +
    +
    +
    +
    +
    +

    Gender

    +
    +
    +
    +
    + {% for choice in choices['gender'] %} + + {% endfor %} +
    +
    +
    +
    +
    +
    +

    Job

    +
    +
    +
    +
    +
    + + (in this rank and/or unit, if specified) +
    +
    +
    +
    +
    + + +
    +
    +
    +
    +
    + + +
    +
    +
    +
    +
    +
    +
    +

    Age range

    +
    +
    +
    +
    +
    + + +
    +
    + + +
    +
    +
    +
    +
    +
    +
    +

    Unique ID

    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +

    Photo

    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    + {{ wtf.form_field(form.submit, id="submit", button_map={'submit':'primary'}) }} + Clear Filters +
    -
    -
    -
    -
    -

    Badge

    -
    -
    -
    -
    - -
    -
    -
    -
    -
    -
    -

    Race

    -
    -
    -
    -
    - {% for choice in choices['race'] %} - - {% endfor %} -
    -
    -
    -
    -
    -
    -

    Gender

    -
    -
    -
    -
    - {% for choice in choices['gender'] %} - - {% endfor %} -
    -
    -
    -
    -
    -
    -

    Job

    -
    -
    -
    -
    -
    - - (in this rank and/or unit, if specified) -
    -
    -
    - -
    -
    - - -
    -
    -
    - -
    -
    - - -
    -
    + + {% with paginate=officers, location='bottom' %} + {% include "partials/paginate_nav.html" %} + {% endwith %}
    -
    +
    -
    -
    -

    Age range

    -
    -
    -
    -
    -
    - - -
    -
    - - -
    -
    -
    -
    -
    -
    -
    -

    Unique ID

    -
    -
    -
    -
    - -
    -
    -
    -
    -
    -
    -

    Photo

    -
    -
    -
    -
    -
    - -
    -
    -
    -
    -
    - {{ wtf.form_field(form.submit, id="submit", button_map={'submit':'primary'}) }} - Clear Filters - +
    -
    - {% with paginate=officers, location='top' %} - {% include "partials/paginate_nav.html" %} - {% endwith %} -
      - {% for officer in officers.items %} -
    • -
      -
      - - {{ officer.full_name() }} - -
      -
      -

      - {{ officer.full_name() }} - {{ officer.badge_number()|default('') }} -

      -
      -
      -
      -
      Rank
      -
      {{ officer.job_title()|default('Unknown') }}
      -
      Unit
      -
      {{ officer.unit_descrip()|default('Unknown') }}
      -
      Currently on the Force
      -
      {{ officer.currently_on_force() }}
      -
      Known incidents
      -
      {{ officer.incidents | length }}
      -
      -
      -
      -
      -
      Race
      -
      {{ officer.race_label()|default('Unknown')|lower|title }}
      -
      Gender
      -
      {{ officer.gender_label()|default('Unknown') }}
      -
      Number of Photos
      -
      {{ officer.face | count }}
      -
      -
      -
      -
      -
      -
    • - {% endfor %} -
    - {% with paginate=officers, location='bottom' %} - {% include "partials/paginate_nav.html" %} - {% endwith %} -
    -
    -
    + {% endblock content %} From d009908d7355fe056e70d3deca546b29ed8f39d1 Mon Sep 17 00:00:00 2001 From: michplunkett <5885605+michplunkett@users.noreply.github.com> Date: Tue, 11 Jul 2023 11:06:39 -0500 Subject: [PATCH 15/29] Update list_officer.html --- OpenOversight/app/templates/list_officer.html | 645 +++++++++--------- 1 file changed, 322 insertions(+), 323 deletions(-) diff --git a/OpenOversight/app/templates/list_officer.html b/OpenOversight/app/templates/list_officer.html index 94923a00b..6675def66 100644 --- a/OpenOversight/app/templates/list_officer.html +++ b/OpenOversight/app/templates/list_officer.html @@ -1,332 +1,331 @@ {% extends "base.html" %} {% import "bootstrap/wtf.html" as wtf %} -{% block title %}Browse {{ department.name|title }} officers - OpenOversight{% endblock %} +{% block title %} + Browse {{ department.name|title }} officers - OpenOversight +{% endblock title %} {% block meta %} - -{% endblock %} + +{% endblock meta %} {% block head %} - -{% endblock %} + +{% endblock head %} {% block content %} -
    -

    {{ department.name|title }} Officers

    -
    -
    - -
    -
    -
    -

    Name

    -
    -
    -
    -
    -
    - - -
    -
    -
    -
    -
    - - -
    -
    -
    -
    -
    -
    -
    -

    Badge

    -
    -
    -
    -
    - -
    -
    -
    -
    -
    -
    -

    Race

    -
    -
    -
    -
    - {% for choice in choices['race'] %} - - {% endfor %} -
    -
    -
    -
    -
    -
    -

    Gender

    -
    -
    -
    -
    - {% for choice in choices['gender'] %} - - {% endfor %} -
    -
    -
    -
    -
    -
    -

    Job

    -
    -
    -
    -
    -
    - - (in this rank and/or unit, if specified) -
    -
    -
    -
    -
    - - -
    -
    -
    -
    -
    - - -
    -
    -
    -
    -
    -
    -
    -

    Age range

    -
    -
    -
    -
    -
    - - -
    -
    - - -
    -
    -
    -
    -
    -
    -
    -

    Unique ID

    -
    -
    -
    -
    - -
    -
    -
    -
    -
    -
    -

    Photo

    -
    -
    -
    -
    -
    - -
    -
    -
    -
    -
    - {{ wtf.form_field(form.submit, id="submit", button_map={'submit':'primary'}) }} - Clear Filters -
    +
    +

    {{ department.name|title }} Officers

    +
    +
    + +
    +
    +
    +

    Name

    +
    +
    +
    +
    +
    + + +
    +
    +
    +
    +
    + + +
    +
    +
    +
    +
    +
    +
    +

    Badge

    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +

    Race

    -
    - {% with paginate=officers, location='top' %} - {% include "partials/paginate_nav.html" %} - {% endwith %} -
      - {% for officer in officers.items %} -
    • -
      -
      - - {{ officer.full_name() }} - -
      -
      -

      - {{ officer.full_name() }} - {{ officer.badge_number() |default('') }} -

      -
      -
      -
      -
      Rank
      -
      - {{ officer.job_title() |default('Unknown') }} -
      -
      Unit
      -
      - {{ officer.unit_descrip() |default('Unknown') }} -
      -
      Currently on the Force
      -
      - {{ officer.currently_on_force() }} -
      -
      Known incidents
      -
      - {{ officer.incidents | length }} -
      -
      -
      -
      -
      -
      Race
      -
      - {{ officer.race_label() |default('Unknown')|lower|title }} -
      -
      Gender
      -
      - {{ officer.gender_label() |default('Unknown') }} -
      -
      Number of Photos
      -
      - {{ officer.face | count }} -
      -
      -
      -
      -
      -
      -
    • - {% endfor %} -
    - {% with paginate=officers, location='bottom' %} - {% include "partials/paginate_nav.html" %} - {% endwith %} +
    +
    +
    + {% for choice in choices['race'] %} + + {% endfor %} +
    +
    - -
    - +
    +
    +
    +

    Gender

    +
    +
    +
    +
    + {% for choice in choices['gender'] %} + + {% endfor %} +
    +
    +
    +
    +
    +
    +

    Job

    +
    +
    +
    +
    +
    + + (in this rank and/or unit, if specified) +
    +
    +
    +
    +
    + + +
    +
    +
    +
    +
    + + +
    +
    +
    +
    +
    +
    +
    +

    Age range

    +
    +
    +
    +
    +
    + + +
    +
    + + +
    +
    +
    +
    +
    +
    +
    +

    Unique ID

    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +

    Photo

    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    + {{ wtf.form_field(form.submit, id="submit", button_map={'submit':'primary'}) }} + Clear Filters +
    +
    +
    + {% with paginate=officers, location='top' %} + {% include "partials/paginate_nav.html" %} + {% endwith %} +
      + {% for officer in officers.items %} +
    • +
      +
      + + {{ officer.full_name() }} + +
      +
      +

      + {{ officer.full_name() }} + {{ officer.badge_number() |default('') }} +

      +
      +
      +
      +
      Rank
      +
      + {{ officer.job_title() |default('Unknown') }} +
      +
      Unit
      +
      + {{ officer.unit_descrip() |default('Unknown') }} +
      +
      Currently on the Force
      +
      + {{ officer.currently_on_force() }} +
      +
      Known incidents
      +
      + {{ officer.incidents | length }} +
      +
      +
      +
      +
      +
      Race
      +
      + {{ officer.race_label() |default('Unknown')|lower|title }} +
      +
      Gender
      +
      + {{ officer.gender_label() |default('Unknown') }} +
      +
      Number of Photos
      +
      + {{ officer.face | count }} +
      +
      +
      +
      +
      +
      +
    • + {% endfor %} +
    + {% with paginate=officers, location='bottom' %} + {% include "partials/paginate_nav.html" %} + {% endwith %} +
    +
    - + +
    + {% endblock content %} From 4b498d03a40b24d74f8547d663190e5e590c4772 Mon Sep 17 00:00:00 2001 From: michplunkett <5885605+michplunkett@users.noreply.github.com> Date: Tue, 11 Jul 2023 11:10:02 -0500 Subject: [PATCH 16/29] Update list_officer.html --- OpenOversight/app/templates/list_officer.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/OpenOversight/app/templates/list_officer.html b/OpenOversight/app/templates/list_officer.html index 6675def66..88ab3fc00 100644 --- a/OpenOversight/app/templates/list_officer.html +++ b/OpenOversight/app/templates/list_officer.html @@ -258,7 +258,7 @@

    Photo

    - {% with paginate=officers, location='top' %} + {% with paginate=officers, location="top" %} {% include "partials/paginate_nav.html" %} {% endwith %}
      @@ -267,7 +267,7 @@

      Photo

      @@ -319,7 +319,7 @@

      {% endfor %}

    - {% with paginate=officers, location='bottom' %} + {% with paginate=officers, location="bottom" %} {% include "partials/paginate_nav.html" %} {% endwith %}
    From bc87b28c7bfe9562316b0cda571a44c3502f4117 Mon Sep 17 00:00:00 2001 From: michplunkett <5885605+michplunkett@users.noreply.github.com> Date: Tue, 11 Jul 2023 11:24:58 -0500 Subject: [PATCH 17/29] Update test_officer_and_department.py --- OpenOversight/tests/routes/test_officer_and_department.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/OpenOversight/tests/routes/test_officer_and_department.py b/OpenOversight/tests/routes/test_officer_and_department.py index bf7d93452..79ba91de7 100644 --- a/OpenOversight/tests/routes/test_officer_and_department.py +++ b/OpenOversight/tests/routes/test_officer_and_department.py @@ -1655,7 +1655,8 @@ def test_browse_filtering_allows_good(client, mockdata, session): assert officer.race == "WHITE" assert officer.gender == "M" - # Check that added officer appears when filtering for this race, gender, rank and age + # Check that added officer appears when filtering for this race, gender, rank + # and age form = BrowseForm( race="WHITE", gender="M", @@ -1696,7 +1697,8 @@ def test_find_officer_redirect(client, mockdata, session): min_age = datetime.now().year - 1991 max_age = datetime.now().year - 1989 - # Check that added officer appears when filtering for this race, gender, rank and age + # Check that added officer appears when filtering for this race, gender, rank + # and age form = FindOfficerForm( dept=department_id, first_name="A", From 0e8e8bf8a1f4ce564107e6d7f24d167d76923994 Mon Sep 17 00:00:00 2001 From: michplunkett <5885605+michplunkett@users.noreply.github.com> Date: Tue, 11 Jul 2023 11:40:04 -0500 Subject: [PATCH 18/29] Update test --- .../routes/test_officer_and_department.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/OpenOversight/tests/routes/test_officer_and_department.py b/OpenOversight/tests/routes/test_officer_and_department.py index 79ba91de7..77f5e5add 100644 --- a/OpenOversight/tests/routes/test_officer_and_department.py +++ b/OpenOversight/tests/routes/test_officer_and_department.py @@ -1675,18 +1675,24 @@ def test_browse_filtering_allows_good(client, mockdata, session): ) filter_list = rv.data.decode(ENCODING_UTF_8).split("
    Rank
    ")[1:] - assert any( - "
    {}
    ".format(job.job_title) in token for token in filter_list - ) + assert any("{}".format(job.job_title) in token for token in filter_list) + assert any("
    " in token for token in filter_list) + assert any("
    " in token for token in filter_list) filter_list = rv.data.decode(ENCODING_UTF_8).split("
    Unit
    ")[1:] - assert any("
    {}
    ".format(unit.descrip) in token for token in filter_list) + assert any("{}".format(unit.descrip) in token for token in filter_list) + assert any("
    " in token for token in filter_list) + assert any("
    " in token for token in filter_list) filter_list = rv.data.decode(ENCODING_UTF_8).split("
    Race
    ")[1:] - assert any("
    White
    " in token for token in filter_list) + assert any("White" in token for token in filter_list) + assert any("
    " in token for token in filter_list) + assert any("
    " in token for token in filter_list) filter_list = rv.data.decode(ENCODING_UTF_8).split("
    Gender
    ")[1:] - assert any("
    Male
    " in token for token in filter_list) + assert any("Male" in token for token in filter_list) + assert any("
    " in token for token in filter_list) + assert any("
    " in token for token in filter_list) def test_find_officer_redirect(client, mockdata, session): From ebf3c8cb3c3f82435436651e9a23032df7fa3a3e Mon Sep 17 00:00:00 2001 From: michplunkett <5885605+michplunkett@users.noreply.github.com> Date: Tue, 11 Jul 2023 11:42:51 -0500 Subject: [PATCH 19/29] Update test_officer_and_department.py --- OpenOversight/tests/routes/test_officer_and_department.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenOversight/tests/routes/test_officer_and_department.py b/OpenOversight/tests/routes/test_officer_and_department.py index 77f5e5add..4b8859c8b 100644 --- a/OpenOversight/tests/routes/test_officer_and_department.py +++ b/OpenOversight/tests/routes/test_officer_and_department.py @@ -1620,7 +1620,7 @@ def test_browse_filtering_allows_good(client, mockdata, session): with current_app.test_request_context(): department_id = Department.query.first().id - # Add a officer with a specific race, gender, rank and age to the first page + # Add an officer with a specific race, gender, rank and age to the first page login_admin(client) links = [ LinkForm(url="http://www.pleasework.com", link_type="link").data, From 2745329efd2e7e2451ff002d5329b4c41ee074a2 Mon Sep 17 00:00:00 2001 From: michplunkett <5885605+michplunkett@users.noreply.github.com> Date: Tue, 11 Jul 2023 11:44:02 -0500 Subject: [PATCH 20/29] Update list_officer.html --- OpenOversight/app/templates/list_officer.html | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/OpenOversight/app/templates/list_officer.html b/OpenOversight/app/templates/list_officer.html index 88ab3fc00..9684ccf47 100644 --- a/OpenOversight/app/templates/list_officer.html +++ b/OpenOversight/app/templates/list_officer.html @@ -274,18 +274,18 @@

    Photo

    {{ officer.full_name() }} - {{ officer.badge_number() |default('') }} + {{ officer.badge_number() | default('') }}

    Rank
    - {{ officer.job_title() |default('Unknown') }} + {{ officer.job_title() | default('Unknown') }}
    Unit
    - {{ officer.unit_descrip() |default('Unknown') }} + {{ officer.unit_descrip() | default('Unknown') }}
    Currently on the Force
    @@ -301,11 +301,11 @@

    Race
    - {{ officer.race_label() |default('Unknown')|lower|title }} + {{ officer.race_label() | default('Unknown') | lower | title }}
    Gender
    - {{ officer.gender_label() |default('Unknown') }} + {{ officer.gender_label() | default('Unknown') }}
    Number of Photos
    From b3592159f560e545d098db53277944dbea131fde Mon Sep 17 00:00:00 2001 From: michplunkett <5885605+michplunkett@users.noreply.github.com> Date: Tue, 11 Jul 2023 11:46:35 -0500 Subject: [PATCH 21/29] Update list_officer.html --- OpenOversight/app/templates/list_officer.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/OpenOversight/app/templates/list_officer.html b/OpenOversight/app/templates/list_officer.html index 9684ccf47..0f9d1b889 100644 --- a/OpenOversight/app/templates/list_officer.html +++ b/OpenOversight/app/templates/list_officer.html @@ -1,11 +1,11 @@ {% extends "base.html" %} {% import "bootstrap/wtf.html" as wtf %} {% block title %} - Browse {{ department.name|title }} officers - OpenOversight + Browse {{ department.name | title }} officers - OpenOversight {% endblock title %} {% block meta %} + content="Browse or search for officers in the {{ department.name | title }}."> {% endblock meta %} {% block head %} -

    {{ department.name|title }} Officers

    +

    {{ department.name | title }} Officers

    From 858c01fe2d47336a57f97dcb4af3d5c9a40d1333 Mon Sep 17 00:00:00 2001 From: michplunkett <5885605+michplunkett@users.noreply.github.com> Date: Tue, 11 Jul 2023 12:00:28 -0500 Subject: [PATCH 22/29] Update forms.py --- OpenOversight/app/main/forms.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/OpenOversight/app/main/forms.py b/OpenOversight/app/main/forms.py index d7e497793..19a2ff205 100644 --- a/OpenOversight/app/main/forms.py +++ b/OpenOversight/app/main/forms.py @@ -125,6 +125,9 @@ class FindOfficerForm(Form): max_age = IntegerField( "max_age", default=85, validators=[NumberRange(min=16, max=100)] ) + require_photo = BooleanField( + "require_photo", default=False, validators=[Optional()] + ) class FaceTag(Form): @@ -547,18 +550,20 @@ class IncidentForm(DateFieldForm): class BrowseForm(Form): # Any fields added to this form should generally also be added to FindOfficerForm + # query set in view function rank = QuerySelectField( "rank", validators=[Optional()], get_label="job_title", get_pk=lambda job: job.job_title, - ) # query set in view function + ) + # query set in view function unit = QuerySelectField( "unit", validators=[Optional()], get_label="descrip", get_pk=lambda unit: unit.descrip, - ) # query set in view function + ) current_job = BooleanField("current_job", default=None, validators=[Optional()]) name = StringField("Last name") badge = StringField("Badge number") @@ -587,6 +592,9 @@ class BrowseForm(Form): choices=AGE_CHOICES, validators=[AnyOf(allowed_values(AGE_CHOICES))], ) + require_photo = BooleanField( + "require_photo", default=False, validators=[Optional()] + ) submit = SubmitField(label="Submit") From 6468e2d0dccdeed1d7c0d5c0fd1d4856dd292a76 Mon Sep 17 00:00:00 2001 From: michplunkett <5885605+michplunkett@users.noreply.github.com> Date: Tue, 11 Jul 2023 12:12:44 -0500 Subject: [PATCH 23/29] Update forms.py --- OpenOversight/app/main/forms.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/OpenOversight/app/main/forms.py b/OpenOversight/app/main/forms.py index 19a2ff205..e0472ede0 100644 --- a/OpenOversight/app/main/forms.py +++ b/OpenOversight/app/main/forms.py @@ -426,11 +426,13 @@ class DateFieldForm(Form): date_field = DateField("Date*", validators=[DataRequired()]) time_field = TimeField("Time", validators=[Optional()]) - def validate_time_field(self, field): + @staticmethod + def validate_time_field(field): if not type(field.data) == datetime.time: raise ValidationError("Not a valid time.") - def validate_date_field(self, field): + @staticmethod + def validate_date_field(field): if field.data.year < 1900: raise ValidationError("Incidents prior to 1900 not allowed.") From 515f97e111ca2ec1450ac0afd69c1652928c5b97 Mon Sep 17 00:00:00 2001 From: michplunkett <5885605+michplunkett@users.noreply.github.com> Date: Tue, 11 Jul 2023 12:18:09 -0500 Subject: [PATCH 24/29] Update list_officer.html --- OpenOversight/app/templates/list_officer.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenOversight/app/templates/list_officer.html b/OpenOversight/app/templates/list_officer.html index 0f9d1b889..7b01a4dbb 100644 --- a/OpenOversight/app/templates/list_officer.html +++ b/OpenOversight/app/templates/list_officer.html @@ -265,7 +265,7 @@

    Photo

    {% for officer in officers.items %}
  • -
    +
    {{ officer.full_name() }} From e02b42de0da5377bff2e5d4feabd3e72596a6a6b Mon Sep 17 00:00:00 2001 From: michplunkett <5885605+michplunkett@users.noreply.github.com> Date: Tue, 11 Jul 2023 12:18:12 -0500 Subject: [PATCH 25/29] Update openoversight.css --- OpenOversight/app/static/css/openoversight.css | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/OpenOversight/app/static/css/openoversight.css b/OpenOversight/app/static/css/openoversight.css index 2db2347bb..91fd01e0d 100644 --- a/OpenOversight/app/static/css/openoversight.css +++ b/OpenOversight/app/static/css/openoversight.css @@ -114,10 +114,6 @@ a > .tutorial{ max-width:80%; } - .center-text { - text-align: center; - } - /* Carousel base class */ .carousel { min-height: 700px; @@ -590,6 +586,7 @@ tr:hover .row-actions { .officer-face { height: 300px; + margin: auto; } .face-wrap { From f4aff854cc64d3a6eda5126a66bf812e1d3cb525 Mon Sep 17 00:00:00 2001 From: michplunkett <5885605+michplunkett@users.noreply.github.com> Date: Tue, 11 Jul 2023 12:27:43 -0500 Subject: [PATCH 26/29] Revert "Update forms.py" This reverts commit 6468e2d0dccdeed1d7c0d5c0fd1d4856dd292a76. --- OpenOversight/app/main/forms.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/OpenOversight/app/main/forms.py b/OpenOversight/app/main/forms.py index e0472ede0..19a2ff205 100644 --- a/OpenOversight/app/main/forms.py +++ b/OpenOversight/app/main/forms.py @@ -426,13 +426,11 @@ class DateFieldForm(Form): date_field = DateField("Date*", validators=[DataRequired()]) time_field = TimeField("Time", validators=[Optional()]) - @staticmethod - def validate_time_field(field): + def validate_time_field(self, field): if not type(field.data) == datetime.time: raise ValidationError("Not a valid time.") - @staticmethod - def validate_date_field(field): + def validate_date_field(self, field): if field.data.year < 1900: raise ValidationError("Incidents prior to 1900 not allowed.") From 8bc3a7e65041ab83600ba8b08cbfc08bc9aaf852 Mon Sep 17 00:00:00 2001 From: michplunkett <5885605+michplunkett@users.noreply.github.com> Date: Tue, 11 Jul 2023 23:08:00 -0500 Subject: [PATCH 27/29] Update views.py --- OpenOversight/app/main/views.py | 1 - 1 file changed, 1 deletion(-) diff --git a/OpenOversight/app/main/views.py b/OpenOversight/app/main/views.py index 9b0cb7d10..898e44713 100644 --- a/OpenOversight/app/main/views.py +++ b/OpenOversight/app/main/views.py @@ -708,7 +708,6 @@ def list_officer( ): form_data["gender"] = genders if require_photo_arg := request.args.get("require_photo"): - current_app.logger.info("SETTING THE REQUIRE_PHOTO KEY") form_data["require_photo"] = require_photo_arg unit_selections = ["Not Sure"] + [ From 81339ad1087dca0f969a8755dd3451146e023303 Mon Sep 17 00:00:00 2001 From: michplunkett <5885605+michplunkett@users.noreply.github.com> Date: Wed, 12 Jul 2023 11:44:43 -0500 Subject: [PATCH 28/29] Update test_officer_and_department.py --- .../routes/test_officer_and_department.py | 37 +++++++++++-------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/OpenOversight/tests/routes/test_officer_and_department.py b/OpenOversight/tests/routes/test_officer_and_department.py index 4b8859c8b..901133c65 100644 --- a/OpenOversight/tests/routes/test_officer_and_department.py +++ b/OpenOversight/tests/routes/test_officer_and_department.py @@ -3,6 +3,7 @@ import csv import json import random +import re from datetime import date, datetime from http import HTTPStatus from io import BytesIO @@ -1674,25 +1675,29 @@ def test_browse_filtering_allows_good(client, mockdata, session): follow_redirects=True, ) - filter_list = rv.data.decode(ENCODING_UTF_8).split("
    Rank
    ")[1:] - assert any("{}".format(job.job_title) in token for token in filter_list) - assert any("
    " in token for token in filter_list) - assert any("
    " in token for token in filter_list) + def normalize_filter_tokens_for_comparison(html_str: str, split_str: str): + """Remove new lines, leading, and closing spaces between
    elements in + formatting HTML.""" + parsed_list = html_str.data.decode(ENCODING_UTF_8).split(split_str)[1:] + parsed_list = [re.sub(r"
    \n\s+", "
    ", token) for token in parsed_list] + parsed_list = [ + re.sub(r"\n\s+
    ", "
  • ", token) for token in parsed_list + ] + return parsed_list - filter_list = rv.data.decode(ENCODING_UTF_8).split("
    Unit
    ")[1:] - assert any("{}".format(unit.descrip) in token for token in filter_list) - assert any("
    " in token for token in filter_list) - assert any("
    " in token for token in filter_list) + filter_list = normalize_filter_tokens_for_comparison(rv, "
    Rank
    ") + assert any( + "
    {}
    ".format(job.job_title) in token for token in filter_list + ) + + filter_list = normalize_filter_tokens_for_comparison(rv, "
    Unit
    ") + assert any("
    {}
    ".format(unit.descrip) in token for token in filter_list) - filter_list = rv.data.decode(ENCODING_UTF_8).split("
    Race
    ")[1:] - assert any("White" in token for token in filter_list) - assert any("
    " in token for token in filter_list) - assert any("
    " in token for token in filter_list) + filter_list = normalize_filter_tokens_for_comparison(rv, "
    Race
    ") + assert any("
    White
    " in token for token in filter_list) - filter_list = rv.data.decode(ENCODING_UTF_8).split("
    Gender
    ")[1:] - assert any("Male" in token for token in filter_list) - assert any("
    " in token for token in filter_list) - assert any("
    " in token for token in filter_list) + filter_list = normalize_filter_tokens_for_comparison(rv, "
    Gender
    ") + assert any("
    Male
    " in token for token in filter_list) def test_find_officer_redirect(client, mockdata, session): From a916d2ba71842e477e699a8eacf99847233328ea Mon Sep 17 00:00:00 2001 From: michplunkett <5885605+michplunkett@users.noreply.github.com> Date: Wed, 12 Jul 2023 11:45:42 -0500 Subject: [PATCH 29/29] Update test_officer_and_department.py --- .../tests/routes/test_officer_and_department.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/OpenOversight/tests/routes/test_officer_and_department.py b/OpenOversight/tests/routes/test_officer_and_department.py index 901133c65..31dac39ed 100644 --- a/OpenOversight/tests/routes/test_officer_and_department.py +++ b/OpenOversight/tests/routes/test_officer_and_department.py @@ -1675,9 +1675,9 @@ def test_browse_filtering_allows_good(client, mockdata, session): follow_redirects=True, ) - def normalize_filter_tokens_for_comparison(html_str: str, split_str: str): + def normalize_tokens_for_comparison(html_str: str, split_str: str): """Remove new lines, leading, and closing spaces between
    elements in - formatting HTML.""" + formatted HTML.""" parsed_list = html_str.data.decode(ENCODING_UTF_8).split(split_str)[1:] parsed_list = [re.sub(r"
    \n\s+", "
    ", token) for token in parsed_list] parsed_list = [ @@ -1685,18 +1685,18 @@ def normalize_filter_tokens_for_comparison(html_str: str, split_str: str): ] return parsed_list - filter_list = normalize_filter_tokens_for_comparison(rv, "
    Rank
    ") + filter_list = normalize_tokens_for_comparison(rv, "
    Rank
    ") assert any( "
    {}
    ".format(job.job_title) in token for token in filter_list ) - filter_list = normalize_filter_tokens_for_comparison(rv, "
    Unit
    ") + filter_list = normalize_tokens_for_comparison(rv, "
    Unit
    ") assert any("
    {}
    ".format(unit.descrip) in token for token in filter_list) - filter_list = normalize_filter_tokens_for_comparison(rv, "
    Race
    ") + filter_list = normalize_tokens_for_comparison(rv, "
    Race
    ") assert any("
    White
    " in token for token in filter_list) - filter_list = normalize_filter_tokens_for_comparison(rv, "
    Gender
    ") + filter_list = normalize_tokens_for_comparison(rv, "
    Gender
    ") assert any("
    Male
    " in token for token in filter_list)