def __init__(self, project_name, task_name): self.kb = Kanboard(kb_endpoint, kb_user, kb_apikey, "X-API-Auth") self.project_name = project_name self.task = None self.columns = None # This pulls in the Kanboard project ("Pentesting" as of yet) self.kbb_project = self.kb.get_project_by_name(name=self.project_name) if not self.kbb_project: error( "Could not find the *%s* project in Kanboard. Verify endpoint." % self.project_name) exit(-1) # This pulls in the task that will be manipulated tasks = self.kb.search_tasks(project_id=self.kbb_project["id"], query="title:%s" % task_name) if len(tasks) == 0: error("Could not find kanboard task with the title: %s" % task_name) exit(-1) for task in tasks: if task_name == task["title"]: self.task = task break if not self.task: error( "Similar kanboard tasks for *%s* have been found, but no exact match. Check spelling." % task_name) exit(-1) self.description = task["description"].split("\r\n")
def connect(self): self.gl = Gitlab(self.gitlab['endpoint'], self.gitlab['token'], ssl_verify=False) self.gl.auth() self.kb = Kanboard(self.kanboard['endpoint'], self.kanboard['user'], self.kanboard['token'])
def get_tasks(options): """ Return a list of tasks from the specified kanboard """ tasks = None print(options) kanboard = Kanboard(options['host'] + "/jsonrpc.php", username=options['username'], password=options['password'], http_username=options['http_username'], http_password=options['http_password'], proxies=options['proxy'], verify=(not options['no_ssl_verify']), auth_header=options['auth_header']) try: tasks = kanboard.get_all_tasks(project_id=options['tasks']) except requests.exceptions.RequestException as exception: logging.error('Could not retrieve tasks: %s', exception) sys.exit(-1) except requests.packages.urllib3.exceptions.LocationParseError as exception: logging.error('Could not parse address: %s', exception) return tasks
class KanboardAdapter(): def __init__(self, project_name, task_name): self.kb = Kanboard(kb_endpoint, kb_user, kb_apikey, "X-API-Auth") self.project_name = project_name self.task = None self.columns = None # This pulls in the Kanboard project ("Pentesting" as of yet) self.kbb_project = self.kb.get_project_by_name(name=self.project_name) if not self.kbb_project: error( "Could not find the *%s* project in Kanboard. Verify endpoint." % self.project_name) exit(-1) # This pulls in the task that will be manipulated tasks = self.kb.search_tasks(project_id=self.kbb_project["id"], query="title:%s" % task_name) if len(tasks) == 0: error("Could not find kanboard task with the title: %s" % task_name) exit(-1) for task in tasks: if task_name == task["title"]: self.task = task break if not self.task: error( "Similar kanboard tasks for *%s* have been found, but no exact match. Check spelling." % task_name) exit(-1) self.description = task["description"].split("\r\n") # At this point the kbb project, the task and the description are loaded def get_columns(self): columns = self.kb.get_columns(project_id=self.kbb_project["id"]) self.columns = dict() for column in columns: self.columns[int(column["id"])] = Column(int(column["id"]), int(column["position"]), column["title"]) return self.columns def get_column(self): if not self.columns: self.get_columns() column_id = int( self.task["column_id"] ) # Make sure this is cast to int, otherwise comparison might go wrong for id in self.columns: if id == column_id: return self.columns[id] error("Could not determine the current column of the project") def update_column(self, column): result = self.kb.move_task_position(project_id=self.kbb_project["id"], task_id=self.task["id"], column_id=column.id, position=1) if not result: error("Unable to update column") def save_project_description(self): # Format into string desc = "\r\n".join(self.description) result = self.kb.update_task(id=self.task["id"], description=desc) if not result: error("Unable to update checklist") def update_project_description(self, linenr, content): self.description[linenr] = content def get_checklist_of_column(self, column): heading = "### Checklist %s" % column.title record = False found = False index = 1 checklist = dict() # Loop through each line in the description for line in self.description: # Did we find the heading we're looking for? Start recording all subsequent lines if line.find(heading) is not -1: found = True record = True continue # Found a blank line? We're done. Stop recording if len(line.strip()) == 0: record = False # Add line to the checklist and update the index if record: checklist[index] = self.description.index( line ), line # Tuple that stores the index to the line in the description + the line itself index += 1 if found is False: if checklist_template_url: error( "Could not find the checklist for *%s* in kanboard task *%s*. Verify in kanboard if the task description contains the pentest checklist, which can be found here: %s" % (column.title, self.task["title"], checklist_template_url)) else: error( "Could not find the checklist for column: *%s* in kanboard task *%s*" % (column.title, self.task["title"])) exit(-1) return checklist def save_checklist_backup(self): # Save description in temp dir before changing _, filename = tempfile.mkstemp(prefix="checklist_%s_" % self.task["title"]) f = open(filename, "w") f.write("\n".join(self.description)) f.close()
def auth(self): return Kanboard(self.url, 'jsonrpc', self.token)
def __init__(self, url: str, user: str, token: str): self.kb = Kanboard(url, user, token)
class KanboardLibrary: def __init__(self, url: str, user: str, token: str): self.kb = Kanboard(url, user, token) def get_version(self) -> str: return self.kb.execute("getVersion") def get_prioritys(self) -> list: pass def find_task_date_due(self, tasks: list, date_due: str) -> Task: for task in tasks: if task.date_due == date_due: return task return None def get_summary_tasks(self, tasks: list) -> str: table_list = list() headers = ['Project name', 'Title', 'Priority', 'Status', 'Assignee', 'Due date'] table_list.append(headers) for task in tasks: data = task.get_summary() table_list.append(data) table = AsciiTable(table_list) return table.table def get_my_dashboard(self, printable: bool =True) -> Task: my_dashboard = self.kb.execute('getMyDashboard') tasks = list() for project in my_dashboard: task = Task(project['project_name'], project['title'], project['priority'], project['column_name'], project['assignee_username'], project['date_due']) tasks.append(task) if printable: table = self.get_summary_tasks(tasks) print(table) return tasks def get_overdue_tasks(self, printable: bool =True) -> Task: overdue_tasks = self.kb.execute('getMyOverdueTasks') my_dashboard = self.get_my_dashboard(printable=False) tasks = list() for overdue_task in overdue_tasks: t = self.find_task_date_due(my_dashboard, overdue_task['date_due']) task = Task(overdue_task['project_name'], overdue_task['title'], t.priority, t.column_name, overdue_task['assignee_username'], overdue_task['date_due']) tasks.append(task) if printable: table = self.get_summary_tasks(tasks) print(table) return tasks def get_project_list(self, printable=True) -> Project: # Get dict of projects projects = self.kb.execute('getMyProjectsList') if printable: table_list = list() headers = ['Project id', 'Project name', 'Boards'] table_list.append(headers) for id in projects: boards = self.kb.execute('getBoard', project_id=id) boards_list = list() for item in boards: boards_list.append(item['name']) data = [id, projects[id], ','.join(boards_list)] table_list.append(data) table = AsciiTable(table_list) print(table.table) return projects def get_project_id(self, project_name: str, printable=True) -> int: # Get dict of projects projects = self.get_project_list(printable=False) for id in projects: if projects[id] == project_name: return id raise KanboardException('Project not found') def _get_board(self, project_name: str, board_name: str) -> dict: project_id = self.get_project_id(project_name, printable=False) boards = self.kb.execute('getBoard', project_id=project_id) for board in boards: if board['name'] == board_name: return board raise KanboardException('Project or board does not exist') def get_board_stats(self, project_name: str, board_name: str) -> Task: board_data = self._get_board(project_name, board_name) board = Board(project_name, board_name) for column in board.columns: tasks = create_tasks_from_dict(column.tasks) board.add_column(column['title'], tasks) # tasks = list() # for project in my_dashboard: # task = Task(project['project_name'], project['title'], project['priority'], project['column_name'], # project['assignee_username'], project['date_due']) # tasks.append(task) # # if printable: # table = self.get_summary_tasks(tasks) # print(table) # # return tasks pass
##################################### reload_json() updater = Updater(token=bot_token) dispatcher = updater.dispatcher logging.basicConfig( format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO) #connect to kanboard try: kb = Kanboard(kb_url, kb_user, kb_pw) except: print(str(lang["error"]["load_bot"])) ##################################### def is_granted(cur_id, cur_list): for e in range(0, len(cur_list)): if int(cur_id) == int(cur_list[e]): return True return False def has_permission(bot, update): access = False cur_id = update.message.chat_id
from slackclient import SlackClient from kanboard import Kanboard import time import os import sys slacktoken = os.environ['SLACKTOKEN'] kbtoken = os.environ['KBTOKEN'] kburl = os.environ['KBURL'] slack_client = SlackClient(slacktoken) kb = Kanboard(kburl, "jsonrpc", kbtoken) def opentask(description, projectname, channel): try: project = kb.getProjectByName(name=projectname) project_id = project.get('id') task_id = kb.create_task(project_id=project_id, title=description) message = "Task Opened" sendmessage(channel, message) except: message = "Unknow Project" sendmessage(channel, message) def sendmessage(channel, message): slack_client.api_call( 'chat.postMessage', channel=channel, text=message, as_user='******' )
def cli(ctx, api_url, api_user, api_token, project_owner): """Record project info from JSON file on Kanboard.""" project = parser_json(ctx.json_file) headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.3' } kb = Kanboard(api_url, api_user, api_token) # Validating url, username and api_token provided. user = None if api_user == 'jsonrpc': if project_owner is None: print(u'You must inform the Project Owner.') sys.exit() try: user = kb.get_user_by_name(username=project_owner) if user is not None: print(u'User {} - {} successfully connected.'.format( user['username'], user['name'])) print_line() else: raise InvalidUsername except InvalidUsername: print( u'Failed to get username: {}\nWith API user: {}\nAnd API token: \"{}\"\nOn address: {}.' .format(project_owner, api_user, api_token, api_url)) sys.exit() except Exception as e: print(repr(e)) sys.exit() else: try: user = kb.get_me() print(u'User {} - {} successfully connected.'.format( user['username'], user['name'])) print_line() except Exception as e: print(repr(e)) print( u'Failed to get user: {}\nWith api token: \"{}\"\nOn address: {}.' .format(api_user, api_token, api_url)) sys.exit() # Creating project project_id = False while project_id is False: try: project_id = kb.create_project(owner_id=user['id'], name=project.name) print(u'Project {} successfully created.'.format(project_id)) print(u'Project name: {}.'.format(project.name)) print_line() except Exception as e: print(repr(e)) print(u'Failed on Project creation. Trying again.') # Adding user to project when using the jsonrpc API user if api_user == 'jsonrpc': user_added = False while user_added is False: user_added = kb.add_project_user(project_id=project_id, user_id=user['id'], role='project-manager') print(u'User {} successfully added to Project {}.'.format( user['username'], project_id)) print_line() # Erasing default columns all_columns = False while all_columns is False: try: all_columns = kb.get_columns(project_id=project_id) except Exception as e: print(repr(e)) print(u'Failed to get Projects columns. Trying again.') for c in all_columns: erased = False while erased is False: try: erased = kb.remove_column(column_id=c['id']) print(u'Default Column erased.') except Exception as e: print(repr(e)) print(u'Failed to erase default Column. Trying again.') print_line() # Creating Columns for column in project.columns: column_id = False while column_id is False: try: column_id = kb.add_column(project_id=project_id, title=column.name) print(u'Column {} successfully created.'.format(column_id)) print(u'Column name: {}.'.format(column.name)) except Exception as e: print(repr(e)) print(u'Failed on Column creation. Trying again.') # Creating Tasks for task in column.tasks: task_id = False while task_id is False: try: task_id = kb.create_task(title=task.name, project_id=project_id, column_id=column_id, date_due=task.date_due, description=task.desc) print(u'Task {} successfully created.'.format(task_id)) except Exception as e: print(repr(e)) print(u'Failed on Task creation. Trying again.') # Creating Subtask for subtask in task.subtasks: subtask_id = False while subtask_id is False: try: subtask_id = kb.create_subtask(task_id=task_id, title=subtask.content, status=subtask.status) print(u'Subtask {} successfully created.'.format( subtask_id)) except Exception as e: print(repr(e)) print(u'Failed on Subtask creation. Trying again.') # Creating Comments for comment in task.comments: comment_id = False while comment_id is False: try: comment_id = kb.create_comment(task_id=task_id, content=comment.content, user_id=user['id']) print(u'Comment {} successfully created.'.format( comment_id)) except Exception as e: print(repr(e)) print(u'Failed on Comment creation. Trying again.') # Creating Attachments for attachment in task.attachments: attachment_id = False while attachment_id is False: try: req = urllib.request.Request(url=attachment.url, headers=headers) filedata = base64.b64encode( urllib.request.urlopen(req).read()).decode('ascii') attachment_id = kb.create_task_file( project_id=project_id, task_id=task_id, filename=attachment.filename, blob=filedata) print(u'Attachment {} successfully created.'.format( attachment_id)) except Exception as e: print(repr(e)) print(u'Failed on Attachment creation. Trying again.') print_line() print(u'Project Imported successfully.')
class GitlabImporter(object): def __init__(self, label_to_columns): self.label_to_columns = label_to_columns self.findlabel = re.compile(r'~([0-9]+)') # TODO: It should be optional requests.packages.urllib3.disable_warnings(InsecureRequestWarning) def setup_gitlab(self, endpoint, token): self.gitlab = { 'endpoint': endpoint, 'token': token, } def setup_kanboard(self, endpoint, user, token): self.kanboard = { 'endpoint': endpoint, 'user': user, 'token': token, } def connect(self): self.gl = Gitlab(self.gitlab['endpoint'], self.gitlab['token'], ssl_verify=False) self.gl.auth() self.kb = Kanboard(self.kanboard['endpoint'], self.kanboard['user'], self.kanboard['token']) def migrate(self, namespace, project): _groups = [ g for g in self.gl.groups.search(namespace) if g.name == namespace ] if not _groups: print(_('Error: namespace {} not found !').format(namespace)) return False group = _groups[0] _projects = [ p for p in group.projects.list(search=project) if p.name == project ] if not _projects: print( _('Error: project {} not found in namespace {} !').format( project, namespace)) return False origin = _projects[0] count = 0 self.target = self.kb.createProject( name='{}/{}'.format(namespace, project)) print( _('Project {}/{} created, id: {} !').format( namespace, project, self.target)) self.project_users = self.kb.getProjectUsers(project_id=self.target) self.columns = self.kb.getColumns(project_id=self.target) self.users = self.kb.getAllUsers() self.labels = origin.labels.list(all=True) for issue in reversed(origin.issues.list(all=True)): creator = self.get_user_id(issue.author.username) owner = None if issue.assignee: owner = self.get_user_id(issue.assignee.username) params = { 'title': issue.title, 'project_id': self.target, 'description': issue.description, 'reference': '#{}'.format(issue.iid), 'tags': issue.labels, 'date_due': issue.due_date, } if creator: params['creator_id'] = self.check_member(creator) if owner: params['owner_id'] = self.check_member(owner) for label, column in self.label_to_columns.items(): if label in issue.labels: params['column_id'] = self.get_column(column) params['tags'].remove(label) if (issue.state == 'closed'): params['column_id'] = self.get_column(_('Done')) if not params['tags']: del params['tags'] task = self.kb.createTask(**params) if task: for comment in issue.notes.list(all=True): body = comment.body if 'label' in body: for l in self.findlabel.findall(body): body = body.replace('~{}'.format(l), self.get_label_by_id(l)) commenter_id = self.get_user_id( comment.author.username) or self.users[0]['id'] self.kb.createComment( task_id=task, user_id=commenter_id, content=body, ) if (issue.state == 'closed' and task): self.kb.closeTask(task_id=task) count += 1 print( _('... issue {} migrated to task {} {}').format( issue.iid, task, _('(closed)') if issue.state == 'closed' else '')) else: print(_('Oops: problem to import {}').format(issue.iid)) print(_('{} issue(s) migrated !').format(count)) return True def check_member(self, member): if str(member) not in self.project_users: self.kb.addProjectUser(project_id=self.target, user_id=member) self.project_users = self.kb.getProjectUsers( project_id=self.target) return member def get_user_id(self, username): found = [u['id'] for u in self.users if u['username'] == username] if found: return found[0] def get_column(self, column): for c in self.columns: if c['title'] == column: return c['id'] def get_label_by_id(self, label): # Some old versions of gitlab don't send id :( found = [l.name for l in self.labels if l.id == int(label)] return found[0] if found else '~{}'.format(label)
import configparser import datetime from kanboard import Kanboard import json2kanboard # Import configuration config = configparser.ConfigParser() config.read("demo.example.conf") # Create Kanboard API instance kanboard_instance = Kanboard( config.get("kanboard","url"), config.get("kanboard","user"), config.get("kanboard","password") ) # Map roles in the JSON file to task owners roles = { 'ROLE_MANAGER': 'user_b' } # Create Kanboard project json2kanboard.create_project( "onboarding_project.demo.json", kanboard_instance, project_title = "TEST_PROJECT", project_identifier = "TEST_PROJECT_ID", due_date = datetime.date(2020, 1, 1),