Ejemplo n.º 1
0
 async def submit(self, submission):
     """Save a user submission in the submissions collection."""
     submission_time = utils.now()
     if submission_time < self.start or submission_time >= self.end:
         raise errors.SurveyDoesNotAcceptSubmissionsAtTheMomentError()
     if not self.validator.validate(submission):
         raise errors.InvalidSubmissionError()
     submission = {
         'submission_time': submission_time,
         'data': submission,
     }
     if self.authentication == 'open':
         await self.submissions.insert_one(submission)
     if self.authentication == 'email':
         submission['_id'] = verification.token()
         while True:
             try:
                 await self.submissions.insert_one(submission)
                 break
             except pymongo.errors.DuplicateKeyError:
                 submission['_id'] = verification.token()
         status = await email.send_submission_verification(
             submission['data'][str(self.ei + 1)],
             self.username,
             self.survey_name,
             self.configuration['title'],
             submission['_id'],
         )
         if status != 200:
             raise errors.InternalServerError()
Ejemplo n.º 2
0
    async def update(self, username, account_data):
        """Update existing user account data in the database."""

        # TODO handle username change with transactions
        # TODO handle email change specially, as it needs to be reverified

        if not self.validator.validate(account_data):
            raise errors.InvalidAccountDataError()
        entry = await database.database['accounts'].find_one(
            filter={'_id': username},
            projection={
                '_id': False,
                'email_address': True,
                'password_hash': True,
            },
        )
        if entry is None:
            raise errors.UserNotFoundError()
        update = {}
        if account_data['username'] != username:
            raise errors.NotImplementedError()
        if account_data['email_address'] != entry['email_address']:
            raise errors.NotImplementedError()
        if not pw.verify(account_data['password'], entry['password_hash']):
            update['password_hash'] = pw.hash(account_data['password'])
        if update:
            update['modification_time'] = utils.now()
            result = await database.database['accounts'].update_one(
                filter={'_id': username},
                update={'$set': update},
            )
            if result.matched_count == 0:
                raise errors.UserNotFoundError()
Ejemplo n.º 3
0
def min_max_for_all():
    """Logic for sending min/max mail"""
    config = get_config()

    for recipient in config['recipients']:
        for transaction in recipient['transactions']:

            print('\n' + '-' * 50 + '\n')

            sv = StockValue(symbol=transaction['symbol'], config=config)
            bankier = sv.get_bankier()
            current_value, bankier_time = sv.get_values(bankier)

            hm = HistoryManager()
            global_min = hm.get_min(transaction['symbol'],
                                    recipient['address'])
            global_max = hm.get_max(transaction['symbol'],
                                    recipient['address'])

            calculator = Calculator(transaction['buy_quantity'],
                                    transaction['buy_price'],
                                    transaction['buy_quantity'], current_value)
            if transaction['min_max_mail'] == 'yes':
                prepare_min_max_email(recipient['address'],
                                      transaction['symbol'], current_value,
                                      global_min, global_max, config,
                                      calculator)
            hm.update_history(current_value, transaction['symbol'],
                              recipient['address'], bankier_time, now())
Ejemplo n.º 4
0
    async def create(self, username, account_data):
        """Create new user account with some default account data."""
        if username != account_data['username']:
            raise errors.InvalidAccountDataError()
        if not self.validator.validate(account_data):
            raise errors.InvalidAccountDataError()
        timestamp = utils.now()
        account_data = {
            '_id': username,
            'email_address': account_data['email_address'],
            'password_hash': pw.hash(account_data['password']),
            'superuser': False,
            'creation_time': timestamp,
            'modification_time': timestamp,
            'verified': False,
            'verification_token': verification.token(),
        }
        while True:
            try:
                await database.database['accounts'].insert_one(account_data)
                break
            except pymongo.errors.DuplicateKeyError as error:
                index = str(error).split()[7]
                if index == '_id_':
                    raise errors.UsernameAlreadyTakenError()
                if index == 'email_address_index':
                    raise errors.EmailAddressAlreadyTakenError()
                if index == 'verification_token_index':
                    account_data['verification_token'] = verification.token()
                else:
                    raise errors.InternalServerError()

        status = await email.send_account_verification(
            account_data['email_address'],
            username,
            account_data['verification_token'],
        )
        if status != 200:
            # we do not delete the unverified account here, as the user could
            # request a new verification email, and the account gets deleted
            # anyways after a few minutes
            raise errors.InternalServerError()
Ejemplo n.º 5
0
 async def verify(self, verification_token):
     """Verify the user's email address and save submission as verified."""
     verification_time = utils.now()
     if self.authentication != 'email':
         raise errors.InvalidVerificationTokenError()
     if verification_time < self.start or verification_time >= self.end:
         raise errors.SurveyDoesNotAcceptSubmissionsAtTheMomentError()
     submission = await self.submissions.find_one(
         {'_id': verification_token}, )
     if submission is None:
         raise errors.InvalidVerificationTokenError()
     submission['verification_time'] = verification_time
     submission['_id'] = submission['data'][str(self.ei + 1)]
     await self.verified_submissions.find_one_and_replace(
         filter={'_id': submission['_id']},
         replacement=submission,
         upsert=True,
     )
     return fastapi.responses.RedirectResponse(
         f'{settings.FRONTEND_URL}/{self.username}/{self.survey_name}'
         f'/success')
Ejemplo n.º 6
0
def generate(username):
    """Generate JWT access token containing username and expiration.

    Note that the backend returns the access_token in the form
    {'access_token': 'tomato', 'token_type': 'bearer'} but expects only
    the actual 'tomato' value for any routes that require authorization.

    """
    timestamp = utils.now()
    payload = {
        'iss': 'FastSurvey',
        'sub': username,
        'iat': timestamp,
        'exp': timestamp + 7 * 24 * 60 * 60,  # tokens are valid for 7 days
    }
    access_token = jwt.encode(
        payload,
        settings.PRIVATE_RSA_KEY,
        algorithm='RS256',
    )
    access_token = access_token.decode('utf-8')
    return {'access_token': access_token, 'token_type': 'bearer'}
Ejemplo n.º 7
0
 async def aggregate(self):
     """Query the survey submissions and return aggregated results."""
     if utils.now() < self.end:
         raise errors.NotImplementedError()
     self.results = self.results or await self.aggregator.fetch()
     return self.results
Ejemplo n.º 8
0
    'COMMIT_SHA',
    'BRANCH_NAME',
]
for env in _ENVS:
    assert os.getenv(env), f'environment variable {env} not set'

# development / production / test environment
ENVIRONMENT = os.getenv('ENVIRONMENT')
# frontend url
FRONTEND_URL = os.getenv('FRONTEND_URL')
# console url
CONSOLE_URL = os.getenv('CONSOLE_URL')
# backend url
BACKEND_URL = os.getenv('BACKEND_URL')
# public JSON Web Token signature key
PUBLIC_RSA_KEY = base64.b64decode(os.getenv('PUBLIC_RSA_KEY'))
# private JSON Web Token signature key
PRIVATE_RSA_KEY = base64.b64decode(os.getenv('PRIVATE_RSA_KEY'))
# MongoDB connection string
MONGODB_CONNECTION_STRING = os.getenv('MONGODB_CONNECTION_STRING')
# Mailgun api key
MAILGUN_API_KEY = os.getenv('MAILGUN_API_KEY')
# git commit hash
COMMIT_SHA = os.getenv('COMMIT_SHA')
# git branch name
BRANCH_NAME = os.getenv('BRANCH_NAME')
# timestamp of when the server was started
START_TIME = utils.now()
# sender email address
SENDER = 'FastSurvey <*****@*****.**>'