def update_settings(uuid,
                    settings: AccountSettingsSchema,
                    Authorize: AuthJWT = Depends(),
                    db: Session = Depends(get_db)):
    Authorize.jwt_required()
    check_matching_user(uuid, Authorize)
    updated_settings = AccountSettings(**settings.dict())
    db.merge(updated_settings)
    db.commit()
    return updated_settings
def update_account(uuid,
                   account: AccountBaseSchema,
                   Authorize: AuthJWT = Depends(),
                   db: Session = Depends(get_db)):
    Authorize.jwt_required()
    check_matching_user(uuid, Authorize)
    check_for_diff_user_with_same_username(uuid, account, db)
    updated_acct = Account(uuid=uuid, **account.dict())
    db.merge(updated_acct)
    db.commit()
    return updated_acct
def update_password(uuid,
                    partial_account: AccountNewPasswordSchema,
                    Authorize: AuthJWT = Depends(),
                    db: Session = Depends(get_db)):
    try:
        Authorize.jwt_required()
        check_matching_user(uuid, Authorize)
        account = db.query(Account).filter_by(uuid=uuid).first()
        if partial_account.password is None:
            raise HTTPException(status_code=400, detail=f"Password is missing")
        else:
            check_valid_password(partial_account.password)
            account.password = encrypt_password(partial_account.password)
        db.merge(account)
        db.commit()
        db.refresh(account)
    except Exception as e:
        logging.warning(e)
        raise e
    return account
def get_settings_from_hash(pw_reset_hash: str,
                           Authorize: AuthJWT = Depends(),
                           db: Session = Depends(get_db)):
    existing_settings = db.query(AccountSettings).filter_by(
        password_reset_hash=pw_reset_hash).first()
    if existing_settings is not None:
        time_diff = minutes_difference(existing_settings.password_reset_time)
        if time_diff >= 15:
            existing_settings.password_reset_hash = None
            existing_settings.password_reset_time = None
            db.merge(existing_settings)
            db.commit()
            raise HTTPException(
                status_code=400,
                detail=f"Invalid or expired password reset URL!")
        else:
            create_access_and_refresh_tokens(str(existing_settings.uuid),
                                             Authorize)
            return existing_settings
    else:
        raise HTTPException(status_code=400,
                            detail=f"Invalid or expired password reset URL!")
def complete_account_registration(verify_hash: str,
                                  Authorize: AuthJWT = Depends(),
                                  db: Session = Depends(get_db)):
    settings = db.query(AccountSettings).filter_by(
        verify_account_hash=verify_hash).first()
    if settings is not None:
        acct_uuid = settings.uuid
        settings.verify_account_hash = None
        settings.cancel_registration_hash = None
        db.merge(settings)
        db.commit()
        account = db.query(Account).filter_by(uuid=acct_uuid).first()
        if account is not None:
            account.is_verified = True
            db.merge(account)
            db.commit()
            create_access_and_refresh_tokens(str(acct_uuid), Authorize)
            user = row2dict(account)
            user.update(row2dict(settings))
            return user
    else:
        raise HTTPException(status_code=400,
                            detail=f"invalid hash or account does not exist")
def create_and_send_email(notification_payload: AccountNotificationSchema,
                          existing_acct: Account, db: Session):
    email_message = None
    if existing_acct is not None:
        if notification_payload.notification_type == 'password_reset':
            email_message = f'<p>Dear {existing_acct.first_name},</p>'
            if existing_acct.oauth is None:
                base_url = Config['routes']['client']
                acct_settings = db.query(AccountSettings).filter_by(
                    uuid=existing_acct.uuid).first()
                curr_time = datetime.now()
                password_reset_hash = generate_str_for_hash(
                    existing_acct.username, curr_time)
                acct_settings.password_reset_hash = password_reset_hash
                acct_settings.password_reset_time = curr_time
                db.merge(acct_settings)
                db.commit()

                reset_url = f'{base_url}/reset_password?hash={password_reset_hash}'
                message_body = CreateParagraph(
                    f"""We have received a request to reset your password. To reset your password,
                        please click the following""")
                message_body += CreateButton("Reset Password", reset_url)
                message_body += CreateParagraph(
                    "This link will expire in 15 minutes")
            else:
                oauth_type = existing_acct.oauth.capitalize()
                message_body = CreateParagraph(
                    f"""We have received a request to reset your password.
                    Your account was created with {oauth_type} OAuth; therefore,
                    you cannot set or reset a password.
                    Please try signing in with {oauth_type}.""")
            message_body += CreateParagraph(
                '<b>If this action was not performed by you, please ignore this message.</b>'
            )

            email_message = BASE_EMAIL_TEMPLATE.format(body_text=message_body)
            nm.send_notification(recipient=existing_acct.email,
                                 message=email_message,
                                 channel=NotificationChannel.EMAIL,
                                 scheduled_send_date=datetime.now(),
                                 subject='HF Volunteer Portal Password Reset')
        elif notification_payload.notification_type == 'verify_registration':
            base_url = Config['routes']['client']
            acct_settings = db.query(AccountSettings).filter_by(
                uuid=existing_acct.uuid).first()
            curr_time = datetime.now()
            verify_account_hash = generate_str_for_hash(
                existing_acct.username, curr_time)
            acct_settings.verify_account_hash = verify_account_hash
            cancel_registration_hash = generate_str_for_hash(
                existing_acct.username, curr_time)
            acct_settings.cancel_registration_hash = cancel_registration_hash
            db.merge(acct_settings)
            db.commit()

            verify_url = f'{base_url}/verify_account?hash={verify_account_hash}'
            cancel_url = f'{base_url}/cancel_registration?hash={cancel_registration_hash}'

            message_body = CreateParagraph(f'Hi {existing_acct.first_name},')
            message_body += CreateParagraph(
                f"""We have received a request to create an account associated with this email.
                Please click below to verify your account""")
            message_body += CreateButton("Verify My Account", verify_url)

            message_body += CreateParagraph(
                f"""If this action was not performed by you or performed by accident,
                you may click the following to undo account creation""")
            message_body += CreateButton("Undo Account Registration",
                                         cancel_url)

            email_message = BASE_EMAIL_TEMPLATE.format(body_text=message_body)

            nm.send_notification(
                recipient=existing_acct.email,
                message=email_message,
                channel=NotificationChannel.EMAIL,
                scheduled_send_date=datetime.now(),
                subject='HF Volunteer Portal Account Registration')