コード例 #1
0
    def validate_job(self, request):
        """ Gets file for job, validates each row, and sends valid rows to a staging table
        Args:
        request -- HTTP request containing the jobId
        Returns:
        Http response object
        """
        # Create connection to job tracker database
        sess = GlobalDB.db().session

        requestDict = RequestDictionary(request)
        if requestDict.exists('job_id'):
            job_id = requestDict.getValue('job_id')
        else:
            # Request does not have a job ID, can't validate
            validation_error_type = ValidationError.jobError
            raise ResponseException('No job ID specified in request',
                                    StatusCode.CLIENT_ERROR, None,
                                    validation_error_type)

        # Get the job
        job = sess.query(Job).filter_by(job_id=job_id).one_or_none()
        if job is None:
            validation_error_type = ValidationError.jobError
            writeFileError(job_id, None, validation_error_type)
            raise ResponseException(
                'Job ID {} not found in database'.format(job_id),
                StatusCode.CLIENT_ERROR, None, validation_error_type)

        # Make sure job's prerequisites are complete
        if not run_job_checks(job_id):
            validation_error_type = ValidationError.jobError
            writeFileError(job_id, None, validation_error_type)
            raise ResponseException(
                'Prerequisites for Job ID {} are not complete'.format(job_id),
                StatusCode.CLIENT_ERROR, None, validation_error_type)

        # Make sure this is a validation job
        if job.job_type.name in ('csv_record_validation', 'validation'):
            job_type_name = job.job_type.name
        else:
            validation_error_type = ValidationError.jobError
            writeFileError(job_id, None, validation_error_type)
            raise ResponseException(
                'Job ID {} is not a validation job (job type is {})'.format(
                    job_id, job.job_type.name), StatusCode.CLIENT_ERROR, None,
                validation_error_type)

        # set job status to running and do validations
        mark_job_status(job_id, "running")
        if job_type_name == 'csv_record_validation':
            self.runValidation(job)
        elif job_type_name == 'validation':
            self.runCrossValidation(job)
        else:
            raise ResponseException("Bad job type for validator",
                                    StatusCode.INTERNAL_ERROR)

        return JsonResponse.create(StatusCode.OK,
                                   {"message": "Validation complete"})
コード例 #2
0
    def finalize(self):
        """ Set upload job in job tracker database to finished, allowing dependent jobs to be started

        Flask request should include key "upload_id", which holds the job_id for the file_upload job

        Returns:
        A flask response object, if successful just contains key "success" with value True, otherwise value is False
        """
        responseDict = {}
        try:
            inputDictionary = RequestDictionary(self.request)
            jobId = inputDictionary.getValue("upload_id")
            # Compare user ID with user who submitted job, if no match return 400
            job = self.jobManager.getJobById(jobId)
            submission = self.jobManager.getSubmissionForJob(job)
            if(submission.user_id != LoginSession.getName(session)):
                # This user cannot finalize this job
                raise ResponseException("Cannot finalize a job created by a different user", StatusCode.CLIENT_ERROR)
            # Change job status to finished
            if(self.jobManager.checkUploadType(jobId)):
                self.jobManager.changeToFinished(jobId)
                responseDict["success"] = True
                return JsonResponse.create(StatusCode.OK,responseDict)
            else:
                raise ResponseException("Wrong job type for finalize route",StatusCode.CLIENT_ERROR)

        except ( ValueError , TypeError ) as e:
            return JsonResponse.error(e,StatusCode.CLIENT_ERROR)
        except ResponseException as e:
            return JsonResponse.error(e,e.status)
        except Exception as e:
            # Unexpected exception, this is a 500 server error
            return JsonResponse.error(e,StatusCode.INTERNAL_ERROR)
コード例 #3
0
    def getErrorMetrics(self) :
        """ Returns an Http response object containing error information for every validation job in specified submission """
        responseDict = {}
        returnDict = {}
        try:
            safeDictionary = RequestDictionary(self.request)
            submission_id =  safeDictionary.getValue("submission_id")

            # Check if user has permission to specified submission
            self.checkSubmissionPermission(self.jobManager.getSubmissionById(submission_id))

            jobIds = self.jobManager.getJobsBySubmission(submission_id)
            for currentId in jobIds :
                if(self.jobManager.getJobType(currentId) == "csv_record_validation"):
                    fileName = self.jobManager.getFileType(currentId)
                    dataList = self.interfaces.errorDb.getErrorMetricsByJobId(currentId)
                    returnDict[fileName]  = dataList
            return JsonResponse.create(StatusCode.OK,returnDict)
        except ( ValueError , TypeError ) as e:
            return JsonResponse.error(e,StatusCode.CLIENT_ERROR)
        except ResponseException as e:
            return JsonResponse.error(e,e.status)
        except Exception as e:
            # Unexpected exception, this is a 500 server error
            return JsonResponse.error(e,StatusCode.INTERNAL_ERROR)
コード例 #4
0
    def resetPassword(self, system_email, session):
        """

        Remove old password and email user a token to set a new password.  Request should have key "email"

        arguments:

        system_email  -- (string) email used to send messages
        session  -- (Session) object from flask

        """
        requestDict = RequestDictionary(self.request)
        if (not (requestDict.exists("email"))):
            # Don't have the keys we need in request
            exc = ResponseException(
                "Reset password route requires key 'email'",
                StatusCode.CLIENT_ERROR)
            return JsonResponse.error(exc, exc.status)
        # Get user object
        try:
            user = self.interfaces.userDb.getUserByEmail(
                requestDict.getValue("email"))
        except Exception as e:
            exc = ResponseException("Unknown Error", StatusCode.CLIENT_ERROR,
                                    ValueError)
            return JsonResponse.error(exc, exc.status)

        email = requestDict.getValue("email")
        LoginSession.logout(session)
        self.sendResetPasswordEmail(user, system_email, email)

        # Return success message
        return JsonResponse.create(StatusCode.OK,
                                   {"message": "Password reset"})
コード例 #5
0
 def getErrorReportURLsForSubmission(self):
     """
     Gets the Signed URLs for download based on the submissionId
     """
     try :
         self.s3manager = s3UrlHandler()
         safeDictionary = RequestDictionary(self.request)
         submissionId = safeDictionary.getValue("submission_id")
         responseDict ={}
         for jobId in self.jobManager.getJobsBySubmission(submissionId):
             if(self.jobManager.getJobType(jobId) == "csv_record_validation"):
                 if(not self.isLocal):
                     responseDict["job_"+str(jobId)+"_error_url"] = self.s3manager.getSignedUrl("errors",self.jobManager.getReportPath(jobId),"GET")
                 else:
                     path = os.path.join(self.serverPath, self.jobManager.getReportPath(jobId))
                     responseDict["job_"+str(jobId)+"_error_url"] = path
         if(not self.isLocal):
             crossFileReport = self.s3manager.getSignedUrl("errors",self.jobManager.getCrossFileReportPath(submissionId),"GET")
         else:
             crossFileReport = os.path.join(self.serverPath, self.jobManager.getCrossFileReportPath(submissionId))
         responseDict["cross_file_error_url"] = crossFileReport
         return JsonResponse.create(StatusCode.OK,responseDict)
     except ResponseException as e:
         return JsonResponse.error(e,StatusCode.CLIENT_ERROR)
     except Exception as e:
         # Unexpected exception, this is a 500 server error
         return JsonResponse.error(e,StatusCode.INTERNAL_ERROR)
コード例 #6
0
    def listUsersWithStatus(self):
        """ List all users with the specified status.  Associated request body must have key 'status' """
        requestDict = RequestDictionary(self.request)
        if(not (requestDict.exists("status"))):
            # Missing a required field, return 400
            exc = ResponseException("Request body must include status", StatusCode.CLIENT_ERROR)
            return JsonResponse.error(exc,exc.status)

        current_user = self.interfaces.userDb.getUserByUID(flaskSession["name"])

        try:
            if self.interfaces.userDb.hasPermission(current_user, "agency_admin"):
                users = self.interfaces.userDb.getUsersByStatus(requestDict.getValue("status"), current_user.cgac_code)
            else:
                users = self.interfaces.userDb.getUsersByStatus(requestDict.getValue("status"))
        except ValueError as e:
            # Client provided a bad status
            exc = ResponseException(str(e),StatusCode.CLIENT_ERROR,ValueError)
            return JsonResponse.error(exc,exc.status)
        userInfo = []
        for user in users:
            agency_name = self.interfaces.validationDb.getAgencyName(user.cgac_code)
            thisInfo = {"name":user.name, "title":user.title, "agency_name":agency_name, "cgac_code":user.cgac_code,
                        "email":user.email, "id":user.user_id }
            userInfo.append(thisInfo)
        return JsonResponse.create(StatusCode.OK,{"users":userInfo})
コード例 #7
0
    def resetPassword(self,system_email,session):
        """

        Remove old password and email user a token to set a new password.  Request should have key "email"

        arguments:

        system_email  -- (string) email used to send messages
        session  -- (Session) object from flask

        """
        requestDict = RequestDictionary(self.request)
        if(not (requestDict.exists("email"))):
            # Don't have the keys we need in request
            exc = ResponseException("Reset password route requires key 'email'",StatusCode.CLIENT_ERROR)
            return JsonResponse.error(exc,exc.status)
        # Get user object
        try:
            user = self.interfaces.userDb.getUserByEmail(requestDict.getValue("email"))
        except Exception as e:
            exc = ResponseException("Unknown Error",StatusCode.CLIENT_ERROR,ValueError)
            return JsonResponse.error(exc,exc.status)

        email = requestDict.getValue("email")
        LoginSession.logout(session)
        self.sendResetPasswordEmail(user, system_email, email)

        # Return success message
        return JsonResponse.create(StatusCode.OK,{"message":"Password reset"})
コード例 #8
0
    def checkEmailConfirmationToken(self,session):
        """

        Creates user record and email

        arguments:

        session -- (Session) object from flask

        return the reponse object with a error code and a message

        """
        requestFields = RequestDictionary(self.request)
        if(not requestFields.exists("token")):
            exc = ResponseException("Request body must include token", StatusCode.CLIENT_ERROR)
            return JsonResponse.error(exc,exc.status)
        token = requestFields.getValue("token")
        success,message,errorCode = sesEmail.checkToken(token,self.interfaces.userDb,"validate_email")
        if(success):
            #mark session that email can be filled out
            LoginSession.register(session)

            #remove token so it cant be used again
            # The following line is commented out for issues with registration email links bouncing users back
            # to the original email input page instead of the registration page
            #self.interfaces.userDb.deleteToken(token)

            #set the status only if current status is awaiting confirmation
            user = self.interfaces.userDb.getUserByEmail(message)
            if self.interfaces.userDb.checkStatus(user,"awaiting_confirmation"):
                self.interfaces.userDb.changeStatus(user,"email_confirmed")
            return JsonResponse.create(StatusCode.OK,{"email":message,"errorCode":errorCode,"message":"success"})
        else:
            #failure but alert UI of issue
            return JsonResponse.create(StatusCode.OK,{"errorCode":errorCode,"message":message})
コード例 #9
0
 def setSkipGuide(self, session):
     """ Set current user's skip guide parameter """
     uid = session["name"]
     userDb = self.interfaces.userDb
     user = userDb.getUserByUID(uid)
     requestDict = RequestDictionary(self.request)
     if not requestDict.exists("skip_guide"):
         exc = ResponseException("Must include skip_guide parameter",
                                 StatusCode.CLIENT_ERROR)
         return JsonResponse.error(exc, exc.status)
     skipGuide = requestDict.getValue("skip_guide")
     if type(skipGuide) == type(True):
         # param is a bool
         user.skip_guide = skipGuide
     elif type(skipGuide) == type("string"):
         # param is a string, allow "true" or "false"
         if skipGuide.lower() == "true":
             user.skip_guide = True
         elif skipGuide.lower() == "false":
             user.skip_guide = False
         else:
             exc = ResponseException("skip_guide must be true or false",
                                     StatusCode.CLIENT_ERROR)
             return JsonResponse.error(exc, exc.status)
     else:
         exc = ResponseException("skip_guide must be a boolean",
                                 StatusCode.CLIENT_ERROR)
         return JsonResponse.error(exc, exc.status)
     userDb.session.commit()
     return JsonResponse.create(StatusCode.OK, {
         "message": "skip_guide set successfully",
         "skip_guide": skipGuide
     })
コード例 #10
0
 def listUsersWithStatus(self):
     """ List all users with the specified status.  Associated request body must have key 'status' """
     requestDict = RequestDictionary(self.request)
     if (not (requestDict.exists("status"))):
         # Missing a required field, return 400
         exc = ResponseException("Request body must include status",
                                 StatusCode.CLIENT_ERROR)
         return JsonResponse.error(exc, exc.status)
     try:
         users = self.interfaces.userDb.getUsersByStatus(
             requestDict.getValue("status"))
     except ValueError as e:
         # Client provided a bad status
         exc = ResponseException(str(e), StatusCode.CLIENT_ERROR,
                                 ValueError)
         return JsonResponse.error(exc, exc.status)
     userInfo = []
     for user in users:
         thisInfo = {
             "name": user.name,
             "title": user.title,
             "agency": user.agency,
             "email": user.email,
             "id": user.user_id
         }
         userInfo.append(thisInfo)
     return JsonResponse.create(StatusCode.OK, {"users": userInfo})
コード例 #11
0
    def createEmailConfirmation(self,system_email,session):
        """

        Creates user record and email

        arguments:

        system_email  -- (string) email used to send messages
        session  -- (Session) object from flask

        """
        requestFields = RequestDictionary(self.request)
        if(not requestFields.exists("email")):
            exc = ResponseException("Request body must include email", StatusCode.CLIENT_ERROR)
            return JsonResponse.error(exc,exc.status)
        email = requestFields.getValue("email")
        if( not re.match("[^@]+@[^@]+\.[^@]+",email)) :
            return JsonResponse.error(ValueError("Invalid Email Format"),StatusCode.CLIENT_ERROR)
        try :
            user = self.interfaces.userDb.getUserByEmail(requestFields.getValue("email"))
        except ResponseException as e:
            self.interfaces.userDb.addUnconfirmedEmail(email)
        else:
            if(not (user.user_status_id == self.interfaces.userDb.getUserStatusId("awaiting_confirmation") or user.user_status_id == self.interfaces.userDb.getUserStatusId("email_confirmed"))):
                exc = ResponseException("User already registered", StatusCode.CLIENT_ERROR)
                return JsonResponse.error(exc,exc.status)
        emailToken = sesEmail.createToken(email,self.interfaces.userDb,"validate_email")
        link= "".join([AccountHandler.FRONT_END,'#/registration/',emailToken])
        emailTemplate = {'[USER]': email, '[URL]':link}
        newEmail = sesEmail(email, system_email,templateType="validate_email",parameters=emailTemplate,database=self.interfaces.userDb)
        newEmail.send()
        return JsonResponse.create(StatusCode.OK,{"message":"Email Sent"})
コード例 #12
0
    def checkPasswordToken(self,session):
        """

        Checks the password token if its valid

        arguments:

        session -- (Session) object from flask

        return the reponse object with a error code and a message

        """
        requestFields = RequestDictionary(self.request)
        if(not requestFields.exists("token")):
            exc = ResponseException("Request body must include token", StatusCode.CLIENT_ERROR)
            return JsonResponse.error(exc,exc.status)
        token = requestFields.getValue("token")
        success,message,errorCode = sesEmail.checkToken(token,self.interfaces.userDb,"password_reset")
        if(success):
            #mark session that password can be filled out
            LoginSession.resetPassword(session)

            return JsonResponse.create(StatusCode.OK,{"email":message,"errorCode":errorCode,"message":"success"})
        else:
            #failure but alert UI of issue
            return JsonResponse.create(StatusCode.OK,{"errorCode":errorCode,"message":message})
コード例 #13
0
    def resetPassword(self,system_email,session):
        """

        Remove old password and email user a token to set a new password.  Request should have key "email"

        arguments:

        system_email  -- (string) email used to send messages
        session  -- (Session) object from flask

        """
        requestDict = RequestDictionary(self.request)
        if(not (requestDict.exists("email"))):
            # Don't have the keys we need in request
            exc = ResponseException("Reset password route requires key 'email'",StatusCode.CLIENT_ERROR)
            return JsonResponse.error(exc,exc.status)
        # Get user object
        try:
            user = self.interfaces.userDb.getUserByEmail(requestDict.getValue("email"))
        except Exception as e:
            exc = ResponseException("Unknown Error",StatusCode.CLIENT_ERROR,ValueError)
            return JsonResponse.error(exc,exc.status)

        LoginSession.logout(session)
        self.interfaces.userDb.session.commit()
        email = requestDict.getValue("email")
        # Send email with token
        emailToken = sesEmail.createToken(email,self.interfaces.userDb,"password_reset")
        link= "".join([ AccountHandler.FRONT_END,'#/forgotpassword/',emailToken])
        emailTemplate = { '[URL]':link}
        newEmail = sesEmail(user.email, system_email,templateType="reset_password",parameters=emailTemplate,database=self.interfaces.userDb)
        newEmail.send()
        # Return success message
        return JsonResponse.create(StatusCode.OK,{"message":"Password reset"})
コード例 #14
0
    def checkPasswordToken(self, session):
        """

        Checks the password token if its valid

        arguments:

        session -- (Session) object from flask

        return the reponse object with a error code and a message

        """
        requestFields = RequestDictionary(self.request)
        if (not requestFields.exists("token")):
            exc = ResponseException("Request body must include token",
                                    StatusCode.CLIENT_ERROR)
            return JsonResponse.error(exc, exc.status)
        token = requestFields.getValue("token")
        success, message, errorCode = sesEmail.checkToken(
            token, self.interfaces.userDb, "password_reset")
        if (success):
            #mark session that password can be filled out
            LoginSession.resetPassword(session)

            return JsonResponse.create(StatusCode.OK, {
                "email": message,
                "errorCode": errorCode,
                "message": "success"
            })
        else:
            #failure but alert UI of issue
            return JsonResponse.create(StatusCode.OK, {
                "errorCode": errorCode,
                "message": message
            })
コード例 #15
0
 def setSkipGuide(self, session):
     """ Set current user's skip guide parameter """
     uid =  session["name"]
     userDb = self.interfaces.userDb
     user =  userDb.getUserByUID(uid)
     requestDict = RequestDictionary(self.request)
     if not requestDict.exists("skip_guide"):
         exc = ResponseException("Must include skip_guide parameter", StatusCode.CLIENT_ERROR)
         return JsonResponse.error(exc, exc.status)
     skipGuide = requestDict.getValue("skip_guide")
     if type(skipGuide) == type(True):
         # param is a bool
         user.skip_guide = skipGuide
     elif type(skipGuide) == type("string"):
         # param is a string, allow "true" or "false"
         if skipGuide.lower() == "true":
             user.skip_guide = True
         elif skipGuide.lower() == "false":
             user.skip_guide = False
         else:
             exc = ResponseException("skip_guide must be true or false", StatusCode.CLIENT_ERROR)
             return JsonResponse.error(exc, exc.status)
     else:
         exc = ResponseException("skip_guide must be a boolean", StatusCode.CLIENT_ERROR)
         return JsonResponse.error(exc, exc.status)
     userDb.session.commit()
     return JsonResponse.create(StatusCode.OK,{"message":"skip_guide set successfully","skip_guide":skipGuide})
コード例 #16
0
    def startGenerationJob(self, submission_id, file_type):
        """ Initiates a file generation job

        Args:
            submission_id: ID of submission to start job for
            file_type: Type of file to be generated

        Returns:
            Tuple of boolean indicating successful start, and error response if False

        """
        jobDb = self.interfaces.jobDb
        file_type_name = self.fileTypeMap[file_type]

        if file_type in ["D1", "D2"]:
            # Populate start and end dates, these should be provided in MM/DD/YYYY format, using calendar year (not fiscal year)
            requestDict = RequestDictionary(self.request)
            start_date = requestDict.getValue("start")
            end_date = requestDict.getValue("end")

            if not (StringCleaner.isDate(start_date) and StringCleaner.isDate(end_date)):
                exc = ResponseException("Start or end date cannot be parsed into a date", StatusCode.CLIENT_ERROR)
                return False, JsonResponse.error(exc, exc.status, start = "", end = "", file_type = file_type, status = "failed")
        elif file_type not in ["E","F"]:
            exc = ResponseException("File type must be either D1, D2, E or F", StatusCode.CLIENT_ERROR)
            return False, JsonResponse.error(exc, exc.status, file_type = file_type, status = "failed")

        cgac_code = self.jobManager.getSubmissionById(submission_id).cgac_code

        # Generate and upload file to S3
        user_id = LoginSession.getName(session)
        timestamped_name = s3UrlHandler.getTimestampedFilename(CONFIG_BROKER["".join([str(file_type_name),"_file_name"])])
        if self.isLocal:
            upload_file_name = "".join([CONFIG_BROKER['broker_files'], timestamped_name])
        else:
            upload_file_name = "".join([str(user_id), "/", timestamped_name])

        job = jobDb.getJobBySubmissionFileTypeAndJobType(submission_id, file_type_name, "file_upload")
        job.filename = upload_file_name
        job.original_filename = timestamped_name
        job.job_status_id = jobDb.getJobStatusId("running")
        jobDb.session.commit()
        if file_type in ["D1", "D2"]:
            CloudLogger.log("DEBUG: Adding job info for job id of " + str(job.job_id),
                            log_type="debug",
                            file_name=self.debug_file_name)
            return self.addJobInfoForDFile(upload_file_name, timestamped_name, submission_id, file_type, file_type_name, start_date, end_date, cgac_code, job)
        elif file_type == 'E':
            generate_e_file.delay(
                submission_id, job.job_id, InterfaceHolder, timestamped_name,
                upload_file_name, self.isLocal)
        elif file_type == 'F':
            generate_f_file.delay(
                submission_id, job.job_id, InterfaceHolder, timestamped_name,
                upload_file_name, self.isLocal)

        return True, None
コード例 #17
0
    def login(self,session):
        """

        Logs a user in if their password matches

        arguments:

        session  -- (Session) object from flask

        return the reponse object

        """
        try:
            safeDictionary = RequestDictionary(self.request)

            username = safeDictionary.getValue('username')

            password = safeDictionary.getValue('password')

            try:
                user  = self.interfaces.userDb.getUserByEmail(username)
            except Exception as e:
                raise ValueError("user name and or password invalid")

            if(not self.interfaces.userDb.checkStatus(user,"approved")):
                raise ValueError("user name and or password invalid")

            # Only check if user is active after they've logged in for the first time
            if user.last_login_date is not None and not self.isUserActive(user):
                raise ValueError("Your account has expired. Please contact an administrator.")

            try:
                if(self.interfaces.userDb.checkPassword(user,password,self.bcrypt)):
                    # We have a valid login
                    LoginSession.login(session,user.user_id)
                    permissionList = []
                    for permission in self.interfaces.userDb.getPermssionList():
                        if(self.interfaces.userDb.hasPermission(user, permission.name)):
                            permissionList.append(permission.permission_type_id)
                    self.interfaces.userDb.updateLastLogin(user)
                    return JsonResponse.create(StatusCode.OK,{"message":"Login successful","user_id": int(user.user_id),"name":user.name,"title":user.title ,"agency":user.agency, "permissions" : permissionList})
                else :
                    raise ValueError("user name and or password invalid")
            except Exception as e:
                    LoginSession.logout(session)
                    raise ValueError("user name and or password invalid")

        except (TypeError, KeyError, NotImplementedError) as e:
            # Return a 400 with appropriate message
            return JsonResponse.error(e,StatusCode.CLIENT_ERROR)
        except ValueError as e:
            # Return a 401 for login denied
            return JsonResponse.error(e,StatusCode.LOGIN_REQUIRED)
        except Exception as e:
            # Return 500
            return JsonResponse.error(e,StatusCode.INTERNAL_ERROR)
        return self.response
コード例 #18
0
    def getErrorReportURLsForSubmission(self, isWarning = False):
        """
        Gets the Signed URLs for download based on the submissionId
        """
        try :
            self.s3manager = s3UrlHandler()
            safeDictionary = RequestDictionary(self.request)
            submissionId = safeDictionary.getValue("submission_id")
            responseDict ={}
            sess = GlobalDB.db().session
            for jobId in self.jobManager.getJobsBySubmission(submissionId):
                # get the job object here so we can call the refactored getReportPath
                # todo: replace other db access functions with job object attributes
                job = sess.query(Job).filter(Job.job_id == jobId).one()
                if job.job_type.name == 'csv_record_validation':
                    if isWarning:
                        reportName = getReportPath(job, 'warning')
                        key = "job_"+str(jobId)+"_warning_url"
                    else:
                        reportName = getReportPath(job, 'error')
                        key = "job_"+str(jobId)+"_error_url"
                    if(not self.isLocal):
                        responseDict[key] = self.s3manager.getSignedUrl("errors",reportName,method="GET")
                    else:
                        path = os.path.join(self.serverPath, reportName)
                        responseDict[key] = path

            # For each pair of files, get url for the report
            fileTypes = self.interfaces.validationDb.getFileTypeList()
            for source in fileTypes:
                sourceId = self.interfaces.validationDb.getFileTypeIdByName(source)
                for target in fileTypes:
                    targetId = self.interfaces.validationDb.getFileTypeIdByName(target)
                    if targetId <= sourceId:
                        # Skip redundant reports
                        continue
                    # Retrieve filename
                    if isWarning:
                        reportName = getCrossWarningReportName(submissionId, source, target)
                    else:
                        reportName = getCrossReportName(submissionId, source, target)
                    # If not local, get a signed URL
                    if self.isLocal:
                        reportPath = os.path.join(self.serverPath,reportName)
                    else:
                        reportPath = self.s3manager.getSignedUrl("errors",reportName,method="GET")
                    # Assign to key based on source and target
                    responseDict[self.getCrossReportKey(source,target,isWarning)] = reportPath

            return JsonResponse.create(StatusCode.OK,responseDict)
        except ResponseException as e:
            return JsonResponse.error(e,StatusCode.CLIENT_ERROR)
        except Exception as e:
            # Unexpected exception, this is a 500 server error
            return JsonResponse.error(e,StatusCode.INTERNAL_ERROR)
コード例 #19
0
 def deleteUser(self):
     """ Deletes user specified by 'email' in request """
     requestDict = RequestDictionary(self.request)
     if not requestDict.exists("email"):
         # missing required fields, return 400
         exc = ResponseException(
             "Request body must include email of user to be deleted",
             StatusCode.CLIENT_ERROR)
         return JsonResponse.error(exc, exc.status)
     email = requestDict.getValue("email")
     self.interfaces.userDb.deleteUser(email)
     return JsonResponse.create(StatusCode.OK, {"message": "success"})
コード例 #20
0
    def getObligations(self):
        input_dictionary = RequestDictionary(self.request)

        # Get submission
        submission_id = input_dictionary.getValue("submission_id")
        submission = self.jobManager.getSubmissionById(submission_id)

        # Check that user has access to submission
        user = self.checkSubmissionPermission(submission)

        obligations_info = obligationStatsForSubmission(submission_id)

        return JsonResponse.create(StatusCode.OK, obligations_info)
コード例 #21
0
 def getJobID(request):
     """ Pull job ID out of request
     Args:
         request: HTTP request containing the job ID
     Returns:
         job ID, or raises exception if job ID not found in request
     """
     requestDict = RequestDictionary(request)
     if(requestDict.exists("job_id")):
         jobId = requestDict.getValue("job_id")
         return jobId
     else:
             # Request does not have a job ID, can't validate
         raise ResponseException("No job ID specified in request",StatusCode.CLIENT_ERROR)
コード例 #22
0
    def login(self, session):
        """

        Logs a user in if their password matches

        arguments:

        session  -- (Session) object from flask

        return the response object

        """
        try:
            sess = GlobalDB.db().session
            safe_dictionary = RequestDictionary(self.request)

            username = safe_dictionary.get_value('username')

            password = safe_dictionary.get_value('password')

            try:
                user = sess.query(User).filter(
                    func.lower(User.email) == func.lower(username)).one()
            except Exception:
                raise ValueError("Invalid username and/or password")

            try:
                if check_correct_password(user, password, self.bcrypt):
                    # We have a valid login

                    return self.create_session_and_response(session, user)
                else:
                    raise ValueError("Invalid username and/or password")
            except ValueError as ve:
                LoginSession.logout(session)
                raise ve
            except Exception as e:
                LoginSession.logout(session)
                raise e

        except (TypeError, KeyError, NotImplementedError) as e:
            # Return a 400 with appropriate message
            return JsonResponse.error(e, StatusCode.CLIENT_ERROR)
        except ValueError as e:
            # Return a 401 for login denied
            return JsonResponse.error(e, StatusCode.LOGIN_REQUIRED)
        except Exception as e:
            # Return 500
            return JsonResponse.error(e, StatusCode.INTERNAL_ERROR)
コード例 #23
0
 def getJobID(request):
     """ Pull job ID out of request
     Args:
         request: HTTP request containing the job ID
     Returns:
         job ID, or raises exception if job ID not found in request
     """
     requestDict = RequestDictionary(request)
     if (requestDict.exists("job_id")):
         jobId = requestDict.getValue("job_id")
         return jobId
     else:
         # Request does not have a job ID, can't validate
         raise ResponseException("No job ID specified in request",
                                 StatusCode.CLIENT_ERROR)
コード例 #24
0
        def wrapped(*args, **kwargs):
            sess = GlobalDB.db().session
            try:
                req_args = {
                    'agency_code':
                    RequestDictionary.derive(request).get('agency_code', None),
                    'existing_submission_id':
                    RequestDictionary.derive(request).get(
                        'existing_submission_id', None)
                }
            except (ValueError, TypeError) as e:
                raise ResponseException(e, StatusCode.CLIENT_ERROR)
            except BadRequest:
                raise ResponseException(
                    'Bad request: agency_code or existing_submission_id not included properly',
                    StatusCode.CLIENT_ERROR)

            if req_args['agency_code'] is None and req_args[
                    'existing_submission_id'] is None:
                raise ResponseException(
                    'Missing required parameter: agency_code or existing_submission_id',
                    StatusCode.CLIENT_ERROR)
            if not isinstance(req_args['agency_code'], str) and not isinstance(
                    req_args['existing_submission_id'], str):
                raise ResponseException(
                    'Bad request: agency_code or existing_submission_id' +
                    'required and must be strings', StatusCode.CLIENT_ERROR)
            if req_args['existing_submission_id'] is not None:
                check_existing_submission_perms(
                    perm, req_args['existing_submission_id'])
            else:
                sub_tier_agency = sess.query(SubTierAgency).\
                    filter(SubTierAgency.sub_tier_agency_code == req_args['agency_code']).one_or_none()

                if sub_tier_agency is None:
                    raise ResponseException(
                        'sub_tier_agency must be a valid sub_tier_agency_code',
                        StatusCode.CLIENT_ERROR)

                cgac_code = sub_tier_agency.cgac.cgac_code if sub_tier_agency.cgac_id else None
                frec_code = sub_tier_agency.frec.frec_code if sub_tier_agency.frec_id else None
                if not active_user_can(
                        perm, cgac_code=cgac_code, frec_code=frec_code):
                    raise ResponseException(
                        "User does not have permissions to write to that subtier agency",
                        StatusCode.PERMISSION_DENIED)

            return fn(*args, **kwargs)
コード例 #25
0
    def login(self, session):
        """

        Logs a user in if their password matches

        arguments:

        session  -- (Session) object from flask

        return the response object

        """
        try:
            sess = GlobalDB.db().session
            safe_dictionary = RequestDictionary(self.request)

            username = safe_dictionary.get_value('username')

            password = safe_dictionary.get_value('password')

            try:
                user = sess.query(User).filter(func.lower(User.email) == func.lower(username)).one()
            except Exception:
                raise ValueError("Invalid username and/or password")

            try:
                if check_correct_password(user, password, self.bcrypt):
                    # We have a valid login

                    return self.create_session_and_response(session, user)
                else:
                    raise ValueError("Invalid username and/or password")
            except ValueError as ve:
                LoginSession.logout(session)
                raise ve
            except Exception as e:
                LoginSession.logout(session)
                raise e

        except (TypeError, KeyError, NotImplementedError) as e:
            # Return a 400 with appropriate message
            return JsonResponse.error(e, StatusCode.CLIENT_ERROR)
        except ValueError as e:
            # Return a 401 for login denied
            return JsonResponse.error(e, StatusCode.LOGIN_REQUIRED)
        except Exception as e:
            # Return 500
            return JsonResponse.error(e, StatusCode.INTERNAL_ERROR)
コード例 #26
0
    def listUsers(self):
        """ List all users ordered by status. Associated request body must have key 'filter_by' """
        requestDict = RequestDictionary(self.request, optionalRequest=True)
        user_status = requestDict.getValue("status") if requestDict.exists(
            "status") else "all"

        user = self.interfaces.userDb.getUserByUID(
            LoginSession.getName(flaskSession))
        isAgencyAdmin = self.userManager.hasPermission(
            user, "agency_admin") and not self.userManager.hasPermission(
                user, "website_admin")
        try:
            if isAgencyAdmin:
                users = self.interfaces.userDb.getUsers(
                    cgac_code=user.cgac_code, status=user_status)
            else:
                users = self.interfaces.userDb.getUsers(status=user_status)
        except ValueError as e:
            # Client provided a bad status
            exc = ResponseException(str(e), StatusCode.CLIENT_ERROR,
                                    ValueError)
            return JsonResponse.error(exc, exc.status)
        userInfo = []
        for user in users:
            agency_name = self.interfaces.validationDb.getAgencyName(
                user.cgac_code)
            thisInfo = {
                "name":
                user.name,
                "title":
                user.title,
                "agency_name":
                agency_name,
                "cgac_code":
                user.cgac_code,
                "email":
                user.email,
                "id":
                user.user_id,
                "is_active":
                user.is_active,
                "permissions":
                ",".join(self.interfaces.userDb.getUserPermissions(user)),
                "status":
                user.user_status.name
            }
            userInfo.append(thisInfo)
        return JsonResponse.create(StatusCode.OK, {"users": userInfo})
コード例 #27
0
    def reset_password(self,system_email,session):
        """

        Remove old password and email user a token to set a new password.  Request should have key "email"

        arguments:

        system_email  -- (string) email used to send messages
        session  -- (Session) object from flask

        """
        sess = GlobalDB.db().session
        request_dict = RequestDictionary.derive(self.request)
        try:
            if 'email' not in request_dict:
                # Don't have the keys we need in request
                raise ResponseException(
                    "Reset password route requires key 'email'",
                    StatusCode.CLIENT_ERROR
                )
            user = sess.query(User).filter(
                func.lower(User.email) == func.lower(request_dict['email'])
            ).one()
        except Exception as exc:
            return JsonResponse.error(exc, StatusCode.CLIENT_ERROR)

        email = request_dict['email']
        LoginSession.logout(session)
        self.send_reset_password_email(user, system_email, email)

        # Return success message
        return JsonResponse.create(StatusCode.OK,{"message":"Password reset"})
コード例 #28
0
    def list_users_with_status(self):
        """ List all users with the specified status.  Associated request body must have key 'status' """
        request_dict = RequestDictionary.derive(self.request)
        try:
            if 'status' not in request_dict:
                # Missing a required field, return 400
                raise ResponseException(
                    "Request body must include status", StatusCode.CLIENT_ERROR)
        except ResponseException as exc:
            return JsonResponse.error(exc, exc.status)

        sess = GlobalDB.db().session

        try:
            users = sess.query(User).filter_by(
                user_status_id=USER_STATUS_DICT[request_dict['status']]
            ).all()
        except ValueError as exc:
            # Client provided a bad status
            return JsonResponse.error(exc, StatusCode.CLIENT_ERROR)
        user_info = []
        for user in users:
            agency_name = sess.query(CGAC.agency_name).\
                filter(CGAC.cgac_code == user.cgac_code).\
                one_or_none()
            this_info = {"name":user.name, "title":user.title, "agency_name":agency_name, "cgac_code":user.cgac_code,
                        "email":user.email, "id":user.user_id }
            user_info.append(this_info)
        return JsonResponse.create(StatusCode.OK,{"users":user_info})
コード例 #29
0
    def list_users(self):
        """ List all users ordered by status. Associated request body must have key 'filter_by' """
        request_dict = RequestDictionary.derive(
            self.request, optional_request=True)
        user_status = request_dict.get('status', 'all')
        sess = GlobalDB.db().session
        try:
            user_query = sess.query(User)
            if user_status != "all":
                user_query = user_query.filter(User.user_status_id == USER_STATUS_DICT[user_status])
            users = user_query.all()
        except ValueError as exc:
            # Client provided a bad status
            return JsonResponse.error(exc, StatusCode.CLIENT_ERROR)
        user_info = []
        for user in users:
            agency_name = sess.query(CGAC.agency_name).\
                filter(CGAC.cgac_code == user.cgac_code).\
                one_or_none()

            thisInfo = {"name":user.name, "title":user.title, "agency_name":agency_name, "cgac_code":user.cgac_code,
                        "email":user.email, "id":user.user_id, "is_active":user.is_active,
                        "permission": PERMISSION_TYPE_DICT_ID.get(user.permission_type_id), "status": user.user_status.name}
            user_info.append(thisInfo)
        return JsonResponse.create(StatusCode.OK,{"users":user_info})
コード例 #30
0
    def checkPasswordToken(self,session):
        """

        Checks the password token if its valid

        arguments:

        session -- (Session) object from flask

        return the reponse object with a error code and a message

        """
        request_fields = RequestDictionary.derive(self.request)
        try:
            if 'token' not in request_fields:
                raise ResponseException(
                    "Request body must include token", StatusCode.CLIENT_ERROR)
        except ResponseException as exc:
            return JsonResponse.error(exc, exc.status)
        token = request_fields['token']
        # Save token to be deleted after reset
        session["token"] = token
        success, message, errorCode = sesEmail.check_token(token, "password_reset")
        if success:
            #mark session that password can be filled out
            LoginSession.reset_password(session)

            return JsonResponse.create(StatusCode.OK,{"email":message,"errorCode":errorCode,"message":"success"})
        else:
            #failure but alert UI of issue
            return JsonResponse.create(StatusCode.OK,{"errorCode":errorCode,"message":message})
コード例 #31
0
 def upload_fabs_file():
     if "multipart/form-data" not in request.headers['Content-Type']:
         return JsonResponse.error(ValueError("Request must be a multipart/form-data type"), StatusCode.CLIENT_ERROR)
     params = RequestDictionary.derive(request)
     fabs = params.get('_files', {}).get('fabs', None)
     file_manager = FileHandler(request, is_local=is_local, server_path=server_path)
     return file_manager.upload_fabs_file(fabs)
コード例 #32
0
    def set_new_password(self, session):
        """ Set a new password for a user, request should have keys "user_email" and "password" """
        sess = GlobalDB.db().session
        request_dict = RequestDictionary.derive(self.request)
        required = ('user_email', 'password')
        try:
            if any(field not in request_dict for field in required):
                # Don't have the keys we need in request
                raise ResponseException(
                    "Set password route requires keys user_email and password",
                    StatusCode.CLIENT_ERROR
                )
            if not self.checkPassword(request_dict['password']):
                raise ResponseException(
                    "Invalid Password", StatusCode.CLIENT_ERROR)
        except ResponseException as exc:
            return JsonResponse.error(exc,exc.status)

        # Get user from email
        user = sess.query(User).filter(
            func.lower(User.email) == func.lower(request_dict["user_email"])
        ).one()
        # Set new password
        set_user_password(user,request_dict["password"],self.bcrypt)
        # Invalidate token
        oldToken = sess.query(EmailToken).filter(EmailToken.token == session["token"]).one()
        sess.delete(oldToken)
        sess.commit()
        session["reset"] = None
        # Return success message
        return JsonResponse.create(StatusCode.OK,{"message":"Password successfully changed"})
コード例 #33
0
    def email_users(self, system_email):
        """ Send email notification to list of users

            Args:
                system_email: the address of the system to send the email from

            Returns:
                A JsonReponse containing a message that the email sent successfully or the details of the missing
                parameters
        """
        sess = GlobalDB.db().session
        request_dict = RequestDictionary.derive(self.request)
        required = ('users', 'submission_id', 'email_template')
        try:
            if any(field not in request_dict for field in required):
                raise ResponseException(
                    "Email users route requires users, email_template, and submission_id",
                    StatusCode.CLIENT_ERROR)
        except ResponseException as exc:
            return JsonResponse.error(exc, exc.status)

        user_ids = request_dict['users']
        submission_id = request_dict['submission_id']
        # Check if submission id is valid
        _, agency_name = sess.query(Submission.submission_id, CGAC.agency_name).\
            join(CGAC, Submission.cgac_code == CGAC.cgac_code).filter(Submission.submission_id == submission_id).one()
        if not agency_name:
            _, agency_name = sess.query(Submission.submission_id, FREC.agency_name).\
                join(FREC, Submission.frec_code == FREC.frec_code).\
                filter(Submission.submission_id == submission_id).one()

        template_type = request_dict['email_template']
        # Check if email template type is valid
        get_email_template(template_type)

        users = []

        link = "".join(
            [AccountHandler.FRONT_END, '#/reviewData/',
             str(submission_id)])
        email_template = {
            '[REV_USER_NAME]': g.user.name,
            '[REV_AGENCY]': agency_name,
            '[REV_URL]': link
        }

        for user_id in user_ids:
            # Check if user id is valid, if so add User object to array
            users.append(
                sess.query(User).filter(User.user_id == user_id).one())

        for user in users:
            new_email = SesEmail(user.email,
                                 system_email,
                                 template_type=template_type,
                                 parameters=email_template)
            new_email.send()

        return JsonResponse.create(StatusCode.OK,
                                   {"message": "Emails successfully sent"})
    def set_skip_guide(self):
        """ Set current user's skip guide parameter

            Returns:
                JsonResponse object containing results of setting the skip guide or details of the error that occurred.
                Possible errors include the request not containing a skip_guide parameter or it not being a boolean
                value
        """
        sess = GlobalDB.db().session
        request_dict = RequestDictionary.derive(self.request)
        try:
            if 'skip_guide' not in request_dict:
                raise ResponseException(
                    "Must include skip_guide parameter",
                    StatusCode.CLIENT_ERROR
                )
            skip_guide = str(request_dict['skip_guide']).lower()
            if skip_guide not in ("true", "false"):
                raise ResponseException(
                    "skip_guide must be true or false",
                    StatusCode.CLIENT_ERROR
                )
            g.user.skip_guide = skip_guide == "true"
        except ResponseException as exc:
            return JsonResponse.error(exc, exc.status)
        sess.commit()
        return JsonResponse.create(StatusCode.OK, {"message": "skip_guide set successfully", "skip_guide": skip_guide})
コード例 #35
0
    def set_skip_guide(self):
        """ Set current user's skip guide parameter

            Returns:
                JsonResponse object containing results of setting the skip guide or details of the error that occurred.
                Possible errors include the request not containing a skip_guide parameter or it not being a boolean
                value
        """
        sess = GlobalDB.db().session
        request_dict = RequestDictionary.derive(self.request)
        try:
            if 'skip_guide' not in request_dict:
                raise ResponseException("Must include skip_guide parameter",
                                        StatusCode.CLIENT_ERROR)
            skip_guide = str(request_dict['skip_guide']).lower()
            if skip_guide not in ("true", "false"):
                raise ResponseException("skip_guide must be true or false",
                                        StatusCode.CLIENT_ERROR)
            g.user.skip_guide = skip_guide == "true"
        except ResponseException as exc:
            return JsonResponse.error(exc, exc.status)
        sess.commit()
        return JsonResponse.create(StatusCode.OK, {
            "message": "skip_guide set successfully",
            "skip_guide": skip_guide
        })
コード例 #36
0
 def upload_fabs_file():
     if "multipart/form-data" not in request.headers['Content-Type']:
         return JsonResponse.error(ValueError("Request must be a multipart/form-data type"), StatusCode.CLIENT_ERROR)
     params = RequestDictionary.derive(request)
     fabs = params.get('_files', {}).get('fabs', None)
     file_manager = FileHandler(request, is_local=is_local, server_path=server_path)
     return file_manager.upload_fabs_file(fabs)
コード例 #37
0
    def login(self, session):
        """ Logs a user in if their password matches using local data

            Args:
                session: the Session object from flask

            Returns:
                A JsonResponse containing the user information or details on which error occurred, such as whether a
                type was wrong, something wasn't implemented, invalid keys were provided, login was denied, or a
                different, unexpected error occurred.
        """
        try:
            sess = GlobalDB.db().session
            safe_dictionary = RequestDictionary(self.request)

            username = safe_dictionary.get_value('username')
            password = safe_dictionary.get_value('password')

            try:
                user = sess.query(User).filter(
                    func.lower(User.email) == func.lower(username)).one()
            except Exception:
                raise ValueError("Invalid username and/or password")

            try:
                if check_correct_password(user, password, self.bcrypt):
                    # We have a valid login
                    return self.create_session_and_response(session, user)
                else:
                    raise ValueError("Invalid username and/or password")
            except ValueError as ve:
                LoginSession.logout(session)
                raise ve
            except Exception as e:
                LoginSession.logout(session)
                raise e

        # Catch any specifically raised errors or any other errors that may have happened and return them cleanly
        except (TypeError, KeyError, NotImplementedError) as e:
            # Return a 400 with appropriate message
            return JsonResponse.error(e, StatusCode.CLIENT_ERROR)
        except ValueError as e:
            # Return a 401 for login denied
            return JsonResponse.error(e, StatusCode.LOGIN_REQUIRED)
        except Exception as e:
            # Return 500
            return JsonResponse.error(e, StatusCode.INTERNAL_ERROR)
コード例 #38
0
    def changeStatus(self, system_email):
        """

        Changes status for specified user.  Associated request body should have keys 'uid' and 'new_status'

        arguments:

        system_email  -- (string) the emaily to send emails from

        return the reponse object with a success message

        """
        requestDict = RequestDictionary(self.request)
        if (not (requestDict.exists("uid")
                 and requestDict.exists("new_status"))):
            # Missing a required field, return 400
            exc = ResponseException(
                "Request body must include uid and new_status",
                StatusCode.CLIENT_ERROR)
            return JsonResponse.error(exc, exc.status)

        # Find user that matches specified uid
        user = self.interfaces.userDb.getUserByUID(
            int(requestDict.getValue("uid")))

        if (user.email == None):
            return JsonResponse.error(
                ResponseException("User does not have a defined email",
                                  StatusCode.INTERNAL_ERROR),
                StatusCode.INTERNAL_ERROR)

        #check if the user is waiting
        if (self.interfaces.userDb.checkStatus(user, "awaiting_approval")):
            if (requestDict.getValue("new_status") == "approved"):
                # Grant agency_user permission to newly approved users
                self.interfaces.userDb.grantPermission(user, "agency_user")
                link = AccountHandler.FRONT_END
                emailTemplate = {'[URL]': link, '[EMAIL]': system_email}
                newEmail = sesEmail(user.email,
                                    system_email,
                                    templateType="account_approved",
                                    parameters=emailTemplate,
                                    database=self.interfaces.userDb)
                newEmail.send()
            elif (requestDict.getValue("new_status") == "denied"):
                emailTemplate = {}
                newEmail = sesEmail(user.email,
                                    system_email,
                                    templateType="account_rejected",
                                    parameters=emailTemplate,
                                    database=self.interfaces.userDb)
                newEmail.send()
        # Change user's status
        self.interfaces.userDb.changeStatus(user,
                                            requestDict.getValue("new_status"))
        return JsonResponse.create(StatusCode.OK,
                                   {"message": "Status change successful"})
コード例 #39
0
    def checkEmailConfirmationToken(self, session):
        """

        Creates user record and email

        arguments:

        session -- (Session) object from flask

        return the reponse object with a error code and a message

        """
        requestFields = RequestDictionary(self.request)
        if (not requestFields.exists("token")):
            exc = ResponseException("Request body must include token",
                                    StatusCode.CLIENT_ERROR)
            return JsonResponse.error(exc, exc.status)
        token = requestFields.getValue("token")
        session["token"] = token
        success, message, errorCode = sesEmail.checkToken(
            token, self.interfaces.userDb, "validate_email")
        if (success):
            #mark session that email can be filled out
            LoginSession.register(session)

            #remove token so it cant be used again
            # The following line is commented out for issues with registration email links bouncing users back
            # to the original email input page instead of the registration page
            #self.interfaces.userDb.deleteToken(token)

            #set the status only if current status is awaiting confirmation
            user = self.interfaces.userDb.getUserByEmail(message)
            if self.interfaces.userDb.checkStatus(user,
                                                  "awaiting_confirmation"):
                self.interfaces.userDb.changeStatus(user, "email_confirmed")
            return JsonResponse.create(StatusCode.OK, {
                "email": message,
                "errorCode": errorCode,
                "message": "success"
            })
        else:
            #failure but alert UI of issue
            return JsonResponse.create(StatusCode.OK, {
                "errorCode": errorCode,
                "message": message
            })
    def login(self, session):
        """ Logs a user in if their password matches using local data

            Args:
                session: the Session object from flask

            Returns:
                A JsonResponse containing the user information or details on which error occurred, such as whether a
                type was wrong, something wasn't implemented, invalid keys were provided, login was denied, or a
                different, unexpected error occurred.
        """
        try:
            sess = GlobalDB.db().session
            safe_dictionary = RequestDictionary(self.request)

            username = safe_dictionary.get_value('username')
            password = safe_dictionary.get_value('password')

            try:
                user = sess.query(User).filter(func.lower(User.email) == func.lower(username)).one()
            except Exception:
                raise ValueError("Invalid username and/or password")

            try:
                if check_correct_password(user, password, self.bcrypt):
                    # We have a valid login
                    return self.create_session_and_response(session, user)
                else:
                    raise ValueError("Invalid username and/or password")
            except ValueError as ve:
                LoginSession.logout(session)
                raise ve
            except Exception as e:
                LoginSession.logout(session)
                raise e

        # Catch any specifically raised errors or any other errors that may have happened and return them cleanly
        except (TypeError, KeyError, NotImplementedError) as e:
            # Return a 400 with appropriate message
            return JsonResponse.error(e, StatusCode.CLIENT_ERROR)
        except ValueError as e:
            # Return a 401 for login denied
            return JsonResponse.error(e, StatusCode.LOGIN_REQUIRED)
        except Exception as e:
            # Return 500
            return JsonResponse.error(e, StatusCode.INTERNAL_ERROR)
コード例 #41
0
    def setNewPassword(self, session):
        """ Set a new password for a user, request should have keys "user_email" and "password" """
        requestDict = RequestDictionary(self.request)
        if (not (requestDict.exists("user_email")
                 and requestDict.exists("password"))):
            # Don't have the keys we need in request
            exc = ResponseException(
                "Set password route requires keys user_email and password",
                StatusCode.CLIENT_ERROR)
            return JsonResponse.error(exc, exc.status)

        if (not self.checkPassword(requestDict.getValue("password"))):
            exc = ResponseException("Invalid Password",
                                    StatusCode.CLIENT_ERROR)
            return JsonResponse.error(exc, exc.status)
        # Get user from email
        user = self.interfaces.userDb.getUserByEmail(
            requestDict.getValue("user_email"))
        # Set new password
        self.interfaces.userDb.setPassword(user,
                                           requestDict.getValue("password"),
                                           self.bcrypt)
        # Invalidate token
        self.interfaces.userDb.deleteToken(session["token"])
        session["reset"] = None
        # Return success message
        return JsonResponse.create(
            StatusCode.OK, {"message": "Password successfully changed"})
コード例 #42
0
    def createEmailConfirmation(self, system_email, session):
        """

        Creates user record and email

        arguments:

        system_email  -- (string) email used to send messages
        session  -- (Session) object from flask

        """
        requestFields = RequestDictionary(self.request)
        if (not requestFields.exists("email")):
            exc = ResponseException("Request body must include email",
                                    StatusCode.CLIENT_ERROR)
            return JsonResponse.error(exc, exc.status)
        email = requestFields.getValue("email")
        if (not re.match("[^@]+@[^@]+\.[^@]+", email)):
            return JsonResponse.error(ValueError("Invalid Email Format"),
                                      StatusCode.CLIENT_ERROR)
        try:
            user = self.interfaces.userDb.getUserByEmail(
                requestFields.getValue("email"))
        except ResponseException as e:
            self.interfaces.userDb.addUnconfirmedEmail(email)
        else:
            if (not (user.user_status_id == self.interfaces.userDb.
                     getUserStatusId("awaiting_confirmation")
                     or user.user_status_id == self.interfaces.userDb.
                     getUserStatusId("email_confirmed"))):
                exc = ResponseException("User already registered",
                                        StatusCode.CLIENT_ERROR)
                return JsonResponse.error(exc, exc.status)
        emailToken = sesEmail.createToken(email, self.interfaces.userDb,
                                          "validate_email")
        link = "".join(
            [AccountHandler.FRONT_END, '#/registration/', emailToken])
        emailTemplate = {'[USER]': email, '[URL]': link}
        newEmail = sesEmail(email,
                            system_email,
                            templateType="validate_email",
                            parameters=emailTemplate,
                            database=self.interfaces.userDb)
        newEmail.send()
        return JsonResponse.create(StatusCode.OK, {"message": "Email Sent"})
コード例 #43
0
    def resetPassword(self, system_email, session):
        """

        Remove old password and email user a token to set a new password.  Request should have key "email"

        arguments:

        system_email  -- (string) email used to send messages
        session  -- (Session) object from flask

        """
        requestDict = RequestDictionary(self.request)
        if (not (requestDict.exists("email"))):
            # Don't have the keys we need in request
            exc = ResponseException(
                "Reset password route requires key 'email'",
                StatusCode.CLIENT_ERROR)
            return JsonResponse.error(exc, exc.status)
        # Get user object
        try:
            user = self.interfaces.userDb.getUserByEmail(
                requestDict.getValue("email"))
        except Exception as e:
            exc = ResponseException("Unknown Error", StatusCode.CLIENT_ERROR,
                                    ValueError)
            return JsonResponse.error(exc, exc.status)

        LoginSession.logout(session)
        self.interfaces.userDb.session.commit()
        email = requestDict.getValue("email")
        # Send email with token
        emailToken = sesEmail.createToken(email, self.interfaces.userDb,
                                          "password_reset")
        link = "".join(
            [AccountHandler.FRONT_END, '#/forgotpassword/', emailToken])
        emailTemplate = {'[URL]': link}
        newEmail = sesEmail(user.email,
                            system_email,
                            templateType="reset_password",
                            parameters=emailTemplate,
                            database=self.interfaces.userDb)
        newEmail.send()
        # Return success message
        return JsonResponse.create(StatusCode.OK,
                                   {"message": "Password reset"})
コード例 #44
0
 def listUsersWithStatus(self):
     """ List all users with the specified status.  Associated request body must have key 'status' """
     requestDict = RequestDictionary(self.request)
     if(not (requestDict.exists("status"))):
         # Missing a required field, return 400
         exc = ResponseException("Request body must include status", StatusCode.CLIENT_ERROR)
         return JsonResponse.error(exc,exc.status)
     try:
         users = self.interfaces.userDb.getUsersByStatus(requestDict.getValue("status"))
     except ValueError as e:
         # Client provided a bad status
         exc = ResponseException(str(e),StatusCode.CLIENT_ERROR,ValueError)
         return JsonResponse.error(exc,exc.status)
     userInfo = []
     for user in users:
         thisInfo = {"name":user.name, "title":user.title,  "agency":user.agency, "email":user.email, "id":user.user_id }
         userInfo.append(thisInfo)
     return JsonResponse.create(StatusCode.OK,{"users":userInfo})
コード例 #45
0
        def wrapped(*args, **kwargs):
            sess = GlobalDB.db().session
            try:
                req_args = {
                    'agency_code': RequestDictionary.derive(request).get('agency_code', None),
                    'existing_submission_id': RequestDictionary.derive(request).get('existing_submission_id', None)
                    }
            except (ValueError, TypeError) as e:
                raise ResponseException(e, StatusCode.CLIENT_ERROR)
            except BadRequest as e:
                raise ResponseException('Bad request: agency_code or existing_submission_id not included properly',
                                        StatusCode.CLIENT_ERROR)

            if req_args['agency_code'] is None and req_args['existing_submission_id'] is None:
                raise ResponseException('Missing required parameter: agency_code or existing_submission_id',
                                        StatusCode.CLIENT_ERROR)
            if not isinstance(req_args['agency_code'], str) and not isinstance(req_args['existing_submission_id'], str):
                raise ResponseException('Bad request: agency_code or existing_submission_id' +
                                        'required and must be strings', StatusCode.CLIENT_ERROR)
            if req_args['existing_submission_id'] is not None:
                check_existing_submission_perms(perm, req_args['existing_submission_id'])
            else:
                sub_tier_agency = sess.query(SubTierAgency).\
                    filter(SubTierAgency.sub_tier_agency_code == req_args['agency_code']).one_or_none()

                if sub_tier_agency is None:
                    raise ResponseException('sub_tier_agency must be a valid sub_tier_agency_code',
                                            StatusCode.CLIENT_ERROR)

                cgac_code = sub_tier_agency.cgac.cgac_code if sub_tier_agency.cgac_id else None
                frec_code = sub_tier_agency.frec.frec_code if sub_tier_agency.frec_id else None
                if not current_user_can(perm, cgac_code=cgac_code, frec_code=frec_code):
                    raise ResponseException("User does not have permissions to write to that subtier agency",
                                            StatusCode.PERMISSION_DENIED)

            return fn(*args, **kwargs)
コード例 #46
0
    def email_users(self, system_email):
        """ Send email notification to list of users """
        sess = GlobalDB.db().session
        request_dict = RequestDictionary.derive(self.request)
        required = ('users', 'submission_id', 'email_template')
        try:
            if any(field not in request_dict for field in required):
                raise ResponseException(
                    "Email users route requires users, email_template, and "
                    "submission_id", StatusCode.CLIENT_ERROR
                )
        except ResponseException as exc:
            return JsonResponse.error(exc, exc.status)

        user_ids = request_dict['users']
        submission_id = request_dict['submission_id']
        # Check if submission id is valid
        _, agency_name = sess.query(Submission.submission_id, CGAC.agency_name)\
            .join(CGAC, Submission.cgac_code == CGAC.cgac_code)\
            .filter(Submission.submission_id == submission_id).one()
        if not agency_name:
            _, agency_name = sess.query(Submission.submission_id, FREC.agency_name) \
                .join(FREC, Submission.frec_code == FREC.frec_code) \
                .filter(Submission.submission_id == submission_id).one()

        template_type = request_dict['email_template']
        # Check if email template type is valid
        get_email_template(template_type)

        users = []

        link = "".join([AccountHandler.FRONT_END, '#/reviewData/', str(submission_id)])
        email_template = {'[REV_USER_NAME]': g.user.name, '[REV_AGENCY]': agency_name, '[REV_URL]': link}

        for user_id in user_ids:
            # Check if user id is valid, if so add User object to array
            users.append(sess.query(User).filter(User.user_id == user_id).one())

        for user in users:
            new_email = SesEmail(user.email, system_email, template_type=template_type, parameters=email_template)
            new_email.send()

        return JsonResponse.create(StatusCode.OK, {"message": "Emails successfully sent"})
コード例 #47
0
 def set_skip_guide(self):
     """ Set current user's skip guide parameter """
     sess = GlobalDB.db().session
     request_dict = RequestDictionary.derive(self.request)
     try:
         if 'skip_guide' not in request_dict:
             raise ResponseException(
                 "Must include skip_guide parameter",
                 StatusCode.CLIENT_ERROR
             )
         skip_guide = str(request_dict['skip_guide']).lower()
         if skip_guide not in ("true", "false"):
             raise ResponseException(
                 "skip_guide must be true or false",
                 StatusCode.CLIENT_ERROR
             )
         g.user.skip_guide = skip_guide == "true"
     except ResponseException as exc:
         return JsonResponse.error(exc, exc.status)
     sess.commit()
     return JsonResponse.create(StatusCode.OK, {"message": "skip_guide set successfully", "skip_guide": skip_guide})
コード例 #48
0
    def changeStatus(self,system_email):
        """

        Changes status for specified user.  Associated request body should have keys 'uid' and 'new_status'

        arguments:

        system_email  -- (string) the emaily to send emails from

        return the reponse object with a success message

        """
        requestDict = RequestDictionary(self.request)
        if(not (requestDict.exists("uid") and requestDict.exists("new_status"))):
            # Missing a required field, return 400
            exc = ResponseException("Request body must include uid and new_status", StatusCode.CLIENT_ERROR)
            return JsonResponse.error(exc,exc.status)

        # Find user that matches specified uid
        user = self.interfaces.userDb.getUserByUID(int(requestDict.getValue("uid")))

        if(user.email == None):
            return JsonResponse.error(ResponseException("User does not have a defined email",StatusCode.INTERNAL_ERROR),StatusCode.INTERNAL_ERROR)

        #check if the user is waiting
        if(self.interfaces.userDb.checkStatus(user,"awaiting_approval")):
            if(requestDict.getValue("new_status") == "approved"):
                # Grant agency_user permission to newly approved users
                self.interfaces.userDb.grantPermission(user,"agency_user")
                link=  AccountHandler.FRONT_END
                emailTemplate = { '[URL]':link,'[EMAIL]':system_email}
                newEmail = sesEmail(user.email, system_email,templateType="account_approved",parameters=emailTemplate,database=self.interfaces.userDb)
                newEmail.send()
            elif (requestDict.getValue("new_status") == "denied"):
                emailTemplate = {}
                newEmail = sesEmail(user.email, system_email,templateType="account_rejected",parameters=emailTemplate,database=self.interfaces.userDb)
                newEmail.send()
        # Change user's status
        self.interfaces.userDb.changeStatus(user,requestDict.getValue("new_status"))
        return JsonResponse.create(StatusCode.OK,{"message":"Status change successful"})
コード例 #49
0
    def setNewPassword(self):
        """ Set a new password for a user, request should have keys "user_email" and "password" """
        requestDict = RequestDictionary(self.request)
        if(not (requestDict.exists("user_email") and requestDict.exists("password"))):
            # Don't have the keys we need in request
            exc = ResponseException("Set password route requires keys user_email and password",StatusCode.CLIENT_ERROR)
            return JsonResponse.error(exc,exc.status)

        if(not self.checkPassword(requestDict.getValue("password"))):
            exc = ResponseException("Invalid Password", StatusCode.CLIENT_ERROR)
            return JsonResponse.error(exc,exc.status)
        # Get user from email
        user = self.interfaces.userDb.getUserByEmail(requestDict.getValue("user_email"))
        # Set new password
        self.interfaces.userDb.setPassword(user,requestDict.getValue("password"),self.bcrypt)

        # Return success message
        return JsonResponse.create(StatusCode.OK,{"message":"Password successfully changed"})
コード例 #50
0
    def updateUser(self, system_email):
        """
        Update editable fields for specified user. Editable fields for a user:
        * is_active
        * user_status_id
        * permissions

        Args:
            None: Request body should contain the following keys:
                * uid (integer)
                * status (string)
                * permissions (comma separated string)
                * is_active (boolean)

        Returns: JSON response object with either an exception or success message

        """
        requestDict = RequestDictionary(self.request)

        # throw an exception if nothing is provided in the request
        if not requestDict.exists("uid") or not (requestDict.exists("status") or requestDict.exists("permissions") or
                    requestDict.exists("is_active")):
            # missing required fields, return 400
            exc = ResponseException("Request body must include uid and at least one of the following: status, permissions, is_active",
                                    StatusCode.CLIENT_ERROR)
            return JsonResponse.error(exc, exc.status)

        # Find user that matches specified uid
        user = self.interfaces.userDb.getUserByUID(int(requestDict.getValue("uid")))

        if requestDict.exists("status"):
            #check if the user is waiting
            if(self.interfaces.userDb.checkStatus(user,"awaiting_approval")):
                if(requestDict.getValue("status") == "approved"):
                    # Grant agency_user permission to newly approved users
                    self.interfaces.userDb.grantPermission(user,"agency_user")
                    link=  AccountHandler.FRONT_END
                    emailTemplate = { '[URL]':link,'[EMAIL]':system_email}
                    newEmail = sesEmail(user.email, system_email,templateType="account_approved",parameters=emailTemplate,database=self.interfaces.userDb)
                    newEmail.send()
                elif (requestDict.getValue("status") == "denied"):
                    emailTemplate = {}
                    newEmail = sesEmail(user.email, system_email,templateType="account_rejected",parameters=emailTemplate,database=self.interfaces.userDb)
                    newEmail.send()
            # Change user's status
            self.interfaces.userDb.changeStatus(user,requestDict.getValue("status"))

        if requestDict.exists("permissions"):
            permissions_list = requestDict.getValue("permissions").split(',')

            # Remove all existing permissions for user
            user_permissions = self.interfaces.userDb.getUserPermissions(user)
            for permission in user_permissions:
                self.interfaces.userDb.removePermission(user, permission)

            # Grant specified permissions
            for permission in permissions_list:
                self.interfaces.userDb.grantPermission(user, permission)

        # Activate/deactivate user
        if requestDict.exists("is_active"):
            is_active = bool(requestDict.getValue("is_active"))
            if not self.isUserActive(user) and is_active:
                # Reset password count to 0
                self.resetPasswordCount(user)
                # Reset last login date so the account isn't expired
                self.interfaces.userDb.updateLastLogin(user, unlock_user=True)
                self.sendResetPasswordEmail(user, system_email, unlock_user=True)
            self.interfaces.userDb.setUserActive(user, is_active)

        return JsonResponse.create(StatusCode.OK, {"message": "User successfully updated"})
コード例 #51
0
    def login(self,session):
        """

        Logs a user in if their password matches

        arguments:

        session  -- (Session) object from flask

        return the reponse object

        """
        try:
            safeDictionary = RequestDictionary(self.request)

            username = safeDictionary.getValue('username')

            password = safeDictionary.getValue('password')

            try:
                user = self.interfaces.userDb.getUserByEmail(username)
            except Exception as e:
                raise ValueError("Invalid username and/or password")

            if(not self.interfaces.userDb.checkStatus(user,"approved")):
                raise ValueError("Invalid username and/or password")

            # Only check if user is active after they've logged in for the first time
            if user.last_login_date is not None and self.isAccountExpired(user):
                raise ValueError("Your account has expired. Please contact an administrator.")

            # for whatever reason, your account is not active, therefore it's locked
            if not self.isUserActive(user):
                raise ValueError("Your account has been locked. Please contact an administrator.")

            try:
                if(self.interfaces.userDb.checkPassword(user,password,self.bcrypt)):
                    # We have a valid login

                    # Reset incorrect password attempt count to 0
                    self.resetPasswordCount(user)

                    LoginSession.login(session,user.user_id)
                    permissionList = []
                    for permission in self.interfaces.userDb.getPermissionList():
                        if(self.interfaces.userDb.hasPermission(user, permission.name)):
                            permissionList.append(permission.permission_type_id)
                    self.interfaces.userDb.updateLastLogin(user)
                    agency_name = self.interfaces.validationDb.getAgencyName(user.cgac_code)
                    return JsonResponse.create(StatusCode.OK,{"message":"Login successful","user_id": int(user.user_id),
                                                              "name":user.name,"title":user.title,"agency_name":agency_name,
                                                              "cgac_code":user.cgac_code, "permissions" : permissionList})
                else :
                    # increase incorrect password attempt count by 1
                    # if this is the 3rd incorrect attempt, lock account
                    self.incrementPasswordCount(user)
                    if user.incorrect_password_attempts == 3:
                        raise ValueError("Your account has been locked due to too many failed login attempts. Please contact an administrator.")

                    raise ValueError("Invalid username and/or password")
            except ValueError as ve:
                LoginSession.logout(session)
                raise ve
            except Exception as e:
                LoginSession.logout(session)
                raise ValueError("Invalid username and/or password")

        except (TypeError, KeyError, NotImplementedError) as e:
            # Return a 400 with appropriate message
            return JsonResponse.error(e,StatusCode.CLIENT_ERROR)
        except ValueError as e:
            # Return a 401 for login denied
            return JsonResponse.error(e,StatusCode.LOGIN_REQUIRED)
        except Exception as e:
            # Return 500
            return JsonResponse.error(e,StatusCode.INTERNAL_ERROR)
        return self.response
コード例 #52
0
    def getStatus(self):
        """ Get description and status of all jobs in the submission specified in request object

        Returns:
            A flask response object to be sent back to client, holds a JSON where each job ID has a dictionary holding file_type, job_type, status, and filename
        """
        try:
            inputDictionary = RequestDictionary(self.request)

            # Get submission
            submissionId = inputDictionary.getValue("submission_id")
            submission = self.jobManager.getSubmissionById(submissionId)

            # Check that user has access to submission
            user = self.checkSubmissionPermission(submission)

            # Get jobs in this submission
            jobs = self.jobManager.getJobsBySubmission(submissionId)

            # Build dictionary of submission info with info about each job
            submissionInfo = {}
            submissionInfo["jobs"] = []
            submissionInfo["agency_name"] = submission.agency_name
            submissionInfo["reporting_period_start_date"] = submission.reporting_start_date.strftime("%m/%d/%Y")
            submissionInfo["reporting_period_end_date"] = submission.reporting_end_date.strftime("%m/%d/%Y")
            submissionInfo["created_on"] = self.interfaces.jobDb.getFormattedDatetimeBySubmissionId(submissionId)
            # Include number of errors in submission
            submissionInfo["number_of_errors"] = self.interfaces.errorDb.sumNumberOfErrorsForJobList(jobs)
            submissionInfo["number_of_rows"] = self.interfaces.jobDb.sumNumberOfRowsForJobList(jobs)


            for jobId in jobs:
                jobInfo = {}
                if(self.jobManager.getJobType(jobId) != "csv_record_validation"):
                    continue
                jobInfo["job_id"] = jobId
                jobInfo["job_status"] = self.jobManager.getJobStatus(jobId)
                jobInfo["job_type"] = self.jobManager.getJobType(jobId)
                jobInfo["filename"] = self.jobManager.getOriginalFilenameById(jobId)
                try:
                    jobInfo["file_status"] = self.interfaces.errorDb.getStatusLabelByJobId(jobId)
                except ResponseException as e:
                    # Job ID not in error database, probably did not make it to validation, or has not yet been validated
                    jobInfo["file_status"] = ""
                    jobInfo["missing_headers"] = []
                    jobInfo["duplicated_headers"] = []
                    jobInfo["error_type"] = ""
                    jobInfo["error_data"] = []
                else:
                    # If job ID was found in file_status, we should be able to get header error lists and file data
                    # Get string of missing headers and parse as a list
                    missingHeaderString = self.interfaces.errorDb.getMissingHeadersByJobId(jobId)
                    if missingHeaderString is not None:
                        # Split header string into list, excluding empty strings
                        jobInfo["missing_headers"] = [n.strip() for n in missingHeaderString.split(",") if len(n) > 0]
                    else:
                        jobInfo["missing_headers"] = []
                    # Get string of duplicated headers and parse as a list
                    duplicatedHeaderString = self.interfaces.errorDb.getDuplicatedHeadersByJobId(jobId)
                    if duplicatedHeaderString is not None:
                        # Split header string into list, excluding empty strings
                        jobInfo["duplicated_headers"] = [n.strip() for n in duplicatedHeaderString.split(",") if len(n) > 0]
                    else:
                        jobInfo["duplicated_headers"] = []
                    jobInfo["error_type"] = self.interfaces.errorDb.getErrorType(jobId)
                    jobInfo["error_data"] = self.interfaces.errorDb.getErrorMetricsByJobId(jobId)
                # File size and number of rows not dependent on error DB
                # Get file size
                jobInfo["file_size"] = self.jobManager.getFileSizeById(jobId)
                # Get number of rows in file
                jobInfo["number_of_rows"] = self.jobManager.getNumberOfRowsById(jobId)

                try :
                    jobInfo["file_type"] = self.jobManager.getFileType(jobId)
                except Exception as e:
                    jobInfo["file_type"]  = ''
                submissionInfo["jobs"].append(jobInfo)

            # Build response object holding dictionary
            return JsonResponse.create(StatusCode.OK,submissionInfo)
        except ResponseException as e:
            return JsonResponse.error(e,e.status)
        except Exception as e:
            # Unexpected exception, this is a 500 server error
            return JsonResponse.error(e,StatusCode.INTERNAL_ERROR)
コード例 #53
0
    def validateJob(self, request,interfaces):
        """ Gets file for job, validates each row, and sends valid rows to staging database
        Args:
        request -- HTTP request containing the jobId
        interfaces -- InterfaceHolder object to the databases
        Returns:
        Http response object
        """
        # Create connection to job tracker database
        self.filename = None
        tableName = ""
        jobId = None
        jobTracker = None

        try:
            jobTracker = interfaces.jobDb
            requestDict = RequestDictionary(request)
            tableName = ""
            if(requestDict.exists("job_id")):
                jobId = requestDict.getValue("job_id")
            else:
                # Request does not have a job ID, can't validate
                raise ResponseException("No job ID specified in request",StatusCode.CLIENT_ERROR)

            # Check that job exists and is ready
            if(not (jobTracker.runChecks(jobId))):
                raise ResponseException("Checks failed on Job ID",StatusCode.CLIENT_ERROR)
            tableName = interfaces.stagingDb.getTableName(jobId)
            jobType = interfaces.jobDb.checkJobType(jobId)

        except ResponseException as e:
            CloudLogger.logError(str(e),e,traceback.extract_tb(sys.exc_info()[2]))
            if(e.errorType == None):
                # Error occurred while trying to get and check job ID
                e.errorType = ValidationError.jobError
            interfaces.errorDb.writeFileError(jobId,self.filename,e.errorType,e.extraInfo)
            return JsonResponse.error(e,e.status,table=tableName)
        except Exception as e:
            exc = ResponseException(str(e),StatusCode.INTERNAL_ERROR,type(e))
            CloudLogger.logError(str(e),e,traceback.extract_tb(sys.exc_info()[2]))
            self.markJob(jobId,jobTracker,"failed",interfaces.errorDb,self.filename,ValidationError.unknownError)
            return JsonResponse.error(exc,exc.status,table=tableName)

        try:
            jobTracker.markJobStatus(jobId,"running")
            if jobType == interfaces.jobDb.getJobTypeId("csv_record_validation"):
                self.runValidation(jobId,interfaces)
            elif jobType == interfaces.jobDb.getJobTypeId("validation"):
                self.runCrossValidation(jobId, interfaces)
            else:
                raise ResponseException("Bad job type for validator", StatusCode.INTERNAL_ERROR)
            interfaces.errorDb.markFileComplete(jobId,self.filename)
            return  JsonResponse.create(StatusCode.OK,{"table":tableName})
        except ResponseException as e:
            CloudLogger.logError(str(e),e,traceback.extract_tb(sys.exc_info()[2]))
            self.markJob(jobId,jobTracker,"invalid",interfaces.errorDb,self.filename,e.errorType,e.extraInfo)
            return JsonResponse.error(e,e.status,table=tableName)
        except ValueError as e:
            CloudLogger.logError(str(e),e,traceback.extract_tb(sys.exc_info()[2]))
            # Problem with CSV headers
            exc = ResponseException(str(e),StatusCode.CLIENT_ERROR,type(e),ValidationError.unknownError) #"Internal value error"
            self.markJob(jobId,jobTracker,"invalid",interfaces.errorDb,self.filename,ValidationError.unknownError)
            return JsonResponse.error(exc,exc.status,table=tableName)
        except Error as e:
            CloudLogger.logError(str(e),e,traceback.extract_tb(sys.exc_info()[2]))
            # CSV file not properly formatted (usually too much in one field)
            exc = ResponseException("Internal error",StatusCode.CLIENT_ERROR,type(e),ValidationError.unknownError)
            self.markJob(jobId,jobTracker,"invalid",interfaces.errorDb,self.filename,ValidationError.unknownError)
            return JsonResponse.error(exc,exc.status,table=tableName)
        except Exception as e:
            CloudLogger.logError(str(e),e,traceback.extract_tb(sys.exc_info()[2]))
            exc = ResponseException(str(e),StatusCode.INTERNAL_ERROR,type(e),ValidationError.unknownError)
            self.markJob(jobId,jobTracker,"failed",interfaces.errorDb,self.filename,ValidationError.unknownError)
            return JsonResponse.error(exc,exc.status,table=tableName)
コード例 #54
0
    def max_login(self, session):
        """

        Logs a user in if their password matches

        arguments:

        session  -- (Session) object from flask

        return the response object

        """
        try:
            safe_dictionary = RequestDictionary(self.request)

            # Obtain POST content
            ticket = safe_dictionary.get_value("ticket")
            service = safe_dictionary.get_value('service')

            # Call MAX's serviceValidate endpoint and retrieve the response
            max_dict = get_max_dict(ticket, service)

            if 'cas:authenticationSuccess' not in max_dict['cas:serviceResponse']:
                raise ValueError("You have failed to login successfully with MAX")
            cas_attrs = max_dict['cas:serviceResponse']['cas:authenticationSuccess']['cas:attributes']

            # Grab the email and list of groups from MAX's response
            email = cas_attrs['maxAttribute:Email-Address']

            try:
                sess = GlobalDB.db().session
                user = sess.query(User).filter(func.lower(User.email) == func.lower(email)).one_or_none()

                # If the user does not exist, create them since they are allowed to access the site because they got
                # past the above group membership checks
                if user is None:
                    user = User()

                    first_name = cas_attrs['maxAttribute:First-Name']
                    middle_name = cas_attrs['maxAttribute:Middle-Name']
                    last_name = cas_attrs['maxAttribute:Last-Name']

                    user.email = email

                    # Check for None first so the condition can short-circuit without
                    # having to worry about calling strip() on a None object
                    if middle_name is None or middle_name.strip() == '':
                        user.name = first_name + " " + last_name
                    else:
                        user.name = first_name + " " + middle_name[0] + ". " + last_name

                set_max_perms(user, cas_attrs['maxAttribute:GroupList'])

                sess.add(user)
                sess.commit()

            except MultipleResultsFound:
                raise ValueError("An error occurred during login.")

            return self.create_session_and_response(session, user)

        except (TypeError, KeyError, NotImplementedError) as e:
            # Return a 400 with appropriate message
            return JsonResponse.error(e, StatusCode.CLIENT_ERROR)
        except ValueError as e:
            # Return a 401 for login denied
            return JsonResponse.error(e, StatusCode.LOGIN_REQUIRED)
        except Exception as e:
            # Return 500
            return JsonResponse.error(e, StatusCode.INTERNAL_ERROR)
コード例 #55
0
    def register(self,system_email,session):
        """

        Save user's information into user database.  Associated request body should have keys 'email', 'name', 'agency', and 'title'

        arguments:

        system_email  -- (string) email used to send messages
        session  -- (Session) object from flask


        Returns message that registration is successful or error message that fields are not valid

        """
        def ThreadedFunction (from_email="",username="",title="",agency="",userEmail="" ,link="") :
            """
            This inner function sends emails in a new thread as there could be lots of admins

            from_email -- (string) the from email address
            username -- (string) the name of the  user
            title  --   (string) the title of the  user
            agency -- (string) the agency of the  user
            userEmail -- (string) the email of the user
            link  -- (string) the broker email link
            """
            threadedDatabase =  UserHandler()
            try:
                for user in threadedDatabase.getUsersByType("website_admin") :
                    emailTemplate = {'[REG_NAME]': username, '[REG_TITLE]':title, '[REG_AGENCY]':agency,'[REG_EMAIL]' : userEmail,'[URL]':link}
                    newEmail = sesEmail(user.email, system_email,templateType="account_creation",parameters=emailTemplate,database=threadedDatabase)
                    newEmail.send()
            finally:
                InterfaceHolder.closeOne(threadedDatabase)

        requestFields = RequestDictionary(self.request)
        if(not (requestFields.exists("email") and requestFields.exists("name") and requestFields.exists("agency") and requestFields.exists("title") and requestFields.exists("password"))):
            # Missing a required field, return 400
            exc = ResponseException("Request body must include email, name, agency, title, and password", StatusCode.CLIENT_ERROR)
            return JsonResponse.error(exc,exc.status)

        if(not self.checkPassword(requestFields.getValue("password"))):
            exc = ResponseException("Invalid Password", StatusCode.CLIENT_ERROR)
            return JsonResponse.error(exc,exc.status)
        # Find user that matches specified email
        user = self.interfaces.userDb.getUserByEmail(requestFields.getValue("email"))
        # Check that user's status is before submission of registration
        if not (self.interfaces.userDb.checkStatus(user,"awaiting_confirmation") or self.interfaces.userDb.checkStatus(user,"email_confirmed")):
            # Do not allow duplicate registrations
            exc = ResponseException("User already registered",StatusCode.CLIENT_ERROR)
            return JsonResponse.error(exc,exc.status)
        # Add user info to database
        self.interfaces.userDb.addUserInfo(user,requestFields.getValue("name"),requestFields.getValue("agency"),requestFields.getValue("title"))
        self.interfaces.userDb.setPassword(user,requestFields.getValue("password"),self.bcrypt)

        userLink= "".join([AccountHandler.FRONT_END, '#/login?redirect=/admin'])
        # Send email to approver list
        emailThread = Thread(target=ThreadedFunction, kwargs=dict(from_email=system_email,username=user.name,title=user.title,agency=user.agency,userEmail=user.email,link=userLink))
        emailThread.start()

        #email user
        link= AccountHandler.FRONT_END
        emailTemplate = {'[EMAIL]' : system_email}
        newEmail = sesEmail(user.email, system_email,templateType="account_creation_user",parameters=emailTemplate,database=self.interfaces.userDb)
        newEmail.send()

        LoginSession.logout(session)
        # Mark user as awaiting approval
        self.interfaces.userDb.changeStatus(user,"awaiting_approval")
        return JsonResponse.create(StatusCode.OK,{"message":"Registration successful"})
コード例 #56
0
    def submit(self,name,CreateCredentials):
        """ Builds S3 URLs for a set of files and adds all related jobs to job tracker database

        Flask request should include keys from FILE_TYPES class variable above

        Arguments:
        name -- User ID from the session handler

        Returns:
        Flask response returned will have key_url and key_id for each key in the request
        key_url is the S3 URL for uploading
        key_id is the job id to be passed to the finalize_submission route
        """
        try:
            responseDict= {}

            fileNameMap = []
            safeDictionary = RequestDictionary(self.request)
            submissionId = self.jobManager.createSubmission(name, safeDictionary)
            existingSubmission = False
            if safeDictionary.exists("existing_submission_id"):
                existingSubmission = True
                # Check if user has permission to specified submission
                self.checkSubmissionPermission(self.jobManager.getSubmissionById(submissionId))

            for fileType in FileHandler.FILE_TYPES :
                # If filetype not included in request, and this is an update to an existing submission, skip it
                if not safeDictionary.exists(fileType):
                    if existingSubmission:
                        continue
                    else:
                        # This is a new submission, all files are required
                        raise ResponseException("Must include all files for new submission",StatusCode.CLIENT_ERROR)
                filename = safeDictionary.getValue(fileType)
                if( safeDictionary.exists(fileType)) :
                    if(not self.isLocal):
                        uploadName =  str(name)+"/"+s3UrlHandler.getTimestampedFilename(filename)
                    else:
                        uploadName = filename
                    responseDict[fileType+"_key"] = uploadName
                    fileNameMap.append((fileType,uploadName,filename))

            fileJobDict = self.jobManager.createJobs(fileNameMap,submissionId,existingSubmission)
            for fileType in fileJobDict.keys():
                if (not "submission_id" in fileType) :
                    responseDict[fileType+"_id"] = fileJobDict[fileType]
            if(CreateCredentials and not self.isLocal) :
                self.s3manager = s3UrlHandler(CONFIG_BROKER["aws_bucket"])
                responseDict["credentials"] = self.s3manager.getTemporaryCredentials(name)
            else :
                responseDict["credentials"] ={"AccessKeyId" : "local","SecretAccessKey" :"local","SessionToken":"local" ,"Expiration" :"local"}

            responseDict["submission_id"] = fileJobDict["submission_id"]
            if self.isLocal:
                responseDict["bucket_name"] = CONFIG_BROKER["broker_files"]
            else:
                responseDict["bucket_name"] = CONFIG_BROKER["aws_bucket"]
            return JsonResponse.create(StatusCode.OK,responseDict)
        except (ValueError , TypeError, NotImplementedError) as e:
            return JsonResponse.error(e,StatusCode.CLIENT_ERROR)
        except Exception as e:
            # Unexpected exception, this is a 500 server error
            return JsonResponse.error(e,StatusCode.INTERNAL_ERROR)
        except:
            return JsonResponse.error(Exception("Failed to catch exception"),StatusCode.INTERNAL_ERROR)
    def max_login(self, session):
        """ Logs a user in if their password matches using MAX

            Args:
                session: Session object from flask

            Returns:
                A JsonResponse containing the user information or details on which error occurred, such as whether a
                type was wrong, something wasn't implemented, invalid keys were provided, login was denied, or a
                different, unexpected error occurred.
        """
        try:
            safe_dictionary = RequestDictionary(self.request)

            ticket = safe_dictionary.get_value("ticket")
            service = safe_dictionary.get_value('service')

            # Call MAX's serviceValidate endpoint and retrieve the response
            max_dict = get_max_dict(ticket, service)

            if 'cas:authenticationSuccess' not in max_dict['cas:serviceResponse']:
                raise ValueError("The Max CAS endpoint was unable to locate your session "
                                 "using the ticket/service combination you provided.")
            cas_attrs = max_dict['cas:serviceResponse']['cas:authenticationSuccess']['cas:attributes']

            # Grab MAX ID to see if a service account is being logged in
            max_id_components = cas_attrs['maxAttribute:MAX-ID'].split('_')
            service_account_flag = (len(max_id_components) > 1 and max_id_components[0].lower() == 's')

            # Grab the email and list of groups from MAX's response
            email = cas_attrs['maxAttribute:Email-Address']

            try:
                sess = GlobalDB.db().session
                user = sess.query(User).filter(func.lower(User.email) == func.lower(email)).one_or_none()

                # If the user does not exist, create them since they are allowed to access the site because they got
                # past the above group membership checks
                if user is None:
                    user = User()
                    user.email = email

                set_user_name(user, cas_attrs)

                set_max_perms(user, cas_attrs['maxAttribute:GroupList'], service_account_flag)

                sess.add(user)
                sess.commit()

            except MultipleResultsFound:
                raise ValueError("An error occurred during login.")

            return self.create_session_and_response(session, user)

        # Catch any specifically raised errors or any other errors that may have happened and return them cleanly.
        # We add the error parameter here because this endpoint needs to provide better feedback, and to avoid changing
        # the default behavior of the JsonResponse class globally.
        except (TypeError, KeyError, NotImplementedError) as e:
            # Return a 400 with appropriate message
            return JsonResponse.error(e, StatusCode.CLIENT_ERROR, error=str(e))
        except ValueError as e:
            # Return a 401 for login denied
            return JsonResponse.error(e, StatusCode.LOGIN_REQUIRED, error=str(e))
        except Exception as e:
            # Return 500
            return JsonResponse.error(e, StatusCode.INTERNAL_ERROR, error=str(e))