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
Esempio n. 2
0
def auto_tag(project):
    """ First step of the analysis for Git projects. Determines if automatic tags have already been added and, if not
    adds them from the requirements.txt file, if one exists in the repository.
    :param project: project to auto tag
    :return:
    """
    logger.debug("Adding automatic tags to {}".format(project.pk))
    repository = project.git.eager.repository

    # auto tag the project (but only once)
    if project.get('automatic_tags_added'):
        return

    default_branch = project.git.get_default_branch()
    if default_branch is None:
        return
    tags = extract_tags_from_requirements_txt(repository, default_branch)

    with backend.transaction():
        for tag_name in tags:
            try:
                tag = backend.get(Tag, {'name': tag_name})
            except Tag.DoesNotExist:
                tag = Tag({'name': tag_name})
                backend.save(tag)

            project.tags.append(tag)

    project.automatic_tags_added = True
    with backend.transaction():
        backend.update(project, ['automatic_tags_added'])
    def post(self):
        form = PasswordResetRequestForm(request.form)
        if form.validate():
            with backend.transaction():
                try:
                    user = backend.get(User, {'email': form.email.data})
                    if 'email_validated' in user and user.email_validated:
                        backend.update(
                            user,
                            {'password_reset_code': uuid.uuid4().hex}
                        )

                        reset_url = "{}{}/user/password-reset?reset_code={}".format(
                            settings.get('url'),
                            settings.get('frontend.url'),
                            user.password_reset_code
                        )

                        # Reset Email
                        send_mail(
                            email_to=form.email.data,
                            template="reset_password",
                            template_context={
                                "user_name": user.name,
                                "reset_url": reset_url
                            }
                        )
                        return {'message': 'Email with reset link was sent.'}, 200
                    return {'message': "Your email is not validated, so we cannot send you "
                                       "a password-reset token."}, 403
                except User.DoesNotExist:
                    return {'message': 'Unknown user'}, 404
        return {'message': 'Invalid data', 'errors': form.errors}, 403
def generate_key_pair(project):
    """ Generates a new SSH key pair for the given remote in the given project.
    Effect: saves the public and private keys on the appropriate remote in the project object
    :param project: project to generate the key pair for
    """

    tempdir = tempfile.mkdtemp()

    try:
        subprocess.call([
            "ssh-keygen", "-t", "rsa", "-q", "-f", "testkey", "-N", "", "-C",
            project.pk
        ],
                        cwd=tempdir)

        with open(os.path.join(tempdir, "testkey"), 'r') as private_key_file:
            private_key = private_key_file.read()

        with open(os.path.join(tempdir, "testkey.pub"),
                  'r') as public_key_file:
            public_key = public_key_file.read()

        with backend.transaction():
            backend.update(project.git, {
                'private_key': private_key,
                'public_key': public_key
            })
    finally:
        shutil.rmtree(tempdir)
    def post(self, password_reset_code):
        form = PasswordResetForm(request.form)
        if form.validate():
            with backend.transaction():
                try:
                    user = backend.get(
                        User,
                        {'password_reset_code': password_reset_code}
                    )
                except User.DoesNotExist:
                    return {'message': 'Unknown user'}, 404

                user.set_password(form.password.data)
                backend.update(user, ['password', 'password_set'], unset_fields=['password_reset_code'])
                access_token = user.get_access_token()
                backend.save(access_token)

                send_mail(
                    email_to=user.email,
                    template="password_reset_successful",
                    template_context={
                        "user_name": user.name
                    }
                )

                return {'message': 'success'}, 200

        return ({'message': 'Invalid data',
                 'errors': form.errors},
                403)
Esempio n. 6
0
 def delete(self, project_id):
     with backend.transaction():
         backend.update(
             request.project,
             {'reset': True,
              'reset_requested_at': datetime.datetime.now()})
     return ({'message': 'Success, project scheduled for reset. Please be patient.'},
             200)
Esempio n. 7
0
 def delete(self, project_id, issue_class_id):
     """
     Delete an issue class from a project.
     """
     with backend.transaction():
         project_issue_class = self._get_project_issue_class()
         backend.update(project_issue_class, {'enabled': False})
     return {'message': 'success'}, 200
def fetch_remote(project,
                 branch=None,
                 git_config=None,
                 git_credentials=None,
                 report_error=True):
    """ Fetches the remote for the given project
    :param project:
    :param git_config:
    :param branch:
    :param git_credentials:
    :param report_error:
    :return:
    """
    repository = project.git.eager.repository
    remote_name = "origin"

    # do not fetch the directory directly but instead use a copy.
    # This mitigates the risk of being unable to serve a simultaneous request
    # which relies on the git repository, f.e. to get a list of branches.
    tmp_repo_path = repository.path + "_temp"
    if os.path.exists(tmp_repo_path):
        # we should have an exclusive task log on the project, so deleting the temporary copy is ok.
        shutil.rmtree(tmp_repo_path)
    try:
        shutil.copytree(repository.path, tmp_repo_path)
        tmp_repository = Repository(tmp_repo_path)

        tmp_repository.update_remote_url(remote_name, project.git.url)

        # actually fetch the repository
        with tempfile.NamedTemporaryFile(delete=False) as tf:
            tf.write(project.git.private_key)
            tf.close()
            rc = tmp_repository.fetch(remote_name,
                                      branch=branch,
                                      ssh_identity_file=tf.name,
                                      git_config=git_config,
                                      git_credentials=git_credentials)

        # move the repository back if the fetch was successful
        if rc == 0:
            shutil.rmtree(repository.path)
            shutil.move(tmp_repo_path, repository.path)
    finally:
        if os.path.isdir(tmp_repo_path):
            shutil.rmtree(tmp_repo_path)

    with backend.transaction():
        backend.update(
            project, {
                'fetch_status': 'failed' if rc != 0 else 'succeeded',
                'fetched_at': datetime.datetime.utcnow(),
                'fetch_error': '' if rc == 0 else repository.stderr
            })

    if rc != 0:
        raise IOError("Cannot fetch git repository!")
 def delete(self):
     """
     Marks a user for deletion (will be done in a backend task)
     """
     logger.warning("Ouch, we lost user {0}".format(request.user.name))
     with backend.transaction():
         backend.update(request.user, {'delete': True})
     return ({'message': 'We\'re sad to see you leave! Your account will be fully deleted within a few minutes.',
              'user_id': request.user.pk},
             200)
def update_analysis_status(project, status, extra=None):
    """ Updates the analysis status of the given project to the given status.
    :param project: project to update the analysis status for
    :param status: new analysis status
    :param extra: dictionary with extra data to update
    """
    extra = extra if extra is not None else {}
    with backend.transaction():
        data = extra.copy()
        data['analyzed_at'] = datetime.datetime.now()
        data['analysis_status'] = status
        backend.update(project, data)
Esempio n. 11
0
 def _schedule_analysis(project_id, analysis_priority=Project.AnalysisPriority.high):
     if not (request.project.get('analyze') and request.project.get('analysis_priority', Project.AnalysisPriority.low) >= analysis_priority):
         with backend.transaction():
             backend.update(request.project,
                            {'analyze': True,
                             'analysis_requested_at': datetime.datetime.now(),
                             'analysis_priority': analysis_priority})
         return ({'message': 'Success, project scheduled for analysis. Please be patient.'},
                 200)
     else:
         return ({'message': 'Project was already scheduled for analysis. Please be patient.'},
                 200)
Esempio n. 12
0
 def post(self, project_id, issue_class_id):
     """
     Add a new issue class to a project
     """
     with backend.transaction():
         project_issue_class = self._get_project_issue_class()
         if project_issue_class.pk:
             backend.update(project_issue_class, {'enabled': True})
         else:
             project_issue_class.enabled = True
             backend.save(project_issue_class)
     return {'message': 'success'}, 201
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 put(self, project_id, issue_id):
        
        form = IssueStatusForm(request.form)

        if not form.validate():
            return {
                'message' : 'Please correct the errors mentioned below.',
                'errors' : form.errors
            }, 400

        with backend.transaction():
            backend.update(request.issue,form.data)

        return {'message' : 'success'}, 200
 def put(self):
     """ Enable or disable email notifications
     :return: message with status, status code
     """
     user = request.user
     form = EmailNotificationsForm(request.form)
     if form.validate():
         with backend.transaction():
             email_settings = user.get('email_settings', {})
             email_settings.update({'notifications': form.email_notifications_enabled.data})
             user.email_settings = email_settings
             backend.update(user, ["email_settings"])
         return {'message': "success"}, 200
     return {'message': "error", 'errors': form.errors}, 400
def update_project_statistics(project):
    """ After analysis hook. Updates the project statistics
    :param project: project that is being analyzed
    """

    checkmate_settings = settings.checkmate_settings

    update_stats_command = UpdateStatsCommand(project, checkmate_settings,
                                              backend)
    update_stats_command.run()

    if 'stats' in project:
        with backend.transaction():
            backend.update(project, ['stats'])
Esempio n. 17
0
    def put(self, project_id):
        form = EditProjectForm(request.form)
        project = request.project
        if project.git is None:
            return {'message': 'not a Git project!'}, 400
        if not form.validate():
            return ({
                'message': 'Please correct the errors mentioned below.',
                'errors': form.errors
            }, 400)

        with backend.transaction():
            backend.update(project.git, form.data)

        return {'message': 'success'}, 200
    def put(self):

        form = UserProfileForm(request.form)

        if not form.validate():
            return {u'errors': form.errors}, 403

        user = request.user
        data = form.data
        email = data.get(u'email')
        if email:
            if (user.get('email_change_requested_at') and
                    datetime.datetime.utcnow() - user.email_change_requested_at < datetime.timedelta(minutes=30)):
                return {'message': "Please wait at least 30 minutes before requesting another e-mail change."}, 403
            with backend.transaction():
                backend.update(user, {'new_email': email,
                                      'email_validation_code': uuid.uuid4().hex,
                                      'email_change_requested_at': datetime.datetime.utcnow()})
            activation_url = "{}{}/user/validate/{}".format(
                settings.get('url'),
                settings.get('frontend.url'),
                request.user.email_validation_code
            )

            # activate email
            send_mail(
                email_to=user.new_email,
                template="verify_email",
                template_context={
                    "user_name": user.name,
                    "activation_url": activation_url
                }
            )

        email_settings = data.get(u'email_settings')

        with backend.transaction():
            if email_settings:
                email_settings = user.get('email_settings', {})
                email_settings.update(data[u'email_settings'])
                user.email_settings = email_settings
                backend.update(user, ['email_settings'])

        return {'user': self.export(user)}, 200
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 put(self):
        form = ChangePasswordForm(request.form)
        if not form.validate():
            return ({u'errors': form.errors},
                    400)

        password = form.password.data
        request.user.set_password(password)
        if request.user.email_validated:
            send_mail(
                email_to=request.user.email,
                template="change_password",
                template_context={
                    "user_name": request.user.name
                }
            )

        with backend.transaction():
            backend.update(request.user, ['password', 'password_set'])

        return ({u'user': self.export(request.user)},
                200)
def reset_project(project_id, task_id=None):
    if not task_id:
        task_id = reset_project.request.id
    try:
        project = backend.get(Project, {'pk': project_id})
    except Project.DoesNotExist:
        logger.warning(
            "Project %s does not exist and thus cannot be deleted." %
            project_id)
        return

    try:
        with ExclusiveTask(
                backend, {
                    'project.pk': project.pk,
                    'type': {
                        '$in': ['analysis', 'reset', 'delete']
                    }
                }, {
                    'type': 'reset',
                    'project': project
                }, task_id) as reset_task:
            with TaskLogger(reset_task, backend=backend, ping=True):
                _reset_project(project)
    except ExclusiveTask.LockError:
        # We were unable to acquire a lock for this project.
        logger.info(
            "Project %s (%s) is currently being processed, aborting..." %
            (project.name, project.pk))
        with backend.transaction():
            backend.update(project, {
                'last_reset': {
                    'dt': datetime.datetime.now(),
                    'status': 'blocked'
                }
            })
    finally:
        logger.info("Done.")
Esempio n. 22
0
    def put(self, project_id):
        form = ProjectForm(request.form)
        if not form.validate():
            return ({'message': 'Please correct the errors mentioned below.',
                     'errors': form.errors},
                    400)

        data = {}

        if form.description.data:
            data['description'] = form.description.data

        if form.public.data is not None:
            data['public'] = form.public.data

        for key, value in data.items():
            request.project[key] = value

        with backend.transaction():
            backend.update(request.project, data.keys())

        return ({'message': 'success!',
                 'project': self.export(request.project)},
                200)
def _reset_project(project):
    try:

        settings.hooks.call("project.reset.before", project)

        reset_command = ResetCommand(project, settings.checkmate_settings,
                                     backend)
        reset_command.run()

        with backend.transaction():
            backend.update(project, {
                'last_reset': {
                    'dt': datetime.datetime.now(),
                    'status': 'succeeded'
                },
                'analyze': True,
                'analysis_priority': Project.AnalysisPriority.high,
                'analysis_requested_at': datetime.datetime.now()
            },
                           unset_fields=["first_analysis_email_sent"])

        settings.hooks.call("project.reset.after", project)

    except:
        with backend.transaction():
            backend.update(
                project, {
                    'last_reset': {
                        'dt': datetime.datetime.now(),
                        'status': 'failed'
                    },
                })
        logger.error(
            "Reset of project {project.name} (pk={project.pk}) failed!".format(
                project=project))
        raise
    finally:
        with backend.transaction():
            backend.update(project, {'reset': False},
                           unset_fields=['reset_requested_at'])
Esempio n. 24
0
 def delete(self, project_id):
     with backend.transaction():
         backend.update(request.project, {'delete': True})
     return ({'message': 'success! Your project will be fully deleted within a few minutes.',
              'project_id': request.project.pk},
             200)