def create_statuses_and_status_lists(): """Creates the statuses needed for Project, Task, Asset, Shot and Sequence entities """ # Also create basic Status and status lists for # Project, Asset, Shot, Sequence # Project from stalker import Status, StatusList project_status_list = StatusList.query\ .filter_by(target_entity_type='Project').first() if not project_status_list: project_status_list = StatusList(name='Project Statuses', target_entity_type='Project') new = Status.query.filter_by(code='NEW').first() wip = Status.query.filter_by(code='WIP').first() cmpl = Status.query.filter_by(code='CMPL').first() # now use them in status lists project_status_list.statuses = [new, wip, cmpl] # Warning! Not using scoped_session here, it is the plain old session from stalker.db.session import DBSession DBSession.add_all([ project_status_list, ]) DBSession.commit()
def fix_reference_namespace(cls): """fixes reference namespace """ ref_count = len(pm.listReferences(recursive=True)) if ref_count > 25: result = pm.windows.confirmBox( 'Fix Reference Namespace', 'You have %s references in your scene,\n' 'this will take too much time\n\nIs that Ok?' % ref_count) if not result: return from stalker import LocalSession from anima.env import mayaEnv m = mayaEnv.Maya() local_session = LocalSession() logged_in_user = local_session.logged_in_user if not logged_in_user: raise RuntimeError('Please login before running the script') versions = m.fix_reference_namespaces() for version in versions: version.created_by = logged_in_user from stalker.db.session import DBSession DBSession.commit()
def test_status_list_attribute_is_skipped_and_there_is_a_db_setup(self): """testing if there will be no error and the status_list attribute is filled with the correct StatusList instance coming from the database if there is already a database setup and there is a StatusList instance defined for the StatusListAutoAddClass. """ # create a StatusList for StatusListAutoAddClass test_status_list = StatusList( name="StatusListAutoAddClass Statuses", statuses=[ Status(name="Status1", code="Sts1"), Status(name="Status2", code="Sts2"), Status(name="Status3", code="Sts3"), ], target_entity_type=StatusListAutoAddClass, ) # add it to the db from stalker.db.session import DBSession DBSession.add(test_status_list) DBSession.commit() # now try to create a StatusListAutoAddClass without a status_list # argument test_StatusListAutoAddClass = StatusListAutoAddClass( name="Test StatusListAutoAddClass", ) # now check if the status_list is equal to test_status_list assert test_StatusListAutoAddClass.status_list == test_status_list
def setUp(self): """set the test """ super(SimpleEntityDBTester, self).setUp() from stalker import User import json self.test_user = User( name="Test User", login="******", email="*****@*****.**", password="******", generic_text=json.dumps({'Phone number': '123'}, sort_keys=True), ) from stalker.db.session import DBSession DBSession.add(self.test_user) DBSession.commit() import datetime import pytz self.date_created = \ datetime.datetime(2010, 10, 21, 3, 8, 0, tzinfo=pytz.utc) self.date_updated = self.date_created self.kwargs = { "name": "Test Entity", "code": "TstEnt", "description": "This is a test entity, and this is a proper \ description for it", "created_by": self.test_user, "updated_by": self.test_user, "date_created": self.date_created, "date_updated": self.date_updated, 'generic_text': json.dumps({'Phone number': '123'}, sort_keys=True), }
def reject(self): QtWidgets.QDialog.reject(self) from stalker.db.session import DBSession if self.version: DBSession.delete(self.version) DBSession.commit() DBSession.rollback()
def test_start_end_and_duration_values_are_rounded_to_the_Studio_timing_resolution( self): """testing if the start and end dates are rounded to the Studio timing_resolution """ import logging logging.getLogger('stalker.models.studio').setLevel(logging.DEBUG) from stalker.models.studio import Studio studio = Studio(name='Test Studio', timing_resolution=datetime.timedelta(minutes=5)) from stalker.db.session import DBSession DBSession.add(studio) DBSession.commit() self.kwargs['start'] = \ datetime.datetime(2013, 3, 22, 2, 38, 55, 531, tzinfo=pytz.utc) self.kwargs['end'] = \ datetime.datetime(2013, 3, 24, 16, 46, 32, 102, tzinfo=pytz.utc) new_foo_obj = DateRangeMixFooMixedInClass(**self.kwargs) # check the start expected_start = \ datetime.datetime(2013, 3, 22, 2, 40, tzinfo=pytz.utc) assert new_foo_obj.start == expected_start # check the end expected_end = \ datetime.datetime(2013, 3, 24, 16, 45, tzinfo=pytz.utc) assert new_foo_obj.end == expected_end # check the duration assert new_foo_obj.duration == expected_end - expected_start
def test_authenticate_updates_user_password_if_stalker_fails_but_ldap_successes(ldap_server, create_db, monkeypatch): """testing if the anima.utils.authenticate() will update the user password if stalker fails but ldap doesn't fail and the user exists """ from ldap3.extend import StandardExtendedOperations def mock_return(*arg, **kwargs): return "pipeline" monkeypatch.setattr(StandardExtendedOperations, "who_am_i", mock_return) # This is not working with mock server login = '******' ldap_password = '******' stalker_password = '******' # create a user in Stalker with a different password from stalker import User from stalker.db.session import DBSession new_user = User(login=login, password=stalker_password, email='*****@*****.**', name='Pipeline') DBSession.add(new_user) DBSession.commit() assert new_user.check_password(ldap_password) is False assert new_user.check_password(stalker_password) is True # now authenticate with the new password from anima.utils import authenticate result = authenticate(login, ldap_password) # result should be True assert result is True # and the password should be updated pipeline_user = User.query.filter(User.login==login).first() assert pipeline_user is not None assert new_user.check_password(ldap_password) is True assert new_user.check_password(stalker_password) is False
def test_update_paths_will_preserve_extension(self): """testing if update_paths method will preserve the extension. """ # create a FilenameTemplate for Task instances ft = FilenameTemplate( name="Task Filename Template", target_entity_type="Task", path="{{project.code}}/{%- for parent_task in parent_tasks -%}" "{{parent_task.nice_name}}/{%- endfor -%}", filename="{{task.nice_name}}_{{version.take_name}}" '_v{{"%03d"|format(version.version_number)}}{{extension}}', ) self.test_project.structure.templates.append(ft) new_version1 = Version(**self.kwargs) DBSession.add(new_version1) DBSession.commit() new_version1.update_paths() self.assertEqual(new_version1.path, "tp/SH001/Task1") extension = ".ma" new_version1.extension = extension self.assertEqual(new_version1.filename, "Task1_TestTake_v001.ma") # rename the task and update the paths self.test_task1.name = "Task2" # now call update_paths and expect the extension to be preserved new_version1.update_paths() self.assertEqual(new_version1.filename, "Task2_TestTake_v001.ma") self.assertEqual(new_version1.extension, extension)
def accept(self): """overridden accept method """ # get the project try: project_id = self.projects_combo_box.currentData() except AttributeError: index = self.projects_combo_box.currentIndex() project_id = self.projects_combo_box.itemData(index) from stalker import Project project = Project.query.get(project_id) # get the users user_names = [ item.text() for item in self.users_double_list_widget.secondary_items() ] from stalker import User if user_names: users = User.query.filter(User.name.in_(user_names)) else: users = [] # set the project users project.users = users from stalker.db.session import DBSession DBSession.commit() super(MainDialog, self).accept()
def setUp(self): """setup the test """ super(SequenceTester, self).setUp() # create a test project, user and a couple of shots from stalker import Type self.project_type = Type( name="Test Project Type", code='test', target_entity_type='Project', ) from stalker.db.session import DBSession DBSession.add(self.project_type) # create a repository self.repository_type = Type( name="Test Type", code='test', target_entity_type='Repository' ) DBSession.add(self.repository_type) from stalker import Repository self.test_repository = Repository( name="Test Repository", type=self.repository_type, ) DBSession.add(self.test_repository) # create projects from stalker import Project self.test_project = Project( name="Test Project 1", code='tp1', type=self.project_type, repository=self.test_repository, ) DBSession.add(self.test_project) self.test_project2 = Project( name="Test Project 2", code='tp2', type=self.project_type, repository=self.test_repository, ) DBSession.add(self.test_project2) # the parameters self.kwargs = { "name": "Test Sequence", 'code': 'tseq', "description": "A test sequence", "project": self.test_project, } # the test sequence from stalker import Sequence self.test_sequence = Sequence(**self.kwargs) DBSession.commit()
def upload_thumbnail(task, thumbnail_full_path): """Uploads the given thumbnail for the given entity :param task: An instance of :class:`~stalker.models.entity.SimpleEntity` or a derivative. :param str thumbnail_full_path: A string which is showing the path of the thumbnail image """ extension = os.path.splitext(thumbnail_full_path)[-1] # move the file to the task thumbnail folder # and mimic StalkerPyramids output format thumbnail_original_file_name = 'thumbnail%s' % extension thumbnail_final_full_path = os.path.join( task.absolute_path, 'Thumbnail', thumbnail_original_file_name ) try: os.makedirs(os.path.dirname(thumbnail_final_full_path)) except OSError: pass # # convert the thumbnail to jpg if it is a format that is not supported by # # browsers # ext_not_supported_by_browsers = ['.bmp', '.tga', '.tif', '.tiff', '.exr'] # if extension in ext_not_supported_by_browsers: # # use MediaManager to convert them # from anima.utils import MediaManager # mm = MediaManager() # thumbnail_full_path = mm.generate_image_thumbnail(thumbnail_full_path) shutil.copy(thumbnail_full_path, thumbnail_final_full_path) from stalker import Link, Version, Repository thumbnail_os_independent_path = \ Repository.to_os_independent_path(thumbnail_final_full_path) l_thumb = Link.query\ .filter(Link.full_path == thumbnail_os_independent_path).first() if not l_thumb: l_thumb = Link( full_path=thumbnail_os_independent_path, original_filename=thumbnail_original_file_name ) task.thumbnail = l_thumb # get a version of this Task from stalker.db.session import DBSession v = Version.query.filter(Version.task == task).first() if v: for naming_parent in v.naming_parents: if not naming_parent.thumbnail: naming_parent.thumbnail = l_thumb DBSession.add(naming_parent) DBSession.add(l_thumb) DBSession.commit()
def test_is_latest_published_version_is_working_properly(self): """testing if the is_latest_published_version is working properly """ new_version1 = Version(**self.kwargs) DBSession.add(new_version1) DBSession.commit() new_version2 = Version(**self.kwargs) DBSession.add(new_version2) DBSession.commit() new_version3 = Version(**self.kwargs) DBSession.add(new_version3) DBSession.commit() new_version4 = Version(**self.kwargs) DBSession.add(new_version4) DBSession.commit() new_version5 = Version(**self.kwargs) DBSession.add(new_version5) DBSession.commit() new_version1.is_published = True new_version3.is_published = True new_version4.is_published = True self.assertFalse(new_version1.is_latest_published_version()) self.assertFalse(new_version2.is_latest_published_version()) self.assertFalse(new_version3.is_latest_published_version()) self.assertTrue(new_version4.is_latest_published_version()) self.assertFalse(new_version5.is_latest_published_version())
def set_shot_from_range(self, version): """sets the Shot.cut_in and Shot.cut_out attributes from the current frame range if the current task is related to a Stalker Shot instance. :param Stalker.Version version: A Stalker Version instance. :return: """ # check if this is a shot related task is_shot_related_task = False shot = None from stalker import Shot for task in version.task.parents: if isinstance(task, Shot): is_shot_related_task = True shot = task break if is_shot_related_task and shot: # set frame ranges cut_in, cut_out = self.get_frame_range() shot.cut_in = int(cut_in) shot.cut_out = int(cut_out) from stalker.db.session import DBSession DBSession.add(shot) DBSession.commit()
def test_logged_in_user_returns_the_stored_User_instance_from_last_time( self): """testing if logged_in_user returns the logged in user """ # create a new user from stalker import User new_user = User(name='Test User', login='******', email='*****@*****.**', password='******') # save it to the Database from stalker.db.session import DBSession DBSession.add(new_user) DBSession.commit() assert new_user.id is not None # save it to the local storage from stalker import LocalSession local_session = LocalSession() local_session.store_user(new_user) # save the session local_session.save() # now get it back with a new local_session local_session2 = LocalSession() assert local_session2.logged_in_user_id == new_user.id assert local_session2.logged_in_user == new_user
def test_stalker_entity_decoder_will_not_create_existing_tasks( create_db, create_empty_project): """testing if JSON decoder will not recreate existing data """ from stalker import Task project = create_empty_project import json from anima.utils import task_hierarchy_io global __here__ file_path = os.path.join(__here__, "data", "test_template3.json") with open(file_path) as f: data = json.load(f) decoder = \ task_hierarchy_io.StalkerEntityDecoder( project=project ) loaded_entity = decoder.loads(data) from stalker.db.session import DBSession DBSession.add(loaded_entity) DBSession.commit() # now there should be only one Assets task from stalker import Task assets_tasks = Task.query.filter(Task.name == 'Assets').all() assert len(assets_tasks) == 1
def test_status_list_attribute_is_skipped_and_there_is_a_db_setup_but_no_suitable_StatusList( self): """testing if a TypeError will be raised even a database is setup but there is no suitable StatusList for StatusListNoAutoAddClass in the database """ # create a StatusList for StatusListAutoAddClass test_status_list = StatusList( name="StatusListAutoAddClass Statuses", statuses=[ Status(name="Status1", code="Sts1"), Status(name="Status2", code="Sts2"), Status(name="Status3", code="Sts3"), ], target_entity_type=StatusListAutoAddClass, ) # add it to the db DBSession.add(test_status_list) DBSession.commit() # now try to create a StatusListAutoAddClass without a status_list # argument self.assertRaises( TypeError, StatusListNoAutoAddClass, **{"name": "Test StatusListNoAutoAddClass"} )
def test_status_list_attribute_is_skipped_and_there_is_a_db_setup_but_no_suitable_StatusList(self): """testing if a TypeError will be raised even a database is setup but there is no suitable StatusList for StatusListNoAutoAddClass in the database """ # create a StatusList for StatusListAutoAddClass test_status_list = StatusList( name="StatusListAutoAddClass Statuses", statuses=[ Status(name="Status1", code="Sts1"), Status(name="Status2", code="Sts2"), Status(name="Status3", code="Sts3"), ], target_entity_type=StatusListAutoAddClass, ) # add it to the db from stalker.db.session import DBSession DBSession.add(test_status_list) DBSession.commit() # now try to create a StatusListAutoAddClass without a status_list # argument with pytest.raises(TypeError) as cm: StatusListNoAutoAddClass(name="Test StatusListNoAutoAddClass") assert str(cm.value) == \ "StatusListNoAutoAddClass instances can not be initialized " \ "without a stalker.models.status.StatusList instance, please " \ "pass a suitable StatusList " \ "(StatusList.target_entity_type=StatusListNoAutoAddClass) with " \ "the 'status_list' argument"
def test_latest_version_attribute_is_working_properly(self): """testing if the last_version attribute is working properly """ new_version1 = Version(**self.kwargs) DBSession.add(new_version1) DBSession.commit() new_version2 = Version(**self.kwargs) DBSession.add(new_version2) DBSession.commit() new_version3 = Version(**self.kwargs) DBSession.add(new_version3) DBSession.commit() new_version4 = Version(**self.kwargs) DBSession.add(new_version4) DBSession.commit() new_version5 = Version(**self.kwargs) DBSession.add(new_version5) DBSession.commit() self.assertEqual(new_version5.version_number, 5) self.assertEqual(new_version1.latest_version, new_version5) self.assertEqual(new_version2.latest_version, new_version5) self.assertEqual(new_version3.latest_version, new_version5) self.assertEqual(new_version4.latest_version, new_version5) self.assertEqual(new_version5.latest_version, new_version5)
def test_OverbookedError_9(self): """testing if no OverBookedError will be raised when the resource is not already booked for the given time period. Simple case diagram: ####### ####### """ # time_log1 kwargs = copy.copy(self.kwargs) kwargs["resource"] = self.test_resource2 kwargs["start"] =\ datetime.datetime(2013, 3, 22, 4, 0, tzinfo=pytz.utc) \ + datetime.timedelta(20) kwargs["duration"] = datetime.timedelta(5) time_log1 = TimeLog(**kwargs) from stalker.db.session import DBSession DBSession.add(time_log1) DBSession.commit() # time_log2 kwargs["start"] = \ datetime.datetime(2013, 3, 22, 4, 0, tzinfo=pytz.utc) # no warning time_log2 = TimeLog(**kwargs) DBSession.add(time_log2) DBSession.commit()
def test_OverbookedError_3(self): """testing if a OverBookedError will be raised when the resource is already booked for the given time period. Simple case diagram: ##### ####### """ # time_log1 kwargs = copy.copy(self.kwargs) kwargs["resource"] = self.test_resource2 kwargs["start"] = datetime.datetime(2013, 3, 22, 4, 0, tzinfo=pytz.utc) kwargs["duration"] = datetime.timedelta(8) time_log1 = TimeLog(**kwargs) from stalker.db.session import DBSession DBSession.add(time_log1) DBSession.commit() # time_log2 kwargs["duration"] = datetime.timedelta(10) from stalker.exceptions import OverBookedError with pytest.raises(OverBookedError) as cm: TimeLog(**kwargs) assert str(cm.value) == \ 'The resource has another TimeLog between %s and %s' % ( time_log1.start, time_log1.end )
def accept(self): """overridden accept method """ if not self.name_lineEdit.is_valid: QtWidgets.QMessageBox.critical( self, 'Error', 'Please fix <b>name</b> field!' ) return name = self.name_lineEdit.text() windows_path = self.windows_path_lineEdit.text() linux_path = self.linux_path_lineEdit.text() osx_path = self.osx_path_lineEdit.text() from stalker import Repository from stalker.db.session import DBSession logged_in_user = self.get_logged_in_user() if self.mode == 'Create': # Create a new Repository try: repo = Repository( name=name, windows_path=windows_path, linux_path=linux_path, osx_path=osx_path ) self.repository = repo DBSession.add(repo) DBSession.commit() except Exception as e: DBSession.rollback() QtWidgets.QMessageBox.critical( self, 'Error', str(e) ) return elif self.mode == 'Update': # Update the repository try: self.repository.name = name self.repository.windows_path = windows_path self.repository.linux_path = linux_path self.repository.osx_path = osx_path self.repository.updated_by = logged_in_user DBSession.add(self.repository) DBSession.commit() except Exception as e: DBSession.rollback() QtWidgets.QMessageBox.critical( self, 'Error', str(e) ) return super(MainDialog, self).accept()
def test_version_number_attribute_is_set_to_a_lower_then_it_should_be(self): """testing if the version_number attribute will be set to a correct unique value when it is set to a lower number then it should be """ self.test_version.version_number = -1 self.assertEqual(self.test_version.version_number, 1) self.test_version.version_number = -10 self.assertEqual(self.test_version.version_number, 1) DBSession.add(self.test_version) DBSession.commit() self.test_version.version_number = -100 # it should be 1 again self.assertEqual(self.test_version.version_number, 1) new_version = Version(**self.kwargs) self.assertEqual(new_version.version_number, 2) new_version.version_number = 1 self.assertEqual(new_version.version_number, 2) new_version.version_number = 100 self.assertEqual(new_version.version_number, 100)
def test_status_list_attribute_is_skipped_and_there_is_a_db_setup(self): """testing if there will be no error and the status_list attribute is filled with the correct StatusList instance coming from the database if there is already a database setup and there is a StatusList instance defined for the StatusListAutoAddClass. """ # create a StatusList for StatusListAutoAddClass test_status_list = StatusList( name="StatusListAutoAddClass Statuses", statuses=[ Status(name="Status1", code="Sts1"), Status(name="Status2", code="Sts2"), Status(name="Status3", code="Sts3"), ], target_entity_type=StatusListAutoAddClass, ) # add it to the db DBSession.add(test_status_list) DBSession.commit() # now try to create a StatusListAutoAddClass without a status_list # argument test_StatusListAutoAddClass = StatusListAutoAddClass( name="Test StatusListAutoAddClass", ) # now check if the status_list is equal to test_status_list self.assertEqual( test_StatusListAutoAddClass.status_list, test_status_list )
def __create_admin__(): """creates the admin """ from stalker.models.auth import User from stalker.models.department import Department logger.debug("creating the default administrator user") # create the admin department admin_department = Department.query.filter_by( name=defaults.admin_department_name ).first() if not admin_department: admin_department = Department(name=defaults.admin_department_name) DBSession.add(admin_department) # create the admins group from stalker.models.auth import Group admins_group = Group.query \ .filter_by(name=defaults.admin_group_name) \ .first() if not admins_group: admins_group = Group(name=defaults.admin_group_name) DBSession.add(admins_group) # check if there is already an admin in the database admin = User.query.filter_by(name=defaults.admin_name).first() if admin: # there should be an admin user do nothing logger.debug("there is an admin already") return admin else: admin = User( name=defaults.admin_name, login=defaults.admin_login, password=defaults.admin_password, email=defaults.admin_email, departments=[admin_department], groups=[admins_group] ) admin.created_by = admin admin.updated_by = admin # update the department as created and updated by admin user admin_department.created_by = admin admin_department.updated_by = admin admins_group.created_by = admin admins_group.updated_by = admin DBSession.add(admin) DBSession.commit() return admin
def __create_admin__(): """creates the admin """ from stalker.models.auth import User from stalker.models.department import Department # check if there is already an admin in the database admin = User.query.filter_by(name=defaults.admin_name).first() if admin: # there should be an admin user do nothing logger.debug("there is an admin already") return logger.debug("creating the default administrator user") # create the admin department admin_department = Department.query.filter_by(name=defaults.admin_department_name).first() if not admin_department: admin_department = Department(name=defaults.admin_department_name) DBSession.add(admin_department) # create the admins group from stalker.models.auth import Group admins_group = Group.query.filter_by(name=defaults.admin_group_name).first() if not admins_group: admins_group = Group(name=defaults.admin_group_name) DBSession.add(admins_group) # # create the admin user # admin = User.query \ # .filter_by(name=defaults.admin_name) \ # .first() # if not admin: admin = User( name=defaults.admin_name, login=defaults.admin_login, password=defaults.admin_password, email=defaults.admin_email, departments=[admin_department], groups=[admins_group], ) admin.created_by = admin admin.updated_by = admin # update the department as created and updated by admin user admin_department.created_by = admin admin_department.updated_by = admin admins_group.created_by = admin admins_group.updated_by = admin DBSession.add(admin) DBSession.commit()
def setUp(self): """set up the test """ db.setup() db.init() self.temp_path = tempfile.mkdtemp() self.repo = Repository( name='Test Repository', linux_path=self.temp_path, windows_path=self.temp_path, osx_path=self.temp_path ) self.status_new = Status.query.filter_by(code='NEW').first() self.status_wip = Status.query.filter_by(code='WIP').first() self.status_cmpl = Status.query.filter_by(code='CMPL').first() self.project_status_list = \ StatusList.query.filter_by(target_entity_type='Project').first() self.task_filename_template = FilenameTemplate( name='Task Filename Template', target_entity_type='Task', path='{{project.code}}/{%- for parent_task in parent_tasks -%}' '{{parent_task.nice_name}}/{%- endfor -%}', filename='{{version.nice_name}}' '_v{{"%03d"|format(version.version_number)}}{{extension}}' ) self.project_structure = Structure( name='Project Structure', templates=[self.task_filename_template] ) self.project = Project( name='Test Project', code='TP', status_list=self.project_status_list, repository=self.repo, structure=self.project_structure ) self.task = Task( name='Test Task', project=self.project ) from stalker.db.session import DBSession DBSession.add(self.task) DBSession.commit() self.version = Version( task=self.task ) self.kwargs = { 'name': 'Photoshop', 'extensions': ['psd'], 'structure': ['Outputs'] } self.external_env = ExternalEnv(**self.kwargs)
def upload_thumbnail(task, thumbnail_full_path): """Uploads the given thumbnail for the given entity :param task: An instance of :class:`~stalker.models.entity.SimpleEntity` or a derivative. :param str thumbnail_full_path: A string which is showing the path of the thumbnail image """ extension = os.path.splitext(thumbnail_full_path)[-1] # move the file to the task thumbnail folder # and mimic StalkerPyramids output format thumbnail_original_file_name = 'thumbnail%s' % extension thumbnail_final_full_path = os.path.join(task.absolute_path, 'Thumbnail', thumbnail_original_file_name) try: os.makedirs(os.path.dirname(thumbnail_final_full_path)) except OSError: pass # # convert the thumbnail to jpg if it is a format that is not supported by # # browsers # ext_not_supported_by_browsers = ['.bmp', '.tga', '.tif', '.tiff', '.exr'] # if extension in ext_not_supported_by_browsers: # # use MediaManager to convert them # from anima.utils import MediaManager # mm = MediaManager() # thumbnail_full_path = mm.generate_image_thumbnail(thumbnail_full_path) import shutil shutil.copy(thumbnail_full_path, thumbnail_final_full_path) from stalker import Link, Version, Repository thumbnail_os_independent_path = \ Repository.to_os_independent_path(thumbnail_final_full_path) l_thumb = Link.query\ .filter(Link.full_path == thumbnail_os_independent_path).first() if not l_thumb: l_thumb = Link(full_path=thumbnail_os_independent_path, original_filename=thumbnail_original_file_name) task.thumbnail = l_thumb # get a version of this Task from stalker.db.session import DBSession v = Version.query.filter(Version.task == task).first() if v: for naming_parent in v.naming_parents: if not naming_parent.thumbnail: naming_parent.thumbnail = l_thumb DBSession.add(naming_parent) DBSession.add(l_thumb) DBSession.commit()
def test_tasks_are_correctly_scheduled(self): """testing if the tasks are correctly scheduled """ tjp_sched = TaskJugglerScheduler(compute_resources=True) from stalker import Studio test_studio = Studio(name='Test Studio', now=datetime.datetime(2013, 4, 16, 0, 0, tzinfo=pytz.utc)) test_studio.start = \ datetime.datetime(2013, 4, 16, 0, 0, tzinfo=pytz.utc) test_studio.end = \ datetime.datetime(2013, 4, 30, 0, 0, tzinfo=pytz.utc) test_studio.daily_working_hours = 9 from stalker.db.session import DBSession DBSession.add(test_studio) tjp_sched.studio = test_studio tjp_sched.schedule() DBSession.commit() # check if the task and project timings are all adjusted assert \ datetime.datetime(2013, 4, 16, 9, 0, tzinfo=pytz.utc) == \ self.test_proj1.computed_start assert \ datetime.datetime(2013, 4, 24, 10, 0, tzinfo=pytz.utc) == \ self.test_proj1.computed_end possible_resources = [ self.test_user1, self.test_user2, self.test_user3, self.test_user4, self.test_user5 ] assert \ datetime.datetime(2013, 4, 16, 9, 0, tzinfo=pytz.utc) == \ self.test_task1.computed_start assert \ datetime.datetime(2013, 4, 18, 16, 0, tzinfo=pytz.utc) == \ self.test_task1.computed_end assert len(self.test_task1.computed_resources) == 2 assert self.test_task1.computed_resources[0] in possible_resources assert self.test_task1.computed_resources[1] in possible_resources assert \ datetime.datetime(2013, 4, 18, 16, 0, tzinfo=pytz.utc) == \ self.test_task2.computed_start assert \ datetime.datetime(2013, 4, 24, 10, 0, tzinfo=pytz.utc) == \ self.test_task2.computed_end assert len(self.test_task2.computed_resources) == 2 assert self.test_task2.computed_resources[0] in possible_resources assert self.test_task2.computed_resources[1] in possible_resources
def accept(self): """overridden accept method """ if not self.name_lineEdit.is_valid: QtWidgets.QMessageBox.critical(self, 'Error', 'Please fix <b>name</b> field!') return name = self.name_lineEdit.text() custom_template = self.custom_template_plainTextEdit.toPlainText() filename_template_items = \ self.filename_templates_double_list_widget.secondary_items() filename_template_ids = [] for item in filename_template_items: filename_template_id = \ int(item.text().split('(')[-1].split(')')[0]) filename_template_ids.append(filename_template_id) from stalker import FilenameTemplate filename_templates = FilenameTemplate.query\ .filter(FilenameTemplate.id.in_(filename_template_ids)).all() from stalker import Structure from stalker.db.session import DBSession logged_in_user = self.get_logged_in_user() if self.mode == 'Create': # Create a new Structure try: structure = Structure(name=name, templates=filename_templates, custom_template=custom_template, created_by=logged_in_user) self.structure = structure DBSession.add(structure) DBSession.commit() except Exception as e: DBSession.rollback() QtWidgets.QMessageBox.critical(self, 'Error', str(e)) return elif self.mode == 'Update': # Update the structure try: self.structure.name = name self.structure.templates = filename_templates self.structure.custom_template = custom_template self.structure.updated_by = logged_in_user DBSession.add(self.structure) DBSession.commit() except Exception as e: DBSession.rollback() QtWidgets.QMessageBox.critical(self, 'Error', str(e)) return super(MainDialog, self).accept()
def accept(self): """the overridden accept method """ target_entity_type = self.target_entity_type_combo_box.currentText() if not self.name_line_edit.is_valid: QtWidgets.QMessageBox.critical(self, 'Error', 'Please fix <b>name</b> field!') return name = self.name_line_edit.text() path = self.path_line_edit.text() if path == '': QtWidgets.QMessageBox.critical(self, 'Error', 'Please fix <b>path</b> field!') return filename = self.filename_line_edit.text() if path == '': QtWidgets.QMessageBox.critical( self, 'Error', 'Please fix <b>filename</b> field!') return logged_in_user = self.get_logged_in_user() from stalker.db.session import DBSession if self.mode == 'Create': try: from stalker import FilenameTemplate # create a new FilenameTemplate ft = FilenameTemplate(name=name, path=path, filename=filename, target_entity_type=target_entity_type, created_by=logged_in_user) self.filename_template = ft DBSession.add(ft) DBSession.commit() except Exception as e: DBSession.rollback() QtWidgets.QMessageBox.critical(self, 'Error', str(e)) return elif self.mode == 'Update': try: self.filename_template.name = name self.filename_template.path = path self.filename_template.filename = filename self.filename_template.updated_by = logged_in_user DBSession.add(self.filename_template) DBSession.commit() except Exception as e: DBSession.rollback() QtWidgets.QMessageBox.critical(self, 'Error', str(e)) return super(MainDialog, self).accept()
def export_as(self, version): """the export action for max environment """ import MaxPlus # check if there is something selected if MaxPlus.SelectionManager.GetCount() < 1: raise RuntimeError("There is nothing selected to export") # check if this is the first version if version.is_published and not self.allow_publish_on_export: # it is not allowed to publish the first version (desdur) raise RuntimeError( 'It is not allowed to Publish while export!!!' '<br><br>' 'Export it normally. Then open the file and publish it.' ) # do not save if there are local files # self.check_external_files(version) # set the extension to max by default version.update_paths() version.extension = self.extensions[0] # define that this version is created with Max version.created_with = self.name # create the folder if it doesn't exists import os try: os.makedirs(version.absolute_path) except OSError: # already exists pass # workspace_path = os.path.dirname(version.absolute_path) workspace_path = version.absolute_path # self.create_workspace_file(workspace_path) # self.create_workspace_folders(workspace_path) # export the file MaxPlus.FileManager.SaveSelected(version.absolute_full_path) # save the version to database from stalker.db.session import DBSession DBSession.add(version) DBSession.commit() # create a local copy self.create_local_copy(version) return True
def fix_task_status(self): """fix current task status """ from stalker import Task assert isinstance(self.task, Task) from anima import utils utils.fix_task_statuses(self.task) utils.fix_task_computed_time(self.task) from stalker.db.session import DBSession DBSession.add(self.task) DBSession.commit()
def create_alembic_table(): """creates the default alembic_version table and creates the data so that any new database will be considered as the latest version """ # Now, this is not the correct way of doing this, there is a proper way of # doing it and it is explained nicely in the Alembic library documentation. # # But it is simply not working when Stalker is installed as a package. # # So as a workaround here we are doing it manually # don't forget to update the version_num (and the corresponding test # whenever a new alembic revision is created) version_num = alembic_version from sqlalchemy import Table, Column, Text table_name = 'alembic_version' from stalker.db.session import DBSession conn = DBSession.connection() engine = conn.engine # check if the table is already there from stalker.db.declarative import Base table = Table( table_name, Base.metadata, Column('version_num', Text), extend_existing=True ) if not engine.dialect.has_table(conn, table_name): logger.debug('creating alembic_version table') # create the table no matter if it exists or not we need it either way Base.metadata.create_all(engine) # first try to query the version value sql_query = 'select version_num from alembic_version' try: version_num = \ DBSession.connection().execute(sql_query).fetchone()[0] except TypeError: logger.debug('inserting %s to alembic_version table' % version_num) # the table is there but there is no value so insert it ins = table.insert().values(version_num=version_num) DBSession.connection().execute(ins) DBSession.commit() logger.debug('alembic_version table is created and initialized') else: # the value is there do not touch the table logger.debug( 'alembic_version table is already there, not doing anything!' )
def create_ticket_statuses(): """creates the default ticket statuses """ from stalker import defaults, User # create as admin admin = User.query.filter(User.login == defaults.admin_name).first() # create statuses for Tickets ticket_names = defaults.ticket_status_names ticket_codes = defaults.ticket_status_codes create_entity_statuses('Ticket', ticket_names, ticket_codes, admin) # Again I hate doing this in this way from stalker import Type types = Type.query \ .filter_by(target_entity_type="Ticket") \ .all() t_names = [t.name for t in types] # create Ticket Types logger.debug("Creating Ticket Types") from stalker.db.session import DBSession if 'Defect' not in t_names: ticket_type_1 = Type( name='Defect', code='Defect', target_entity_type='Ticket', created_by=admin, updated_by=admin ) DBSession.add(ticket_type_1) if 'Enhancement' not in t_names: ticket_type_2 = Type( name='Enhancement', code='Enhancement', target_entity_type='Ticket', created_by=admin, updated_by=admin ) DBSession.add(ticket_type_2) from sqlalchemy.exc import IntegrityError try: DBSession.commit() except IntegrityError: DBSession.rollback() logger.debug("Ticket Types are already in the database!") else: # DBSession.flush() logger.debug("Ticket Types are created successfully")
def test_to_os_independent_path_is_working_properly(self): """testing if to_os_independent_path class method is working properly """ from stalker.db.session import DBSession DBSession.add(self.test_repo) DBSession.commit() relative_part = 'some/path/to/a/file.ma' test_path = '%s/%s' % (self.test_repo.path, relative_part) from stalker import Repository assert Repository.to_os_independent_path(test_path) == \ '$REPO%s/%s' % (self.test_repo.id, relative_part)
def test_versions_attribute_will_return_a_list_of_versions(self): """testing if the versions attribute is a list of Version instances related to the given links """ from stalker import Daily daily = Daily(name='Test Daily', project=self.test_project, status_list=self.daily_status_list) daily.links = [self.test_link1, self.test_link2] from stalker.db.session import DBSession DBSession.add(daily) DBSession.commit() assert daily.versions == [self.test_version1]
def test_cut_duration_initialization_bug_with_cut_in(self): """testing if the _cut_duration attribute is initialized correctly for a Shot restored from DB """ # retrieve the shot back from DB from stalker import Shot test_shot_db = Shot.query.filter_by(name=self.kwargs['name']).first() # trying to change the cut_in and cut_out values should not raise any # errors test_shot_db.cut_in = 1 from stalker.db.session import DBSession DBSession.add(test_shot_db) DBSession.commit()
def test_timeLog_prevents_auto_flush_when_expanding_task_schedule_timing(self): """testing timeLog prevents auto flush when expanding task schedule_timing attribute """ from stalker.db.session import DBSession tlog1 = TimeLog(**self.kwargs) DBSession.add(tlog1) DBSession.commit() # create a new time log self.kwargs['start'] = self.kwargs['start'] + self.kwargs['duration'] tlog2 = TimeLog(**self.kwargs)
def create_version(cls, task, take_name): """A helper method for creating a new version :param task: the task :param take_name: the take_name name :return: the version """ from stalker import Version from stalker.db.session import DBSession v = Version(task=task, take_name=take_name) DBSession.add(v) DBSession.commit() return v
def create_alembic_table(): """creates the default alembic_version table and creates the data so that any new database will be considered as the latest version """ # Now, this is not the correct way of doing, there is a proper way of doing # it and it is explained nicely in the Alembic library documentation. # # But it is simply not working when Stalker is installed as a package. # # So as a workaround here we are doing it manually # don't forget to update the version_num (and the corresponding test # whenever a new alembic revision is created) version_num = '2e4a3813ae76' from sqlalchemy import Table, Column, Text table_name = 'alembic_version' conn = DBSession.connection() engine = conn.engine # check if the table is already there table = Table( table_name, Base.metadata, Column('version_num', Text), extend_existing=True ) if not engine.dialect.has_table(conn, table_name): logger.debug('creating alembic_version table') # create the table no matter if it exists or not we need it either way Base.metadata.create_all(engine) # first try to query the version value sql_query = 'select version_num from "alembic_version"' try: version_num = \ DBSession.connection().execute(sql_query).fetchone()[0] except TypeError: logger.debug('inserting %s to alembic_version table' % version_num) # the table is there but there is no value so insert it ins = table.insert().values(version_num=version_num) DBSession.connection().execute(ins) DBSession.commit() logger.debug('alembic_version table is created and initialized') else: # the value is there do not touch the table logger.debug( 'alembic_version table is already there, not doing anything!' )
def test_version_number_attribute_is_automatically_generated(self): """testing if the version_number attribute is automatically generated """ self.assertEqual(self.test_version.version_number, 1) DBSession.add(self.test_version) DBSession.commit() new_version = Version(**self.kwargs) DBSession.add(new_version) DBSession.commit() self.assertEqual(self.test_version.task, new_version.task) self.assertEqual(self.test_version.take_name, new_version.take_name) self.assertEqual(new_version.version_number, 2) new_version = Version(**self.kwargs) DBSession.add(new_version) DBSession.commit() self.assertEqual(self.test_version.task, new_version.task) self.assertEqual(self.test_version.take_name, new_version.take_name) self.assertEqual(new_version.version_number, 3) new_version = Version(**self.kwargs) DBSession.add(new_version) DBSession.commit() self.assertEqual(self.test_version.task, new_version.task) self.assertEqual(self.test_version.take_name, new_version.take_name) self.assertEqual(new_version.version_number, 4)
def create_ticket_statuses(): """creates the default ticket statuses """ from stalker import User # create as admin admin = User.query.filter(User.login == defaults.admin_name).first() # create statuses for Tickets ticket_names = defaults.ticket_status_names ticket_codes = defaults.ticket_status_codes create_entity_statuses('Ticket', ticket_names, ticket_codes, admin) # Again I hate doing this in this way from stalker import Type types = Type.query \ .filter_by(target_entity_type="Ticket") \ .all() t_names = [t.name for t in types] # create Ticket Types logger.debug("Creating Ticket Types") if 'Defect' not in t_names: ticket_type_1 = Type( name='Defect', code='Defect', target_entity_type='Ticket', created_by=admin, updated_by=admin ) DBSession.add(ticket_type_1) if 'Enhancement' not in t_names: ticket_type_2 = Type( name='Enhancement', code='Enhancement', target_entity_type='Ticket', created_by=admin, updated_by=admin ) DBSession.add(ticket_type_2) try: DBSession.commit() except IntegrityError: DBSession.rollback() logger.debug("Ticket Types are already in the database!") else: # DBSession.flush() logger.debug("Ticket Types are created successfully")
def create_entity_statuses(entity_type="", status_names=None, status_codes=None, user=None): """creates the default task statuses """ if not entity_type: raise ValueError("Please supply entity_type") if not status_names: raise ValueError("Please supply status names") if not status_codes: raise ValueError("Please supply status codes") # create statuses for entity from stalker import Status, StatusList logger.debug("Creating %s Statuses" % entity_type) statuses = Status.query.filter(Status.name.in_(status_names)).all() status_names_in_db = map(lambda x: x.name, statuses) for name, code in zip(status_names, status_codes): if name not in status_names_in_db: logger.debug("Creating Status: %s (%s)" % (name, code)) new_status = Status(name=name, code=code, created_by=user, updated_by=user) statuses.append(new_status) DBSession.add(new_status) # create the Status List status_list = StatusList.query.filter(StatusList.target_entity_type == entity_type).first() if status_list is None: logger.debug("No %s Status List found, creating new!" % entity_type) status_list = StatusList( name="%s Statuses" % entity_type, target_entity_type=entity_type, created_by=user, updated_by=user ) else: logger.debug("%s Status List already created, updating statuses" % entity_type) status_list.statuses = statuses DBSession.add(status_list) try: DBSession.commit() except IntegrityError as e: logger.debug("error in DBSession.commit, rolling back: %s" % e) DBSession.rollback() else: logger.debug("Created %s Statuses successfully" % entity_type) DBSession.flush()
def test_number_attribute_is_automatically_increased(self): """testing if the number attribute is automatically increased """ # create two new tickets ticket1 = Ticket(**self.kwargs) DBSession.add(ticket1) DBSession.commit() ticket2 = Ticket(**self.kwargs) DBSession.add(ticket2) DBSession.commit() self.assertEqual(ticket1.number + 1, ticket2.number) self.assertEqual(ticket1.number, 2) self.assertEqual(ticket2.number, 3)
def test_email_argument_should_be_a_unique_value(self): """testing if the email argument should be a unique value """ # this test should include a database test_email = "*****@*****.**" self.kwargs["login"] = "******" self.kwargs["email"] = test_email user1 = User(**self.kwargs) DBSession.add(user1) DBSession.commit() self.kwargs["login"] = "******" user2 = User(**self.kwargs) DBSession.add(user2) self.assertRaises(Exception, DBSession.commit)
def test_login_argument_should_be_a_unique_value(self): """testing if the login argument should be a unique value """ # this test should include a database test_login = '******' self.kwargs['login'] = test_login self.kwargs['email'] = "*****@*****.**" user1 = User(**self.kwargs) DBSession.add(user1) DBSession.commit() self.kwargs['email'] = "*****@*****.**" user2 = User(**self.kwargs) DBSession.add(user2) self.assertRaises(Exception, DBSession.commit)
def test_nice_name_attribute_is_working_properly(self): """testing if the nice_name attribute is working properly """ # for self.test_version self.assertEqual(self.test_version.naming_parents, [self.test_shot1, self.test_task1]) # for a new version of a task task1 = Task(name="Test Task 1", project=self.test_project, status_list=self.test_task_status_list) task2 = Task(name="Test Task 2", parent=task1, status_list=self.test_task_status_list) task3 = Task(name="Test Task 3", parent=task2, status_list=self.test_task_status_list) DBSession.add_all([task1, task2, task3]) DBSession.commit() version1 = Version(task=task3, take_name="Take1") DBSession.add(version1) DBSession.commit() self.assertEqual( version1.nice_name, "%s_%s_%s_%s" % (task1.nice_name, task2.nice_name, task3.nice_name, version1.take_name) ) # for a an asset version asset_statuses = StatusList( target_entity_type="Asset", statuses=[self.test_status1, self.test_status2, self.test_status3] ) character_type = Type(target_entity_type="Asset", name="Character", code="Char") asset1 = Asset(name="Asset1", code="Asset1", parent=task1, status_list=asset_statuses, type=character_type) version2 = Version(task=asset1) self.assertEqual(version2.nice_name, "%s_%s" % (asset1.nice_name, version2.take_name)) # for a version of a task of a shot shot2 = Shot(name="SH002", code="SH002", parent=task3, status_list=self.test_shot_status_list) task4 = Task(name="Test Task 4", parent=shot2, status_list=self.test_task_status_list) version3 = Version(task=task4) self.assertEqual(version3.nice_name, "%s_%s_%s" % (shot2.nice_name, task4.nice_name, version3.take_name)) # for an asset of a shot asset2 = Asset(name="Asset2", code="Asset2", parent=shot2, status_list=asset_statuses, type=character_type) version4 = Version(task=asset2) self.assertEqual(version4.nice_name, "%s_%s" % (asset2.nice_name, version4.take_name))
def login(self): """does the nasty details for user to login """ # check the given user password from stalker import User # get the user first login = self.login_or_email_lineEdit.text() password = self.password_lineEdit.text() # check with the login or email attribute user = User.query \ .filter(or_(User.login == login, User.email == login)) \ .first() if user: self.success = user.check_password(password) if self.success: from stalker.models.auth import LocalSession session = LocalSession() session.store_user(user) session.save() # also store a log import datetime from stalker.models.auth import LOGIN, AuthenticationLog al = AuthenticationLog( user=user, date=datetime.datetime.now(), action=LOGIN ) from stalker.db.session import DBSession DBSession.add(al) DBSession.commit() self.accept() else: QtWidgets.QMessageBox.critical( self, "Error", "login or password is incorrect" )
def test_absolute_full_path_works_properly(self): """testing if the absolute_full_path attribute works properly """ ft = FilenameTemplate( name="Task Filename Template", target_entity_type="Task", path="{{project.code}}/{%- for parent_task in parent_tasks -%}" "{{parent_task.nice_name}}/{%- endfor -%}", filename="{{task.nice_name}}_{{version.take_name}}" '_v{{"%03d"|format(version.version_number)}}{{extension}}', ) self.test_project.structure.templates.append(ft) new_version1 = Version(**self.kwargs) DBSession.add(new_version1) DBSession.commit() new_version1.update_paths() new_version1.extension = ".ma" self.assertEqual(new_version1.extension, ".ma") self.assertEqual(new_version1.absolute_full_path, "/mnt/T/tp/SH001/Task1/Task1_TestTake_v001.ma")
def test_inequality_operator(self): """testing inequality of two Version instances """ new_version1 = Version(**self.kwargs) DBSession.add(new_version1) DBSession.commit() new_version2 = Version(**self.kwargs) DBSession.add(new_version2) DBSession.commit() new_version3 = Version(**self.kwargs) DBSession.add(new_version3) DBSession.commit() new_version4 = Version(**self.kwargs) DBSession.add(new_version4) DBSession.commit() new_version5 = Version(**self.kwargs) DBSession.add(new_version5) DBSession.commit() new_version1.is_published = True new_version3.is_published = True new_version4.is_published = True self.assertTrue(new_version1 != new_version2) self.assertTrue(new_version1 != new_version3) self.assertTrue(new_version1 != new_version4) self.assertTrue(new_version1 != new_version5) self.assertTrue(new_version2 != new_version3) self.assertTrue(new_version2 != new_version4) self.assertTrue(new_version2 != new_version5) self.assertTrue(new_version3 != new_version4) self.assertTrue(new_version3 != new_version5) self.assertTrue(new_version4 != new_version5)
def test_start_end_and_duration_values_are_rounded_to_the_Studio_timing_resolution(self): """testing if the start and end dates are rounded to the Studio timing_resolution """ from stalker.models.studio import Studio studio = Studio( name='Test Studio', timing_resolution=datetime.timedelta(minutes=5) ) DBSession.add(studio) DBSession.commit() self.kwargs['start'] = datetime.datetime(2013, 3, 22, 2, 38, 55, 531) self.kwargs['end'] = datetime.datetime(2013, 3, 24, 16, 46, 32, 102) new_foo_obj = DateRangeMixFooMixedInClass(**self.kwargs) # check the start expected_start = datetime.datetime(2013, 3, 22, 2, 40) self.assertEqual(new_foo_obj.start, expected_start) # check the end expected_end = datetime.datetime(2013, 3, 24, 16, 45) self.assertEqual(new_foo_obj.end, expected_end) # check the duration self.assertEqual(new_foo_obj.duration, expected_end - expected_start)
def update_version_inputs(self, parent_ref=None): """updates the references list of the current version :param parent_ref: the parent ref, if given will override the given version argument and a Version instance will be get from the given parent_ref.path. """ logger.debug('parent_ref: %s' % parent_ref) logger.debug('get a version') if not parent_ref: logger.debug('got no parent_ref') version = self.get_current_version() else: logger.debug('have a parent_ref') version = self.get_version_from_full_path(parent_ref.path) if version: logger.debug('got a version: %s' % version.absolute_full_path) # use the original version if it is a Repr version from anima.representation import Representation if Representation.repr_separator in version.take_name \ and version.parent: version = version.parent logger.debug( 'this is a representation switching to its parent: %s' % version ) # update the reference list referenced_versions = self.get_referenced_versions(parent_ref) version.inputs = referenced_versions # commit data to the database from stalker.db.session import DBSession DBSession.add(version) DBSession.commit()
def reference(self, version, use_namespace=True): """Creates an XRef for the given version in the current scene. :param version: The Stalker Verison instance. :param bool use_namespace: Use a namespace or not. :return: """ import os from anima.representation import Representation import pymxs rt = pymxs.runtime file_full_path = version.absolute_full_path namespace = os.path.basename(version.nice_name) namespace = namespace.split(Representation.repr_separator)[0] xref_objects = rt.getMAXFileObjectNames(file_full_path) xref = rt.xrefs.addNewXRefObject( file_full_path, xref_objects, # dupMtlNameAction='#autoRename' ) # append the referenced version to the current versions references # attribute current_version = self.get_current_version() if current_version: current_version.inputs.append(version) from stalker.db.session import DBSession DBSession.commit() # append it to reference path self.append_to_recent_files(file_full_path) return xref
def test_timeLog_creation_for_a_child_task(self): """testing TimeLog creation for a child task which has a couple of parent tasks """ dt = datetime.datetime td = datetime.timedelta parent_task1 = Task( name="Parent Task 1", project=self.test_project, status_list=self.test_task_status_list, ) parent_task2 = Task( name="Parent Task 2", project=self.test_project, status_list=self.test_task_status_list, ) child_task1 = Task( name="Child Task 1", project=self.test_project, status_list=self.test_task_status_list, resources=[self.test_resource1] ) child_task2 = Task( name="Child Task 1", project=self.test_project, status_list=self.test_task_status_list, resources=[self.test_resource2] ) # Task hierarchy # +-> p1 # | | # | +-> p2 # | | | # | | +-> c1 # | | # | +-> c2 # | # +-> self.test_task1 parent_task2.parent = parent_task1 child_task2.parent = parent_task1 child_task1.parent = parent_task2 from stalker.db.session import DBSession self.assertEqual(parent_task1.total_logged_seconds, 0) self.assertEqual(parent_task2.total_logged_seconds, 0) self.assertEqual(child_task1.total_logged_seconds, 0) self.assertEqual(child_task2.total_logged_seconds, 0) # now create a time log for child_task2 tlog1 = TimeLog( task=child_task2, resource=child_task2.resources[0], start=dt(2013, 7, 31, 10, 0), end=dt(2013, 7, 31, 19, 0) ) # before commit self.assertEqual(parent_task1.total_logged_seconds, 9 * 3600) self.assertEqual(parent_task2.total_logged_seconds, 0) self.assertEqual(child_task1.total_logged_seconds, 0) self.assertEqual(child_task2.total_logged_seconds, 9 * 3600) # commit changes DBSession.add(tlog1) DBSession.commit() # after commit it should not change self.assertEqual(parent_task1.total_logged_seconds, 9 * 3600) self.assertEqual(parent_task2.total_logged_seconds, 0) self.assertEqual(child_task1.total_logged_seconds, 0) self.assertEqual(child_task2.total_logged_seconds, 9 * 3600) # add a new tlog to child_task2 and commit it # now create a time log for child_task2 tlog2 = TimeLog( task=child_task2, resource=child_task2.resources[0], start=dt(2013, 7, 31, 19, 0), end=dt(2013, 7, 31, 22, 0) ) self.assertEqual(parent_task1.total_logged_seconds, 12 * 3600) self.assertEqual(parent_task2.total_logged_seconds, 0) self.assertEqual(child_task1.total_logged_seconds, 0) self.assertEqual(child_task2.total_logged_seconds, 12 * 3600) # commit changes DBSession.add(tlog2) DBSession.commit() self.assertEqual(parent_task1.total_logged_seconds, 12 * 3600) self.assertEqual(parent_task2.total_logged_seconds, 0) self.assertEqual(child_task1.total_logged_seconds, 0) self.assertEqual(child_task2.total_logged_seconds, 12 * 3600) # add a new time log to child_task1 and commit it tlog3 = TimeLog( task=child_task1, resource=child_task1.resources[0], start=dt(2013, 7, 31, 10, 0), end=dt(2013, 7, 31, 19, 0) ) self.assertEqual(parent_task1.total_logged_seconds, 21 * 3600) self.assertEqual(parent_task2.total_logged_seconds, 9 * 3600) self.assertEqual(child_task1.total_logged_seconds, 9 * 3600) self.assertEqual(child_task2.total_logged_seconds, 12 * 3600) # commit changes DBSession.add(tlog3) DBSession.commit() self.assertEqual(parent_task1.total_logged_seconds, 21 * 3600) self.assertEqual(parent_task2.total_logged_seconds, 9 * 3600) self.assertEqual(child_task1.total_logged_seconds, 9 * 3600) self.assertEqual(child_task2.total_logged_seconds, 12 * 3600)
def accept(self): """overridden accept method """ # get the info task = self.tasks_combo_box.currentTask() resource = self.get_current_resource() # war the user if the resource is not the logged_in_user if resource != self.logged_in_user: msg_box = QtWidgets.QMessageBox(self) msg_box.setWindowTitle( 'Entering TimeLog On Behalf of Somebody Else' ) msg_box.setText( "You're entering a TimeLog on behalf of somebody else???" ) accept_button = msg_box.addButton( 'Accept the responsibility', QtWidgets.QMessageBox.AcceptRole ) cancel_button = msg_box.addButton( 'Cancel', QtWidgets.QMessageBox.RejectRole ) msg_box.setDefaultButton(cancel_button) msg_box.exec_() clicked_button = msg_box.clickedButton() msg_box.deleteLater() if clicked_button == cancel_button: return description = self.description_plain_text_edit.toPlainText() revision_cause_text = \ self.revision_type_combo_box.currentText().replace(' ', '_') is_complete = self.set_as_complete_radio_button.isChecked() submit_to_final_review = \ self.submit_for_final_review_radio_button.isChecked() # get the revision Types from stalker import Type revision_type = Type.query\ .filter(Type.target_entity_type == 'Note')\ .filter(Type.name == revision_cause_text)\ .first() date = self.calendar_widget.selectedDate() start = self.start_time_edit.time() end = self.end_time_edit.time() # construct proper datetime.DateTime instances import datetime start_date = datetime.datetime( date.year(), date.month(), date.day(), start.hour(), start.minute() ) end_date = datetime.datetime( date.year(), date.month(), date.day(), end.hour(), end.minute() ) today_midnight = datetime.datetime.now().replace( hour=23, minute=59, second=59, microsecond=999 ) # raise an error if the user is trying to enter a TimeLog to the future if start_date > today_midnight or end_date > today_midnight: QtWidgets.QMessageBox.critical( self, 'Error', 'Gelecege TimeLog giremezsiniz!!!', ) return # convert them to utc from anima.utils import local_to_utc utc_start_date = local_to_utc(start_date) utc_end_date = local_to_utc(end_date) # create a TimeLog # print('Task : %s' % task.name) # print('Resource : %s' % resource.name) # print('utc_start_date: %s' % utc_start_date) # print('utc_end_date : %s' % utc_end_date) # now if we are not using extra time just create the TimeLog from stalker import TimeLog from stalker.db.session import DBSession from stalker.exceptions import (OverBookedError, DependencyViolationError) utc_now = local_to_utc(datetime.datetime.now()) # TODO: Remove this in a later version import stalker from distutils.version import LooseVersion if LooseVersion(stalker.__version__) >= LooseVersion('0.2.18'): # inject timezone info import pytz utc_start_date = utc_start_date.replace(tzinfo=pytz.utc) utc_end_date = utc_end_date.replace(tzinfo=pytz.utc) utc_now = utc_now.replace(tzinfo=pytz.utc) from sqlalchemy.exc import IntegrityError if not self.timelog: try: new_time_log = TimeLog( task=task, resource=resource, start=utc_start_date, end=utc_end_date, description=description, date_created=utc_now ) except (OverBookedError, DependencyViolationError) as e: # inform the user that it can not do that QtWidgets.QMessageBox.critical( self, 'Error', '%s' % e ) DBSession.rollback() return try: DBSession.add(new_time_log) DBSession.commit() self.timelog_created = True except IntegrityError as e: DBSession.rollback() QtWidgets.QMessageBox.critical( self, 'Error', 'Database Error!!!' '<br>' '%s' % e ) return else: # just update the date values self.timelog.start = utc_start_date self.timelog.end = utc_end_date self.timelog.date_updated = utc_now DBSession.add(self.timelog) DBSession.commit() if self.no_time_left: # we have no time left so automatically extend the task from stalker import Task schedule_timing, schedule_unit = \ task.least_meaningful_time_unit( task.total_logged_seconds ) if schedule_timing != 0: task.schedule_timing = schedule_timing task.schedule_unit = schedule_unit # also create a Note from stalker import Note new_note = Note( content='Extending timing of the task <b>%s h %s min.</b>' % ( self.extended_hours, self.extended_minutes ), type=revision_type, created_by=self.logged_in_user, date_created=utc_now ) DBSession.add(new_note) task.notes.append(new_note) try: DBSession.commit() except IntegrityError as e: QtWidgets.QMessageBox.critical( self, 'Error', 'Database Error!!!' '<br>' '%s' % e ) DBSession.rollback() return if is_complete: # set the status to complete from stalker import Type, Status status_cmpl = Status.query.filter(Status.code == 'CMPL').first() forced_status_type = \ Type.query.filter(Type.name == 'Forced Status').first() # also create a Note from stalker import Note new_note = Note( content='%s has changed this task status to Completed' % resource.name, type=forced_status_type, created_by=self.logged_in_user, date_created=utc_now ) DBSession.add(new_note) task.notes.append(new_note) task.status = status_cmpl DBSession.commit() elif submit_to_final_review: # clip the Task timing to current time logs from stalker import Task schedule_timing, schedule_unit = \ task.least_meaningful_time_unit( task.total_logged_seconds ) task.schedule_timing = schedule_timing task.schedule_unit = schedule_unit DBSession.add(task) try: DBSession.commit() except IntegrityError as e: QtWidgets.QMessageBox.critical( self, 'Error', 'Database Error!!!' '<br>' '%s' % e ) DBSession.rollback() return # request a review reviews = task.request_review() for review in reviews: review.created_by = review.updated_by = self.logged_in_user review.date_created = utc_now review.date_updated = utc_now DBSession.add_all(reviews) # and create a Note for the Task request_review_note_type = \ Type.query\ .filter(Type.target_entity_type == 'Note')\ .filter(Type.name == 'Request Review')\ .first() from stalker import Note request_review_note = Note( type=request_review_note_type, created_by=self.logged_in_user, date_created=utc_now ) DBSession.add(request_review_note) DBSession.add(task) task.notes.append(request_review_note) try: DBSession.commit() except IntegrityError as e: DBSession.rollback() QtWidgets.QMessageBox.critical( self, 'Error', 'Database Error!!!' '<br>' '%s' % e ) return # Fix statuses from anima import utils utils.fix_task_statuses(task) try: DBSession.commit() except IntegrityError as e: DBSession.rollback() QtWidgets.QMessageBox.critical( self, 'Error', 'Database Error!!!' '<br>' '%s' % e ) return # if nothing bad happens close the dialog super(MainDialog, self).accept()
def register(class_): """Registers the given class to the database. It is mainly used to create the :class:`.Action`\ s needed for the :class:`.User`\ s and :class:`.Group`\ s to be able to interact with the given class. Whatever class you have created needs to be registered. Example, lets say that you have a data class which is specific to your studio and it is not present in Stalker Object Model (SOM), so you need to extend SOM with a new data type. Here is a simple Data class inherited from the :class:`.SimpleEntity` class (which is the simplest class you should inherit your classes from or use more complex classes down to the hierarchy):: from sqlalchemy import Column, Integer, ForeignKey from stalker.models.entity import SimpleEntity class MyDataClass(SimpleEntity): '''This is an example class holding a studio specific data which is not present in SOM. ''' __tablename__ = 'MyData' __mapper_arguments__ = {'polymorphic_identity': 'MyData'} my_data_id = Column('id', Integer, ForeignKey('SimpleEntities.c.id'), primary_key=True) Now because Stalker is using Pyramid authorization mechanism it needs to be able to have an :class:`.Permission` about your new class, so you can assign this :class;`.Permission` to your :class:`.User`\ s or :class:`.Group`\ s. So you ned to register your new class with :func:`stalker.db.register` like shown below:: from stalker import db db.register(MyDataClass) This will create the necessary Actions in the 'Actions' table on your database, then you can create :class:`.Permission`\ s and assign these to your :class:`.User`\ s and :class:`.Group`\ s so they are Allowed or Denied to do the specified Action. :param class_: The class itself that needs to be registered. """ from stalker.models.auth import Permission # create the Permissions permissions_db = Permission.query.all() if not isinstance(class_, type): raise TypeError("To register a class please supply the class itself.") # register the class name to entity_types table from stalker import EntityType, StatusMixin, DateRangeMixin, ReferenceMixin, ScheduleMixin class_name = class_.__name__ if not EntityType.query.filter_by(name=class_name).first(): new_entity_type = EntityType(class_name) # update attributes if issubclass(class_, StatusMixin): new_entity_type.statusable = True if issubclass(class_, DateRangeMixin): new_entity_type.dateable = True if issubclass(class_, ScheduleMixin): new_entity_type.schedulable = True if issubclass(class_, ReferenceMixin): new_entity_type.accepts_references = True DBSession.add(new_entity_type) for action in defaults.actions: for access in ["Allow", "Deny"]: permission_obj = Permission(access, action, class_name) if permission_obj not in permissions_db: DBSession.add(permission_obj) try: DBSession.commit() except IntegrityError: DBSession.rollback()