diff --git a/setup.cfg b/setup.cfg index 527ffbb453..a8d1042fe1 100644 --- a/setup.cfg +++ b/setup.cfg @@ -43,7 +43,7 @@ install_requires = flask-fs2[swift, s3]==0.7.27 flask-jwt-extended==4.6.0 flask-migrate==4.0.7 - flask-socketio==5.4.0 + flask-socketio==5.4.1 flask==3.0.3 gazu==0.10.15 gevent-websocket==0.10.1 @@ -56,7 +56,7 @@ install_requires = matterhook==0.2 meilisearch==0.31.5 numpy==2.0.1; python_version == '3.9' - numpy==2.1.1; python_version >= '3.10' + numpy==2.1.2; python_version >= '3.10' opencv-python==4.10.0.84 OpenTimelineIO==0.17.0 OpenTimelineIO-Plugins==0.17.0 @@ -70,7 +70,7 @@ install_requires = python-slugify==8.0.4 python-socketio==5.11.4 pytz==2024.2 - redis==5.1.0 + redis==5.1.1 requests==2.32.3 rq==1.16.2 slackclient==2.9.4 @@ -103,12 +103,12 @@ test = monitoring = prometheus-flask-exporter==0.23.1 pygelf==0.4.2 - sentry-sdk==2.14.0 + sentry-sdk==2.16.0 lint = autoflake==2.3.1 - black==24.8.0 - pre-commit==3.8.0; python_version >= '3.9' + black==24.10.0 + pre-commit==4.0.0 [options.entry_points] console_scripts = diff --git a/tests/services/test_names_service.py b/tests/services/test_names_service.py index d3627845f4..349698f0dc 100644 --- a/tests/services/test_names_service.py +++ b/tests/services/test_names_service.py @@ -26,12 +26,8 @@ def setUp(self): self.shot_task = self.generate_fixture_shot_task().serialize() def test_get_full_entity_name(self): - (asset_name, episode_id) = names_service.get_full_entity_name( - self.asset.id - ) - (shot_name, episode_id) = names_service.get_full_entity_name( - self.shot.id - ) + asset_name, _, _ = names_service.get_full_entity_name(self.asset.id) + shot_name, _, _ = names_service.get_full_entity_name(self.shot.id) self.assertEqual(asset_name, "Props / Tree") self.assertEqual(shot_name, "E01 / S01 / P01") diff --git a/zou/app/blueprints/chats/resources.py b/zou/app/blueprints/chats/resources.py index cd9e6a2533..24073bd789 100644 --- a/zou/app/blueprints/chats/resources.py +++ b/zou/app/blueprints/chats/resources.py @@ -116,7 +116,9 @@ def post(self, entity_id): chat = chats_service.get_chat(entity_id) if person["id"] not in chat["participants"]: - raise WrongParameterException("You are not a participant of this chat") + raise WrongParameterException( + "You are not a participant of this chat" + ) return ( chats_service.create_chat_message( diff --git a/zou/app/blueprints/crud/day_off.py b/zou/app/blueprints/crud/day_off.py index b69bbd6f6d..032e1c2392 100644 --- a/zou/app/blueprints/crud/day_off.py +++ b/zou/app/blueprints/crud/day_off.py @@ -21,7 +21,9 @@ def check_creation_integrity(self, data): if time_spents_service.get_day_offs_between( data["date"], data["end_date"], data["person_id"] ): - raise WrongParameterException("Day off already exists for this period") + raise WrongParameterException( + "Day off already exists for this period" + ) return data def post_creation(self, instance): @@ -67,5 +69,7 @@ def pre_update(self, instance_dict, data): data.get("person_id", instance_dict["person_id"]), exclude_id=instance_dict["id"], ): - raise WrongParameterException("Day off already exists for this period") + raise WrongParameterException( + "Day off already exists for this period" + ) return data diff --git a/zou/app/blueprints/crud/entity_type.py b/zou/app/blueprints/crud/entity_type.py index 235db77eba..86ebffe542 100644 --- a/zou/app/blueprints/crud/entity_type.py +++ b/zou/app/blueprints/crud/entity_type.py @@ -7,7 +7,6 @@ from zou.app.services.exception import WrongParameterException - class EntityTypesResource(BaseModelsResource): def __init__(self): BaseModelsResource.__init__(self, EntityType) @@ -32,11 +31,9 @@ def post_creation(self, instance): return instance.serialize(relations=True) def check_creation_integrity(self, data): - entity_type = ( - EntityType.query - .filter(EntityType.name.ilike(data.get("name", ""))) - .first() - ) + entity_type = EntityType.query.filter( + EntityType.name.ilike(data.get("name", "")) + ).first() if entity_type is not None: raise WrongParameterException( "Entity type with this name already exists" diff --git a/zou/app/blueprints/crud/project.py b/zou/app/blueprints/crud/project.py index ab1c0be230..b155151ba3 100644 --- a/zou/app/blueprints/crud/project.py +++ b/zou/app/blueprints/crud/project.py @@ -71,7 +71,9 @@ def update_data(self, data): or data["preview_background_file_id"] not in data["preview_background_files_ids"] ): - raise WrongParameterException("Invalid preview_background_file_id") + raise WrongParameterException( + "Invalid preview_background_file_id" + ) return data def post_creation(self, project): @@ -131,7 +133,9 @@ def pre_update(self, project_dict, data): data["preview_background_file_id"] not in preview_background_files_ids ): - raise WrongParameterException("Invalid preview_background_file_id") + raise WrongParameterException( + "Invalid preview_background_file_id" + ) return data diff --git a/zou/app/blueprints/crud/schedule_item.py b/zou/app/blueprints/crud/schedule_item.py index c3dae3e187..a7e39aa908 100644 --- a/zou/app/blueprints/crud/schedule_item.py +++ b/zou/app/blueprints/crud/schedule_item.py @@ -17,7 +17,9 @@ def check_creation_integrity(self, data): object_id=data.get("object_id", None), ) if schedule_item is not None: - raise WrongParameterException("A similar schedule item already exists") + raise WrongParameterException( + "A similar schedule item already exists" + ) return schedule_item diff --git a/zou/app/blueprints/export/csv/playlists.py b/zou/app/blueprints/export/csv/playlists.py index 44d6c27965..2637dffb8d 100644 --- a/zou/app/blueprints/export/csv/playlists.py +++ b/zou/app/blueprints/export/csv/playlists.py @@ -100,7 +100,7 @@ def build_headers(self, playlist, project, episode=None): def build_row(self, shot): entity = entities_service.get_entity(shot["entity_id"]) - name, _ = names_service.get_full_entity_name(shot["entity_id"]) + name, _, _ = names_service.get_full_entity_name(shot["entity_id"]) preview_file = files_service.get_preview_file(shot["preview_file_id"]) task = tasks_service.get_task(preview_file["task_id"]) task_type = self.task_type_map[task["task_type_id"]] diff --git a/zou/app/blueprints/export/csv/time_spents.py b/zou/app/blueprints/export/csv/time_spents.py index f724f902c5..212e272fa5 100644 --- a/zou/app/blueprints/export/csv/time_spents.py +++ b/zou/app/blueprints/export/csv/time_spents.py @@ -72,7 +72,7 @@ def build_row(self, time_spent_row): person_last_name, ) = time_spent_row if entity_type_name == "Shot": - entity_name, _ = names_service.get_full_entity_name(entity_id) + entity_name, _, _ = names_service.get_full_entity_name(entity_id) date = "" if time_spent.date is not None: diff --git a/zou/app/blueprints/user/resources.py b/zou/app/blueprints/user/resources.py index d1340fb34a..37ace5bf6a 100644 --- a/zou/app/blueprints/user/resources.py +++ b/zou/app/blueprints/user/resources.py @@ -865,14 +865,13 @@ def get(self): ) return notifications - def get_arguments(self): return ( self.get_text_parameter("after"), self.get_text_parameter("before"), self.get_text_parameter("task_type_id"), self.get_text_parameter("task_status_id"), - self.get_text_parameter("type") + self.get_text_parameter("type"), ) diff --git a/zou/app/models/subscription.py b/zou/app/models/subscription.py index 6fec1ae7fc..2900a33f82 100644 --- a/zou/app/models/subscription.py +++ b/zou/app/models/subscription.py @@ -22,10 +22,10 @@ class Subscription(db.Model, BaseMixin, SerializerMixin): entity_id = db.Column( UUIDType(binary=False), db.ForeignKey("entity.id"), index=True - ) # Deprecated + ) # Deprecated task_type_id = db.Column( UUIDType(binary=False), db.ForeignKey("task_type.id"), index=True - ) # Deprecated + ) # Deprecated __table_args__ = ( db.UniqueConstraint( diff --git a/zou/app/models/task.py b/zou/app/models/task.py index 344b3646c3..a493ed2a8c 100644 --- a/zou/app/models/task.py +++ b/zou/app/models/task.py @@ -33,11 +33,7 @@ class Task(db.Model, BaseMixin, SerializerMixin): description = db.Column(db.Text()) priority = db.Column(db.Integer, default=0) - difficulty = db.Column( - db.Integer, - db.CheckConstraint('difficulty > 0 AND difficulty < 6'), - default=3, - ) + difficulty = db.Column(db.Integer, default=3, nullable=False) duration = db.Column(db.Float, default=0) estimation = db.Column(db.Float, default=0) completion_rate = db.Column(db.Integer, default=0) @@ -75,6 +71,9 @@ class Task(db.Model, BaseMixin, SerializerMixin): db.UniqueConstraint( "name", "project_id", "task_type_id", "entity_id", name="task_uc" ), + db.CheckConstraint( + "difficulty > 0 AND difficulty < 6", name="check_difficulty" + ), ) def assignees_as_string(self): diff --git a/zou/app/services/assets_service.py b/zou/app/services/assets_service.py index cd8a921b2f..fb0f328f57 100644 --- a/zou/app/services/assets_service.py +++ b/zou/app/services/assets_service.py @@ -104,8 +104,8 @@ def get_assets(criterions={}, is_admin=False): if "is_shared" in criterions: if not is_admin: - query = ( - query.join(Project).filter(user_service.build_team_filter()) + query = query.join(Project).filter( + user_service.build_team_filter() ) if episode_id is not None: @@ -725,7 +725,7 @@ def set_shared_assets( project_id=None, asset_type_id=None, asset_ids=None, - with_events=False + with_events=False, ): """ Set all assets of a project to is_shared=True or False. diff --git a/zou/app/services/chats_service.py b/zou/app/services/chats_service.py index b1ebcfe44e..64dcaba18d 100644 --- a/zou/app/services/chats_service.py +++ b/zou/app/services/chats_service.py @@ -213,7 +213,7 @@ def get_chats_for_person(person_id): result = [] for chat_model, project_id, preview_file_id in chats: chat = chat_model.present() - chat["entity_name"], _ = names_service.get_full_entity_name( + chat["entity_name"], _, _ = names_service.get_full_entity_name( chat["object_id"] ) chat["project_id"] = project_id diff --git a/zou/app/services/emails_service.py b/zou/app/services/emails_service.py index d1bb7bfae5..80645bcc8b 100644 --- a/zou/app/services/emails_service.py +++ b/zou/app/services/emails_service.py @@ -296,7 +296,7 @@ def get_task_descriptors(person_id, task): project = projects_service.get_project(task["project_id"]) task_type = tasks_service.get_task_type(task["task_type_id"]) entity = entities_service.get_entity(task["entity_id"]) - (entity_name, episode_id) = names_service.get_full_entity_name( + entity_name, episode_id, _ = names_service.get_full_entity_name( entity["id"] ) diff --git a/zou/app/services/news_service.py b/zou/app/services/news_service.py index 5e1425f460..9b7cd28f14 100644 --- a/zou/app/services/news_service.py +++ b/zou/app/services/news_service.py @@ -185,7 +185,7 @@ def get_last_news_for_project( preview_file_annotations, entity_preview_file_id, ) in news_list: - (full_entity_name, episode_id) = names_service.get_full_entity_name( + full_entity_name, episode_id, _ = names_service.get_full_entity_name( task_entity_id ) diff --git a/zou/app/services/preview_files_service.py b/zou/app/services/preview_files_service.py index d51462bb5f..b822e6069a 100644 --- a/zou/app/services/preview_files_service.py +++ b/zou/app/services/preview_files_service.py @@ -561,7 +561,7 @@ def get_running_preview_files(): result = preview_file.serialize() result["project_id"] = fields.serialize_value(project_id) result["task_type_id"] = fields.serialize_value(task_type_id) - (result["full_entity_name"], _) = names_service.get_full_entity_name( + result["full_entity_name"], _, _ = names_service.get_full_entity_name( entity_id ) results.append(result) diff --git a/zou/app/services/shots_service.py b/zou/app/services/shots_service.py index 85f8747edd..efe2b8ffab 100644 --- a/zou/app/services/shots_service.py +++ b/zou/app/services/shots_service.py @@ -1481,7 +1481,7 @@ def get_weighted_quota_shots_between( for entity, task_duration, duration in query_shots: shot = entity.serialize() if shot["id"] not in already_listed: - full_name, _ = names_service.get_full_entity_name(shot["id"]) + full_name, _, _ = names_service.get_full_entity_name(shot["id"]) shot["full_name"] = full_name shot["weight"] = round(duration / task_duration, 2) or 0 shots.append(shot) @@ -1528,7 +1528,7 @@ def get_weighted_quota_shots_between( business_days = ( date_helpers.get_business_days(task_start, task_end) + 1 ) - full_name, _ = names_service.get_full_entity_name(shot["id"]) + full_name, _, _ = names_service.get_full_entity_name(shot["id"]) shot["full_name"] = full_name multiplicator = 1 if task_start >= start and task_end <= end: @@ -1586,7 +1586,7 @@ def get_raw_quota_shots_between( for entity in query_shots: shot = entity.serialize() - full_name, _ = names_service.get_full_entity_name(shot["id"]) + full_name, _, _ = names_service.get_full_entity_name(shot["id"]) shot["full_name"] = full_name shot["weight"] = 1 shots.append(shot) diff --git a/zou/app/services/user_service.py b/zou/app/services/user_service.py index dfe9d1c109..bb9077a9da 100644 --- a/zou/app/services/user_service.py +++ b/zou/app/services/user_service.py @@ -1210,6 +1210,7 @@ def get_unread_notifications_count(notification_id=None): from sqlalchemy import and_, func + def get_last_notifications( notification_id=None, after=None, @@ -1233,11 +1234,12 @@ def get_last_notifications( .join(Author, Author.id == Notification.author_id) .join(Task, Task.id == Notification.task_id) .join(Project, Project.id == Task.project_id) - .outerjoin(Subscription, + .outerjoin( + Subscription, and_( Subscription.task_id == Task.id, - Subscription.person_id == current_user["id"] - ) + Subscription.person_id == current_user["id"], + ), ) .outerjoin(Comment, Comment.id == Notification.comment_id) .add_columns( @@ -1303,11 +1305,9 @@ def get_last_notifications( subscription_id, role, ) in notifications: - ( - full_entity_name, - episode_id, - entity_preview_file_id - ) = names_service.get_full_entity_name(task_entity_id) + (full_entity_name, episode_id, entity_preview_file_id) = ( + names_service.get_full_entity_name(task_entity_id) + ) preview_file_id = None mentions = [] department_mentions = [] diff --git a/zou/migrations/versions/8e67c183bed7_add_preference_fields.py b/zou/migrations/versions/8e67c183bed7_add_preference_fields.py index 3094125786..a0874562d8 100644 --- a/zou/migrations/versions/8e67c183bed7_add_preference_fields.py +++ b/zou/migrations/versions/8e67c183bed7_add_preference_fields.py @@ -5,47 +5,67 @@ Create Date: 2024-09-26 10:48:45.678791 """ + from alembic import op import sqlalchemy as sa -import sqlalchemy_utils # revision identifiers, used by Alembic. -revision = '8e67c183bed7' -down_revision = '59a7445a966c' +revision = "8e67c183bed7" +down_revision = "59a7445a966c" branch_labels = None depends_on = None def upgrade(): # ### commands auto generated by Alembic - please adjust! ### - with op.batch_alter_table('organisation', schema=None) as batch_op: - batch_op.add_column(sa.Column('dark_theme_by_default', sa.Boolean(), nullable=True)) - batch_op.add_column(sa.Column('format_duration_in_hours', sa.Boolean(), nullable=True)) + with op.batch_alter_table("organisation", schema=None) as batch_op: + batch_op.add_column( + sa.Column("dark_theme_by_default", sa.Boolean(), nullable=True) + ) + batch_op.add_column( + sa.Column("format_duration_in_hours", sa.Boolean(), nullable=True) + ) - with op.batch_alter_table('project', schema=None) as batch_op: - batch_op.add_column(sa.Column('is_publish_default_for_artists', sa.Boolean(), nullable=True)) - batch_op.add_column(sa.Column('hd_bitrate_compression', sa.Integer(), nullable=True)) - batch_op.add_column(sa.Column('ld_bitrate_compression', sa.Integer(), nullable=True)) + with op.batch_alter_table("project", schema=None) as batch_op: + batch_op.add_column( + sa.Column( + "is_publish_default_for_artists", sa.Boolean(), nullable=True + ) + ) + batch_op.add_column( + sa.Column("hd_bitrate_compression", sa.Integer(), nullable=True) + ) + batch_op.add_column( + sa.Column("ld_bitrate_compression", sa.Integer(), nullable=True) + ) - with op.batch_alter_table('task', schema=None) as batch_op: - batch_op.add_column(sa.Column('difficulty', sa.Integer(), nullable=True)) + with op.batch_alter_table("task", schema=None) as batch_op: + batch_op.add_column( + sa.Column( + "difficulty", sa.Integer(), nullable=False, server_default="3" + ) + ) + batch_op.create_check_constraint( + "check_difficulty", "difficulty > 0 AND difficulty < 6" + ) # ### end Alembic commands ### def downgrade(): # ### commands auto generated by Alembic - please adjust! ### - with op.batch_alter_table('task', schema=None) as batch_op: - batch_op.drop_column('difficulty') + with op.batch_alter_table("task", schema=None) as batch_op: + batch_op.drop_constraint("check_difficulty", type_="check") + batch_op.drop_column("difficulty") - with op.batch_alter_table('project', schema=None) as batch_op: - batch_op.drop_column('ld_bitrate_compression') - batch_op.drop_column('hd_bitrate_compression') - batch_op.drop_column('is_publish_default_for_artists') + with op.batch_alter_table("project", schema=None) as batch_op: + batch_op.drop_column("ld_bitrate_compression") + batch_op.drop_column("hd_bitrate_compression") + batch_op.drop_column("is_publish_default_for_artists") - with op.batch_alter_table('organisation', schema=None) as batch_op: - batch_op.drop_column('format_duration_in_hours') - batch_op.drop_column('dark_theme_by_default') + with op.batch_alter_table("organisation", schema=None) as batch_op: + batch_op.drop_column("format_duration_in_hours") + batch_op.drop_column("dark_theme_by_default") # ### end Alembic commands ###