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
예제 #3
0
    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
예제 #5
0
    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)
예제 #9
0
    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)
예제 #11
0
    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
예제 #12
0
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
예제 #14
0
    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)
예제 #15
0
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
예제 #17
0
 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
예제 #18
0
    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)
예제 #19
0
    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