def login(): if request.method == 'POST': username = request.form.get('username', '') password = request.form.get('password', '') user = PocketChangeUser(None, username, password) User = sqlalchemy_db.models['User'] db_session = sqlalchemy_db.create_scoped_session() try: db_user = (db_session.query(User) .filter(User.name==user.name).one()) except: db_user = None user = PocketChangeUser(None, username, password) else: user = PocketChangeUser(db_user, password=password) if user.is_authenticated(): User = sqlalchemy_db.models['User'] if db_user: user.populate_name_from_database() else: db_user = User(name=user.name) db_user.password = password db_session.add(db_user) db_session.commit() user.token = db_user.get_new_token(current_app.secret_key[:16], expires=datetime.now() + login_lifetime) db_session.commit() session['username'] = user.name login_user(user) return 'logged in' else: return 'login failed' else: return render_template('login.html')
def complete_link(): token = request.args.get('oauth_token', None) if not token or current_user.user.jira.oauth_token != token: return 'Linking failed' with open(current_app.config['JIRA_RSA_KEY_FILE'], 'r') as rsa_file: rsa_data = rsa_file.read() oauth_session = OAuth1Session(current_app.config['JIRA_APP_KEY'], signature_method=SIGNATURE_RSA, rsa_key=rsa_data, resource_owner_key=current_user.user.jira.oauth_token, resource_owner_secret=current_user.user.jira.oauth_secret) jira_host = current_app.config['JIRA_HOST'].rstrip('/') token_response = oauth_session.fetch_access_token(jira_host + '/plugins/servlet/oauth/access-token') db_session = sqlalchemy_db.create_scoped_session() db_user = db_session.merge(current_user.user) db_user.jira.oauth_token = token_response['oauth_token'] db_user.jira.oauth_secret = token_response['oauth_token_secret'] db_user.jira.expires = datetime.now() + timedelta(seconds=int(token_response['oauth_expires_in'])) db_session.commit() g.jira._session.auth = OAuth1(current_app.config['JIRA_APP_KEY'], signature_method=SIGNATURE_RSA, rsa_key=rsa_data, resource_owner_key=db_user.jira.oauth_token, resource_owner_secret=db_user.jira.oauth_secret) g.jira.priorities() return redirect(url_for('core_ui.cycle_listing'))
def case_execution_details(case_execution_id): CaseExecution = sqlalchemy_db.models['CaseExecution'] execution = (sqlalchemy_db.create_scoped_session().query(CaseExecution) .filter(CaseExecution.id==case_execution_id) .one()) return render_template('case_execution_details.html', case_execution=execution)
def __init__(self, db_entity, name=None, password=None, populate_name_from_database=False): if db_entity: self.session = sqlalchemy_db.create_scoped_session() db_entity = self.session.merge(db_entity) try: self.token = db_entity.get_new_token(current_app.secret_key[:16], expires=login_timeout) except AttributeError: self.token = db_entity else: self.session.commit() self.last_refresh = datetime.now() if name is None and populate_name_from_database: self.populate_name_from_database() else: self.name = name self.password = password
def cycle_listing(filter=None, offset=1): TestCycle = sqlalchemy_db.models['TestCycle'] query = sqlalchemy_db.create_scoped_session().query(TestCycle) if request.method == 'POST': filter = request.form.get('filter', None) offset = 1 if filter: query = query.filter(or_(TestCycle.name.contains(filter), TestCycle.description.contains(filter))) query = query.order_by(TestCycle.id.desc()) if offset == 1: query = query.limit(21) cycles = query.all() cycle_list = cycles[:20] has_next = (len(cycles) == 21) else: query = query.limit(22).offset(((offset - 1) * 20) - 1) cycles = query.all() cycle_list = cycles[1:22] has_next = (len(cycles) == 22) cycle_issues = {} use_jira = bool(current_app.config['KAICHU_ENABLED'] and current_user and current_user.is_authenticated() and hasattr(current_user, 'user') and current_user.user and hasattr(current_user.user, 'jira') and current_user.user.jira and current_user.user.jira.active) if use_jira: for cycle in cycle_list: if cycle.jira_issue and cycle.jira_issue.issue_id: cycle_issues[cycle.id] = g.jira.issue(str(cycle.jira_issue.issue_id)) return render_template('cycle_listing.html', filter=filter, offset=offset, cycle_list=cycle_list, has_next=has_next, use_jira=use_jira, jira_host=current_app.config.get('JIRA_HOST', ''), cycle_issues=cycle_issues)
def start_linking(): if (hasattr(current_user.user, 'jira') and current_user.user.jira and current_user.user.jira.active and current_user.user.jira.expires is not None): # TODO: Correct manually revoked jira oauth token return 'link already active' if request.method == 'POST': with open(current_app.config['JIRA_RSA_KEY_FILE'], 'r') as rsa_file: rsa_data = rsa_file.read() username = request.form.get('username', '') password = request.form.get('password', '') jira_host = current_app.config['JIRA_HOST'].rstrip('/') if g.jira.verify_credentials(username, password): oauth_session = OAuth1Session(current_app.config['JIRA_APP_KEY'], signature_method=SIGNATURE_RSA, rsa_key=rsa_data) token_response = oauth_session.fetch_request_token(jira_host + '/plugins/servlet/oauth/request-token') db_session = sqlalchemy_db.create_scoped_session() db_user = db_session.merge(current_user.user) if hasattr(db_user, 'jira') and db_user.jira and db_user.jira is not None: db_user.jira.name = username db_user.jira.oauth_token = token_response['oauth_token'] db_user.jira.oauth_secret = token_response['oauth_token_secret'] db_user.jira.expires=None db_user.jira.revoked=False else: db_user.jira = sqlalchemy_db.models['UserJiraData'](name=username, oauth_token=token_response['oauth_token'], oauth_secret=token_response['oauth_token_secret'], expires=None, revoked=False) db_session.commit() auth_url = oauth_session.authorization_url(jira_host + '/plugins/servlet/oauth/authorize') return redirect(auth_url + '&redirect_uri=' + current_app.config['APP_HOST'] + ':' + current_app.config['APP_PORT'] + url_for('kaichu_ui.complete_link')) else: return 'Bad username/password' else: return render_template('jira_linking.html', user=current_user)
def cycle_cases(test_cycle_id): CaseExecution = sqlalchemy_db.models["CaseExecution"] TestCycle = sqlalchemy_db.models["TestCycle"] db_session = sqlalchemy_db.create_scoped_session() test_cycle = db_session.query(TestCycle).filter(TestCycle.id == test_cycle_id).one() executions_by_case = defaultdict(list) cases = [] case_ids = set() case_issues = defaultdict(lambda: {"issue_ids": set(), "issues": list()}) cycle_issue = None # TODO: The hasattr jira_issue and jira_issue trueish tests are are flakey hack # to fix displaying PASS status for executions not linked in Jira. Need to fix # this in a better way. Right now, a case with an execution reported in to a # cycle will show a Jira status whether or not that case had any executions run # while linked to Jira as long as the cycle itself is linked to Jira. Conversely, # an execution with a Jira issue being displayed as part of a cycle without an # issue will not show its issue. This may not actually be a problem though. use_jira = bool( current_app.config["KAICHU_ENABLED"] and current_user and current_user.is_authenticated() and hasattr(current_user, "user") and current_user.user and hasattr(current_user.user, "jira") and current_user.user.jira and current_user.user.jira.active and hasattr(test_cycle, "jira_issue") and test_cycle.jira_issue ) for case_execution in ( db_session.query(CaseExecution) .filter(CaseExecution.test_cycles.contains(test_cycle)) .order_by(CaseExecution.id) ): if "Out of case scope :" not in case_execution.case.label: if case_execution.case_id not in case_ids: case_ids.add(case_execution.case_id) cases.append(case_execution.case) executions_by_case[case_execution.case_id].append(case_execution) if use_jira: try: issue_id = case_execution.jira_issue.issue_id except: pass else: if issue_id: case_issues[case_execution.case_id]["issue_ids"].add(issue_id) if use_jira: if test_cycle.jira_issue and test_cycle.jira_issue.issue_id: cycle_issue = g.jira.issue(str(test_cycle.jira_issue.issue_id)) for case_id in case_ids: statuses = set() resolutions = set() if case_issues[case_id]["issue_ids"]: for issue_id in case_issues[case_id]["issue_ids"]: issue = g.jira.issue(str(issue_id)) statuses.add(issue.fields.status.name) if issue.fields.status.name == "Closed": resolutions.add(issue.fields.resolution.name) case_issues[case_id]["issues"].append(issue) if len(statuses) > 1 or next(iter(statuses)) != "Closed": case_issues[case_id]["rollup_result"] = "FAIL - UNDER REVIEW" else: if len(resolutions) > 1: case_issues[case_id]["rollup_result"] = "FAIL - REVIEWED" else: resolution = next(iter(resolutions)) if resolution == "Cannot Reproduce": case_issues[case_id]["rollup_result"] = "PASS - %s" % resolution.upper() else: case_issues[case_id]["rollup_result"] = "FAIL - %s" % resolution.upper() else: execution_statuses = set(execution.result for execution in executions_by_case[case_id]) if "PENDING" in execution_statuses: case_issues[case_id]["rollup_result"] = "PENDING" else: case_issues[case_id]["rollup_result"] = "PASS" return render_template( "cycle_case_rollup.html", cycle=test_cycle, cycle_issue=cycle_issue, cases=cases, executions_by_case=executions_by_case, use_jira=use_jira, jira_host=current_app.config.get("JIRA_HOST", ""), case_issues=case_issues, )
def refresh(self, force=False): if force or datetime.now() > self.last_refresh + user_data_timeout: self.session = sqlalchemy_db.create_scoped_session() self.token = self.session.merge(self.token) self.last_refresh = datetime.now()