Ejemplo n.º 1
0
    def updateTasks(self, ftrackEntity):
        '''Update task with the provided *ftrackEntity*'''
        self.currentTask = ftrackEntity
        try:
            shotpath = self.currentTask.getName()
            taskParents = self.currentTask.getParents()

            for parent in taskParents:
                shotpath = '{0}.{1}'.format(parent.getName(), shotpath)

            self.ui.AssetTaskComboBox.clear()
            tasks = self.currentTask.getTasks()
            curIndex = 0
            ftrackuser = ftrack.User(getpass.getuser())
            taskids = [x.getId() for x in ftrackuser.getTasks()]

            for i in range(len(tasks)):
                assetTaskItem = QtGui.QStandardItem(tasks[i].getName())
                assetTaskItem.id = tasks[i].getId()
                self.ui.AssetTaskComboBoxModel.appendRow(assetTaskItem)

                if (os.environ.get('FTRACK_TASKID') == assetTaskItem.id):
                    curIndex = i
                else:
                    if assetTaskItem.id in taskids:
                        curIndex = i

            self.ui.AssetTaskComboBox.setCurrentIndex(curIndex)

        except:
            print 'Not a task'
Ejemplo n.º 2
0
def callback(event):
    """ This plugin creates a template folder structure on disk.
    """
    for entity in event['data'].get('entities', []):
        if entity.get('entityType') == 'task' and entity['action'] == 'add':
            task = ftrack.Task(id=entity['entityId'])
            user = ftrack.User(id=event['source']['user']['id'])
            taskName = task.getName().lower()
            if task.getObjectType() == 'Task':
                project = task.getProject()
                projFolder = getProjectFolder(project)
                shotName = task.getParent().getName()
                if task.getParent().get('objecttypename') == 'Asset Build':
                    taskFolder = createAssetFolders(task, projFolder)
                    shotName = '{0}_{1}'.format(shotName, taskName)
                else:
                    shotsFolder = os.path.join(projFolder, 'shots')
                    shotFolder = getShotFolder(task)
                    if shotFolder == '':
                        return
                    sceneFolder = os.path.join(shotsFolder, shotFolder, 'scene')
                    taskFolder = os.path.join(sceneFolder, taskName)
                    if not os.path.exists(taskFolder):
                        os.makedirs(taskFolder)
                        try:
                            os.chmod(taskFolder, 0777)
                        except:
                            print "could not change directory permission for %s" % taskFolder
                templateFolder = os.path.join(projFolder, 'template_files')
                createTemplateFiles(templateFolder, task, taskFolder, shotName, user)
                syncToCpt(taskFolder.rstrip('/'))
Ejemplo n.º 3
0
    def _updateAssignedList(self):
        '''Update assigned list.'''
        self.assignedTimeLogList.clearItems()

        # Local import to allow configuring of ftrack API at runtime.
        import ftrack

        # TODO: Get logged in user from ftrack API.
        # NOTE: The specific environment variable is used as it is explicitly
        # set post login by the application.
        username = os.environ.get('LOGNAME')
        if not username:
            return

        assignedTasks = ftrack.User(username).getTasks(
            states=['NOT_STARTED', 'IN_PROGRESS', 'BLOCKED'])

        formattedTasks = [
            dict({
                'title': task.getName(),
                'description': self._getPath(task),
                'data': task
            }) for task in assignedTasks
        ]

        formattedTasks = sorted(formattedTasks,
                                key=operator.itemgetter(
                                    'description', 'title'))

        for task in formattedTasks:
            self.assignedTimeLogList.addItem(task)
Ejemplo n.º 4
0
    def launch(self, event):
        """
        Called when action is executed
        """
        selection = event['data'].get('selection', [])
        task = ftrack.Task(selection[0]['entityId'])
        user = ftrack.User(id=event['source']['user']['id'])
        taskType = task.getType().getName().lower()

        taskFolder = self.getTaskFolder(task)
        if not os.path.exists(taskFolder):
            os.makedirs(taskFolder)

        shotName = task.getParent().getName()
        publishFile = ''
        newFilePath = os.path.join(taskFolder, '%s_v01.mb' % shotName)

        if taskType == 'previz':
            publishFile = self.copyFromLayoutPublish(taskFolder, 'previz')
            if os.path.exists(publishFile) and not os.path.exists(newFilePath):
                shutil.copy(publishFile, newFilePath)
            os.chmod(newFilePath, 0666)
        elif taskType == 'animation':
            previzDir = os.path.join(
                taskFolder.split('animation')[0], 'previz')
            previzFiles = [
                f for f in glob.glob(os.path.join(previzDir, '*_v[0-9]*.mb'))
            ]
            # get latest previz file
            if previzFiles:
                maxVersion = 1
                for f in previzFiles:
                    try:
                        version = int(self.version_get(f, 'v')[1])
                    except ValueError:
                        continue
                    if version >= maxVersion:
                        publishFile = f
                        maxVersion = version
                publishFile = os.path.join(previzDir, publishFile)
            # Else get latest layout publish file
            else:
                publishFile = self.copyFromLayoutPublish(
                    taskFolder, 'animation')
            # Copy over the latest publish file.
            if os.path.exists(publishFile) and not os.path.exists(newFilePath):
                shutil.copy(publishFile, newFilePath)
            os.chmod(newFilePath, 0666)
        elif taskType == 'lighting':
            mayapy = '/usr/autodesk/maya2016/bin/mayapy'
            if os.path.exists(mayapy):
                self.buildLightingScene(mayapy, task.getId(), taskFolder, user,
                                        newFilePath, shotName)

        metadata = task.getMeta()
        metadata['filename'] = newFilePath
        task.setMeta(metadata)

        return {'success': True, 'message': 'Action launched successfully.'}
Ejemplo n.º 5
0
def create_job(event):
    values = event['data']['values']
    job = ftrack.createJob('Generating Titles', 'queued',
                           ftrack.User(id=event['source']['user']['id']))
    job.setStatus('running')

    image_magick_dir = r'K:\development\tools\image-magick'
    errors = ''

    # Generateting sources and destinations
    for item in event['data']['selection']:
        try:
            entity = ftrack.AssetVersion(item['entityId'])

            # adding path to errors
            path = ''
            parents = entity.getParents()
            parents.reverse()
            for p in parents:
                path += p.getName() + '/'

            path += 'v' + str(entity.getVersion()).zfill(3)

            input_file = entity.getComponent().getFilesystemPath()
            output_file = ntpath.basename(input_file)

            # get version string
            version_string = '.v' + version_get(input_file, 'v')[1]
            if values['strip_version'] == 'True':
                output_file = output_file.replace(version_string, '')

            # get titles text
            south_west_text = 'Task: "%s"' % path[:-5]
            south_east_text = 'Version: "%s"' % version_string[1:]
            north_west_text = 'Status: "%s"' % entity.getStatus().getName()

            if entity.getAsset().getType().getShort() == 'img':
                src = os.listdir(os.path.dirname(input_file))[0]
                input_file = os.path.join(os.path.dirname(input_file), src)
                output_file = re.sub(r'.%04d', '', output_file)

            output_file = os.path.splitext(output_file)[0] + '.png'
            output_file = os.path.join(values['output_directory'], output_file)

            generate_title(image_magick_dir, output_file, input_file, '25',
                           south_west_text, south_east_text, north_west_text)
        except:
            errors += path + '\n'
            errors += traceback.format_exc() + '\n'

    # generate error report
    if errors:
        temp_txt = os.path.join(values['output_directory'], 'errors.txt')
        f = open(temp_txt, 'w')
        f.write(errors)
        f.close()

    job.setStatus('done')
Ejemplo n.º 6
0
def callback(event):
    for entity in event['data'].get('entities', []):

        # Filter non-assetversions
        if entity.get('entityType') == 'task' and entity['action'] == 'update':

            if 'statusid' not in entity.get('keys'):
                return

            # Find task if it exists
            try:
                task = ftrack.Task(id=entity.get('entityId'))
            except:
                return

            # remove status assigned users
            if task.getMeta('assignees'):
                for userid in task.getMeta('assignees').split(','):
                    try:
                        task.unAssignUser(ftrack.User(userid))
                    except:
                        pass

            # getting status named group
            task_status_name = task.getStatus().get('name').lower()

            project = task.getParents()[-1]
            status_group = None
            for group in project.getAllocatedGroups():
                if group.getSubgroups():
                    if group.get('name').lower() == task_status_name:
                        status_group = group

            users = []
            if status_group:

                for group in status_group.getSubgroups():
                    task_type_name = task.getType().get('name').lower()
                    if task_type_name == group.get('name').lower():

                        # assigning new users
                        for member in group.getMembers():
                            try:
                                task.assignUser(member)
                                users.append(member.get('userid'))
                            except:
                                pass

            # storing new assignees
            value = ''
            for user in users:
                value += user + ','
            try:
                value = value[:-1]
            except:
                pass
            task.setMeta('assignees', value=value)
Ejemplo n.º 7
0
    def launch(self, event):
        """
        Called when action is executed
        """
        selection = event['data'].get('selection', [])
        user = ftrack.User(id=event['source']['user']['id'])
        task = ftrack.Task(id=selection[0]['entityId'])
        shot = task.getParent()

        if 'values' in event['data']:
            values = event['data']['values']
            self.uploadToFtrack(values['file_path'], values['asset_name'],
                                values['note'], values['add_slate'],
                                selection[0]['entityId'], shot, user)
            return {
                'success': True,
                'message': 'Action completed successfully'
            }

        return {
            'items': [{
                    'value': '##{0}##'.format('File Path'.capitalize()),
                    'type': 'label'
                }, {
                    'label': 'Folder',
                    'type': 'text',
                    'value': '',
                    'name': 'file_path'
                }, {
                    'label':'Add Slate',
                    'type':'enumerator',
                    'value': 'No',
                    'name':'add_slate',
                    'data':[{
                        'label': 'Yes',
                        'value': 'Yes'
                    }, {
                        'label': 'No',
                        'value': 'No'
                    }]
                }, {
                    'label': 'Asset Name',
                    'type': 'text',
                    'value': 'ReviewAsset',
                    'name': 'asset_name'
                }, {
                    'label': 'Add Note',
                    'type': 'textarea',
                    'value': 'Done: \nTo Do:',
                    'name': 'note'
                }]
            }
Ejemplo n.º 8
0
    def launch(self, event):
        """
        Called when action is executed
        """
        user = ftrack.User(id=event['source']['user']['id'])

        if 'values' in event['data']:
            values = event['data']['values']
            path = values['file_path']
            value = values['xfer_loc']
            queue = values['queue']
            #if os.path.exists(path):
            self.cptSync(path, value, user, queue)
            return {'success': True, 'message': 'Starting File Sync'}

        return {
            'items': [{
                'value':
                '##{0}##'.format(
                    'Enter a file/folder to transfer.'.capitalize()),
                'type':
                'label'
            }, {
                'label': 'Path:',
                'type': 'text',
                'value': '',
                'name': 'file_path'
            }, {
                'label':
                'Transfer Location:',
                'type':
                'enumerator',
                'value':
                0,
                'name':
                'xfer_loc',
                'data': [{
                    'label': 'CPT -> JHB',
                    'value': 0
                }, {
                    'label': 'JHB -> CPT',
                    'value': 1
                }]
            }, {
                'label': 'Add to overnight queue',
                'name': 'queue',
                'type': 'boolean',
                'value': False
            }]
        }
Ejemplo n.º 9
0
    def create_job(self, event):
        job = ftrack.createJob("Generating Feedback", "queued",
                               ftrack.User(id=event["source"]["user"]["id"]))
        job.setStatus("running")

        try:
            f = self.generate_feedback(event)
            job.createAttachment(f, fileName=f)
            os.remove(f)
        except:
            self.logger.error(traceback.format_exc())
            job.setStatus("failed")
        else:
            job.setStatus("done")
Ejemplo n.º 10
0
def sendEmail(
    userId,
    subject,
    message,
    recipients=[],
    filename='',
):
    sender = ftrack.User(userId).getEmail()
    msg = MIMEMultipart()
    msg['Subject'] = subject
    msg['From'] = sender
    msg['Reply-to'] = sender
    msg['To'] = ', '.join(recipients)

    # That is what u see if dont have an email reader:
    msg.preamble = 'Multipart massage.\n'

    # This is the textual part:
    part = MIMEText(message)
    msg.attach(part)

    filetype = os.path.splitext(filename)[-1]

    if filetype is not '':
        if filetype == '.pdf':
            # This is the binary part:
            part = MIMEApplication(open(filename, "rb").read(),
                                   "pdf",
                                   name="reviewsession.pdf")
            part.add_header('Content-Disposition',
                            'attachment',
                            filename="reviewsession.pdf")
            msg.attach(part)
        elif filetype == '.html':
            f = file(filename)
            attachment = MIMEText(f.read())
            attachment.add_header('Content-Disposition',
                                  'attachment',
                                  filename="reviewsession.html")
            msg.attach(attachment)

    # add any smtp server
    server = SMTP('smtp.gmail.com:587')
    server.ehlo()
    server.starttls()
    # log in with your credentials
    server.login(YOUR_USERNAME, YOUR_PASSWORD)
    server.sendmail(msg['From'], msg['To'], msg.as_string())
    server.quit()
Ejemplo n.º 11
0
def getEntity(entityType=None, entityId=None):
        if entityType is None or entityId is None:
            return None
        if entityType == 'user':
            return ftrack.User(entityId)
        if entityType == 'show':
            return ftrack.Project(entityId)
        elif entityType == 'task':
            return ftrack.Task(entityId)
        elif entityType == 'list':
            return ftrack.List(entityId)
        elif entityType == 'reviewsession':
            return ftrack.ReviewSession(entityId)
        else:
            return None
Ejemplo n.º 12
0
def create_job(event):

    job = ftrack.createJob("Create Structure", "queued",
                           ftrack.User(id=event["source"]["user"]["id"]))
    job.setStatus("running")

    try:
        for item in event["data"]["selection"]:
            # Geting any object types
            entity_id = item["entityId"]
            entity = session.get("TypedContext", entity_id)

            if not entity:
                entity_type = item["entityType"].lower()

                if entity_type == "show":
                    entity = session.get("Project", entity_id)
                if entity_type == "assetversion":
                    entity = session.get("AssetVersion", entity_id)
                if entity_type == "component":
                    entity = session.get("Component", entity_id)

            templates = ftrack_template.discover_templates()
            valid_templates = ftrack_template.format(
                {}, templates, entity, return_mode="all"
            )

            print "Creating Directories/Files:"
            for path, template in valid_templates:

                if template.isfile:
                    if not os.path.exists(os.path.dirname(path)):
                        print os.path.dirname(path)
                        os.makedirs(os.path.dirname(path))

                    if not os.path.exists(path):
                        print path
                        shutil.copy(template.source, path)
                else:
                    if not os.path.exists(path):
                        print path
                        os.makedirs(path)
    except:
        print traceback.format_exc()
        job.setStatus("failed")
    else:
        job.setStatus("done")
def callback(event):
    """ This plugin sets the task status from the version status update.
    """

    for entity in event['data'].get('entities', []):
        if (entity.get('entityType') == 'reviewsessionobject'
                and entity['action'] == 'add'):

            version = None
            try:
                version_id = entity['changes']['version_id']['new']
                version = ftrack.AssetVersion(version_id)
            except:
                return

            user = ftrack.User(event['source']['user']['id'])
            os.environ['LOGNAME'] = user.getUsername()

            myclass = Thread(version, user)
            myclass.start()
Ejemplo n.º 14
0
def create_job(event):

    job = ftrack.createJob("Version Up Tasks", "queued",
                           ftrack.User(id=event["source"]["user"]["id"]))
    job.setStatus("running")

    try:
        for item in event["data"]["selection"]:
            task = ftrack.Task(item["entityId"])

            asset = task.getParent().createAsset(task.getName(),
                                                 "scene",
                                                 task=task)

            asset.createVersion(taskid=task.getId())

            asset.publish()

    except:
        job.setStatus("failed")
    else:
        job.setStatus("done")
Ejemplo n.º 15
0
    def __init__(self, username, parent=None):
        '''Instantiate user name and logo widget using *username*.'''

        super(User, self).__init__(parent=parent)
        self.setObjectName('ftrack-userid-widget')
        self.main_layout = QtWidgets.QHBoxLayout()
        self.main_layout.setContentsMargins(0, 0, 0, 0)
        self.main_layout.setAlignment(QtCore.Qt.AlignRight)
        self.setLayout(self.main_layout)

        self.label = QtWidgets.QLabel(self)
        self.image = thumbnail.User(self)
        self.image.setFixedSize(35, 35)

        self.main_layout.addWidget(self.label)
        self.main_layout.addWidget(self.image)

        self.image.load(username)

        if username not in NAME_CACHE:
            NAME_CACHE[username] = ftrack.User(username).getName().title()

        self.label.setText(NAME_CACHE[username])
Ejemplo n.º 16
0
def callback(event):
    for entity in event['data'].get('entities', []):

        # Filter non-assetversions
        if entity.get('entityType') == 'task' and entity['action'] == 'update':

            if 'statusid' not in entity.get('keys'):
                return

            # Find task if it exists
            task = None
            try:
                task = ftrack.Task(id=entity.get('entityId'))
            except:
                return

            new_status = ftrack.Status(entity["changes"]["statusid"]["new"])

            # To Pending Changes
            if new_status.getName().lower() == "pending changes":

                user = ftrack.User(id=event["source"]["user"]["id"])
                job = ftrack.createJob("Version Up Tasks", "queued", user)
                job.setStatus("running")

                try:
                    asset = task.getParent().createAsset(task.getName(),
                                                         "scene",
                                                         task=task)

                    asset.createVersion(taskid=task.getId())

                    asset.publish()
                except:
                    job.setStatus("failed")
                else:
                    job.setStatus("done")
Ejemplo n.º 17
0
    def launch(self, event):

        msg = 'Breakdown successfull. Click Job for details.'
        ftrack.EVENT_HUB.publishReply(event,
                                      data={
                                          'success': True,
                                          'message': msg
                                      })

        temp_dir = tempfile.gettempdir()
        file_path = os.path.join(temp_dir, 'ftrack_version_breakdown.txt')
        with open(file_path, 'w') as f:
            output = ''
            v = ftrack.AssetVersion('6dec6756-8f94-11e5-929c-42010af00048')
            output += '/'.join([
                v.getParent().getParent().getName(),
                v.getParent().getName(),
                str(v.getVersion()).zfill(3)
            ])
            output += ':\n'
            count = 0
            sessions = []
            project_id = v.getParents()[-1].getId()
            for session in ftrack.getReviewSessions(project_id):
                for obj in session.getObjects():
                    if obj.get('version_id') == v.getId():
                        count += 1
                        sessions.append(session.get('name'))

            output += '\tSession Usage:\t{0}\n'.format(count)
            output += '\tSessions:\t\t{0}\n'.format(list(set(sessions)))

            f.write(output)

        user = ftrack.User(id=event['source']['user']['id'])
        job = ftrack.createJob('Breakdown', 'done', user)
        job.createAttachment(file_path)
Ejemplo n.º 18
0
    def constructWidget(self):
        '''Return widget instance to test.'''
        widget = QtGui.QWidget()
        layout = QtGui.QVBoxLayout()
        widget.setLayout(layout)
        layout.setContentsMargins(0, 0, 0, 0)

        allAssignedTasks = ftrack.User(
            os.environ.get('LOGNAME')
        ).getTasks(
            states=['IN_PROGRESS', 'BLOCKED']
        )

        assignedTasksList = ftrack_connect.ui.widget.time_log_list.TimeLogList(
            title='Assigned tasks'
        )

        layout.addWidget(assignedTasksList, stretch=1)

        for task in allAssignedTasks:
            assignedTasksList.addItem({
                'title': task.getName(),
                'description': self._getPath(task),
                'data': task
            })

        divider = QtGui.QFrame()
        divider.setFrameShape(QtGui.QFrame.HLine)
        layout.addWidget(divider)

        self.selectedTasklabel = QtGui.QLabel()
        assignedTasksList.itemSelected.connect(self._setLabelText)

        layout.addWidget(self.selectedTasklabel)

        return widget
Ejemplo n.º 19
0
def createTimelogBreakdown(entityType=None, entity=None, userId=None, values=None):
    description = u'Generating timelog report'
    job = ftrack.createJob(
        description=description,
        status='running',
        user=userId
    )

    try:
        html = ""
        range=values['date_range']
        report=values['report_type']
        filterOnUserId=values['user']

        today = datetime.date.today()
        date_range = (today - datetime.timedelta(days=1), today)
        if range == "yesterday":
            date_range = (today - datetime.timedelta(days=2), today - datetime.timedelta(days=1))
        if range == "this_week":
            date_range = getWeek(today)
        if range == "prev_week":
            date_range = getWeek(today - datetime.timedelta(weeks=1))
        if range == "this_month":
            date_range = getMonth(today)
        if range == "prev_month":
            date_range = getMonth(today.replace(day=1) - datetime.timedelta(days=1))
        if range == "this_year":
            date_range = (datetime.date(datetime.date.today().year, 1, 1), datetime.date(datetime.date.today().year, 12, 31))
        if range == "prev_year":
            date_range = (datetime.date(datetime.date.today().year-1, 1, 1), datetime.date(datetime.date.today().year-1, 12, 31))

        title = ''
        if filterOnUserId != 'all':
            title = entity.getName() + " <small>["  + ftrack.User(filterOnUserId).getName() + "] " + date_range[0].strftime('%d') + " " + date_range[0].strftime('%B') + ", " + date_range[0].strftime('%Y') + " - " + date_range[1].strftime('%d') + " " + date_range[1].strftime('%B') + ", " + date_range[1].strftime('%Y') + " </small>"
        else:
            title = entity.getName() + " <small>"+ date_range[0].strftime('%d') + " " + date_range[0].strftime('%B') + ", " + date_range[0].strftime('%Y') + " - " + date_range[1].strftime('%d') + " " + date_range[1].strftime('%B') + ", " + date_range[1].strftime('%Y') + " </small>"

        # HTML Header
        html = "  <html><head>\
                <style>\
                @page { padding: 10pt}\
                @page { margin: 20px; }\
                @page { size: A3}\
                @page { size: A3 landscape }\
                body{margin:30px; padding: 10px}\
                img { page-break-inside: avoid; }\
                .break { clear:both; page-break-after:always; }\
                td, th { page-break-inside: avoid; }\
                </style>\
                <link rel='stylesheet' href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css'>\
                <link rel='stylesheet' href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap-theme.min.css'>\
                <script type='text/javascript' src='https://www.google.com/jsapi'></script>"

        # Load Google charts
        html = html + "\
                <script type='text/javascript'>\
                google.load('visualization', '1.0', {'packages':['timeline', 'calendar', 'corechart']});\
                google.setOnLoadCallback(drawChart);"

        # Create Google Timeline object
        html = html + "\
                var chartTimeline = null;\
                var dataTableTimeline = null;\
                var optionsTimeline = null;\
                function drawChart() {\
                    var timeline = document.getElementById('timeline');\
                    chartTimeline = new google.visualization.Timeline(timeline);\
            \
                    dataTableTimeline = new google.visualization.DataTable();\
                    dataTableTimeline.addColumn({ type: 'string', id: 'Task' });\
                    dataTableTimeline.addColumn({ type: 'string', id: 'User' });\
                    dataTableTimeline.addColumn({ type: 'date', id: 'Start' });\
                    dataTableTimeline.addColumn({ type: 'date', id: 'End' });\
                    dataTableTimeline.addRows(["

        # Helpers to keep track of accumulated timelogs/duration
        accumulatedSecondsPerTask = {}
        accumulatedSecondsPerDay = {}
        accumulatedNonBillableSecondsPerDay = {}
        accumulatedSecondsPerUser = {}
        billable = 0
        totalSeconds = 0

        # If selection is a task/folder, add [filtered] timelog events.
        if entityType != 'user':
            tasks = []
            user=None
            if filterOnUserId != 'all':
                user = ftrack.User(filterOnUserId)
                tasks = getTasks(entityType=entityType, entity=entity)
                #tasks = getTasks(entityType=entityType, entity=entity, users=[user.getUsername()])
            else:
                tasks = getTasks(entityType=entityType, entity=entity)
            job.setDescription("Generating timelog report")
            numberOfTasks = len(tasks)
            for i, task in enumerate(tasks):
                if numberOfTasks > 100 and i % 10 == 0:
                    job.setDescription("Generating timelog report - {0:.2f}%".format((float(i)/numberOfTasks)*100))
                timelogs = task.getTimelogs(start=date_range[0], end=date_range[1], includeChildren=False)
                if len(timelogs) == 0:
                    continue

                taskname = task.getName()
                taskId = task.getId()
                isBillable = task.getType().get('isbillable')

                for timelog in timelogs:
                    u = timelog.getUser()
                    if user != None:
                        if u.getId() != filterOnUserId:
                            continue
                    start=timelog.get('start')
                    duration = timelog.get('duration')
                    end=start + datetime.timedelta(seconds = duration)

                    # a fail safe - Google charts will crash if end < start
                    if end < start:
                        end = start + datetime.timedelta(seconds = 60)

                    # accumulate helpers
                    totalSeconds += duration
                    if isBillable:
                        billable += duration
                    else:
                        if start.date() in accumulatedNonBillableSecondsPerDay:
                            accumulatedNonBillableSecondsPerDay[start.date()] += duration
                        else:
                            accumulatedNonBillableSecondsPerDay[start.date()] = duration

                    #create or update dictionary keys/values
                    if start.date() in accumulatedSecondsPerDay:
                        accumulatedSecondsPerDay[start.date()] += duration
                    else:
                        accumulatedSecondsPerDay[start.date()] = duration


                    if taskId in accumulatedSecondsPerTask:
                        accumulatedSecondsPerTask[taskId] += duration
                    else:
                        accumulatedSecondsPerTask[taskId] = duration

                    if u.getId() in accumulatedSecondsPerUser:
                        accumulatedSecondsPerUser[u.getId()] += duration
                    else:
                        accumulatedSecondsPerUser[u.getId()] = duration

                    # add row to timeline object
                    html=html + "\
                        [ '"+ taskname +"', '" + u.getName() + "', new Date(" + start.strftime('%Y') + "," + str(int(start.strftime('%m'))-1) + "," + start.strftime('%d') + ","+start.strftime('%H') + "," + start.strftime('%M') + "," + start.strftime('%S')+"), new Date(" + end.strftime('%Y') + "," +  str(int(end.strftime('%m'))-1) + "," + end.strftime('%d') + ","+end.strftime('%H') + "," + end.strftime('%M') + "," + end.strftime('%S')+")],"
                        #[ '{0}', '{1}', new Date({2},{3},{4},{5},{6},{7}), new Date({8},{9},{10},{11},{12},{13})],".format(taskname, u.getName(), start.strftime('%Y'), str(int(start.strftime('%m'))-1), start.strftime('%d'), start.strftime('%H'), start.strftime('%M'), start.strftime('%S'), end.strftime('%Y'), str(int(end.strftime('%m'))-1), end.strftime('%d'), end.strftime('%H'), end.strftime('%M'), end.strftime('%S'))
                        #[ '"+ taskname +"', '" + u.getName() + "', new Date(" + start.strftime('%Y') + "," + str(int(start.strftime('%m'))-1) + "," + start.strftime('%d') + ","+start.strftime('%H') + "," + start.strftime('%M') + "," + start.strftime('%S')+"), new Date(" + end.strftime('%Y') + "," +  str(int(end.strftime('%m'))-1) + "," + end.strftime('%d') + ","+end.strftime('%H') + "," + end.strftime('%M') + "," + end.strftime('%S')+")],"

        # If selection is a user, add [filtered] user timelog events.
        else:
            user = entity
            timelogs = user.getTimelogs(start=date_range[0], end=date_range[1], includeChildren=True)
            job.setDescription("Generating timelog report")
            for timelog in timelogs:
                try:
                    taskId = timelog.get('context_id')
                    task = ftrack.Task(taskId)
                    isBillable = task.getType().get('isbillable')
                    start=timelog.get('start')
                    duration = timelog.get('duration')
                    end=start + datetime.timedelta(seconds = duration)

                    # a fail safe - Google charts will crash if end < start
                    if end < start:
                        end = start + datetime.timedelta(seconds = 60)

                    # accumulate helpers
                    totalSeconds += duration
                    if isBillable:
                        billable += duration
                    else:
                        if start.date() in accumulatedNonBillableSecondsPerDay:
                            accumulatedNonBillableSecondsPerDay[start.date()] += duration
                        else:
                            accumulatedNonBillableSecondsPerDay[start.date()] = duration
                    #create or update dictionary keys/values
                    if start.date() in accumulatedSecondsPerDay:
                        accumulatedSecondsPerDay[start.date()] += duration
                    else:
                        accumulatedSecondsPerDay[start.date()] = duration

                    if taskId in accumulatedSecondsPerTask:
                        accumulatedSecondsPerTask[taskId] += duration
                    else:
                        accumulatedSecondsPerTask[taskId] = duration
                    if user.getId() in accumulatedSecondsPerUser:
                        accumulatedSecondsPerUser[user.getId()] += duration
                    else:
                        accumulatedSecondsPerUser[user.getId()] = duration

                    # add row to timeline object
                    html=html + "\
                        [ '{0}', '', new Date({1},{2},{3},{4},{5},{6}), new Date({7},{8},{9},{10},{11},{12})],".format(task.getName(), start.strftime('%Y'), str(int(start.strftime('%m'))-1), start.strftime('%d'), start.strftime('%H'), start.strftime('%M'), start.strftime('%S'), end.strftime('%Y'), str(int(end.strftime('%m'))-1), end.strftime('%d'), end.strftime('%H'), end.strftime('%M'), end.strftime('%S'))
                        #[ '" + task.getName() + "', '', new Date(" + start.strftime('%Y') + "," + str(int(start.strftime('%m'))-1) + "," + start.strftime('%d') + ","+start.strftime('%H') + "," + start.strftime('%M') + "," + start.strftime('%S')+"), new Date(" + end.strftime('%Y') + "," + str(int(end.strftime('%m'))-1) + "," + end.strftime('%d') + ","+end.strftime('%H') + "," + end.strftime('%M') + "," + end.strftime('%S')+")],"
                except:
                    pass
        html = html + "]);\
                        optionsTimeline = {\
                        timeline: { rowLabelStyle: {fontName: 'Helvetica', fontSize: 10, color: '#000000'}},\
                        avoidOverlappingGridLines: false,\
                        enableInteractivity: true,\
                    };\
                    chartTimeline.draw(dataTableTimeline, optionsTimeline);"

        # Create Google Pie chart options used by all Pie Charts in document
        html = html + "\
                    var optionsPieChart = {\
                        legend: {position: 'labeled'},\
                        is3D: false,\
                        pieHole: 0,\
                        chartArea:{width:'92%',height:'92%'},\
                        pieSliceText: 'value'\
                    };"

        # Create Google Pie chart object - Total hours
        html = html + "\
                    var dataBillable = google.visualization.arrayToDataTable([\
                    ['Task', 'Hours'],\
                    ['Billable', {0:.2f}],\
                    ['Non-billable',{1:.2f}]]);\
                    \
                    var chartBillable = new google.visualization.PieChart(document.getElementById('billable'));\
                    chartBillable.draw(dataBillable, optionsPieChart);".format(billable/3600, (totalSeconds-billable)/3600)

        # Create Google Pie chart object - User who've logged most hours
        html = html + "\
                    var dataUserMostHours = google.visualization.arrayToDataTable([\
                    ['User', 'Hours'],"
        # Loop through accumulatedSecondsPerUser and add records to chart
        u = sorted(accumulatedSecondsPerUser.items(),key=itemgetter(1),reverse=True)
        for i, t in enumerate(u):
            html = html + "\
                    ['{0}',{1:.2f}],".format(ftrack.User(t[0]).getName().encode('ascii', 'replace'), t[1]/3600)
            if i == 9:
                break

        html = html + "\
                    ]);\
                    var chartUserMostHours = new google.visualization.PieChart(document.getElementById('userMostHours'));\
                    chartUserMostHours.draw(dataUserMostHours, optionsPieChart);"

        # Create Google Pie chart object - Tasks with most hours logged
        html = html + "\
                    var dataTaskMostHours = google.visualization.arrayToDataTable([\
                    ['Task', 'Hours'],"
        # Loop through accumulatedSecondsPerTask and add records to chart
        l = sorted(accumulatedSecondsPerTask.items(),key=itemgetter(1),reverse=True)
        for i, t in enumerate(l):
            html = html + "\
                    ['{0}',{1:.2f}],".format(ftrack.Task(t[0]).getName(), t[1]/3600)
            if i == 9:
                break

        html = html + "\
                    ]);\
                    var chartTaskMostHours = new google.visualization.PieChart(document.getElementById('taskMostHours'));\
                    chartTaskMostHours.draw(dataTaskMostHours, optionsPieChart);"


        # Create Google Calendar object - Heatmap with hours per day
        html = html + "\
                    var dataTableCalendar = new google.visualization.DataTable();\
                    dataTableCalendar.addColumn({ type: 'date', id: 'Date' });\
                    dataTableCalendar.addColumn({ type: 'number', id: 'Won/Loss' });\
                    dataTableCalendar.addRows(["

        # Loop through accumulatedSecondsPerDay and add records to chart
        for day, duration in accumulatedSecondsPerDay.items():
            # adjusting months to match javascript months that starts on 0
            html=html + "\
                    [ new Date({0},{1},{2}),{3:.2f}],".format(day.strftime('%Y'), str(int(day.strftime('%m'))-1), day.strftime('%d'), duration/3600)

        html= html + "]);\
                    var chartCalendar = new google.visualization.Calendar(document.getElementById('calendar'));\
                    var optionsCalendar = {\
                        title: '',\
                        height: 200,\
                        yearLabel: 'none'\
                    };\
                    \
                    chartCalendar.draw(dataTableCalendar, optionsCalendar);"

        # Create Google Area Chart object - Show looged hours per day
        html= html + "\
                    var data = google.visualization.arrayToDataTable([\
                        ['Date', 'Total hours','Non-billable hours'],"
        for day, duration in sorted(accumulatedSecondsPerDay.items()):
            html=html + "\
                        ['{0}',{1:.2f}, {2:.2f}],".format(day.strftime('%d %b, %Y'), duration/3600, (accumulatedNonBillableSecondsPerDay[day]/3600 if day in accumulatedNonBillableSecondsPerDay.keys() else 0))
                        #[ new Date({0},{1},{2}),{3:.2f}, {4:.2f}],".format(day.strftime('%Y'), str(int(day.strftime('%m'))-1), day.strftime('%d'), duration/3600, (accumulatedNonBillableSecondsPerDay[day] if day in accumulatedNonBillableSecondsPerDay.keys() else 0))

        html=html + "\
                    ]);\
                    \
                    var optionsAreaChart = {\
                        vAxis: {minValue: 0},\
                        isStacked: false,\
                        curveType: 'function',\
                        legend: { position: 'bottom' }\
                    };\
                    \
                    var chartAreaChart = new google.visualization.SteppedAreaChart(document.getElementById('areachart'));\
                    chartAreaChart.draw(data, optionsAreaChart);"

        html = html + "\
                }"

        # add event listener to expand Timeline div based on SVG height attribute
        html = html + "\
                window.addEventListener('load', function(){\
                    var svglist = document.getElementsByTagName('svg');\
                    var svg = svglist[svglist.length-1];\
                    console.log(svg.clientHeight || svg.parentNode.clientHeight);\
                    document.getElementById('timeline').setAttribute('style','height:'+(svg.clientHeight+60 || svg.parentNode.clientHeight+60)+'px');\
                    chartTimeline.draw(dataTableTimeline, optionsTimeline);\
                });\
            </script>"

        # HTML Body
        html= html + "\
            </head><body>\
                <ol class='breadcrumb'>"
        # Create Boothstrap Breadcrum
        parents = []
        try:
            parents = entity.getParents()
            parents.reverse()
        except:
            pass
        for parent in parents:
            html = html + "<li>" + parent.getName() + "</li>"
        html= html + "\
                <li class='active'>" + entity.getName() + "</li>\
                </ol>\
                <div class='page-header'>\
                    <h1>"+title+"</h1>\
                </div>\
                <div class='row'>\
                    <div class='col-sm-6 col-md-4'>\
                        <div class='panel panel-default'>\
                            <div class='panel-heading'><h3 class='panel-title'>"+ '{:.2f}'.format(totalSeconds/3600) + " total hours</h3></div>\
                            <div class='panel-body'>\
                                <div id='billable' style='text-align:center'></div>\
                            </div>\
                        </div>\
                    </div>\
                    <div class='col-sm-6 col-md-4'>\
                        <div class='panel panel-default'>\
                            <div class='panel-heading'><h3 class='panel-title'>Who logged most hours?</h3></div>\
                            <div class='panel-body'>\
                                <div id='userMostHours' style='text-align:center'></div>\
                            </div>\
                        </div>\
                    </div>\
                    <div class='col-sm-6 col-md-4'>\
                        <div class='panel panel-default'>\
                            <div class='panel-heading'><h3 class='panel-title'>Task with most hours logged</h3></div>\
                            <div class='panel-body'>\
                                <div id='taskMostHours' style='text-align:center'></div>\
                            </div>\
                        </div>\
                    </div>\
                </div>\
                <div class='panel panel-default'>\
                  <div class='panel-heading'><h3 class='panel-title'>Calendar heatmap</h3></div>\
                  <div class='panel-body' style='overflow:hidden;'>\
                    <div id='calendar' style='margin:auto; width:920px;'></div>\
                  </div>\
                </div>\
                <div class='panel panel-default'>\
                  <div class='panel-heading'><h3 class='panel-title'>Hours logged per day</h3></div>\
                  <div class='panel-body' style='overflow:hidden;'>\
                    <div id='areachart' style=''></div>\
                  </div>\
                </div>\
                <div class='break'></div>\
                <div class='panel panel-default'>\
                    <div class='panel-heading'><h3 class='panel-title'>Timeline</h3></div>\
                    <div class='panel-body'>\
                        <div id='timeline' style='height:100%'></div>\
                    </div>\
                </div>\
            </body>\
        </html>"

        filename = "timelogs-{0}.html".format(str(uuid.uuid1()))
        html_file= open(filename,"w")
        html_file.write(html.encode("utf-8"))
        html_file.close()
        job.createAttachment(filename, fileName=filename)
        job.setDescription("Timelog report")
        job.setStatus('done')
        os.remove(filename)
    except:
        print 'Failed:'
        job.setDescription("Timelog report")
        job.setStatus('failed')
Ejemplo n.º 20
0
 def _download(self, reference):
     '''Return thumbnail from *reference*.'''
     url = ftrack.User(reference).getThumbnail()
     return super(User, self)._download(url)
Ejemplo n.º 21
0
    def launch(self, event):

        msg = "Breakdown successfull. Click Job for details."
        ftrack.EVENT_HUB.publishReply(event,
                                      data={
                                          "success": True,
                                          "message": msg
                                      })

        selection = event["data"]["selection"]
        temp_dir = tempfile.gettempdir()
        file_path = os.path.join(temp_dir, "ftrack_version_breakdown.txt")
        with open(file_path, "w") as f:
            output = ""
            v = ftrack.AssetVersion(selection[0]["entityId"])
            versions = v.getAsset().getVersions()
            ids = []

            data = {
                "None": {
                    "name": "Uncategorized",
                    "notes": [],
                    "versions": []
                }
            }
            for cate in ftrack.getNoteCategories():
                data[cate.get("entityId")] = {
                    "name": cate.get("name"),
                    "notes": [],
                    "versions": []
                }

            for v in versions:
                ids.append(v.getId())
                for note in v.getNotes():
                    if note.get("categoryid"):
                        data[note.get("categoryid")]["notes"].append(note)
                        data[note.get("categoryid")]["versions"].append(v)
                    else:
                        data["None"]["versions"].append(v)
                        data["None"]["notes"].append(note)

            output += "/".join(
                [v.getParent().getParent().getName(),
                 v.getParent().getName()])
            output += ":\n"
            count = 0
            sessions = []
            project_id = v.getParents()[-1].getId()
            for session in ftrack.getReviewSessions(project_id):
                for obj in session.getObjects():
                    if obj.get("version_id") in ids:
                        count += 1
                        sessions.append(session.get("name"))

            output += "\tReview Session Usage:\t{0}\n".format(count)
            output += "\tReview Sessions:\t{0}\n".format(list(set(sessions)))

            output += "\tNotes:\n"

            for entry in data:
                output += "\t\t" + data[entry]["name"] + ":\n"
                amount = len(data[entry]["notes"])
                output += "\t\t\tNotes Amount:{0}\n".format(amount)
                output += "\t\t\tVersions "
                amount = len(set(data[entry]["versions"]))
                output += "Amount:{0}\n".format(amount)

                for note in data[entry]["notes"]:
                    index = data[entry]["notes"].index(note)
                    version_string = data[entry]["versions"][index]
                    version_string = version_string.getVersion()
                    version_string = "v" + str(version_string).zfill(3)
                    output += "\t\t\t{0}:\n".format(version_string)
                    text = note.getText().replace("\n", " ")
                    output += "\t\t\t\t{0}\n".format(text)

            f.write(output)

        user = ftrack.User(id=event["source"]["user"]["id"])
        job = ftrack.createJob("Breakdown", "done", user)
        try:
            job.createAttachment(file_path)
        except:
            self.logger.info(traceback.format_exc())
Ejemplo n.º 22
0
def createPDF(userId=None, entityType=None, entity=None, values=None):
    description = u'Review summary'
    job = ftrack.createJob(description=description,
                           status='running',
                           user=userId)
    email = bool(values['email'])
    subject = values['subject']
    message = values['message']
    #replace {session} with session name
    subject = subject.replace("{session}", entity.get('name'))
    message = message.replace("{session}", entity.get('name'))

    try:
        html = "\
            <html>\
                <head>\
                    <style media='all'>\
                        @page { padding: 0pt}\
                        @page { margin: 0pt; }\
                        @page { size: A4}\
                        img { page-break-inside: avoid; }\
                        .break { clear:both; page-break-after:always; }\
                        td, th { page-break-inside: avoid; word-wrap: break-word; }\
                    </style>\
                    <link rel='stylesheet' href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css' media='all'>\
                    <link rel='stylesheet' href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap-theme.min.css' media='all'>\
                </head>\
            <body>\
                <div class='jumbotron' style='padding:20px; padding-top;0px; margin-bottom:0px'>\
                    <h1>" + entity.get('name') + "</h1>\
                    <p>" + entity.get('description') + "</p>\
                    <div class='media' style='margin-top:5px; margin-bottom: 5px'>\
                        <div class='media-left'>\
                            <img width='40px' src='" + xstr(
            ftrack.User(entity.get('created_by')).getThumbnail()
        ) + "' class='media-object img-circle' style='width:40px;'>\
                        </div>\
                        <div class='media-body text-muted'>\
                            Created by " + ftrack.User(
            entity.get('created_by')).getName() + "<br/>\
                            " + str(
                entity.get('created_at').strftime('%A %d, %Y')) + "\
                        </div>\
                    </div>\
                </div>\
                <table class='table table-striped' style='' >\
                    <tr>\
                        <th style='min-width:3px; max-width:3px; width:3px'>#</th>\
                        <th>Media information</th>\
                        <th>Comments</th>\
                    </tr>"

        lst = getEntityChildren(entityType=entityType, entity=entity)
        for i, reviewSessionObject in enumerate(lst):
            html = html + "\
                    <tr>\
                        <td class=''>\
                            <h4 class='text-muted' style='margin-top:0px'>" + str(
                i + 1) + "</h4>\
                        </td>\
                        <td style='width:250px'>\
                            <div class='thumbnail'>\
                                <img class='img-responsive' src='" + xstr(
                    reviewSessionObject[0].getThumbnail()) + "'>\
                                <div class='caption'>\
                                    <small><strong>" + getName(
                        entityType=entityType,
                        entity=reviewSessionObject[0]) + "</strong></small>\
                                    <p class='text-muted small'>" + getPath(
                            entityType=entityType,
                            entity=reviewSessionObject[0]) + "</p>\
                                    <p>\
                                        <div style='margin-top:10px'>\
                                            <span class='text-success glyphicon glyphicon-thumbs-up' style='padding-right:5px' aria-hidden='true'></span><strong><span style='padding-right:10px'>0</span></strong><span class='text-danger glyphicon glyphicon-thumbs-down' style='padding-right:5px' aria-hidden='true'></span><strong>0</strong>\
                                        </div>\
                                    </p>\
                                </div>\
                            </div>\
                        </td>\
                        <td style=''>\
                            <small>\
                                <ul class='media-list'>"

            notes = reviewSessionObject[1].getNotes()
            if not len(notes):
                html = html + "\
                                    <li class='media' style='max-width:430px;'>\
                                        <p class='lead text-muted text-center' style='padding-top:60px'>\
                                            Bummer, there are no comments here!\
                                        </p>\
                                    </li>"

            for note in notes:
                html = html + "\
                                    <li class='media' style='max-width:430px;'>\
                                        <div class='media-left'>\
                                            <img src='https://www.ftrack.com/wp-content/uploads/haz2.png' class='media-object img-circle' style='width:40px'>\
                                        </div>\
                                        <div class='media-body'>\
                                            <h4 class='media-heading'>\
                                                Collaborator\
                                            </h4>\
                                            <small class='text-muted'>" + str(
                    note.getDate().strftime('%I:%M%p, %A %d, %Y')) + "</small>\
                                            <p>" + note.getText() + "</p>"
                frame = note.getMeta('reviewFrame')
                if frame is not None:
                    html = html + "\
                                            <p><span class='label label-primary'>Frame " + str(
                        json.loads(frame)['number']) + "</span></p>"
                attachments = note.getAttachments()
                for a in attachments:
                    html = html + "\
                                            <img src='" + a.getURL(
                    ) + "' class='' style='max-width:120px; margin-bottom:5px'>"
                replies = note.getNotes()
                for reply in replies:
                    html = html + "\
                                            <div class='media' style='max-width:380px;'>\
                                                <div class='media-left'>\
                                                    <img src='https://www.ftrack.com/wp-content/uploads/fl.png' class='media-object img-circle' style='width:40px'>\
                                                </div>\
                                                <div class='media-body'>\
                                                    <h4 class='media-heading'>\
                                                        Collaborator\
                                                    </h4>\
                                                    <small class='text-muted'>" + str(
                        reply.getDate().strftime(
                            '%I:%M%p, %A %d, %Y')) + "</small>\
                                                    <p>" + reply.getText(
                            ) + "</p>\
                                                </div>\
                                            </div>"

                html = html + "\
                                        </div>\
                                    </li>"

            html = html + "\
                                <br/>\
                                </ul>\
                            </small>\
                        </td>\
                    </tr>"

        html = html + "\
                    </table>\
                </body>\
                </html>"

        # html alternative to create PDF (see below)
        filename = "review-session-{0}.html".format(str(uuid.uuid1()))
        html_file = open(filename, "w")
        html_file.write(html.encode("utf-8"))
        html_file.close()

        # signup for docraptor (free trial) or use other PDF generator library
        # install docraptor with "pip install python-docraptor"

        # docraptor = DocRaptor(ADD YOUR API KEY HERE)
        # filename = "review-session-{0}.pdf".format(str(uuid.uuid1()))
        # resp = docraptor.create({
        #                             'document_content': html,
        #                             'document_type':'pdf',
        #                             'test': False,
        #                             'strict': 'none',
        #                             'async': True,
        #                             'prince_options': {'media': 'screen', 'insecure':False, 'input':'html'}
        #                             })

        # status_id = resp['status_id']

        # resp = docraptor.status(status_id)
        # while resp['status'] != 'completed':
        #     time.sleep(3)
        #     resp = docraptor.status(status_id)

        # f = open(filename, "w+b")
        # f.write(docraptor.download(resp['download_key']).content)
        # f.seek(0)

        job.createAttachment(f, fileName=filename)
        job.setStatus('done')

        if email:
            sendEmail(userId=userId,
                      subject=subject,
                      message=message,
                      recipients=[ftrack.User(userId).getEmail()],
                      filename="filename")

        os.remove(filename)
    except:
        job.setStatus('failed')
Ejemplo n.º 23
0
def create_job(event):
    user_id = event["source"]["user"]["id"]
    ftrack_user = ftrack.User(id=user_id)

    job = ftrack.createJob("Collecting Assets", "queued", ftrack_user)
    job.setStatus("running")
    values = event["data"]["values"]
    errors = ""

    # collecting sources and destinations
    for item in event["data"]["selection"]:
        try:
            entity = ftrack.AssetVersion(item["entityId"])

            # adding path to errors
            parent_path = ""
            parents = entity.getParents()
            parents.reverse()
            for p in parents:
                parent_path += p.getName() + "/"

            parent_number = int(values["parent_number"])
            parent_prefix = ""
            for p in reversed(list(reversed(parents))[:parent_number]):
                parent_prefix += p.getName() + "."

            component_name = values["component_name"]

            try:
                component = entity.getComponent(name=component_name)
            except:
                continue

            src = get_file_for_component(component)

            # copying sources to destinations
            if entity.getAsset().getType().getShort() == "img":
                dir_name = entity.getParent().getParent().getName()
                if parent_prefix:
                    dir_name = parent_prefix

                asset_dir = os.path.join(values["collection_directory"],
                                         dir_name)

                if os.path.exists(asset_dir):
                    # delete existing files
                    shutil.rmtree(asset_dir)

                os.makedirs(asset_dir)

                for f in os.listdir(os.path.dirname(src)):
                    path = os.path.join(os.path.dirname(src), f)

                    basename = format_basename(src, values["file_formatting"])

                    basename = parent_prefix + re.sub(r".%04d", "", basename)
                    dst = os.path.join(asset_dir, basename)

                    shutil.copy(path, dst)
            else:
                basename = format_basename(src, values['file_formatting'])
                basename = parent_prefix + basename

                dst = os.path.join(values["collection_directory"], basename)

                shutil.copy(src, dst)
        except:
            errors += parent_path + "\n"
            errors += traceback.format_exc() + "\n"

    # generate error report
    if errors:
        temp_txt = os.path.join(values["collection_directory"], "errors.txt")
        f = open(temp_txt, "w")
        f.write(errors)
        f.close()

    job.setStatus("done")
Ejemplo n.º 24
0
    def launch(self, event):
        userId = event['source']['user']['id']
        data = event['data']
        selection = data.get('selection', [])
        entityId = selection[0]['entityId']
        entityType = selection[0]['entityType']
        entity = getEntity(entityType=entityType, entityId=entityId)

        if 'values' in event['data']:
            # Do something with the values or return a new form.
            values = event['data']['values']
            ftrack.EVENT_HUB.publishReply(event,
                                          data={
                                              'success': True,
                                              'message':
                                              'Action was successfull'
                                          })
            create(userId=userId,
                   entityType=entityType,
                   entity=entity,
                   values=values)
            return

        return {
            'items': [{
                'type':
                'label',
                'value':
                'Your selection: ' +
                getEntityPath(entityType=entityType, entity=entity)
            }, {
                'type': 'label',
                'value': '___'
            }, {
                'label':
                'Email PDF to collaborators',
                'type':
                'enumerator',
                'name':
                'email',
                'value':
                '0',
                'data': [{
                    'label': 'No',
                    'value': '0'
                }, {
                    'label': 'Yes',
                    'value': '1'
                }]
            }, {
                'label': 'Email subject',
                'type': 'text',
                'value': 'Review session notes - {session}',
                'name': 'subject'
            }, {
                'label':
                'Message',
                'name':
                'message',
                'value':
                'Hello,\nhere are the review notes for {{session}}.\n\nThank you,\n{0}'
                .format(ftrack.User(userId).getName()),
                'type':
                'textarea'
            }]
        }
Ejemplo n.º 25
0
    def launch(self, event):
        """Callback method for DJVView action."""

        # Launching application
        if "values" in event["data"]:

            applicationIdentifier = event["data"]["applicationIdentifier"]
            application = self.applicationStore.getApplication(
                applicationIdentifier
            )
            context = event["data"].copy()
            context["source"] = event["source"]
            command = self.launcher._getApplicationLaunchCommand(
                application, context
            )

            success = True
            message = '{0} application started.'.format(application['label'])

            command.append(event["data"]["values"]["path"])

            try:
                options = dict(
                    env={},
                    close_fds=True
                )

                # Ensure subprocess is detached so closing connect will not
                # also close launched applications.
                if sys.platform == 'win32':
                    options['creationflags'] = subprocess.CREATE_NEW_CONSOLE
                else:
                    options['preexec_fn'] = os.setsid

                self.logger.debug(
                    'Launching {0} with options {1}'.format(command, options)
                )
                process = subprocess.Popen(command, **options)

            except (OSError, TypeError):
                self.logger.exception(
                    '{0} application could not be started with command "{1}".'
                    .format(applicationIdentifier, command)
                )

                success = False
                message = '{0} application could not be started.'.format(
                    application['label']
                )

            else:
                self.logger.debug(
                    '{0} application started. (pid={1})'.format(
                        applicationIdentifier, process.pid
                    )
                )

            return {
                'success': success,
                'message': message
            }

        data = event["data"]
        data["items"] = []

        # Starting a job to show user the progress of scanning for files.
        job = ftrack.createJob("DJV: Scanning for files.", "queued",
                               ftrack.User(id=event["source"]["user"]["id"]))
        job.setStatus("running")

        try:
            ftrack.EVENT_HUB.publish(
                ftrack.Event(
                    topic='djvview.launch',
                    data=data
                ),
                synchronous=True
            )
            session = get_shared_session()
            session.event_hub.publish(
                ftrack_api.event.base.Event(
                    topic='djvview.launch',
                    data=data
                ),
                synchronous=True
            )
        except:
            job.setStatus("failed")
        else:
            job.setStatus("done")

        return {
            "items": [
                {
                    "label": "Items to view",
                    "type": "enumerator",
                    "name": "path",
                    "data": sorted(
                        data["items"],
                        key=itemgetter("label"),
                        reverse=True
                    )
                }
            ]
        }
    def constructWidget(self):
        '''Return widget instance to test.'''
        widget = QtGui.QWidget()
        layout = QtGui.QVBoxLayout()
        widget.setLayout(layout)

        notificationList = _notification_list.Notification()

        notificationList.setStyleSheet('''

            QPushButton {
                border: 1px solid black;
                border-radius: 2px;
                background-color: #505050;
                color: #F0F0F0;
                padding: 4px;
                min-width: 80px;
            }

            QFrame {
                background-color: #2A2A2A;
                color: #969696;
            }

            QLabel {
                background-color: #323232;
            }

            QFrame#notification-list {
                border: 0;
                margin: 20px 0 0 0;
            }

            QFrame#notification-list QTableWidget {
                background-color: transparent;
                border: 0;
            }

            QFrame#notification-list QTableWidget::item {
                background-color: #323232;
                border-bottom: 1px solid #282828;
                padding: 0;
            }
        ''')

        layout.addWidget(notificationList)

        notificationList.addContext('157271fc-5fc6-11e2-a771-f23c91df25eb',
                                    'task', False)

        notificationList.addContext(
            ftrack.User(getpass.getuser()).getId(), 'user', False)

        notificationList.addContext('01cfdcaa-c5ea-11e1-adec-f23c91df25eb',
                                    'asset', False)

        notificationList.addContext('01cfdcaa-c5ea-11e1-adec-f23c91df25es',
                                    'asset', False)

        notificationList.removeContext('01cfdcaa-c5ea-11e1-adec-f23c91df25es',
                                       False)

        notificationList.reload()

        def getEvents(event):
            '''Return events for context.'''
            context = notificationList._context
            cases = []
            events = []

            session = ftrack_api.Session()

            if context['asset']:
                cases.append('(feeds.owner_id in ({asset_ids}) and action is '
                             '"asset.published")'.format(
                                 asset_ids=','.join(context['asset'])))

            if context['task']:
                cases.append(
                    'parent_id in ({task_ids}) and action in '
                    '("change.status.shot", "change.status.task")'.format(
                        task_ids=','.join(context['task'])))

                cases.append(
                    '(parent_id in ({task_ids}) and action in '
                    '("update.custom_attribute.fend", "update.custom_attribute.fstart"))'
                    .format(task_ids=','.join(context['task'])))

            if context['user']:
                cases.append('(feeds.owner_id in ({user_ids}) and action is '
                             '"db.append.task:user" and feeds.distance is "0" '
                             'and feeds.relation is "assigned")'.format(
                                 user_ids=','.join(context['user'])))

            if cases:
                events = session.query(
                    'select id, action, parent_id, parent_type, created_at, data '
                    'from Event where {0}'.format(' or '.join(cases))).all()

                events.sort(key=lambda event: event['created_at'],
                            reverse=True)

            return events

        ftrack.EVENT_HUB.subscribe('topic=ftrack.crew.notification.get-events',
                                   getEvents)

        return widget