def build_playlist_job(playlist, email): """ Build playlist file (concatenate all mnovie previews). This function is aimed at being runned as a job in a job queue. """ from zou.app import app, mail with app.app_context(): job = None try: job = build_playlist_movie_file(playlist) except: if job is not None: end_build_job(playlist, job) raise message_text = """ Your playlist %s is available at: https://%s/api/data/playlists/%s/jobs/%s/build/mp4 """ % ( playlist["name"], config.DOMAIN_NAME, playlist["id"], job["id"], ) message = Message( body=message_text, subject="CGWire playlist download", recipients=[email], ) mail.send(message)
def build_playlist_job(playlist, shots, params, email, full, remote): """ Build playlist file (concatenate all movie previews). This function is aimed at being runned as a job in a job queue. """ from zou.app import app, mail with app.app_context(): job = build_playlist_movie_file(playlist, shots, params, full, remote) # Just in case, since rq jobs which encounter an error raise an # exception in order to be flagged as failed. if job["status"] == "succeeded": message_text = """ Your playlist %s is available at: https://%s/api/data/playlists/%s/jobs/%s/build/mp4 """ % ( playlist["name"], config.DOMAIN_NAME, playlist["id"], job["id"], ) message = Message( body=message_text, subject="CGWire playlist download", recipients=[email], ) mail.send(message)
def test_get_month_time_spents(self): with app.app_context(): tasks = time_spents_service.get_month_time_spents( self.person_id, "2018", "5") self.assertEqual(len(tasks), 1) self.assertEqual(tasks[0]["entity_name"], "Tree") self.assertEqual(tasks[0]["duration"], 600)
def test_get_day_table(self): with app.app_context(): day_table = time_spents_service.get_day_table("2018", "06") self.assertEqual(day_table["3"][self.person_id], 600) self.assertEqual(day_table["4"][self.person_id], 800) self.assertEqual(day_table["3"][self.user_id], 600) self.assertTrue("1" not in day_table)
def download_preview_from_another_instance(preview_file): """ Download all files link to preview file entry: orginal file and variants. """ from zou.app import app print("download preview %s (%s)" % (preview_file.id, preview_file.extension)) is_movie = preview_file.extension == "mp4" is_picture = preview_file.extension == "png" is_file = not is_movie and not is_picture preview_file_id = str(preview_file.id) save_func = file_store.add_file with app.app_context(): if is_file: save_func = file_store.add_file exists_func = file_store.exists_file elif is_movie: save_func = file_store.add_movie exists_func = file_store.exists_movie else: save_func = file_store.add_picture exists_func = file_store.exists_picture if is_movie or is_picture: for prefix in ["thumbnails", "thumbnails-square", "original"]: if not exists_func(prefix, preview_file_id): download_file_from_another_instance( file_store.add_picture, prefix, preview_file_id, preview_file.extension) if not exists_func("previews", preview_file_id): download_file_from_another_instance(save_func, "previews", preview_file_id, preview_file.extension)
def prepare_and_store_movie(preview_file_id, uploaded_movie_path): """ Prepare movie preview, normalize the movie as a .mp4, build the thumbnails and store the files. """ from zou.app import app as current_app with current_app.app_context(): project = get_project_from_preview_file(preview_file_id) fps = get_preview_file_fps(project) (width, height) = get_preview_file_dimensions(project) # Build movie current_app.logger.info("start normalization") try: (normalized_movie_path, normalized_movie_low_path, err) = movie.normalize_movie(uploaded_movie_path, fps=fps, width=width, height=height) if err: current_app.logger.error( "Fail to add silent audiotrack to: %s" % uploaded_movie_path) current_app.logger.error(err) current_app.logger.info("file normalized %s" % normalized_movie_path) file_store.add_movie("previews", preview_file_id, normalized_movie_path) file_store.add_movie("lowdef", preview_file_id, normalized_movie_low_path) current_app.logger.info("file stored") except Exception as exc: if isinstance(exc, ffmpeg.Error): current_app.logger.error(exc.stderr) current_app.logger.error("failed", exc_info=1) preview_file = set_preview_file_as_broken(preview_file_id) return preview_file # Build thumbnails size = movie.get_movie_size(normalized_movie_path) original_picture_path = \ movie.generate_thumbnail(normalized_movie_path) tile_picture_path = \ movie.generate_tile(normalized_movie_path) thumbnail_utils.resize(original_picture_path, size) save_variants(preview_file_id, original_picture_path) file_size = os.path.getsize(normalized_movie_path) current_app.logger.info("thumbnail created %s" % original_picture_path) # Remove files and update status os.remove(uploaded_movie_path) os.remove(normalized_movie_path) preview_file = update_preview_file(preview_file_id, { "status": "ready", "file_size": file_size }) return preview_file
def test_get_week_table(self): with app.app_context(): week_table = time_spents_service.get_week_table("2018") self.assertEqual(week_table["18"][self.person_id], 600) self.assertEqual(week_table["22"][self.person_id], 600) self.assertEqual(week_table["22"][self.user_id], 600) self.assertEqual(week_table["23"][self.person_id], 800) self.assertTrue("1" not in week_table)
def stamp_db(): "Upgrade database schema." from zou.app import app with app.app_context(): import zou directory = os.path.join(os.path.dirname(zou.__file__), "migrations") flask_migrate.stamp(directory=directory)
def test_get_time_spents(self): with app.app_context(): time_spents = time_spents_service.get_time_spents( self.person_id, "2018-06-04") duration = 0 for time_spent in time_spents: duration += time_spent["duration"] self.assertEqual(len(time_spents), 2) self.assertEqual(duration, 800)
def store_db_backup(filename): """ Store given file located in the same directory, inside the files bucket using the `dbbackup` prefix. """ from zou.app import app with app.app_context(): file_store.add_file("dbbackup", filename, filename)
def init_db(): "Creates datababase table (database must be created through PG client)." print("Creating database and tables...") from zou.app import app with app.app_context(): import zou directory = os.path.join(os.path.dirname(zou.__file__), "migrations") flask_migrate.upgrade(directory=directory) print("Database and tables created.")
def reset_migrations(): "Set the database schema revision to first one." from zou.app import app with app.app_context(): import zou directory = os.path.join(os.path.dirname(zou.__file__), "migrations") flask_migrate.stamp(directory=directory, revision="base")
def build_playlist_movie_file(playlist, shots, params, full, remote): """ Build a movie for all files for a given playlist into the temporary folder. """ job = start_build_job(playlist) success = False try: previews = playlist_previews(shots, only_movies=True) movie_file_path = get_playlist_movie_file_path(job) tmp_file_paths = retrieve_playlist_tmp_files(previews) if not remote: success = False if not full: success = _run_concatenation( playlist, job, tmp_file_paths, movie_file_path, params, movie.concat_demuxer, ) # Try again using concat filter if not success: success = _run_concatenation( playlist, job, tmp_file_paths, movie_file_path, params, movie.concat_filter, ) else: from zou.app import app with app.app_context(): try: _run_remote_job_build_playlist( app, job, previews, params, movie_file_path, full ) success = True except Exception as exc: current_app.logger.error(exc) success = False # exception will be logged by rq finally: job = end_build_job(playlist, job, success) if not success: raise Exception("Failure while building playlist %r" % playlist["id"]) return job
def test_get_month_table_with_different_projects(self): with app.app_context(): self.generate_fixture_project_standard() self.generate_fixture_asset_standard() self.generate_fixture_task_standard() tasks_service.create_or_update_time_spent(self.task_standard.id, self.person_id, "2018-05-03", 600) month_table = time_spents_service.get_month_table( "2018", project_id=self.project_standard.id) self.assertEqual(month_table["5"][self.person_id], 600)
def test_check_project_access(self): from zou.app import app with app.app_context(): self.generate_fixture_user_cg_artist() self.log_in_cg_artist() with self.assertRaises(permissions.PermissionDenied): user_service.check_project_access(self.project_id) self.project.team.append(self.user) self.project.save() self.assertTrue(user_service.check_project_access(self.project_id))
def downgrade_db(revision): """ Downgrade db to previous revision of the database schema (for development only). For revision you can use an hash or a relative migration identifier. """ from zou.app import app with app.app_context(): import zou directory = os.path.join(os.path.dirname(zou.__file__), "migrations") flask_migrate.downgrade(directory=directory, revision=revision)
def stamp_db(revision): "Set the database schema revision to current one." from zou.app import app with app.app_context(): import zou directory = os.path.join(os.path.dirname(zou.__file__), "migrations") if revision is None: flask_migrate.stamp(directory=directory) else: flask_migrate.stamp(directory=directory, revision=revision)
def migrate_db(): """ Generate migration files to describe a new revision of the database schema (for development only). """ from zou.app import app with app.app_context(): import zou directory = os.path.join(os.path.dirname(zou.__file__), "migrations") flask_migrate.migrate(directory=directory)
def test_check_entity_access(self): from zou.app import app self.asset_id = str(self.asset.id) with app.app_context(): self.generate_fixture_user_vendor() self.log_in_vendor() person_id = str(self.get_current_user_raw().id) projects_service.add_team_member(self.project_id, person_id) with self.assertRaises(permissions.PermissionDenied): user_service.check_entity_access(str(self.asset_id)) tasks_service.assign_task(self.task_id, person_id) self.assertTrue( user_service.check_entity_access(str(self.asset_id)))
def clear_db(): "Drop all tables from database" from zou.app import app with app.app_context(): import zou print("Deleting database and tables...") dbhelpers.drop_all() print("Database and tables deleted.") directory = os.path.join(os.path.dirname(zou.__file__), "migrations") flask_migrate.stamp(directory=directory, revision="base")
def save_thumbnail(person, thumbnail): from zou.app import app with app.app_context(): thumbnail_path = "/tmp/ldap_th.jpg" with open(thumbnail_path, "wb") as th_file: th_file.write(thumbnail) thumbnail_png_path = thumbnail_utils.convert_jpg_to_png( thumbnail_path) thumbnail_utils.turn_into_thumbnail( thumbnail_png_path, size=thumbnail_utils.BIG_SQUARE_SIZE) file_store.add_picture("thumbnails", person["id"], thumbnail_png_path) os.remove(thumbnail_png_path) persons_service.update_person(person["id"], {"has_avatar": True})
def download_attachment_files_from_another_instance(project=None): from zou.app import app if project: project_dict = gazu.project.get_project_by_name(project) attachment_files = (AttachmentFile.query.join(Comment).join( Task, Comment.object_id == Task.id).filter( Task.project_id == project_dict["id"]).all()) else: attachment_files = AttachmentFile.query.all() for attachment_file in attachment_files: with app.app_context(): download_attachment_file_from_another_instance( attachment_file.present())
def send_email(subject, body, recipient_email, html=None): """ Send an email with given subject and body to given recipient. """ if html is None: html = body with app.app_context(): mail_default_sender = app.config["MAIL_DEFAULT_SENDER"] message = Message(sender="Kitsu Bot <%s>" % mail_default_sender, body=body, html=html, subject=subject, recipients=[recipient_email]) mail.send(message)
def test_check_project_access(self): from zou.app import app with app.app_context(): self.generate_fixture_user_cg_artist() self.log_in_cg_artist() with self.assertRaises(permissions.PermissionDenied): user_service.check_project_access(str(self.project_id)) projects_service.add_team_member( str(self.project.id), str(self.get_current_user_raw().id)) project = projects_service.get_project_with_relations( self.project_id) self.assertTrue( user_service.check_project_access(str(self.project_id)))
def send_email(subject, body, recipient_email, html=None): """ Send an email with given subject and body to given recipient. """ if html is None: html = body with app.app_context(): message = Message( sender="Kitsu Bot <*****@*****.**>", body=body, html=html, subject=subject, recipients=[recipient_email] ) mail.send(message)
def test_get_month_time_spents_with_different_projects(self): with app.app_context(): self.generate_fixture_project_standard() self.generate_fixture_asset_standard() self.generate_fixture_task_standard() tasks_service.create_or_update_time_spent(self.task_standard.id, self.person_id, "2018-05-03", 400) tasks = time_spents_service.get_month_time_spents( self.person_id, "2018", "5", project_id=self.project_standard.id) self.assertEqual(len(tasks), 1) self.assertEqual(tasks[0]["entity_name"], "Car") self.assertEqual(tasks[0]["duration"], 400)
def download_thumbnail_from_another_instance(model_name, model_id): """ Download into the local storage the thumbnail for a given model instance. """ from zou.app import app with app.app_context(): file_path = "/tmp/thumbnails-%s.png" % str(model_id) path = "/pictures/thumbnails/%ss/%s.png" % (model_name, model_id) try: gazu.client.download(path, file_path) file_store.add_picture("thumbnails", model_id, file_path) os.remove(file_path) print("%s downloaded" % file_path) except Exception as e: print(e) print("%s download failed" % file_path) return path
def test_get_last_notifications(self): from zou.app import app with app.app_context(): persons_service.get_current_user = self.get_current_user_artist self.generate_fixture_user_cg_artist() self.log_in_cg_artist() person_id = self.user_cg_artist["id"] projects_service.add_team_member(self.project_id, person_id) tasks_service.assign_task(self.task_id, person_id) notifications = user_service.get_last_notifications() self.assertEqual(len(notifications), 0) comments_service.create_comment( self.user["id"], self.task_id, self.to_review_status_id, "Lets go", [], {}, None, ) notifications = user_service.get_last_notifications() self.assertEqual(len(notifications), 1) comments_service.create_comment( self.user_client["id"], self.task_id, self.to_review_status_id, "Wrong picture", [], {}, None, ) notifications = user_service.get_last_notifications() self.assertEqual(len(notifications), 2) self.assertEqual(len(notifications[0]["comment_text"]), 0) self.assertGreater(len(notifications[1]["comment_text"]), 0)
def build_playlist_movie_file(playlist, shots, params, remote): """ Build a movie for all files for a given playlist into the temporary folder. """ job = start_build_job(playlist) success = False try: previews = playlist_previews(shots, only_movies=True) movie_file_path = get_playlist_movie_file_path(job) tmp_file_paths = retrieve_playlist_tmp_files(previews) # First, try using concat demuxer success = _run_concatenation(playlist, job, tmp_file_paths, movie_file_path, params, movie.concat_demuxer) # Try again using concat filter if not success: if not remote: success = _run_concatenation(playlist, job, tmp_file_paths, movie_file_path, params, movie.concat_filter) else: from zou.app import app with app.app_context(): _execute_nomad_job(job, previews, params, movie_file_path) success = True # exception will by logged by rq finally: job = end_build_job(playlist, job, success) if not success: raise Exception("Failure while building playlist %r" % playlist["id"]) return job
def setUp(self): super(FileStoreTestCase, self).setUp() with app.app_context(): self.preview_path = app.config["PREVIEW_FOLDER"] self.store = file_store self.store.clear()