From d44d663751ba85b356ff01d5a1982bf6e0873e90 Mon Sep 17 00:00:00 2001 From: Michael Plunkett <5885605+michplunkett@users.noreply.github.com> Date: Tue, 18 Jul 2023 22:30:44 -0500 Subject: [PATCH] Rename `star_date` and `descrip` (#977) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Fixes issues https://github.com/lucyparsons/OpenOversight/issues/941 https://github.com/lucyparsons/OpenOversight/issues/427 ## Description of Changes Changed the following column names: - `star_date` -> `start_date` - `descrip` -> `description` ## Tests and linting - [x] This branch is up-to-date with the `develop` branch. - [x] `pytest` passes on my local development environment. - [x] `pre-commit` passes on my local development environment. - [x] Data-migration output: ```shell $ docker exec -it openoversight-web-1 bash $ flask db stamp head /usr/local/lib/python3.11/site-packages/flask_limiter/extension.py:293: UserWarning: Using the in-memory storage for tracking rate limits as no storage was explicitly specified. This is not recommended for production use. See: https://flask-limiter.readthedocs.io#configuring-a-storage-backend for documentation about configuring the storage backend. warnings.warn( [2023-07-18 17:16:06,001] INFO in __init__: OpenOversight startup INFO [alembic.runtime.migration] Context impl PostgresqlImpl. INFO [alembic.runtime.migration] Will assume transactional DDL. INFO [alembic.runtime.migration] Running stamp_revision -> 93fc3e074dcc $ flask db migrate -m "rename 'star_date'" /usr/local/lib/python3.11/site-packages/flask_limiter/extension.py:293: UserWarning: Using the in-memory storage for tracking rate limits as no storage was explicitly specified. This is not recommended for production use. See: https://flask-limiter.readthedocs.io#configuring-a-storage-backend for documentation about configuring the storage backend. warnings.warn( [2023-07-18 17:17:01,906] INFO in __init__: OpenOversight startup ... Generating /usr/src/app/OpenOversight/migrations/versions/2023-07-18-1717_9ce70d7ebd56_rename_star_date.py ... done $ flask db upgrade [2023-07-18 17:18:49,546] INFO in __init__: OpenOversight startup INFO [alembic.runtime.migration] Context impl PostgresqlImpl. INFO [alembic.runtime.migration] Will assume transactional DDL. INFO [alembic.runtime.migration] Running upgrade 93fc3e074dcc -> 9ce70d7ebd56, rename 'star_date' ... (env) % make start docker-compose build ... [+] Running 2/2 ✔ Container openoversight-postgres-1 Started 0.2s ✔ Container openoversight-web-1 Started 0.3s (env) % docker exec -it openoversight-web-1 bash $ flask db stamp head /usr/local/lib/python3.11/site-packages/flask_limiter/extension.py:293: UserWarning: Using the in-memory storage for tracking rate limits as no storage was explicitly specified. This is not recommended for production use. See: https://flask-limiter.readthedocs.io#configuring-a-storage-backend for documentation about configuring the storage backend. warnings.warn( [2023-07-18 19:18:26,742] INFO in __init__: OpenOversight startup INFO [alembic.runtime.migration] Context impl PostgresqlImpl. INFO [alembic.runtime.migration] Will assume transactional DDL. $ flask db migrate -m "rename 'descrip' to 'description'" ... INFO [alembic.autogenerate.compare] Detected added column 'unit_types.description' INFO [alembic.autogenerate.compare] Detected removed index 'ix_unit_types_descrip' on 'unit_types' INFO [alembic.autogenerate.compare] Detected added index 'ix_unit_types_description' on '['description']' INFO [alembic.autogenerate.compare] Detected removed column 'unit_types.descrip' Generating /usr/src/app/OpenOversight/migrations/versions/2023-07-18-1921_eb0266dc8588_rename_descrip_to_description.py ... done $ flask db upgrade /usr/local/lib/python3.11/site-packages/flask_limiter/extension.py:293: UserWarning: Using the in-memory storage for tracking rate limits as no storage was explicitly specified. This is not recommended for production use. See: https://flask-limiter.readthedocs.io#configuring-a-storage-backend for documentation about configuring the storage backend. warnings.warn( [2023-07-18 19:33:12,354] INFO in __init__: OpenOversight startup INFO [alembic.runtime.migration] Context impl PostgresqlImpl. INFO [alembic.runtime.migration] Will assume transactional DDL. INFO [alembic.runtime.migration] Running upgrade 9ce70d7ebd56 -> eb0266dc8588, rename 'descrip' to 'description' $ ``` --- OpenOversight/app/commands.py | 6 +-- OpenOversight/app/csv_imports.py | 22 ++++---- OpenOversight/app/main/downloads.py | 6 +-- OpenOversight/app/main/forms.py | 16 +++--- OpenOversight/app/main/views.py | 16 +++--- OpenOversight/app/models/database.py | 20 ++++---- OpenOversight/app/models/database_imports.py | 6 +-- OpenOversight/app/templates/add_unit.html | 2 +- .../app/templates/edit_assignment.html | 2 +- OpenOversight/app/templates/list_officer.html | 2 +- .../partials/officer_assignment_history.html | 20 ++++---- OpenOversight/app/utils/db.py | 8 +-- OpenOversight/app/utils/forms.py | 8 +-- ...7-18-1717_9ce70d7ebd56_rename_star_date.py | 35 +++++++++++++ ...266dc8588_rename_descrip_to_description.py | 37 ++++++++++++++ OpenOversight/tests/conftest.py | 16 +++--- .../routes/test_officer_and_department.py | 50 ++++++++++--------- OpenOversight/tests/test_commands.py | 12 ++--- OpenOversight/tests/test_functional.py | 12 ++--- OpenOversight/tests/test_models.py | 2 +- OpenOversight/tests/test_utils.py | 2 +- docs/bulk_upload.rst | 6 +-- 22 files changed, 192 insertions(+), 114 deletions(-) create mode 100644 OpenOversight/migrations/versions/2023-07-18-1717_9ce70d7ebd56_rename_star_date.py create mode 100644 OpenOversight/migrations/versions/2023-07-18-1921_eb0266dc8588_rename_descrip_to_description.py diff --git a/OpenOversight/app/commands.py b/OpenOversight/app/commands.py index a1e0c06e3..ccd6aa4fd 100644 --- a/OpenOversight/app/commands.py +++ b/OpenOversight/app/commands.py @@ -324,7 +324,7 @@ def try_else_false(comparable): def process_assignment(row, officer, compare=False): assignment_fields = { "required": [], - "optional": ["job_title", "star_no", "unit_id", "star_date", "resign_date"], + "optional": ["job_title", "star_no", "unit_id", "start_date", "resign_date"], } # See if the row has assignment data @@ -342,7 +342,7 @@ def process_assignment(row, officer, compare=False): assignment_fieldnames = [ "star_no", "unit_id", - "star_date", + "start_date", "resign_date", ] i = 0 @@ -393,7 +393,7 @@ def process_assignment(row, officer, compare=False): assignment.job_id = job.id set_field_from_row(row, assignment, "star_no") set_field_from_row(row, assignment, "unit_id") - set_field_from_row(row, assignment, "star_date", allow_blank=False) + set_field_from_row(row, assignment, "start_date", allow_blank=False) set_field_from_row(row, assignment, "resign_date", allow_blank=False) db.session.add(assignment) db.session.flush() diff --git a/OpenOversight/app/csv_imports.py b/OpenOversight/app/csv_imports.py index 799b8009f..3d07f66ad 100644 --- a/OpenOversight/app/csv_imports.py +++ b/OpenOversight/app/csv_imports.py @@ -115,7 +115,8 @@ def _handle_officers_csv( "birth_year", "unique_internal_identifier", "department_name", - # the following are unused, but allowed since they are included in the csv output + # the following are unused, but allowed since they are included in the + # csv output "badge_number", "unique_identifier", "job_title", @@ -162,7 +163,7 @@ def _handle_assignments_csv( with _csv_reader(assignments_csv) as csv_reader: field_names = csv_reader.fieldnames if "start_date" in field_names: - field_names[field_names.index("start_date")] = "star_date" + field_names[field_names.index("start_date")] = "start_date" if "badge_number" in field_names: field_names[field_names.index("badge_number")] = "star_no" if "end_date" in field_names: @@ -181,7 +182,7 @@ def _handle_assignments_csv( "star_no", "unit_id", "unit_name", - "star_date", + "start_date", "resign_date", "officer_unique_identifier", ], @@ -193,8 +194,8 @@ def _handle_assignments_csv( job_title_to_id = { job.job_title.strip().lower(): job.id for job in jobs_for_department } - unit_descrip_to_id = { - unit.descrip.strip().lower(): unit.id + unit_description_to_id = { + unit.description.strip().lower(): unit.id for unit in Unit.query.filter_by(department_id=department_id).all() } if overwrite_assignments: @@ -211,7 +212,8 @@ def _handle_assignments_csv( ) if len(wrong_department) > 0: raise Exception( - "Referenced {} officers in assignment csv that belong to different department. Example ids: {}".format( + "Referenced {} officers in assignment csv that belong to different " + "department. Example ids: {}".format( len(wrong_department), ", ".join(map(str, list(wrong_department)[:3])), ) @@ -253,17 +255,17 @@ def _handle_assignments_csv( ) elif row.get("unit_name"): unit_name = row["unit_name"].strip() - descrip = unit_name.lower() - unit_id = unit_descrip_to_id.get(descrip) + description = unit_name.lower() + unit_id = unit_description_to_id.get(description) if unit_id is None: unit = Unit( - descrip=unit_name, + description=unit_name, department_id=officer.department_id, ) db.session.add(unit) db.session.flush() unit_id = unit.id - unit_descrip_to_id[descrip] = unit_id + unit_description_to_id[description] = unit_id row["unit_id"] = unit_id job_title = row["job_title"].strip().lower() job_id = job_title_to_id.get(job_title) diff --git a/OpenOversight/app/main/downloads.py b/OpenOversight/app/main/downloads.py index 54b464984..798d747e5 100644 --- a/OpenOversight/app/main/downloads.py +++ b/OpenOversight/app/main/downloads.py @@ -84,7 +84,7 @@ def salary_record_maker(salary: Salary) -> _Record: def officer_record_maker(officer: Officer) -> _Record: if officer.assignments_lazy: most_recent_assignment = max( - officer.assignments_lazy, key=lambda a: a.star_date or date.min + officer.assignments_lazy, key=lambda a: a.start_date or date.min ) most_recent_title = most_recent_assignment.job and check_output( most_recent_assignment.job.job_title @@ -121,10 +121,10 @@ def assignment_record_maker(assignment: Assignment) -> _Record: "officer unique identifier": officer and officer.unique_internal_identifier, "badge number": assignment.star_no, "job title": assignment.job and check_output(assignment.job.job_title), - "start date": assignment.star_date, + "start date": assignment.start_date, "end date": assignment.resign_date, "unit id": assignment.unit and assignment.unit.id, - "unit description": assignment.unit and assignment.unit.descrip, + "unit description": assignment.unit and assignment.unit.description, } diff --git a/OpenOversight/app/main/forms.py b/OpenOversight/app/main/forms.py index 58f13d35e..ae0fd197d 100644 --- a/OpenOversight/app/main/forms.py +++ b/OpenOversight/app/main/forms.py @@ -62,8 +62,8 @@ def validate_money(form, field): def validate_end_date(form, field): - if form.data["star_date"] and field.data: - if form.data["star_date"] > field.data: + if form.data["start_date"] and field.data: + if form.data["start_date"] > field.data: raise ValidationError("End date must come after start date.") @@ -155,11 +155,11 @@ class AssignmentForm(Form): "Unit", validators=[Optional()], query_factory=unit_choices, - get_label="descrip", + get_label="description", allow_blank=True, blank_text="None", ) - star_date = DateField("Assignment start date", validators=[Optional()]) + start_date = DateField("Assignment start date", validators=[Optional()]) resign_date = DateField( "Assignment end date", validators=[Optional(), validate_end_date] ) @@ -321,7 +321,7 @@ class AddOfficerForm(Form): "Unit", validators=[Optional()], query_factory=unit_choices, - get_label="descrip", + get_label="description", allow_blank=True, blank_text="None", ) @@ -401,7 +401,7 @@ class EditOfficerForm(Form): class AddUnitForm(Form): - descrip = StringField( + description = StringField( "Unit name or description", default="", validators=[Regexp(r"\w*"), Length(max=120), DataRequired()], @@ -563,8 +563,8 @@ class BrowseForm(Form): unit = QuerySelectField( "unit", validators=[Optional()], - get_label="descrip", - get_pk=lambda unit: unit.descrip, + get_label="description", + get_pk=lambda unit: unit.description, ) current_job = BooleanField("current_job", default=None, validators=[Optional()]) name = StringField("Last name") diff --git a/OpenOversight/app/main/views.py b/OpenOversight/app/main/views.py index 6ff89b203..76421c3de 100644 --- a/OpenOversight/app/main/views.py +++ b/OpenOversight/app/main/views.py @@ -705,9 +705,9 @@ def list_officer( unit_selections = ["Not Sure"] + [ uc[0] - for uc in db.session.query(Unit.descrip) + for uc in db.session.query(Unit.description) .filter_by(department_id=department_id) - .order_by(Unit.descrip.asc()) + .order_by(Unit.description.asc()) .all() ] rank_selections = [ @@ -842,13 +842,13 @@ def get_dept_units(department_id=None): if department_id: units = Unit.query.filter_by(department_id=department_id) - units = units.order_by(Unit.descrip).all() - unit_list = [(unit.id, unit.descrip) for unit in units] + units = units.order_by(Unit.description).all() + unit_list = [(unit.id, unit.description) for unit in units] else: units = Unit.query.all() # Prevent duplicate units unit_list = sorted( - set((unit.id, unit.descrip) for unit in units), + set((unit.id, unit.description) for unit in units), key=lambda x: x[1], ) @@ -926,10 +926,12 @@ def add_unit(): set_dynamic_default(form.department, current_user.dept_pref_rel) if form.validate_on_submit(): - unit = Unit(descrip=form.descrip.data, department_id=form.department.data.id) + unit = Unit( + description=form.description.data, department_id=form.department.data.id + ) db.session.add(unit) db.session.commit() - flash("New unit {} added to OpenOversight".format(unit.descrip)) + flash("New unit {} added to OpenOversight".format(unit.description)) return redirect(url_for("main.get_started_labeling")) else: current_app.logger.info(form.errors) diff --git a/OpenOversight/app/models/database.py b/OpenOversight/app/models/database.py index 73e252c72..4f0f451a8 100644 --- a/OpenOversight/app/models/database.py +++ b/OpenOversight/app/models/database.py @@ -246,26 +246,26 @@ def gender_label(self): def job_title(self): if self.assignments_lazy: return max( - self.assignments_lazy, key=lambda x: x.star_date or date.min + self.assignments_lazy, key=lambda x: x.start_date or date.min ).job.job_title - def unit_descrip(self): + def unit_description(self): if self.assignments_lazy: unit = max( - self.assignments_lazy, key=lambda x: x.star_date or date.min + self.assignments_lazy, key=lambda x: x.start_date or date.min ).unit - return unit.descrip if unit else None + return unit.description if unit else None def badge_number(self): if self.assignments_lazy: return max( - self.assignments_lazy, key=lambda x: x.star_date or date.min + self.assignments_lazy, key=lambda x: x.start_date or date.min ).star_no def currently_on_force(self): if self.assignments_lazy: most_recent = max( - self.assignments_lazy, key=lambda x: x.star_date or date.min + self.assignments_lazy, key=lambda x: x.start_date or date.min ) return "Yes" if most_recent.resign_date is None else "No" return "Uncertain" @@ -337,7 +337,7 @@ class Assignment(BaseModel): job = db.relationship("Job") unit_id = db.Column(db.Integer, db.ForeignKey("unit_types.id"), nullable=True) unit = db.relationship("Unit") - star_date = db.Column(db.Date, index=True, unique=False, nullable=True) + start_date = db.Column(db.Date, index=True, unique=False, nullable=True) resign_date = db.Column(db.Date, index=True, unique=False, nullable=True) date_created = db.Column(db.DateTime, default=func.now()) date_updated = db.Column( @@ -352,14 +352,14 @@ class Unit(BaseModel): __tablename__ = "unit_types" id = db.Column(db.Integer, primary_key=True) - descrip = db.Column(db.String(120), index=True, unique=False) + description = db.Column(db.String(120), index=True, unique=False) department_id = db.Column(db.Integer, db.ForeignKey("departments.id")) department = db.relationship( - "Department", backref="unit_types", order_by="Unit.descrip.asc()" + "Department", backref="unit_types", order_by="Unit.description.asc()" ) def __repr__(self): - return "Unit: {}".format(self.descrip) + return "Unit: {}".format(self.description) class Face(BaseModel): diff --git a/OpenOversight/app/models/database_imports.py b/OpenOversight/app/models/database_imports.py index e0aba6c90..95a50431a 100644 --- a/OpenOversight/app/models/database_imports.py +++ b/OpenOversight/app/models/database_imports.py @@ -129,7 +129,7 @@ def create_assignment_from_dict( star_no=parse_str(data.get("star_no"), None), job_id=int(data["job_id"]), unit_id=parse_int(data.get("unit_id")), - star_date=parse_date(data.get("star_date")), + start_date=parse_date(data.get("start_date")), resign_date=parse_date(data.get("resign_date")), ) if force_id and data.get("id"): @@ -150,8 +150,8 @@ def update_assignment_from_dict( assignment.job_id = int(data["job_id"]) if "unit_id" in data.keys(): assignment.unit_id = parse_int(data.get("unit_id")) - if "star_date" in data.keys(): - assignment.star_date = parse_date(data.get("star_date")) + if "start_date" in data.keys(): + assignment.start_date = parse_date(data.get("start_date")) if "resign_date" in data.keys(): assignment.resign_date = parse_date(data.get("resign_date")) db.session.flush() diff --git a/OpenOversight/app/templates/add_unit.html b/OpenOversight/app/templates/add_unit.html index 0717fe2c9..6e497f795 100644 --- a/OpenOversight/app/templates/add_unit.html +++ b/OpenOversight/app/templates/add_unit.html @@ -12,7 +12,7 @@

Add Unit

{{ form.hidden_tag() }} {{ wtf.form_errors(form, hiddens="only") }} - {{ wtf.form_field(form.descrip, autofocus="autofocus") }} + {{ wtf.form_field(form.description, autofocus="autofocus") }} {{ wtf.form_field(form.department) }} {{ wtf.form_field(form.submit, id="submit", button_map={'submit':'primary'}) }}
diff --git a/OpenOversight/app/templates/edit_assignment.html b/OpenOversight/app/templates/edit_assignment.html index 604054b82..19694bc31 100644 --- a/OpenOversight/app/templates/edit_assignment.html +++ b/OpenOversight/app/templates/edit_assignment.html @@ -18,7 +18,7 @@

Edit Officer Assignment

Don't see your unit? Add one!

- {{ wtf.form_field(form.star_date) }} + {{ wtf.form_field(form.start_date) }} {{ wtf.form_field(form.resign_date) }} diff --git a/OpenOversight/app/templates/list_officer.html b/OpenOversight/app/templates/list_officer.html index a95974dfc..6f6b23cf8 100644 --- a/OpenOversight/app/templates/list_officer.html +++ b/OpenOversight/app/templates/list_officer.html @@ -282,7 +282,7 @@

Unit
- {{ officer.unit_descrip() | default('Unknown') }} + {{ officer.unit_description() | default('Unknown') }}
Currently on the Force
diff --git a/OpenOversight/app/templates/partials/officer_assignment_history.html b/OpenOversight/app/templates/partials/officer_assignment_history.html index 1a3d3aff4..ec4096dc0 100644 --- a/OpenOversight/app/templates/partials/officer_assignment_history.html +++ b/OpenOversight/app/templates/partials/officer_assignment_history.html @@ -23,16 +23,16 @@

Assignment History

{% endif %} - {% for assignment in assignments|rejectattr('star_date','ne',None) %} + {% for assignment in assignments|rejectattr('start_date','ne',None) %} {{ assignment.job.job_title }} {{ assignment.star_no }} - {% if assignment.unit_id %}{{ assignment.unit.descrip }}{% endif %} + {% if assignment.unit_id %}{{ assignment.unit.description }}{% endif %} - {% if assignment.star_date %} - {{ assignment.star_date }} + {% if assignment.start_date %} + {{ assignment.start_date }} {% else %} Unknown {% endif %} @@ -50,16 +50,16 @@

Assignment History

{% endfor %} - {% for assignment in assignments | rejectattr('star_date', 'none') | sort(attribute='star_date', reverse=True) %} + {% for assignment in assignments | rejectattr('start_date', 'none') | sort(attribute='start_date', reverse=True) %} {{ assignment.job.job_title }} {{ assignment.star_no }} - {% if assignment.unit_id %}{{ assignment.unit.descrip }}{% endif %} + {% if assignment.unit_id %}{{ assignment.unit.description }}{% endif %} - {% if assignment.star_date: %} - {{ assignment.star_date }} + {% if assignment.start_date %} + {{ assignment.start_date }} {% else %} Unknown {% endif %} @@ -132,8 +132,8 @@

Start date of new assignment: - {{ form.star_date }} - {% for error in form.star_date.errors %} + {{ form.start_date }} + {% for error in form.start_date.errors %}

[{{ error }}]

diff --git a/OpenOversight/app/utils/db.py b/OpenOversight/app/utils/db.py index fc068dd37..87c2402bb 100644 --- a/OpenOversight/app/utils/db.py +++ b/OpenOversight/app/utils/db.py @@ -26,9 +26,9 @@ def add_unit_query(form, current_user): if not current_user.is_administrator: form.unit.query = Unit.query.filter_by( department_id=current_user.ac_department_id - ).order_by(Unit.descrip.asc()) + ).order_by(Unit.description.asc()) else: - form.unit.query = Unit.query.order_by(Unit.descrip.asc()).all() + form.unit.query = Unit.query.order_by(Unit.description.asc()).all() def compute_leaderboard_stats(select_top=25): @@ -82,7 +82,7 @@ def unit_choices(department_id: Optional[int] = None): return ( db.session.query(Unit) .filter_by(department_id=department_id) - .order_by(Unit.descrip.asc()) + .order_by(Unit.description.asc()) .all() ) - return db.session.query(Unit).order_by(Unit.descrip.asc()).all() + return db.session.query(Unit).order_by(Unit.description.asc()).all() diff --git a/OpenOversight/app/utils/forms.py b/OpenOversight/app/utils/forms.py index 6771c9619..75ed26b04 100644 --- a/OpenOversight/app/utils/forms.py +++ b/OpenOversight/app/utils/forms.py @@ -40,7 +40,7 @@ def add_new_assignment(officer_id, form): star_no=form.star_no.data, job_id=job.id, unit_id=unit_id, - star_date=form.star_date.data, + start_date=form.start_date.data, resign_date=form.resign_date.data, ) db.session.add(new_assignment) @@ -72,7 +72,7 @@ def add_officer_profile(form, current_user): star_no=form.star_no.data, job_id=form.job_id.data, unit=officer_unit, - star_date=form.employment_date.data, + start_date=form.employment_date.data, ) db.session.add(assignment) if form.links.data: @@ -208,7 +208,7 @@ def edit_existing_assignment(assignment, form): officer_unit = None assignment.unit_id = officer_unit - assignment.star_date = form.star_date.data + assignment.start_date = form.start_date.data assignment.resign_date = form.resign_date.data db.session.add(assignment) db.session.commit() @@ -291,7 +291,7 @@ def filter_by_form(form_data, officer_query, department_id=None): unit_ids = [ unit.id for unit in Unit.query.filter_by(department_id=department_id) - .filter(Unit.descrip.in_(form_data.get("unit"))) + .filter(Unit.description.in_(form_data.get("unit"))) .all() ] diff --git a/OpenOversight/migrations/versions/2023-07-18-1717_9ce70d7ebd56_rename_star_date.py b/OpenOversight/migrations/versions/2023-07-18-1717_9ce70d7ebd56_rename_star_date.py new file mode 100644 index 000000000..0c00be403 --- /dev/null +++ b/OpenOversight/migrations/versions/2023-07-18-1717_9ce70d7ebd56_rename_star_date.py @@ -0,0 +1,35 @@ +"""rename 'star_date' + +Revision ID: 9ce70d7ebd56 +Revises: 93fc3e074dcc +Create Date: 2023-07-18 17:17:02.018209 + +""" +from alembic import op + + +# revision identifiers, used by Alembic. +revision = "9ce70d7ebd56" +down_revision = "93fc3e074dcc" +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table("assignments", schema=None) as batch_op: + batch_op.drop_index("ix_assignments_star_date") + batch_op.alter_column("star_date", nullable=True, new_column_name="start_date") + batch_op.create_index("ix_assignments_start_date", ["start_date"], unique=False) + + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table("assignments", schema=None) as batch_op: + batch_op.drop_index("ix_assignments_start_date") + batch_op.alter_column("start_date", nullable=True, new_column_name="star_date") + batch_op.create_index("ix_assignments_star_date", ["star_date"], unique=False) + + # ### end Alembic commands ### diff --git a/OpenOversight/migrations/versions/2023-07-18-1921_eb0266dc8588_rename_descrip_to_description.py b/OpenOversight/migrations/versions/2023-07-18-1921_eb0266dc8588_rename_descrip_to_description.py new file mode 100644 index 000000000..cece50e13 --- /dev/null +++ b/OpenOversight/migrations/versions/2023-07-18-1921_eb0266dc8588_rename_descrip_to_description.py @@ -0,0 +1,37 @@ +"""rename 'descrip' to 'description' + +Revision ID: eb0266dc8588 +Revises: 9ce70d7ebd56 +Create Date: 2023-07-18 19:21:43.632936 + +""" +from alembic import op + + +# revision identifiers, used by Alembic. +revision = "eb0266dc8588" +down_revision = "9ce70d7ebd56" +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table("unit_types", schema=None) as batch_op: + batch_op.drop_index("ix_unit_types_descrip") + batch_op.alter_column("descrip", nullable=True, new_column_name="description") + batch_op.create_index( + "ix_unit_types_description", ["description"], unique=False + ) + + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table("unit_types", schema=None) as batch_op: + batch_op.drop_index("ix_unit_types_description") + batch_op.alter_column("description", nullable=True, new_column_name="descrip") + batch_op.create_index("ix_unit_types_descrip", ["descrip"], unique=False) + + # ### end Alembic commands ### diff --git a/OpenOversight/tests/conftest.py b/OpenOversight/tests/conftest.py index 0c30eb7c9..7a685de0d 100644 --- a/OpenOversight/tests/conftest.py +++ b/OpenOversight/tests/conftest.py @@ -165,7 +165,7 @@ def build_assignment(officer: Officer, units: List[Optional[Unit]], jobs: Job): job_id=random.choice(jobs).id, officer=officer, unit_id=unit_id, - star_date=pick_date(officer.full_name().encode(ENCODING_UTF_8)), + start_date=pick_date(officer.full_name().encode(ENCODING_UTF_8)), resign_date=pick_date(officer.full_name().encode(ENCODING_UTF_8)), ) @@ -347,11 +347,11 @@ def add_mockdata(session): random.seed(current_app.config["SEED"]) test_units = [ - Unit(descrip="test", department_id=1), - Unit(descrip="District 13", department_id=1), - Unit(descrip="Donut Devourers", department_id=1), - Unit(descrip="Bureau of Organized Crime", department_id=2), - Unit(descrip="Porky's BBQ: Rub Division", department_id=2), + Unit(description="test", department_id=1), + Unit(description="District 13", department_id=1), + Unit(description="Donut Devourers", department_id=1), + Unit(description="Bureau of Organized Crime", department_id=2), + Unit(description="Porky's BBQ: Rub Division", department_id=2), ] session.add_all(test_units) session.commit() @@ -670,7 +670,7 @@ def teardown(): "star_no", "job_title", "unit_id", - "star_date", + "start_date", "resign_date", "salary", "salary_year", @@ -701,7 +701,7 @@ def teardown(): if assignment.job else None, "unit_id": assignment.unit_id, - "star_date": assignment.star_date, + "start_date": assignment.start_date, "resign_date": assignment.resign_date, }, ) diff --git a/OpenOversight/tests/routes/test_officer_and_department.py b/OpenOversight/tests/routes/test_officer_and_department.py index 5d898d193..6553d2038 100644 --- a/OpenOversight/tests/routes/test_officer_and_department.py +++ b/OpenOversight/tests/routes/test_officer_and_department.py @@ -174,7 +174,7 @@ def test_admin_can_add_assignment(mockdata, client, session): form = AssignmentForm( star_no="1234", job_title=job.id, - star_date=date(2019, 1, 1), + start_date=date(2019, 1, 1), resign_date=date(2019, 12, 31), ) @@ -188,7 +188,7 @@ def test_admin_can_add_assignment(mockdata, client, session): assert "2019-01-01" in rv.data.decode(ENCODING_UTF_8) assert "2019-12-31" in rv.data.decode(ENCODING_UTF_8) assignment = Assignment.query.filter_by(star_no="1234", job_id=job.id).first() - assert assignment.star_date == date(2019, 1, 1) + assert assignment.start_date == date(2019, 1, 1) assert assignment.resign_date == date(2019, 12, 31) @@ -202,7 +202,7 @@ def test_admin_add_assignment_validation_error(mockdata, client, session): form = AssignmentForm( star_no="1234", job_title=job.id, - star_date=date(2020, 1, 1), + start_date=date(2020, 1, 1), resign_date=date(2019, 12, 31), ) @@ -227,7 +227,7 @@ def test_ac_can_add_assignment_in_their_dept(mockdata, client, session): form = AssignmentForm( star_no="S1234", job_title=job.id, - star_date=date(2019, 1, 1), + start_date=date(2019, 1, 1), resign_date=date(2019, 12, 31), ) @@ -245,7 +245,7 @@ def test_ac_can_add_assignment_in_their_dept(mockdata, client, session): assignment = Assignment.query.filter_by( star_no="S1234", officer_id=officer.id ).first() - assert assignment.star_date == date(2019, 1, 1) + assert assignment.start_date == date(2019, 1, 1) assert assignment.resign_date == date(2019, 12, 31) @@ -283,7 +283,7 @@ def test_admin_can_edit_assignment(mockdata, client, session): form = AssignmentForm( star_no="1234", job_title=job.id, - star_date=date(2019, 1, 1), + start_date=date(2019, 1, 1), resign_date=date(2019, 12, 31), ) @@ -299,7 +299,7 @@ def test_admin_can_edit_assignment(mockdata, client, session): assert "2019-12-31" in rv.data.decode(ENCODING_UTF_8) assignment = Assignment.query.filter_by(star_no="1234", job_id=job.id).first() - assert assignment.star_date == date(2019, 1, 1) + assert assignment.start_date == date(2019, 1, 1) assert assignment.resign_date == date(2019, 12, 31) job = Job.query.filter_by( @@ -308,7 +308,7 @@ def test_admin_can_edit_assignment(mockdata, client, session): form = AssignmentForm( star_no="12345", job_title=job.id, - star_date=date(2019, 2, 1), + start_date=date(2019, 2, 1), resign_date=date(2019, 11, 30), ) officer = Officer.query.filter_by(id=3).one() @@ -329,7 +329,7 @@ def test_admin_can_edit_assignment(mockdata, client, session): assert "2019-11-30" in rv.data.decode(ENCODING_UTF_8) assignment = Assignment.query.filter_by(star_no="12345", job_id=job.id).first() - assert assignment.star_date == date(2019, 2, 1) + assert assignment.start_date == date(2019, 2, 1) assert assignment.resign_date == date(2019, 11, 30) @@ -346,7 +346,7 @@ def test_admin_edit_assignment_validation_error( form = AssignmentForm( star_no="1234", job_title=job.id, - star_date=date(2019, 1, 1), + start_date=date(2019, 1, 1), resign_date=date(2019, 12, 31), ) @@ -371,7 +371,7 @@ def test_admin_edit_assignment_validation_error( ) assignment = Assignment.query.filter_by(star_no="1234", job_id=job.id).first() assert "End date must come after start date." in rv.data.decode(ENCODING_UTF_8) - assert assignment.star_date == date(2019, 1, 1) + assert assignment.start_date == date(2019, 1, 1) assert assignment.resign_date == date(2019, 12, 31) @@ -388,7 +388,7 @@ def test_ac_can_edit_officer_in_their_dept_assignment(mockdata, client, session) form = AssignmentForm( star_no=star_no, job_title=job.id, - star_date=date(2019, 1, 1), + start_date=date(2019, 1, 1), resign_date=date(2019, 12, 31), ) @@ -405,7 +405,7 @@ def test_ac_can_edit_officer_in_their_dept_assignment(mockdata, client, session) assert "2019-01-01" in rv.data.decode(ENCODING_UTF_8) assert "2019-12-31" in rv.data.decode(ENCODING_UTF_8) assert officer.assignments[0].star_no == star_no - assert officer.assignments[0].star_date == date(2019, 1, 1) + assert officer.assignments[0].start_date == date(2019, 1, 1) assert officer.assignments[0].resign_date == date(2019, 12, 31) officer = Officer.query.filter_by(id=officer.id).one() @@ -415,7 +415,7 @@ def test_ac_can_edit_officer_in_their_dept_assignment(mockdata, client, session) form = AssignmentForm( star_no=new_star_no, job_title=job.id, - star_date=date(2019, 2, 1), + start_date=date(2019, 2, 1), resign_date=date(2019, 11, 30), ) @@ -434,7 +434,7 @@ def test_ac_can_edit_officer_in_their_dept_assignment(mockdata, client, session) assert "2019-02-01" in rv.data.decode(ENCODING_UTF_8) assert "2019-11-30" in rv.data.decode(ENCODING_UTF_8) assert officer.assignments[0].star_no == new_star_no - assert officer.assignments[0].star_date == date(2019, 2, 1) + assert officer.assignments[0].start_date == date(2019, 2, 1) assert officer.assignments[0].resign_date == date(2019, 11, 30) @@ -1327,7 +1327,7 @@ def test_admin_can_add_new_unit(mockdata, client, session, department): with current_app.test_request_context(): login_admin(client) - form = AddUnitForm(descrip="Test", department=department.id) + form = AddUnitForm(description="Test", department=department.id) rv = client.post( url_for("main.add_unit"), data=form.data, follow_redirects=True @@ -1336,7 +1336,7 @@ def test_admin_can_add_new_unit(mockdata, client, session, department): assert "New unit" in rv.data.decode(ENCODING_UTF_8) # Check the unit was added to the database - unit = Unit.query.filter_by(descrip="Test").one() + unit = Unit.query.filter_by(description="Test").one() assert unit.department_id == department.id @@ -1345,7 +1345,7 @@ def test_ac_can_add_new_unit_in_their_dept(mockdata, client, session): login_ac(client) department = Department.query.filter_by(id=AC_DEPT).first() - form = AddUnitForm(descrip="Test", department=department.id) + form = AddUnitForm(description="Test", department=department.id) rv = client.post( url_for("main.add_unit"), data=form.data, follow_redirects=True @@ -1354,7 +1354,7 @@ def test_ac_can_add_new_unit_in_their_dept(mockdata, client, session): assert "New unit" in rv.data.decode(ENCODING_UTF_8) # Check the unit was added to the database - unit = Unit.query.filter_by(descrip="Test").one() + unit = Unit.query.filter_by(description="Test").one() assert unit.department_id == department.id @@ -1365,12 +1365,12 @@ def test_ac_cannot_add_new_unit_not_in_their_dept(mockdata, client, session): department = Department.query.except_( Department.query.filter_by(id=AC_DEPT) ).first() - form = AddUnitForm(descrip="Test", department=department.id) + form = AddUnitForm(description="Test", department=department.id) client.post(url_for("main.add_unit"), data=form.data, follow_redirects=True) # Check the unit was not added to the database - unit = Unit.query.filter_by(descrip="Test").first() + unit = Unit.query.filter_by(description="Test").first() assert unit is None @@ -1486,7 +1486,7 @@ def test_assignments_csv(mockdata, client, session, department): .first() ) form = AssignmentForm( - star_no="9181", job_title=job, star_date=date(2020, 6, 16) + star_no="9181", job_title=job, start_date=date(2020, 6, 16) ) add_new_assignment(officer.id, form) rv = client.get( @@ -1512,7 +1512,7 @@ def test_assignments_csv(mockdata, client, session, department): row for row in lines if row["badge number"] == form.star_no.data ] assert len(new_assignment) == 1 - assert new_assignment[0]["start date"] == str(form.star_date.data) + assert new_assignment[0]["start date"] == str(form.start_date.data) assert new_assignment[0]["job title"] == job.job_title @@ -1692,7 +1692,9 @@ def normalize_tokens_for_comparison(html_str: str, split_str: str): ) filter_list = normalize_tokens_for_comparison(rv, "
Unit
") - assert any("
{}
".format(unit.descrip) in token for token in filter_list) + assert any( + "
{}
".format(unit.description) in token for token in filter_list + ) filter_list = normalize_tokens_for_comparison(rv, "
Race
") assert any("
White
" in token for token in filter_list) diff --git a/OpenOversight/tests/test_commands.py b/OpenOversight/tests/test_commands.py index c73e00df5..f30b22503 100644 --- a/OpenOversight/tests/test_commands.py +++ b/OpenOversight/tests/test_commands.py @@ -369,7 +369,7 @@ def test_csv_new_officer(csvfile): "star_no": 666, "job_title": "CAPTAIN", "unit": None, - "star_date": None, + "start_date": None, "resign_date": None, "salary": 1.23, "salary_year": 2019, @@ -782,7 +782,7 @@ def test_advanced_csv_import__success(session, department, test_csv_dir): id=77021, officer_id=officer.id, star_no="4567", - star_date=datetime.date(2020, 1, 1), + start_date=datetime.date(2020, 1, 1), job_id=department.jobs[0].id, ) session.add(assignment) @@ -856,10 +856,10 @@ def test_advanced_csv_import__success(session, department, test_csv_dir): assert salary_2019.salary == 10001 assignment_po, assignment_cap = sorted( - cop1.assignments, key=operator.attrgetter("star_date") + cop1.assignments, key=operator.attrgetter("start_date") ) assert assignment_po.star_no == "1234" - assert assignment_po.star_date == datetime.date(2019, 7, 12) + assert assignment_po.start_date == datetime.date(2019, 7, 12) assert assignment_po.resign_date == datetime.date(2020, 1, 1) assert assignment_po.job.job_title == "Police Officer" assert assignment_po.unit_id is None @@ -894,13 +894,13 @@ def test_advanced_csv_import__success(session, department, test_csv_dir): assert len(cop4.assignments.all()) == 2 updated_assignment, new_assignment = sorted( - cop4.assignments, key=operator.attrgetter("star_date") + cop4.assignments, key=operator.attrgetter("start_date") ) assert updated_assignment.job.job_title == "Police Officer" assert updated_assignment.resign_date == datetime.date(2020, 7, 10) assert updated_assignment.star_no == "4567" assert new_assignment.job.job_title == "Captain" - assert new_assignment.star_date == datetime.date(2020, 7, 10) + assert new_assignment.start_date == datetime.date(2020, 7, 10) assert new_assignment.star_no == "54321" incident = cop4.incidents[0] diff --git a/OpenOversight/tests/test_functional.py b/OpenOversight/tests/test_functional.py index b5494ea5e..1f82eb166 100644 --- a/OpenOversight/tests/test_functional.py +++ b/OpenOversight/tests/test_functional.py @@ -186,10 +186,10 @@ def test_incident_detail_display_read_more_button_for_descriptions_over_cutoff( # Navigate to profile page for officer with short and long incident descriptions browser.get(f"http://localhost:{server_port}/officer/1") - incident_long_descrip = Incident.query.filter( + incident_long_description = Incident.query.filter( func.length(Incident.description) > DESCRIPTION_CUTOFF ).one_or_none() - incident_id = str(incident_long_descrip.id) + incident_id = str(incident_long_description.id) result = browser.find_element("id", "description-overflow-row_" + incident_id) assert result.is_displayed() @@ -202,10 +202,10 @@ def test_incident_detail_truncate_description_for_descriptions_over_cutoff( # Navigate to profile page for officer with short and long incident descriptions browser.get(f"http://localhost:{server_port}/officer/1") - incident_long_descrip = Incident.query.filter( + incident_long_description = Incident.query.filter( func.length(Incident.description) > DESCRIPTION_CUTOFF ).one_or_none() - incident_id = str(incident_long_descrip.id) + incident_id = str(incident_long_description.id) # Check that the text is truncated and contains more than just the ellipsis truncated_text = browser.find_element( @@ -273,8 +273,8 @@ def test_officer_form_has_units_alpha_sorted(mockdata, browser, server_port): # get the units from the DB in the sort we expect db_units_sorted = list( map( - lambda x: x.descrip, - db.session.query(Unit).order_by(Unit.descrip.asc()).all(), + lambda x: x.description, + db.session.query(Unit).order_by(Unit.description.asc()).all(), ) ) # the Select tag in the interface has a 'None' value at the start diff --git a/OpenOversight/tests/test_models.py b/OpenOversight/tests/test_models.py index 0c8751725..bc0667693 100644 --- a/OpenOversight/tests/test_models.py +++ b/OpenOversight/tests/test_models.py @@ -72,7 +72,7 @@ def test_face_repr(mockdata): def test_unit_repr(mockdata): unit = Unit.query.first() - assert unit.__repr__() == "Unit: {}".format(unit.descrip) + assert unit.__repr__() == "Unit: {}".format(unit.description) def test_user_repr(mockdata): diff --git a/OpenOversight/tests/test_utils.py b/OpenOversight/tests/test_utils.py index c5e8eb1f7..069aebe50 100644 --- a/OpenOversight/tests/test_utils.py +++ b/OpenOversight/tests/test_utils.py @@ -322,7 +322,7 @@ def test_filter_by_form_filter_unit( mockdata, units, has_officers_with_unit, has_officers_with_no_unit ): form_data = dict(unit=units) - unit_id = Unit.query.filter_by(descrip="Donut Devourers").one().id + unit_id = Unit.query.filter_by(description="Donut Devourers").one().id department_id = Department.query.first().id officers = filter_by_form(form_data, Officer.query, department_id).all() diff --git a/docs/bulk_upload.rst b/docs/bulk_upload.rst index e3b84b5c1..e14ee5b7c 100644 --- a/docs/bulk_upload.rst +++ b/docs/bulk_upload.rst @@ -38,7 +38,7 @@ The csv file can have the following fields: star_no job_title unit_id - star_date + start_date resign_date salary salary_year @@ -74,7 +74,7 @@ Current Employment information: - ``job_title`` rank or title, needs to be added to this department verbatim or ``Not Sure`` - ``unit_id`` id of unit within the department -- ``star_date`` (sic) start date of this assignment +- ``start_date`` start date of this assignment - ``resign_date`` resignation date of this assignment Salary information: @@ -94,7 +94,7 @@ Required fields - ``department_id``, ``first_name``, ``last_name``, ``job_title`` and either ``star_no`` or ``unique_internal_identifier`` are required. -- ``employment_date``, ``star_date`` and ``resign_date`` can be either +- ``employment_date``, ``start_date`` and ``resign_date`` can be either in ``yyyy-mm-dd`` or ``mm/dd/yyyy`` format - if the column is present the field cannot be left blank