# coding: utf-8 ''' Created on 30.09.2014 @author: a.vasilev ''' import base64 import array import re, os try: from ru.curs.showcase.activiti import EngineFactory except: from workflow import testConfig as EngineFactory # from workflow import testConfig as EngineFactory import javax.xml.stream.XMLInputFactory as XMLInputFactory import java.io.InputStreamReader as InputStreamReader import org.activiti.engine.ProcessEngineConfiguration as ProcessEngineConfiguration import org.activiti.bpmn.BpmnAutoLayout as BpmnAutoLayout import org.activiti.bpmn.converter.BpmnXMLConverter as BpmnXMLConverter import org.activiti.image.ProcessDiagramGenerator as ProcessDiagramGenerator from java.lang import String from java.io import ByteArrayInputStream from org.activiti.engine.impl.util.io import InputStreamSource from org.activiti.engine.impl.util.io import StreamSource from ru.curs.celesta.syscursors import UserRolesCursor from common.sysfunctions import tableCursorImport from common.grainssettings import SettingsManager from workflow._workflow_orm import act_hi_commentCursor class ActivitiObject(): def __init__(self): # получение запущенного движка Activiti и необходимых сервисов self.processEngine = EngineFactory.getActivitiProcessEngine() self.conf = self.processEngine.getProcessEngineConfiguration() self.repositoryService = self.processEngine.getRepositoryService() self.historyService = self.processEngine.getHistoryService() self.runtimeService = self.processEngine.getRuntimeService() self.identityService = self.processEngine.getIdentityService() self.taskService = self.processEngine.getTaskService() self.formService = self.processEngine.getFormService() def getActualVersionOfProcesses(self): u'''Функция получения списка всех развернутых процессов''' return self.repositoryService.createProcessDefinitionQuery().orderByProcessDefinitionName(). \ asc().latestVersion().list() def getHistory(self): u'''Функция получения списка всех ранее запущенных процессов процессов''' processInstanceList = self.historyService.createHistoricProcessInstanceQuery().orderByProcessInstanceEndTime().asc().list() return processInstanceList def getProcessVersionsByKey(self, key, sort='asc'): u'''Функция получения списка всех версий определенного развернутого процесса по ключу''' actuals = getattr(self.repositoryService.createProcessDefinitionQuery().processDefinitionKey(key).orderByProcessDefinitionVersion(), sort)().list() return actuals def getProcessDefinition(self, key, vernum=None): u'''Функция выбора конкретной версии процесса по ключу''' actuals = self.repositoryService.createProcessDefinitionQuery().processDefinitionKey(key) if vernum is None: selectedProcess = actuals.latestVersion().singleResult() else: selectedProcess = actuals.processDefinitionVersion(vernum).singleResult() return selectedProcess def getProcessDefinitionById(self, id): u'''Функция выбора процесса по id''' actuals = self.repositoryService.createProcessDefinitionQuery().processDefinitionId(id).singleResult() return actuals def getProcessXml(self, key, vernum=None): selectedProcess = self.getProcessDefinition(key, vernum) if selectedProcess : return self.repositoryService.getResourceAsStream(selectedProcess.getDeploymentId(), selectedProcess.getResourceName()) else: return None def getProcessXmlById(self, id): selectedProcess = self.getProcessDefinitionById(id) if selectedProcess : return self.repositoryService.getResourceAsStream(selectedProcess.getDeploymentId(), selectedProcess.getResourceName()) else: return None def getDeployedProcessModel(self, key, vernum=None): u'''картинка развёрнутого процесса''' processDefinition = self.getProcessDefinition(key, vernum) if processDefinition.getDiagramResourceName(): diagramResourceName = processDefinition.getDiagramResourceName() imageStream = self.repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), diagramResourceName) else: # xif = XMLInputFactory.newInstance() # xin = InputStreamReader(self.getProcessXml(key, vernum)) # xtr = xif.createXMLStreamReader(xin) stream = self.getProcessXml(key, vernum) xmlSource = InputStreamSource(stream) model = BpmnXMLConverter().convertToBpmnModel(xmlSource, False, False, String('UTF-8')) # model = BpmnXMLConverter().convertToBpmnModel(xtr) self.repositoryService.validateProcess(model) BpmnAutoLayout(model).execute() generator = self.conf.getProcessDiagramGenerator() imageStream = generator.generatePngDiagram(model) return imageStream def getExecutionModel(self, processInstanceId, vernum=None): u'''картинка выполняющегося процесса с отмеченным таском''' processInstance = self.runtimeService.createProcessInstanceQuery()\ .processInstanceId(processInstanceId).singleResult() processDefinition = self.repositoryService.createProcessDefinitionQuery()\ .processDefinitionId(processInstance.getProcessDefinitionId()).singleResult() key = processDefinition.getKey() self.getProcessDefinitionById(key) if processDefinition.getDiagramResourceName(): model = self.repositoryService.getBpmnModel(processDefinition.getId()) else: # xif = XMLInputFactory.newInstance() # xin = InputStreamReader(self.getProcessXml(key, vernum)) # xtr = xif.createXMLStreamReader(xin) # model = BpmnXMLConverter().convertToBpmnModel(xtr) stream = self.getProcessXml(key, vernum) xmlSource = InputStreamSource(stream) model = BpmnXMLConverter().convertToBpmnModel(xmlSource, False, False, String('UTF-8')) self.repositoryService.validateProcess(model) BpmnAutoLayout(model).execute() # actuals = self.runtimeService.createExecutionQuery().processInstanceId(processInstance.getId()).singleResult() generator = self.conf.getProcessDiagramGenerator() definitionImageStream = generator.generateDiagram(model, "png", self.runtimeService.getActiveActivityIds(processInstance.getProcessInstanceId())) return definitionImageStream def stopProcess(self, processId, reason='stopped manually'): self.runtimeService.deleteProcessInstance(processId, reason) def getUserTasks(self, username): # all assigned, candidate and owner tasks u'''выбирает задачи, которые появились в identityLink, т.е. назначен на задание либо владеет им''' taskQuery = self.taskService.createTaskQuery().taskInvolvedUser(username).list() return taskQuery def getCandUserTasks(self, username): u'''выбирает только те задачи, у которых заданный пользователь является кандидатом на назначение''' taskQuery = self.taskService.createTaskQuery().taskCandidateUser(username).list() return taskQuery def getCandOrAssUserTasks(self, username): u'''выбирает только задачи, на которые назначен заданный пользователь или является кандидатом на назначение''' taskQuery = self.taskService.createTaskQuery().taskCandidateOrAssigned(username).list() return taskQuery # Deprecated ? def getUnassTasks(self): taskQuery = self.taskService.createTaskQuery().taskUnnassigned().list() return taskQuery def getUserAssTasks(self, username): u'''выбирает только те задачи, на которые назначен заданный пользователь''' taskQuery = self.taskService.createTaskQuery().taskAssignee(username).list() return taskQuery def getGroupCandTasks(self, candidateGroup): u'''выбирает только те задачи, кандидатами которых являются пользователи заданной группы''' taskQuery = self.taskService.createTaskQuery().taskCandidateGroup(candidateGroup).list() return taskQuery def addCommentWithUserId(self, context,taskId, processInstanceId, message, userId): u'''Добавляет комментарий к задаче и записывает в таблицу автора комментарий''' comment = self.taskService.addComment(taskId, processInstanceId, message) comments = act_hi_commentCursor(context) comments.get(comment.id) comments.user_id_ = userId comments.update() def getBase64Image(imageStream): stringout = u'' byteArray = [-1, -1, -1] while True: byteArray[0] = imageStream.read() byteArray[1] = imageStream.read() byteArray[2] = imageStream.read() if byteArray[0] == -1: break elif byteArray[1] == -1: stringout += base64.b64encode(array.array('B', byteArray[0:1]).tostring()) break elif byteArray[2] == -1: stringout += base64.b64encode(array.array('B', byteArray[0:2]).tostring()) break else: stringout += base64.b64encode(array.array('B', byteArray).tostring()) return stringout def setVariablesInLink(activiti, processId, taskId, link): pattern = '\$\[\w+\]' params = re.compile(pattern) variables = activiti.runtimeService.createProcessInstanceQuery()\ .processInstanceId(processId).includeProcessVariables().singleResult().getProcessVariables() replaceDict = dict() for param in params.finditer(link): par = link[param.start():param.end()] if par == '$[processId]': replaceDict[par] = processId elif par == '$[taskId]': replaceDict[par] = taskId else: if par[2:-1] in variables: replaceDict[par] = variables[par[2:-1]] for key in replaceDict: link = link.replace(key, unicode(replaceDict[key])) return link def parse_json(context = None): settingsManager = SettingsManager() content = {"default":{}, "manual":{}, "specialFunction":{}, "userInfo":{} } defaultNamesList = settingsManager.getGrainSettings('datapanelSettings/default/parameter/@name','workflow') defaultValuesList = settingsManager.getGrainSettings('datapanelSettings/default/parameter/@value','workflow') for i in range(len(defaultNamesList)): content["default"][defaultNamesList[i]] = defaultValuesList[i] manualNamesList = settingsManager.getGrainSettings('datapanelSettings/manual/parameter/@name','workflow') manualValuesList = settingsManager.getGrainSettings('datapanelSettings/manual/parameter/@value','workflow') for i in range(len(manualNamesList)): content["manual"][manualNamesList[i]] = manualValuesList[i] specNamesList = settingsManager.getGrainSettings('datapanelSettings/specialFunction/parameter/@name','workflow') specValuesList = settingsManager.getGrainSettings('datapanelSettings/specialFunction/parameter/@value','workflow') for i in range(len(specNamesList)): content["specialFunction"][specNamesList[i]] = specValuesList[i] infoNames = settingsManager.getGrainSettings('datapanelSettings/userInfoFunction/parameter/@name','workflow') infoGrains = settingsManager.getGrainSettings('datapanelSettings/userInfoFunction/parameter/@grain','workflow') infoTables = settingsManager.getGrainSettings('datapanelSettings/userInfoFunction/parameter/@table','workflow') infoIdFields = settingsManager.getGrainSettings('datapanelSettings/userInfoFunction/parameter/@idField','workflow') infoNameFields = settingsManager.getGrainSettings('datapanelSettings/userInfoFunction/parameter/@nameField','workflow') for i in range(len(infoNames)): content["userInfo"][infoNames[i]] = {"grain": infoGrains[i], "table": infoTables[i], "idField": infoIdFields[i], "nameField": infoNameFields[i]} return content def functionImport(functionName): u'''импортирует функцию по ее адресу в строке''' mod = __import__(functionName.split('.')[0]) components = functionName.split('.') for comp in components[1:]: mod = getattr(mod, comp) return mod def listFormAccess(userId): u'''из userId выдает список доступных пользователю форм''' activiti = ActivitiObject() permitsList = [] tasks = activiti.historyService.createHistoricTaskInstanceQuery().taskAssignee(userId).list() for task in tasks: if task.getFormKey() is not None: permitsList.append({"procId": task.getProcessInstanceId(), "formId": task.getFormKey(), "accessType": "write" if task.getEndTime() is None else "read"}) return permitsList def checkFormAccess(userId, processInstanceId, formId): u'''проверяет доступность формы пользователю''' activiti = ActivitiObject() tasks = activiti.historyService.createHistoricTaskInstanceQuery()\ .taskAssignee(userId).processInstanceId(processInstanceId).list() result = 'deny' for task in tasks: if task.getFormKey() == formId: if task.getEndTime() is None: result = 'write' break else: result = 'read' return result def getUserGroups(context, sid): u'''функция, которая возвращает список групп, в которые входит пользователь''' rolesList = [] infoDictList = [{"tableName": "UserRoles", # имя таблицы, из которой берется список групп "grainName": "celesta", # имя гранулы, из которой берется список групп "userField": "userid", # название поля, в котором находится id пользователя "roleField": "roleid" # название поля, в котором находится id группы пользователя }, ] # для добавления таблицы, из которой дополнительно будут браться группы пользователя, # добавить в infoDictList словарь вида {"tableName": "...", # "grainName": "...", # "userField": "...", # "roleField": "..." # } # в котором вместо многоточий подставить соответствующие данные добавляемой таблицы for infoDict in infoDictList: if infoDict['grainName'] != 'celesta': userRoles = tableCursorImport(infoDict["grainName"], infoDict["tableName"])(context) else: from ru.curs.celesta.syscursors import UserRolesCursor userRoles = UserRolesCursor(context) userRoles.setRange(infoDict["userField"], sid) if userRoles.tryFirst(): while True: rolesList.append(getattr(userRoles, infoDict["roleField"])) if not userRoles.next(): break return rolesList def getUserName(usersCur, sidField, nameField, sid): u'''фукнция, возвращающая имя пользователя из его логина''' usersCur.setRange(sidField, sid) if usersCur.tryFirst(): return getattr(usersCur, nameField) else: return u'Пользователь не найден' def getUsersCursor(context): grainName = 'security' # имя гранулы, в которой находится таблица пользователей tableName = 'logins' # имя таблицы пользователей users = tableCursorImport(grainName, tableName)(context) return users def getGroupUsers(context,groupId): userList = [] infoDictList = [{"tableName": "UserRoles", # имя таблицы, из которой берется список групп "grainName": "celesta", # имя гранулы, из которой берется список групп "userField": "userid", # название поля, в котором находится id пользователя "roleField": "roleid" # название поля, в котором находится id группы пользователя }, ] for infoDict in infoDictList: if infoDict['grainName'] != 'celesta': userRoles = tableCursorImport(infoDict["grainName"], infoDict["tableName"])(context) else: from ru.curs.celesta.syscursors import UserRolesCursor userRoles = UserRolesCursor(context) userRoles.setRange(infoDict["roleField"], groupId) if userRoles.tryFirst(): while True: userList.append(getattr(userRoles, infoDict["userField"])) if not userRoles.next(): break return userList def getLinkPermisson(context,sid,mode,processKey,processId,taskId): userRoles = UserRolesCursor(context) userRoles.setRange('userid',sid) isUser = False if userRoles.tryFirst(): while True: if userRoles.roleid == 'workflowDev': return True if userRoles.roleid == 'workflowUser': isUser = True if not userRoles.next(): break if isUser: activiti = ActivitiObject() if mode == 'processImage': return False elif mode == 'process': return False elif mode == 'table': return False elif mode == 'instanceImage': filePath = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'datapanelSettings.json') datapanelSettings = parse_json(context)["specialFunction"]["getUserGroups"] getUserGroups = functionImport('.'.join([x for x in datapanelSettings.split('.') if x != 'celesta'])) groupsList = getUserGroups(context,sid) # задачи, у которых кандидат - группа, в которую входит текущий пользователь if groupsList != []: groupTasksList = activiti.taskService.createTaskQuery().taskCandidateGroupIn(groupsList).processInstanceId(processId).list() else: groupTasksList = [] userTasksList = activiti.taskService.createTaskQuery().taskCandidateOrAssigned(sid).processInstanceId(processId).list() if len(userTasksList) == 0 and len(groupTasksList) == 0: return False else: return True elif mode == 'task': userTasksList = activiti.taskService.createTaskQuery().taskAssignee(sid).processInstanceId(processId).list() for task in userTasksList: if taskId == task.getId(): return True return False