def get(self, project_id, remote, branch_name): form = GitSnapshotsForm(request.args) if not form.validate(): return { 'message' : 'please correct the errors mentioned below', 'errors' : form.errors }, 400 data = form.data snapshots = request.project.git.get_snapshots( branch=remote + "/" + branch_name, limit=data['limit'], offset=data['offset'])[::-1] shas = [snapshot.sha for snapshot in snapshots] if data['annotate'] and shas: analyzed_snapshots = backend.filter(GitSnapshot, {'snapshot.project': request.project, 'sha': {'$in': shas}}, raw=True, include=(('snapshot', 'pk', 'analyzed'),), only=GitSnapshots.export_fields) diffs = backend.filter(Diff, { '$or': [ {'$and': [{'snapshot_a.git_snapshot.sha': sha_a}, {'snapshot_b.git_snapshot.sha': sha_b}]} for sha_a, sha_b in zip(shas[1:], shas[:-1]) ] }) diff_stats = self.get_diff_issue_stats(diffs) analyzed_snapshots_by_sha = {snapshot['sha'] : snapshot for snapshot in analyzed_snapshots} for diff in diff_stats: if diff['sha_b'] in analyzed_snapshots_by_sha: analyzed_snapshots_by_sha[diff['sha_b']]['diff'] = diff annotated_snapshots = [] for snapshot in snapshots: if snapshot['sha'] in analyzed_snapshots_by_sha: annotated_snapshots.append( analyzed_snapshots_by_sha[snapshot['sha']]) else: annotated_snapshots.append(snapshot) else: annotated_snapshots = snapshots serialized_snapshots = [self.export(snp) for snp in annotated_snapshots] try: snapshot_count = request.project.git.repository.get_number_of_commits( remote + '/' + branch_name) except subprocess.CalledProcessError as e: snapshot_count = len(serialized_snapshots) return {'snapshots': serialized_snapshots, 'count': snapshot_count}, 200
def get(self): query = {} form = UsersForm(request.args) if not form.validate(): return {'message' : 'Please correct the errors mentioned below.', 'errors' : form.errors}, 400 data = form.data if data['name']: query = {'name': {'$ilike': "%%{}%%".format(data['name'])}} if data['ignore_self']: if request.user: query = {'$and': [ query, {'$not': {'name': request.user.name}}, ]} users = backend.filter(User, query) if len(users) > 10: return {'message': 'Too many results!'}, 403 return {'users': [self.export(user.attributes) for user in users]}, 200
def get(self, project_id): """ Get all tasks for the project with the given id. :param project_id: id of the project :return: tasks for the project """ try: pagination_args = get_pagination_args(request) except ArgumentError as e: return {'message': e.message}, 500 limit = pagination_args[ 'limit'] if 'limit' in pagination_args else self.DEFAULT_LIMIT offset = pagination_args[ 'offset'] if 'offset' in pagination_args else self.DEFAULT_OFFSET tasks = backend.filter(Task, { 'project.pk': request.project.pk }, include=('project', ), only=TaskDetails.export_fields, raw=True).sort('created_at', -1) return { 'tasks': [ TaskDetails.export(task) for task in tasks[offset:offset + limit] ] }, 200
def get(self, email_validation_code): with backend.transaction(): try: user = backend.get( User, {'email_validation_code': email_validation_code} ) if not user.get('new_email'): if not user.get('email'): return {'message': 'no valid e-mail set'}, 403 backend.update(user, {'email_validated': True}, unset_fields=['email_validation_code']) settings.hooks.call("user.email.validated", user) logger.warning("Hooray, user {0} has verified his email address".format(user.name)) else: if backend.filter(User, {'email': user.new_email}): return {'message': 'A user with this e-mail already exists'}, 403 old_email = user.email new_email = user.new_email backend.update(user, {'email_validated': True, 'email': user.new_email}, unset_fields=['new_email', 'email_validation_code']) settings.hooks.call("user.email.updated", user) except User.DoesNotExist: return {'message': 'Unknown validation code'}, 404 return {'message': 'success'}, 200
def get(self): form = ProjectsForm(request.args) if not form.validate(): return {'message' : 'please correct the errors mentioned below'}, 400 data = form.data limit, offset = data['limit'], data['offset'] query = {'user_roles.user': request.user} if data['query']: search_dict = { '$or': [ {'$and': [{'name': {'$ilike': '%%%s%%' % q}} for q in data['query']]} ] } query = {'$and': [query, search_dict]} projects = backend.filter( Project, query, raw=True, only=self.export_fields, include=(('tags', 'name', 'pk'),) ).sort(data['sort'], data['direction'], explicit_nullsfirst=False) serialized_projects = [ self.export(project) for project in projects[offset:offset + limit] ] return ({'projects': serialized_projects, 'count': len(projects)}, 200)
def delete_pending_project(): pending_projects = backend.filter(Project, { 'delete': True }).sort('updated_at', 1).limit(100) logger.debug("%d projects marked for deletion" % len(pending_projects)) for pending_project in pending_projects: return delete_project(pending_project.pk, task_id=delete_pending_project.request.id) logger.debug("No projects left to delete...")
def delete_pending_user(): pending_projects = backend.filter(User, { 'delete': True }).sort('updated_at', 1).limit(100) logger.debug("%d users marked for deletion" % len(pending_projects)) for pending_user in pending_users: return delete_user(pending_user.pk, task_id=delete_pending_user.request.id) logger.debug("No users left to delete...")
def get_relevant_issue_classes(project): """ Returns all relevant issue classes applicable to the given project. :param project: project to get the relevant issue classes for :return: relevant issue classes """ allowed_tags = ['generic'] + [tag.name for tag in project.tags] query = { 'tags.name': { '$in': allowed_tags, } } return backend.filter(IssueClass, query)
def get(self): form = ProjectTagsForm(request.args) if not form.validate(): return {'message' : 'please correct the errors mentioned below', 'errors' : form.errors}, 400 data = form.data query = {'name': {'$ilike': "%%{}%%".format(data['name'])}} tags = backend.filter(Tag, query, only=['name', 'pk'], raw=True) return {'tags': [tag['name'] for tag in tags[:10]]}, 200
def reset_pending_project(): try: pending_project = backend.filter(Project, { 'reset': True }).sort('reset_requested_at', 1).limit(1)[0] except IndexError: logger.debug("No projects left to reset....") return with backend.transaction(): backend.update(pending_project, {'reset_requested_at': datetime.datetime.now()}) return reset_project(pending_project.pk, task_id=reset_pending_project.request.id)
def delete(self, project_id, user_role_id): with backend.transaction(): try: user_role = backend.get(UserRole, {'project': request.project, 'pk': user_role_id}) if user_role.role == 'owner' and user_role.user == request.user: if len(backend.filter(UserRole, {'project': request.project,'role' : 'owner'})) == 1: return {'message' : 'You are the last owner of this project, cannot remove you.'}, 400 except UserRole.DoesNotExist: return {'message': 'invalid role'}, 404 backend.delete(user_role) return {'message': 'success'}, 200
def delete_user(user_id, task_id=None): """ What we need to do here: -Remove all user data from database, unless user was customer - Projects - User profile - AccessToken """ if not task_id: task_id = delete_user.request.id try: user = backend.get(User, {'pk': user_id}) except User.DoesNotExist: logger.error( "User {} does not exist! Cannot delete it.".format(user_id)) return try: with ExclusiveTask(backend, {'type': { '$in': ['delete_{}'.format(user.pk)] }}, {'type': 'delete_{}'.format(user.pk)}, task_id, no_update_on_exit=True) as delete_task: with TaskLogger(delete_task, backend=backend, ping=True): with backend.transaction(): logger.debug("Starting deletion of user {0} ({1}).".format( user.name, user.pk)) # Delete all related models backend.filter(UserRole, {'user': user}).delete() backend.filter(AccessToken, {'user': user}).delete() backend.filter(User, {'pk': user.pk}).delete() # Todo: Delete all of the user's projects that have no "owner" user roles anymore... logger.info("Deletion of user {0} ({1}) complete!".format( user.name, user.pk)) except ExclusiveTask.LockError: pass except BaseException as err: logger.error("Error {0}: Can't delete user {1}.".format( err.__class__.__name__, user)) logger.error(traceback.format_exc())
def analyze_pending_project(): """ Get all projects that are marked for analysis and sort them by priority and request date. Then go through the list and check if the project has been recently analyzed, if not, analyze the first project. """ logger.debug("Retrieving projects pending analysis...") pending_projects_query = { '$and': [{ 'analyze': True }, { '$or': [{ 'deleted': { '$exists': False } }, { 'deleted': False }] }] } pending_projects = backend.filter(Project, pending_projects_query) pending_projects.sort([['analysis_priority', -1], ['analysis_requested_at', 1]]).limit(100) timestamp = datetime.datetime.now() max_allowed_runtime = datetime.timedelta(minutes=120) for pending_project in pending_projects: # skip projects currently being analyzed unless the analysis has been running for too long if (pending_project.analysis_status == pending_project.AnalysisStatus.in_progress and timestamp - pending_project.analyzed_at < max_allowed_runtime): continue # move the project back in the queue with backend.transaction(): backend.update(pending_project, {'analysis_requested_at': datetime.datetime.now()}) analyze_project(pending_project.pk, task_id=analyze_pending_project.request.id) break
def post(self, project_id, role, user_id): with backend.transaction(): try: user = self._get_user(user_id) except AttributeError: return ({'message': 'invalid user'}, 404) if role not in ('admin', 'collaborator', 'owner'): return ({'message': 'invalid role: %s' % role}, 403) try: user_role = backend.get(UserRole, {'project': request.project, 'user': user}) if user_role.role == 'owner' and user_role.user == request.user and role != 'owner': if len(backend.filter(UserRole, {'project': request.project,'role' : 'owner'})) == 1: return {'message' : 'You are the last owner of this project, cannot remove you.'}, 400 except UserRole.DoesNotExist: user_role = UserRole({'project': request.project, 'user': user}) user_role.role = role backend.save(user_role) return ProjectRoles.get(self, project_id=project_id)
def _delete_project(project): """ Deletes the given project """ checkmate_settings = settings.checkmate_settings with backend.transaction(): logger.info("Starting deletion of project {0} ({1}).".format( project.name, project.pk)) # This should delete everything checkmate-related. reset_command = ResetCommand(project, checkmate_settings, backend) reset_command.run() settings.hooks.call("project.delete.before", project) backend.filter(ProjectIssueClass, {'project': project}).delete() backend.filter(UserRole, {'project': project}).delete() backend.filter(Task, {'project': project}).delete() backend.delete(project) settings.hooks.call("project.delete.after", project)
def get(self): form = PublicProjectsForm(request.args) if not form.validate(): return { 'message': 'please correct the errors mentioned below', errors: form.errors }, 400 data = form.data query = {'public': True} if not data['show_failed']: query['analysis_status'] = {'$in': ['succeeded', 'in_progress']} query = { '$and': [ query, { '$or': [{ 'deleted': { '$exists': False } }, { 'deleted': False }] }, { '$or': [{ 'delete': { '$exists': False } }, { 'delete': False }] }, ] } if data['query']: search_dict = { '$or': [{ '$and': [{ 'name': { '$ilike': '%%%s%%' % q } } for q in data['query']] }] } query = {'$and': [query, search_dict]} projects = backend.filter(Project, query, raw=True, only=self.export_fields) projects = projects.sort(data['sort'], data['direction'], explicit_nullsfirst=False) offset, limit = data['offset'], data['limit'] serialized_projects = [ self.export(project) for project in projects[offset:offset + limit] ] res = { 'projects': serialized_projects, 'count': len(projects), 'offset': offset, 'limit': limit, 'query': data['query'] } return res, 200
def get(self, project_id): roles = backend.filter(UserRole, {'project': request.project}, include=(('user', 'name', 'pk'),)) return {'roles': [self.export(role) for role in roles]}, 200
def get(self): #we get all distinct values of languages, analyzers, categories and tags (used by the frontend) issue_classes_table = backend.get_table(IssueClass) categories_table = backend.get_table(IssueCategory) tags_table = backend.get_table(Tag) with backend.transaction(): languages = [ l[0] for l in backend.connection.execute( select([distinct(issue_classes_table.c.language) ])).fetchall() ] analyzers = [ a[0] for a in backend.connection.execute( select([distinct(issue_classes_table.c.analyzer) ])).fetchall() ] categories = [ c[0] for c in backend.connection.execute( select([distinct(categories_table.c.name)])).fetchall() ] tags = [ t[0] for t in backend.connection.execute( select([distinct(tags_table.c.name)])).fetchall() ] form = IssueClassForm(languages, analyzers, categories, request.args) if not form.validate(): return ({ 'message': 'Please correct the errors mentioned below.', 'errors': form.errors }, 400) project = self.get_project(form.data['project_id']) params = {} data = form.data if data['severity']: params['severity'] = {'$in': data['severity']} if data['categories']: params['categories.name'] = {'$in': data['categories']} if data['language']: params['language'] = {'$in': data['language']} if data['analyzer']: params['analyzer'] = {'$in': data['analyzer']} if data['query']: query = data['query'] if query['tag_queries']: params = { '$and': [params, { 'tags.name': { '$all': query['tag_queries'] } }] } if query['title_queries']: params = { '$and': [ params, { '$and': [{ 'title': q } for q in query['title_queries']] } ] } if data['type'] and project: ic_query = { 'project_issue_classes.project': project, } if data['type'] != 'all': ic_query['project_issue_classes.enabled'] = data[ 'type'] == 'enabled' params = {'$and': [params, ic_query]} sort = data['sort'] direction = data['direction'] limit = data['limit'] offset = data['offset'] issue_classes = backend.filter( IssueClass, params, only=self.export_fields, include=( 'categories', 'creator', 'tags', ), ).sort([(sort, direction), ('title', 1)]) count = len(issue_classes) issue_classes = issue_classes[offset:offset + limit] if project: if data['type'] == 'all': active_issue_classes = issue_classes.filter({ 'project_issue_classes.project': project, 'project_issue_classes.enabled': True }) active_issue_classes_by_pk = { issue_class.pk: issue_class for issue_class in active_issue_classes } for issue_class in issue_classes: if issue_class.pk in active_issue_classes_by_pk: issue_class.used_by_project = True else: issue_class.used_by_project = False else: #if we already checked for the enabled field, we just copy the parameter for issue_class in issue_classes: issue_class.used_by_project = data['type'] == 'enabled' return ({ 'issue_classes': [self.export(issue_class) for issue_class in issue_classes], 'count': count, 'languages': languages, 'analyzers': analyzers, 'categories': categories, 'tags': tags }, 200)
def post(self): form = SignupForm(request.form) if form.validate(): with backend.transaction(): email_matches = backend.filter(User, {'email': form.email.data}) if len(email_matches) > 0: for user in email_matches: if user.delete is True: return ({'message': 'Your account is scheduled for deletion. Try again in a few minutes".'}, 403) return {'message': "A user with this e-mail address already exists. " "Please try resetting your password.", 'resetPasswordLink': True}, 403 try: user = backend.get(User, {'name': form.name.data.lower()}) return {'errors': {'name': {'message': 'This login has already been chosen by another user'}}, 'message': 'Login already in use.'}, 403 except User.DoesNotExist: pass except User.MultipleDocumentsReturned: return {'errors': {'name': {'message': 'This login has already been chosen by another user'}}, 'message': 'Login already in use.'}, 403 user = User({ 'email': form.email.data.lower(), 'name': form.name.data.lower(), 'email_validated': False, 'email_validation_code': uuid.uuid4().hex, 'terms_accepted': form.terms.data, 'terms_accepted_at': datetime.datetime.utcnow(), 'terms_accepted_from_ip': request.remote_addr, 'email_settings': { 'newsletter': True, 'notifications': True, }, }) user.set_password(form.password.data) backend.save(user) access_token = AccessToken({'user': user, 'token': uuid.uuid4().hex}) backend.save(access_token) user_profile = UserProfile.export(user) response = self.make_response({ 'access_token': access_token.token, 'message': 'Success!', 'user': user_profile, }) response.set_cookie( 'access_token', value=access_token.token, expires=(datetime.datetime.utcnow() + datetime.timedelta(days=7)), ) activation_url = u"{}{}/user/validate/{}".format( settings.get('url'), settings.get('frontend.url'), user.email_validation_code, ) # Activate email send_mail( email_to=user.email, template="verify_email", template_context={ "user_name": user.name, "activation_url": activation_url, }) logger.warning("Hooray, a new user has just signed up: %s" % user.name) return response return {'message': 'Invalid data', 'errors': form.errors}, 403