Package: workfront-bridge
# workfront-bridgeWorkfront Bridge is a library that make the creation of bridge projects inworkfront easily.## DesignProjects and tasks in workfront have custom forms. Those custom forms haveseveral parameters which are fullfill when the project is created(some otherparameters are being fullfilled while the project is developed and task arebeing excetuted).The library tries to divide and group logical blocks of tasks that can beconvined to build a workfront project.So, in order to achieve this, two main abstractions are provided:* Project Containers* Blocks### Workfront BlocksA Block is a group of one or more task that live inside a workfront templateproject.Each particular block must knows its tasks, the parameters of them and thedependencies among them so it can instantiate and configure them withoutdifficulties.The fact that the tasks live inside a workfront template project is just aconvinient way of storing them(workfront does not allow to define a group oftemplate task out of a template project).### Workfront Project ContainersProject Containers represents empty workfront project templates associated withone or more custom forms that can allocate different blocks.The idea of these project containers is to build different project types byadding different type of blocks to it.So, basically a workfront project will be constructed by creating a projectcontainer, setting the corresponding parameters to it and appending blocks tothe project container according to the behaviour that is needed for thatproject. In this process, the parameters for the different blocks will be alsoset.## Creating BlocksInherit from **WFBlock** class to create a new specific block. A Workfrontservice and a template id needs to be provided to the WFBlock constructor. Thetemplate id must have only the tasks that belongs to this block.Also fields can be marked as optional and required to be automatically validatedwhen a new project is being constructed with this block.For example, supose you want to add a block with 1 task:* My task : which has 2 parameters; name (required) and age (optional)Here it is an example of how you would make the block representing that task:```pythonclass MyWFBlock(WFBlock):def __init__(self, wf):template_id = template_id_from_name(wf, "My block template")super(WFEmailTestSeedBlock, self).__init__(wf, template_id)self._set_required_fields(["name"])self._set_optional_fields(["age"])```In order to set the concrete values for those parameters the**set_task_param_value** method must be used.The **set_task_param_value** receives a **task identifier** (that can be aninteger, indicating the number of the task in the template project, or a stringfor the name of the task).Properties can be utilize for a clean design:```python@propertydef name(self):return self._name@name.setterdef name(self, value):self.name = valueself.set_task_param_value("My task", "name", value)```The purpose of using the **set_task_param_value** is that when the block is usedinside a project container and a workfront project is build, the block knowshow to configure the value in the group of task represented by this block.### Starter taskEach block has as default starter task the first task. However this can bechanged by using the **_set_starter_task(task_identifier)** method wheninheriting from WFBlock.This can be handy when having indentation task that only organize task. So, forexample if you have the following tasks in the block:* Grouping Task* Task 1* Task 2You should set the Task 1 as a starter task skipping the Grouping Task that onlygives some visual clarity indenting Task 1 and 2.Why ? This is required when for example Task 1 is Automatic. The workfront proxyonly starts Automatic tasks when they are a direct predecessor of a completedtask.So, in this case, when the predecessor of Grouping task is complete (andstarter task is the Grouping Task), Task 1 will not start (because Grouping Taskpredecessor is an indirect predecessor of Task 1). So to avoid that, Task 1must be set as starter task.This can be achieved in the constructor of the block like this :```pythondef __init(...)# Other blcok stuff...self._set_starter_task(2) # Task 1 is the second task# or you can set it by nameself._set_starter_task("Task 1")```## Creating Project ContainersTo create a project container the new block should inherit from**WFProjectContainer**.After that, the template id of the workfront template project and the requiredand optional parameters should be provided. This can be done calling the parentconstructor and the methods **_set_required_fields** and**_set_optional_fields** (you can make use of the **template_id_from_name**function to get the template id):```pythonclass MyWFProjectContainer(WFProjectContainer)def __init__(self, wf, prj_name):tid = template_id_from_name(wf, "My WF Template")super(MyWFProjectContainer, self).__init__(wf, tid, prj_name)self._set_required_fields(["workfront_param_value_req"])self._set_optional_fields(["workfront_param_value_optional"])```Then you can set the variables that will fullfill the parameter values of theproject calling the **set_param_value** method. For example:```python@propertydef my_param_value(self):return self._my_param_value@email_subject.setterdef my_param_value(self, v):self._my_param_value = vself.set_param_value("workfront_param_value_req", v)```You can check the **WFProjectEmailContainer** in workfront_bridge.projects.emailfor a complete example.### Using Blocks inside a Project ContainerBlocks are made to be appended to a project container. A project container canhave one or more blocks of the same type.When adding a block to a project container, the block is appended to the projectmaking this new block, dependent of the last added block. So for example, ifblock1, block2, block3 are appended to the same project block in that order,the workfront project will be created so that the starter task in block2 willonly be excetuted when the last task in block1 is completed. The same happens toblock3; the starter task created that belongs to block3 will only start afterthe last task from block2 finishes.The project container does not have any restriction in the order that the blocksare added to the project block, it is the user responsability to add the blocksin an order that has some logic.We recommend using project builders in order to make life easier for those whowant to create workfront projects using this library. This allows user tore-use the code logic used to create particular workfront projects.## Using Project BuildersTo easily create projects you can use project builders. Project builders providea simple interface with setters to create different projects structures.So for example, to create a simple email project with 2 test list and 1 seedlist you will do something similar to this:```pythonfrom workfront.workfront import Workfrontfrom workfront_bridge.projects.email_builder import EmailProjectBuilder# Create a Workfront Service object (using the workfront-sdk)wf = Workfront("email@wf.bridgemarketing.com", "pass***")wf.login()# A project builder needs a Workfront service and a name to be constructedbuilder = EmailProjectBuilder(wf, "Project Test Name")# Then, the subject and a html is needed to be validated:builder.set_html("s3://some/s3/path/creative.html").set_subject("This is the subject!")# In the case of email builder you can use a zip to construct the html. In that# case you will use this:# b.set_html_zip("s3://some/s3/path/creative.zip")# Then, add two test list and a live seed listbuilder.add_test_list("s3://some/s3/test_list1.csv").add_test_list("s3://some/s3/test_list2.csv").set_seed_list("s3://some/s3/live_seed_list.csv)# Finally, build and obtain the Workfront projectwf_project = b.build()# When calling build a WFBrigeException can arise telling you if some# parameters are missing, or something is wrong.```