From 485a1e3d42bf936e4a096d323d493243cce5573f Mon Sep 17 00:00:00 2001 From: Michael Plunkett <5885605+michplunkett@users.noreply.github.com> Date: Tue, 22 Aug 2023 17:23:53 -0500 Subject: [PATCH] Address sql alchemy warning (#1036) ## Fixes issue https://github.com/lucyparsons/OpenOversight/issues/1023 ## Description of Changes Address the warnings that pop up when populating rows in the DB by giving the foreign key constraints names. The warning no longer shows up when running `make dev`. I named the foreign keys according to the motif that they were given by default: Screenshot 2023-08-22 at 3 31 50 PM ```zsh /usr/src/app/OpenOversight/app/../migrations/env.py:75: SAWarning: Cannot correctly sort tables; there are unresolvable cycles between tables "departments, users", which is usually caused by mutually dependent foreign key constraints. Foreign key constraints involving these tables will not be considered; this warning may raise an error in a future release. context.run_migrations() ``` ## 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] Ran `make dev` to create tables and populate data to validate changes to migrations. --- OpenOversight/app/models/database.py | 121 ++++++++++++++---- OpenOversight/app/utils/forms.py | 80 ++++++------ ...-10-0512_114919b27a9f_initial_migration.py | 22 +++- ...dc1ef93_add_preferred_department_column.py | 6 +- ...4a1aa4b58f_add_area_coordinator_columns.py | 10 +- ..._6065d7cdcbf8_add_officers_to_incidents.py | 18 ++- ...4-2105_d86feb8fa5d1_add_incidents_table.py | 23 ++-- ...bf42_add_department_column_to_incidents.py | 10 +- ...8a06_add_columns_to_incidents_and_links.py | 10 +- ...ename_user_id_to_creator_id_in_incident.py | 18 ++- ...06-1906_2040f0c804b0_create_notes_table.py | 8 +- ...1506_4a490771dda1_add_original_image_fk.py | 4 +- ...26aa132_add_explicit_ondelete_for_notes.py | 18 ++- ...e_rename_user_id_to_creator_id_in_notes.py | 6 +- ...ed957db0058_add_description_to_officers.py | 14 +- ...dd_cascading_foreign_key_constraint_to_.py | 9 +- ...25-1501_770ed51b4e16_add_salaries_table.py | 7 +- ...-04-20-1704_3015d1dd9eb4_add_jobs_table.py | 3 +- .../tests/routes/test_descriptions.py | 3 + 19 files changed, 268 insertions(+), 122 deletions(-) diff --git a/OpenOversight/app/models/database.py b/OpenOversight/app/models/database.py index daf0e6958..b6a2e4366 100644 --- a/OpenOversight/app/models/database.py +++ b/OpenOversight/app/models/database.py @@ -36,8 +36,18 @@ officer_links = db.Table( "officer_links", - db.Column("officer_id", db.Integer, db.ForeignKey("officers.id"), primary_key=True), - db.Column("link_id", db.Integer, db.ForeignKey("links.id"), primary_key=True), + db.Column( + "officer_id", + db.Integer, + db.ForeignKey("officers.id", name="officer_links_officer_id_fkey"), + primary_key=True, + ), + db.Column( + "link_id", + db.Integer, + db.ForeignKey("links.id", name="officer_links_link_id_fkey"), + primary_key=True, + ), db.Column( "created_at", db.DateTime(timezone=True), @@ -49,9 +59,17 @@ officer_incidents = db.Table( "officer_incidents", - db.Column("officer_id", db.Integer, db.ForeignKey("officers.id"), primary_key=True), db.Column( - "incident_id", db.Integer, db.ForeignKey("incidents.id"), primary_key=True + "officer_id", + db.Integer, + db.ForeignKey("officers.id", name="officer_incidents_officer_id_fkey"), + primary_key=True, + ), + db.Column( + "incident_id", + db.Integer, + db.ForeignKey("incidents.id", name="officer_incidents_incident_id_fkey"), + primary_key=True, ), db.Column( "created_at", @@ -162,7 +180,9 @@ class Job(BaseModel, TrackUpdates): job_title = db.Column(db.String(255), index=True, unique=False, nullable=False) is_sworn_officer = db.Column(db.Boolean, index=True, default=True) order = db.Column(db.Integer, index=True, unique=False, nullable=False) - department_id = db.Column(db.Integer, db.ForeignKey("departments.id")) + department_id = db.Column( + db.Integer, db.ForeignKey("departments.id", name="jobs_department_id_fkey") + ) department = db.relationship("Department", backref="jobs") __table_args__ = ( @@ -210,7 +230,9 @@ class Officer(BaseModel, TrackUpdates): birth_year = db.Column(db.Integer, index=True, unique=False, nullable=True) assignments = db.relationship("Assignment", back_populates="base_officer") face = db.relationship("Face", backref="officer") - department_id = db.Column(db.Integer, db.ForeignKey("departments.id")) + department_id = db.Column( + db.Integer, db.ForeignKey("departments.id", name="officers_department_id_fkey") + ) department = db.relationship("Department", backref="officers") unique_internal_identifier = db.Column( db.String(50), index=True, unique=True, nullable=True @@ -303,7 +325,12 @@ class Salary(BaseModel, TrackUpdates): __tablename__ = "salaries" id = db.Column(db.Integer, primary_key=True) - officer_id = db.Column(db.Integer, db.ForeignKey("officers.id", ondelete="CASCADE")) + officer_id = db.Column( + db.Integer, + db.ForeignKey( + "officers.id", name="salaries_officer_id_fkey", ondelete="CASCADE" + ), + ) officer = db.relationship("Officer", back_populates="salaries") salary = db.Column(db.Numeric, index=True, unique=False, nullable=False) overtime_pay = db.Column(db.Numeric, index=True, unique=False, nullable=True) @@ -318,12 +345,25 @@ class Assignment(BaseModel, TrackUpdates): __tablename__ = "assignments" id = db.Column(db.Integer, primary_key=True) - officer_id = db.Column(db.Integer, db.ForeignKey("officers.id", ondelete="CASCADE")) + officer_id = db.Column( + db.Integer, + db.ForeignKey( + "officers.id", name="assignments_officer_id_fkey", ondelete="CASCADE" + ), + ) base_officer = db.relationship("Officer", back_populates="assignments") star_no = db.Column(db.String(120), index=True, unique=False, nullable=True) - job_id = db.Column(db.Integer, db.ForeignKey("jobs.id"), nullable=False) + job_id = db.Column( + db.Integer, + db.ForeignKey("jobs.id", name="assignments_job_id_fkey"), + nullable=False, + ) job = db.relationship("Job") - unit_id = db.Column(db.Integer, db.ForeignKey("unit_types.id"), nullable=True) + unit_id = db.Column( + db.Integer, + db.ForeignKey("unit_types.id", name="assignments_unit_id_fkey"), + nullable=True, + ) unit = db.relationship("Unit") start_date = db.Column(db.Date, index=True, unique=False, nullable=True) resign_date = db.Column(db.Date, index=True, unique=False, nullable=True) @@ -337,7 +377,10 @@ class Unit(BaseModel, TrackUpdates): id = db.Column(db.Integer, primary_key=True) description = db.Column(db.String(120), index=True, unique=False) - department_id = db.Column(db.Integer, db.ForeignKey("departments.id")) + department_id = db.Column( + db.Integer, + db.ForeignKey("departments.id", name="unit_types_department_id_fkey"), + ) department = db.relationship( "Department", backref="unit_types", order_by="Unit.description.asc()" ) @@ -350,7 +393,9 @@ class Face(BaseModel, TrackUpdates): __tablename__ = "faces" id = db.Column(db.Integer, primary_key=True) - officer_id = db.Column(db.Integer, db.ForeignKey("officers.id")) + officer_id = db.Column( + db.Integer, db.ForeignKey("officers.id", name="faces_officer_id_fkey") + ) img_id = db.Column( db.Integer, db.ForeignKey( @@ -404,7 +449,10 @@ class Image(BaseModel, TrackUpdates): is_tagged = db.Column(db.Boolean, default=False, unique=False, nullable=True) - department_id = db.Column(db.Integer, db.ForeignKey("departments.id")) + department_id = db.Column( + db.Integer, + db.ForeignKey("departments.id", name="raw_images_department_id_fkey"), + ) department = db.relationship("Department", backref="raw_images") def __repr__(self): @@ -414,9 +462,17 @@ def __repr__(self): incident_links = db.Table( "incident_links", db.Column( - "incident_id", db.Integer, db.ForeignKey("incidents.id"), primary_key=True + "incident_id", + db.Integer, + db.ForeignKey("incidents.id", name="incident_links_incident_id_fkey"), + primary_key=True, + ), + db.Column( + "link_id", + db.Integer, + db.ForeignKey("links.id", name="incident_links_link_id_fkey"), + primary_key=True, ), - db.Column("link_id", db.Integer, db.ForeignKey("links.id"), primary_key=True), db.Column( "created_at", db.DateTime(timezone=True), @@ -429,12 +485,17 @@ def __repr__(self): incident_license_plates = db.Table( "incident_license_plates", db.Column( - "incident_id", db.Integer, db.ForeignKey("incidents.id"), primary_key=True + "incident_id", + db.Integer, + db.ForeignKey("incidents.id", name="incident_license_plates_incident_id_fkey"), + primary_key=True, ), db.Column( "license_plate_id", db.Integer, - db.ForeignKey("license_plates.id"), + db.ForeignKey( + "license_plates.id", name="incident_license_plates_license_plate_id_fkey" + ), primary_key=True, ), db.Column( @@ -449,10 +510,16 @@ def __repr__(self): incident_officers = db.Table( "incident_officers", db.Column( - "incident_id", db.Integer, db.ForeignKey("incidents.id"), primary_key=True + "incident_id", + db.Integer, + db.ForeignKey("incidents.id", name="incident_officers_incident_id_fkey"), + primary_key=True, ), db.Column( - "officers_id", db.Integer, db.ForeignKey("officers.id"), primary_key=True + "officers_id", + db.Integer, + db.ForeignKey("officers.id", name="incident_officers_officers_id_fkey"), + primary_key=True, ), db.Column( "created_at", @@ -545,7 +612,9 @@ class Incident(BaseModel, TrackUpdates): time = db.Column(db.Time, unique=False, index=True) report_number = db.Column(db.String(50), index=True) description = db.Column(db.Text(), nullable=True) - address_id = db.Column(db.Integer, db.ForeignKey("locations.id")) + address_id = db.Column( + db.Integer, db.ForeignKey("locations.id", name="incidents_address_id_fkey") + ) address = db.relationship("Location", backref="incidents") license_plates = db.relationship( "LicensePlate", @@ -565,7 +634,9 @@ class Incident(BaseModel, TrackUpdates): lazy="subquery", backref=db.backref("incidents"), ) - department_id = db.Column(db.Integer, db.ForeignKey("departments.id")) + department_id = db.Column( + db.Integer, db.ForeignKey("departments.id", name="incidents_department_id_fkey") + ) department = db.relationship("Department", backref="incidents", lazy=True) @@ -578,13 +649,17 @@ class User(UserMixin, BaseModel): confirmed = db.Column(db.Boolean, default=False) approved = db.Column(db.Boolean, default=False) is_area_coordinator = db.Column(db.Boolean, default=False) - ac_department_id = db.Column(db.Integer, db.ForeignKey("departments.id")) + ac_department_id = db.Column( + db.Integer, db.ForeignKey("departments.id", name="users_ac_department_id_fkey") + ) ac_department = db.relationship( "Department", backref="coordinators", foreign_keys=[ac_department_id] ) is_administrator = db.Column(db.Boolean, default=False) is_disabled = db.Column(db.Boolean, default=False) - dept_pref = db.Column(db.Integer, db.ForeignKey("departments.id")) + dept_pref = db.Column( + db.Integer, db.ForeignKey("departments.id", name="users_dept_pref_fkey") + ) dept_pref_rel = db.relationship("Department", foreign_keys=[dept_pref]) # creator backlinks diff --git a/OpenOversight/app/utils/forms.py b/OpenOversight/app/utils/forms.py index 5832d49f9..09df6bfd1 100644 --- a/OpenOversight/app/utils/forms.py +++ b/OpenOversight/app/utils/forms.py @@ -1,5 +1,5 @@ import datetime -from typing import Any, Union +from typing import Union from sqlalchemy import or_ from sqlalchemy.orm import selectinload @@ -28,14 +28,16 @@ db, ) from OpenOversight.app.utils.choices import GENDER_CHOICES, RACE_CHOICES -from OpenOversight.app.utils.general import get_or_create -def add_new_assignment(officer_id: int, form: AssignmentForm, current_user: User): - if form.unit.data: - unit_id = form.unit.data.id - else: - unit_id = None +def if_exists_or_none(val: Union[str, None]) -> Union[str, None]: + return val if val else None + + +def add_new_assignment( + officer_id: int, form: AssignmentForm, current_user: User +) -> None: + unit_id = form.unit.data.id if form.unit.data else None job = Job.query.filter_by( department_id=form.job_title.data.department_id, @@ -54,7 +56,7 @@ def add_new_assignment(officer_id: int, form: AssignmentForm, current_user: User db.session.commit() -def add_officer_profile(form: AddOfficerForm, current_user: User): +def add_officer_profile(form: AddOfficerForm, current_user: User) -> Officer: officer = Officer( first_name=form.first_name.data, last_name=form.last_name.data, @@ -69,10 +71,7 @@ def add_officer_profile(form: AddOfficerForm, current_user: User): db.session.add(officer) db.session.commit() - if form.unit.data: - officer_unit = form.unit.data - else: - officer_unit = None + officer_unit = form.unit.data if form.unit.data else None assignment = Assignment( base_officer=officer, @@ -84,11 +83,9 @@ def add_officer_profile(form: AddOfficerForm, current_user: User): db.session.add(assignment) if form.links.data: for link in form.data["links"]: - # don't try to create with a blank string if link["url"]: - li, _ = get_or_create(db.session, Link, **link) - if li: - officer.links.append(li) + li = get_or_create_link_from_form(link, current_user) + officer.links.append(li) if form.notes.data: for note in form.data["notes"]: # don't try to create with a blank string @@ -126,17 +123,14 @@ def add_officer_profile(form: AddOfficerForm, current_user: User): return officer -def create_description(self, form: TextForm, current_user: User): +def create_description(self, form: TextForm, current_user: User) -> Description: return Description( text_contents=form.text_contents.data, officer_id=form.officer_id.data, ) -def create_incident(self, form: IncidentForm, current_user: User): - def if_exists_or_none(val: Union[str, Any]): - return val if val else None - +def create_incident(self, form: IncidentForm, current_user: User) -> Incident: fields = { "date": form.date_field.data, "time": form.time_field.data, @@ -191,23 +185,8 @@ def if_exists_or_none(val: Union[str, Any]): if "links" in form.data: for link in form.data["links"]: - # don't try to create with a blank string if link["url"]: - li = Link.query.filter_by( - author=if_exists_or_none(link["author"]), - link_type=if_exists_or_none(link["link_type"]), - title=if_exists_or_none(link["title"]), - url=if_exists_or_none(link["url"]), - ).first() - if not li: - li = Link( - author=if_exists_or_none(link["author"]), - description=if_exists_or_none(link["description"]), - link_type=if_exists_or_none(link["link_type"]), - title=if_exists_or_none(link["title"]), - url=if_exists_or_none(link["url"]), - ) - db.session.add(li) + li = get_or_create_link_from_form(link, current_user) fields["links"].append(li) return Incident( @@ -223,14 +202,14 @@ def if_exists_or_none(val: Union[str, Any]): ) -def create_note(self, form: TextForm, current_user: User): +def create_note(self, form: TextForm, current_user: User) -> Note: return Note( text_contents=form.text_contents.data, officer_id=form.officer_id.data, ) -def edit_existing_assignment(assignment, form: AssignmentForm): +def edit_existing_assignment(assignment, form: AssignmentForm) -> Assignment: assignment.star_no = form.star_no.data job = form.job_title.data @@ -249,7 +228,28 @@ def edit_existing_assignment(assignment, form: AssignmentForm): return assignment -def edit_officer_profile(officer, form: EditOfficerForm): +def get_or_create_link_from_form(link_form, current_user: User) -> Union[Link, None]: + link = None + if link_form["url"]: + link = Link.query.filter_by( + author=if_exists_or_none(link_form["author"]), + link_type=if_exists_or_none(link_form["link_type"]), + title=if_exists_or_none(link_form["title"]), + url=if_exists_or_none(link_form["url"]), + ).first() + if not link: + link = Link( + author=if_exists_or_none(link_form["author"]), + description=if_exists_or_none(link_form["description"]), + link_type=if_exists_or_none(link_form["link_type"]), + title=if_exists_or_none(link_form["title"]), + url=if_exists_or_none(link_form["url"]), + ) + db.session.add(link) + return link + + +def edit_officer_profile(officer, form: EditOfficerForm) -> Officer: for field, data in form.data.items(): setattr(officer, field, data) diff --git a/OpenOversight/migrations/versions/2017-12-10-0512_114919b27a9f_initial_migration.py b/OpenOversight/migrations/versions/2017-12-10-0512_114919b27a9f_initial_migration.py index 52e017df9..2562e332c 100644 --- a/OpenOversight/migrations/versions/2017-12-10-0512_114919b27a9f_initial_migration.py +++ b/OpenOversight/migrations/versions/2017-12-10-0512_114919b27a9f_initial_migration.py @@ -21,21 +21,35 @@ def upgrade(): op.drop_table("migrate_version") op.add_column("officers", sa.Column("department_id", sa.Integer(), nullable=True)) op.drop_index("ix_officers_pd_id", table_name="officers") - op.create_foreign_key(None, "officers", "departments", ["department_id"], ["id"]) + op.create_foreign_key( + "officers_department_id_fkey", + "officers", + "departments", + ["department_id"], + ["id"], + ) op.drop_column("officers", "pd_id") op.add_column("unit_types", sa.Column("department_id", sa.Integer(), nullable=True)) - op.create_foreign_key(None, "unit_types", "departments", ["department_id"], ["id"]) + op.create_foreign_key( + "unit_types_department_id_fkey", + "unit_types", + "departments", + ["department_id"], + ["id"], + ) # ### end Alembic commands ### def downgrade(): # ### commands auto generated by Alembic - please adjust! ### - op.drop_constraint(None, "unit_types", type_="foreignkey") + op.drop_constraint( + "unit_types_department_id_fkey", "unit_types", type_="foreignkey" + ) op.drop_column("unit_types", "department_id") op.add_column( "officers", sa.Column("pd_id", sa.INTEGER(), autoincrement=False, nullable=True) ) - op.drop_constraint(None, "officers", type_="foreignkey") + op.drop_constraint("officers_department_id_fkey", "officers", type_="foreignkey") op.create_index("ix_officers_pd_id", "officers", ["pd_id"], unique=False) op.drop_column("officers", "department_id") op.create_table( diff --git a/OpenOversight/migrations/versions/2018-04-12-1504_af933dc1ef93_add_preferred_department_column.py b/OpenOversight/migrations/versions/2018-04-12-1504_af933dc1ef93_add_preferred_department_column.py index 8fda29751..b6772b7a8 100644 --- a/OpenOversight/migrations/versions/2018-04-12-1504_af933dc1ef93_add_preferred_department_column.py +++ b/OpenOversight/migrations/versions/2018-04-12-1504_af933dc1ef93_add_preferred_department_column.py @@ -19,12 +19,14 @@ def upgrade(): # ### commands auto generated by Alembic - please adjust! ### op.add_column("users", sa.Column("dept_pref", sa.Integer(), nullable=True)) - op.create_foreign_key(None, "users", "departments", ["dept_pref"], ["id"]) + op.create_foreign_key( + "users_dept_pref_fkey", "users", "departments", ["dept_pref"], ["id"] + ) # ### end Alembic commands ### def downgrade(): # ### commands auto generated by Alembic - please adjust! ### - op.drop_constraint(None, "users", type_="foreignkey") + op.drop_constraint("users_dept_pref_fkey", "users", type_="foreignkey") op.drop_column("users", "dept_pref") # ### end Alembic commands ### diff --git a/OpenOversight/migrations/versions/2018-04-30-1504_e14a1aa4b58f_add_area_coordinator_columns.py b/OpenOversight/migrations/versions/2018-04-30-1504_e14a1aa4b58f_add_area_coordinator_columns.py index 7c94a5ba1..d6de8a3a1 100644 --- a/OpenOversight/migrations/versions/2018-04-30-1504_e14a1aa4b58f_add_area_coordinator_columns.py +++ b/OpenOversight/migrations/versions/2018-04-30-1504_e14a1aa4b58f_add_area_coordinator_columns.py @@ -22,13 +22,19 @@ def upgrade(): op.add_column( "users", sa.Column("is_area_coordinator", sa.Boolean(), nullable=True) ) - op.create_foreign_key(None, "users", "departments", ["ac_department_id"], ["id"]) + op.create_foreign_key( + "users_ac_department_id_fkey", + "users", + "departments", + ["ac_department_id"], + ["id"], + ) # ### end Alembic commands ### def downgrade(): # ### commands auto generated by Alembic - please adjust! ### - op.drop_constraint(None, "users", type_="foreignkey") + op.drop_constraint("users_ac_department_id_fkey", "users", type_="foreignkey") op.drop_column("users", "is_area_coordinator") op.drop_column("users", "ac_department_id") # ### end Alembic commands ### diff --git a/OpenOversight/migrations/versions/2018-05-04-2105_6065d7cdcbf8_add_officers_to_incidents.py b/OpenOversight/migrations/versions/2018-05-04-2105_6065d7cdcbf8_add_officers_to_incidents.py index caf341023..c603339c0 100644 --- a/OpenOversight/migrations/versions/2018-05-04-2105_6065d7cdcbf8_add_officers_to_incidents.py +++ b/OpenOversight/migrations/versions/2018-05-04-2105_6065d7cdcbf8_add_officers_to_incidents.py @@ -23,12 +23,10 @@ def upgrade(): sa.Column("incident_id", sa.Integer(), nullable=False), sa.Column("officers_id", sa.Integer(), nullable=False), sa.ForeignKeyConstraint( - ["incident_id"], - ["incidents.id"], + ["incident_id"], ["incidents.id"], "incident_officers_incident_id_fkey" ), sa.ForeignKeyConstraint( - ["officers_id"], - ["officers.id"], + ["officers_id"], ["officers.id"], "incident_officers_officers_id_fkey" ), sa.PrimaryKeyConstraint("incident_id", "officers_id"), ) @@ -42,7 +40,11 @@ def upgrade(): type_="foreignkey", ) op.create_foreign_key( - None, "incident_license_plates", "license_plates", ["license_plate_id"], ["id"] + "incident_license_plates_license_plate_id_fkey", + "incident_license_plates", + "license_plates", + ["license_plate_id"], + ["id"], ) op.drop_column("incident_license_plates", "link_id") # ### end Alembic commands ### @@ -54,7 +56,11 @@ def downgrade(): "incident_license_plates", sa.Column("link_id", sa.INTEGER(), autoincrement=False, nullable=False), ) - op.drop_constraint(None, "incident_license_plates", type_="foreignkey") + op.drop_constraint( + "incident_license_plates_license_plate_id_fkey", + "incident_license_plates", + type_="foreignkey", + ) op.create_foreign_key( "incident_license_plates_link_id_fkey", "incident_license_plates", diff --git a/OpenOversight/migrations/versions/2018-05-04-2105_d86feb8fa5d1_add_incidents_table.py b/OpenOversight/migrations/versions/2018-05-04-2105_d86feb8fa5d1_add_incidents_table.py index 20f7c4478..3bd4257db 100644 --- a/OpenOversight/migrations/versions/2018-05-04-2105_d86feb8fa5d1_add_incidents_table.py +++ b/OpenOversight/migrations/versions/2018-05-04-2105_d86feb8fa5d1_add_incidents_table.py @@ -66,8 +66,7 @@ def upgrade(): sa.Column("description", sa.Text(), nullable=True), sa.Column("address_id", sa.Integer(), nullable=True), sa.ForeignKeyConstraint( - ["address_id"], - ["locations.id"], + ["address_id"], ["locations.id"], "incidents_address_id_fkey" ), sa.PrimaryKeyConstraint("id"), ) @@ -82,10 +81,12 @@ def upgrade(): sa.ForeignKeyConstraint( ["incident_id"], ["incidents.id"], + "incident_license_plates_incident_id_fkey", ), sa.ForeignKeyConstraint( ["link_id"], ["license_plates.id"], + "incident_license_plates_license_plate_id_fkey", ), sa.PrimaryKeyConstraint("incident_id", "link_id"), ) @@ -94,12 +95,10 @@ def upgrade(): sa.Column("incident_id", sa.Integer(), nullable=False), sa.Column("link_id", sa.Integer(), nullable=False), sa.ForeignKeyConstraint( - ["incident_id"], - ["incidents.id"], + ["incident_id"], ["incidents.id"], "incident_links_incident_id_fkey" ), sa.ForeignKeyConstraint( - ["link_id"], - ["links.id"], + ["link_id"], ["links.id"], "incident_links_link_id_fkey" ), sa.PrimaryKeyConstraint("incident_id", "link_id"), ) @@ -108,12 +107,10 @@ def upgrade(): sa.Column("officer_id", sa.Integer(), nullable=False), sa.Column("incident_id", sa.Integer(), nullable=False), sa.ForeignKeyConstraint( - ["incident_id"], - ["incidents.id"], + ["incident_id"], ["incidents.id"], "officer_incidents_officer_id_fkey" ), sa.ForeignKeyConstraint( - ["officer_id"], - ["officers.id"], + ["officer_id"], ["officers.id"], "officer_incidents_incident_id_fkey" ), sa.PrimaryKeyConstraint("officer_id", "incident_id"), ) @@ -122,12 +119,10 @@ def upgrade(): sa.Column("officer_id", sa.Integer(), nullable=False), sa.Column("link_id", sa.Integer(), nullable=False), sa.ForeignKeyConstraint( - ["link_id"], - ["links.id"], + ["link_id"], ["links.id"], "officer_links_link_id_fkey" ), sa.ForeignKeyConstraint( - ["officer_id"], - ["officers.id"], + ["officer_id"], ["officers.id"], "officer_links_officer_id_fkey" ), sa.PrimaryKeyConstraint("officer_id", "link_id"), ) diff --git a/OpenOversight/migrations/versions/2018-05-10-2005_ca95c047bf42_add_department_column_to_incidents.py b/OpenOversight/migrations/versions/2018-05-10-2005_ca95c047bf42_add_department_column_to_incidents.py index ceb73edc2..04d3e1236 100644 --- a/OpenOversight/migrations/versions/2018-05-10-2005_ca95c047bf42_add_department_column_to_incidents.py +++ b/OpenOversight/migrations/versions/2018-05-10-2005_ca95c047bf42_add_department_column_to_incidents.py @@ -19,12 +19,18 @@ def upgrade(): # ### commands auto generated by Alembic - please adjust! ### op.add_column("incidents", sa.Column("department_id", sa.Integer(), nullable=True)) - op.create_foreign_key(None, "incidents", "departments", ["department_id"], ["id"]) + op.create_foreign_key( + "incidents_department_id_fkey", + "incidents", + "departments", + ["department_id"], + ["id"], + ) # ### end Alembic commands ### def downgrade(): # ### commands auto generated by Alembic - please adjust! ### - op.drop_constraint(None, "incidents", type_="foreignkey") + op.drop_constraint("incidents_department_id_fkey", "incidents", type_="foreignkey") op.drop_column("incidents", "department_id") # ### end Alembic commands ### diff --git a/OpenOversight/migrations/versions/2018-05-15-1705_f4a41e328a06_add_columns_to_incidents_and_links.py b/OpenOversight/migrations/versions/2018-05-15-1705_f4a41e328a06_add_columns_to_incidents_and_links.py index a1fa0b1b6..3947cb1ce 100644 --- a/OpenOversight/migrations/versions/2018-05-15-1705_f4a41e328a06_add_columns_to_incidents_and_links.py +++ b/OpenOversight/migrations/versions/2018-05-15-1705_f4a41e328a06_add_columns_to_incidents_and_links.py @@ -19,24 +19,26 @@ def upgrade(): # ### commands auto generated by Alembic - please adjust! ### op.add_column("incidents", sa.Column("user_id", sa.Integer(), nullable=True)) - op.create_foreign_key(None, "incidents", "users", ["user_id"], ["id"]) + op.create_foreign_key( + "incidents_user_id_fkey", "incidents", "users", ["user_id"], ["id"] + ) op.add_column("links", sa.Column("author", sa.String(length=255), nullable=True)) op.add_column("links", sa.Column("description", sa.Text(), nullable=True)) op.add_column("links", sa.Column("title", sa.String(length=100), nullable=True)) op.add_column("links", sa.Column("user_id", sa.Integer(), nullable=True)) op.create_index(op.f("ix_links_title"), "links", ["title"], unique=False) - op.create_foreign_key(None, "links", "users", ["user_id"], ["id"]) + op.create_foreign_key("links_user_id_fkey", "links", "users", ["user_id"], ["id"]) # ### end Alembic commands ### def downgrade(): # ### commands auto generated by Alembic - please adjust! ### - op.drop_constraint(None, "links", type_="foreignkey") + op.drop_constraint("links_user_id_fkey", "links", type_="foreignkey") op.drop_index(op.f("ix_links_title"), table_name="links") op.drop_column("links", "user_id") op.drop_column("links", "title") op.drop_column("links", "description") op.drop_column("links", "author") - op.drop_constraint(None, "incidents", type_="foreignkey") + op.drop_constraint("incidents_user_id_fkey", "incidents", type_="foreignkey") op.drop_column("incidents", "user_id") # ### end Alembic commands ### diff --git a/OpenOversight/migrations/versions/2018-05-15-1905_bd0398fe4aab_rename_user_id_to_creator_id_in_incident.py b/OpenOversight/migrations/versions/2018-05-15-1905_bd0398fe4aab_rename_user_id_to_creator_id_in_incident.py index ddefaeeec..22322229f 100644 --- a/OpenOversight/migrations/versions/2018-05-15-1905_bd0398fe4aab_rename_user_id_to_creator_id_in_incident.py +++ b/OpenOversight/migrations/versions/2018-05-15-1905_bd0398fe4aab_rename_user_id_to_creator_id_in_incident.py @@ -25,8 +25,16 @@ def upgrade(): "incidents", sa.Column("last_updated_id", sa.Integer(), nullable=True) ) op.drop_constraint("incidents_user_id_fkey", "incidents", type_="foreignkey") - op.create_foreign_key(None, "incidents", "users", ["creator_id"], ["id"]) - op.create_foreign_key(None, "incidents", "users", ["last_updated_id"], ["id"]) + op.create_foreign_key( + "incidents_creator_id_fkey", "incidents", "users", ["creator_id"], ["id"] + ) + op.create_foreign_key( + "incidents_last_updated_id_fkey", + "incidents", + "users", + ["last_updated_id"], + ["id"], + ) # ### end Alembic commands ### @@ -35,8 +43,10 @@ def downgrade(): op.alter_column( "incidents", "creator_id", new_column_name="user_id", existing_type=sa.Integer ) - op.drop_constraint(None, "incidents", type_="foreignkey") - op.drop_constraint(None, "incidents", type_="foreignkey") + op.drop_constraint("incidents_creator_id_fkey", "incidents", type_="foreignkey") + op.drop_constraint( + "incidents_last_updated_id_fkey", "incidents", type_="foreignkey" + ) op.create_foreign_key( "incidents_user_id_fkey", "incidents", "users", ["user_id"], ["id"] ) diff --git a/OpenOversight/migrations/versions/2018-06-06-1906_2040f0c804b0_create_notes_table.py b/OpenOversight/migrations/versions/2018-06-06-1906_2040f0c804b0_create_notes_table.py index 5198e605e..80de388bc 100644 --- a/OpenOversight/migrations/versions/2018-06-06-1906_2040f0c804b0_create_notes_table.py +++ b/OpenOversight/migrations/versions/2018-06-06-1906_2040f0c804b0_create_notes_table.py @@ -27,13 +27,9 @@ def upgrade(): sa.Column("date_created", sa.DateTime(), nullable=True), sa.Column("date_updated", sa.DateTime(), nullable=True), sa.ForeignKeyConstraint( - ["officer_id"], - ["officers.id"], - ), - sa.ForeignKeyConstraint( - ["user_id"], - ["users.id"], + ["officer_id"], ["officers.id"], "notes_officer_id_fkey" ), + sa.ForeignKeyConstraint(["user_id"], ["users.id"], "notes_user_id_fkey"), sa.PrimaryKeyConstraint("id"), ) # ### end Alembic commands ### diff --git a/OpenOversight/migrations/versions/2018-06-07-1506_4a490771dda1_add_original_image_fk.py b/OpenOversight/migrations/versions/2018-06-07-1506_4a490771dda1_add_original_image_fk.py index b31e51917..81dd24a6a 100644 --- a/OpenOversight/migrations/versions/2018-06-07-1506_4a490771dda1_add_original_image_fk.py +++ b/OpenOversight/migrations/versions/2018-06-07-1506_4a490771dda1_add_original_image_fk.py @@ -33,7 +33,7 @@ def upgrade(): use_alter=True, ) op.create_foreign_key( - None, + "raw_images_original_image_id_fkey", "faces", "raw_images", ["fk_face_original_image_id"], @@ -47,7 +47,7 @@ def upgrade(): def downgrade(): # ### commands auto generated by Alembic - please adjust! ### - op.drop_constraint(None, "faces", type_="foreignkey") + op.drop_constraint("raw_images_original_image_id_fkey", "faces", type_="foreignkey") op.drop_constraint("fk_face_image_id", "faces", type_="foreignkey") op.create_foreign_key( "faces_img_id_fkey", "faces", "raw_images", ["img_id"], ["id"] diff --git a/OpenOversight/migrations/versions/2018-06-07-1806_8ce7926aa132_add_explicit_ondelete_for_notes.py b/OpenOversight/migrations/versions/2018-06-07-1806_8ce7926aa132_add_explicit_ondelete_for_notes.py index a081a7775..1fcc8f696 100644 --- a/OpenOversight/migrations/versions/2018-06-07-1806_8ce7926aa132_add_explicit_ondelete_for_notes.py +++ b/OpenOversight/migrations/versions/2018-06-07-1806_8ce7926aa132_add_explicit_ondelete_for_notes.py @@ -20,18 +20,28 @@ def upgrade(): op.drop_constraint("notes_officer_id_fkey", "notes", type_="foreignkey") op.drop_constraint("notes_creator_id_fkey", "notes", type_="foreignkey") op.create_foreign_key( - None, "notes", "officers", ["officer_id"], ["id"], ondelete="CASCADE" + "notes_officer_id_fkey", + "notes", + "officers", + ["officer_id"], + ["id"], + ondelete="CASCADE", ) op.create_foreign_key( - None, "notes", "users", ["creator_id"], ["id"], ondelete="SET NULL" + "notes_creator_id_fkey", + "notes", + "users", + ["creator_id"], + ["id"], + ondelete="SET NULL", ) # ### end Alembic commands ### def downgrade(): # ### commands auto generated by Alembic - please adjust! ### - op.drop_constraint(None, "notes", type_="foreignkey") - op.drop_constraint(None, "notes", type_="foreignkey") + op.drop_constraint("notes_officer_id_fkey", "notes", type_="foreignkey") + op.drop_constraint("notes_creator_id_fkey", "notes", type_="foreignkey") op.create_foreign_key( "notes_creator_id_fkey", "notes", "users", ["creator_id"], ["id"] ) diff --git a/OpenOversight/migrations/versions/2018-06-07-1806_cfc5f3fd5efe_rename_user_id_to_creator_id_in_notes.py b/OpenOversight/migrations/versions/2018-06-07-1806_cfc5f3fd5efe_rename_user_id_to_creator_id_in_notes.py index 2a8f27dc0..0d2efb81c 100644 --- a/OpenOversight/migrations/versions/2018-06-07-1806_cfc5f3fd5efe_rename_user_id_to_creator_id_in_notes.py +++ b/OpenOversight/migrations/versions/2018-06-07-1806_cfc5f3fd5efe_rename_user_id_to_creator_id_in_notes.py @@ -20,7 +20,9 @@ def upgrade(): # ### commands auto generated by Alembic - please adjust! ### op.add_column("notes", sa.Column("creator_id", sa.Integer(), nullable=True)) op.drop_constraint("notes_user_id_fkey", "notes", type_="foreignkey") - op.create_foreign_key(None, "notes", "users", ["creator_id"], ["id"]) + op.create_foreign_key( + "notes_creator_id_fkey", "notes", "users", ["creator_id"], ["id"] + ) op.drop_column("notes", "user_id") # ### end Alembic commands ### @@ -30,7 +32,7 @@ def downgrade(): op.add_column( "notes", sa.Column("user_id", sa.INTEGER(), autoincrement=False, nullable=True) ) - op.drop_constraint(None, "notes", type_="foreignkey") + op.drop_constraint("notes_creator_id_fkey", "notes", type_="foreignkey") op.create_foreign_key("notes_user_id_fkey", "notes", "users", ["user_id"], ["id"]) op.drop_column("notes", "creator_id") # ### end Alembic commands ### diff --git a/OpenOversight/migrations/versions/2018-08-11-2008_0ed957db0058_add_description_to_officers.py b/OpenOversight/migrations/versions/2018-08-11-2008_0ed957db0058_add_description_to_officers.py index 2ddfe3028..d2e95c0c6 100644 --- a/OpenOversight/migrations/versions/2018-08-11-2008_0ed957db0058_add_description_to_officers.py +++ b/OpenOversight/migrations/versions/2018-08-11-2008_0ed957db0058_add_description_to_officers.py @@ -26,8 +26,18 @@ def upgrade(): sa.Column("officer_id", sa.Integer(), nullable=True), sa.Column("date_created", sa.DateTime(), nullable=True), sa.Column("date_updated", sa.DateTime(), nullable=True), - sa.ForeignKeyConstraint(["creator_id"], ["users.id"], ondelete="SET NULL"), - sa.ForeignKeyConstraint(["officer_id"], ["officers.id"], ondelete="CASCADE"), + sa.ForeignKeyConstraint( + ["creator_id"], + ["users.id"], + "descriptions_creator_id_fkey", + ondelete="SET NULL", + ), + sa.ForeignKeyConstraint( + ["officer_id"], + ["officers.id"], + "descriptions_officer_id_fkey", + ondelete="CASCADE", + ), sa.PrimaryKeyConstraint("id"), ) op.alter_column("notes", "note", new_column_name="text_contents") diff --git a/OpenOversight/migrations/versions/2018-08-13-1308_9e2827dae28c_add_cascading_foreign_key_constraint_to_.py b/OpenOversight/migrations/versions/2018-08-13-1308_9e2827dae28c_add_cascading_foreign_key_constraint_to_.py index e40ce1e3b..983eb2fe4 100644 --- a/OpenOversight/migrations/versions/2018-08-13-1308_9e2827dae28c_add_cascading_foreign_key_constraint_to_.py +++ b/OpenOversight/migrations/versions/2018-08-13-1308_9e2827dae28c_add_cascading_foreign_key_constraint_to_.py @@ -19,14 +19,19 @@ def upgrade(): # ### commands auto generated by Alembic - please adjust! ### op.drop_constraint("assignments_officer_id_fkey", "assignments", type_="foreignkey") op.create_foreign_key( - None, "assignments", "officers", ["officer_id"], ["id"], ondelete="CASCADE" + "assignments_officer_id_fkey", + "assignments", + "officers", + ["officer_id"], + ["id"], + ondelete="CASCADE", ) # ### end Alembic commands ### def downgrade(): # ### commands auto generated by Alembic - please adjust! ### - op.drop_constraint(None, "assignments", type_="foreignkey") + op.drop_constraint("assignments_officer_id_fkey", "assignments", type_="foreignkey") op.create_foreign_key( "assignments_officer_id_fkey", "assignments", "officers", ["officer_id"], ["id"] ) diff --git a/OpenOversight/migrations/versions/2019-01-25-1501_770ed51b4e16_add_salaries_table.py b/OpenOversight/migrations/versions/2019-01-25-1501_770ed51b4e16_add_salaries_table.py index 30cd809f7..811b75483 100644 --- a/OpenOversight/migrations/versions/2019-01-25-1501_770ed51b4e16_add_salaries_table.py +++ b/OpenOversight/migrations/versions/2019-01-25-1501_770ed51b4e16_add_salaries_table.py @@ -26,7 +26,12 @@ def upgrade(): sa.Column("overtime_pay", sa.Numeric(), nullable=True), sa.Column("year", sa.Integer(), nullable=False), sa.Column("is_fiscal_year", sa.Boolean(), nullable=False), - sa.ForeignKeyConstraint(["officer_id"], ["officers.id"], ondelete="CASCADE"), + sa.ForeignKeyConstraint( + ["officer_id"], + ["officers.id"], + "salaries_officer_id_fkey", + ondelete="CASCADE", + ), sa.PrimaryKeyConstraint("id"), ) op.create_index( diff --git a/OpenOversight/migrations/versions/2019-04-20-1704_3015d1dd9eb4_add_jobs_table.py b/OpenOversight/migrations/versions/2019-04-20-1704_3015d1dd9eb4_add_jobs_table.py index 54e414e25..313cafd18 100644 --- a/OpenOversight/migrations/versions/2019-04-20-1704_3015d1dd9eb4_add_jobs_table.py +++ b/OpenOversight/migrations/versions/2019-04-20-1704_3015d1dd9eb4_add_jobs_table.py @@ -26,8 +26,7 @@ def upgrade(): sa.Column("order", sa.Integer(), nullable=True), sa.Column("department_id", sa.Integer(), nullable=True), sa.ForeignKeyConstraint( - ["department_id"], - ["departments.id"], + ["department_id"], ["departments.id"], "jobs_department_id_fkey" ), sa.PrimaryKeyConstraint("id"), sa.UniqueConstraint( diff --git a/OpenOversight/tests/routes/test_descriptions.py b/OpenOversight/tests/routes/test_descriptions.py index 7d8569f80..75ed23669 100644 --- a/OpenOversight/tests/routes/test_descriptions.py +++ b/OpenOversight/tests/routes/test_descriptions.py @@ -8,6 +8,7 @@ from OpenOversight.app.models.database import Description, Officer, User, db from OpenOversight.app.utils.constants import ENCODING_UTF_8 from OpenOversight.tests.conftest import AC_DEPT +from OpenOversight.tests.constants import ADMIN_USER_EMAIL from OpenOversight.tests.routes.route_helpers import login_ac, login_admin, login_user @@ -420,9 +421,11 @@ def test_acs_cannot_get_edit_form_for_their_non_dept(mockdata, client, session): def test_users_can_see_descriptions(mockdata, client, session): with current_app.test_request_context(): + admin = User.query.filter_by(email=ADMIN_USER_EMAIL).first() officer = Officer.query.first() text_contents = "You can see me" description = Description( + created_by=admin.id, text_contents=text_contents, officer_id=officer.id, )