コード例 #1
0
def get_user_by_token(token: str) -> namedtuple:
    db = get_db()
    with db.cursor() as cursor:
        cursor.execute('''
        SELECT 
            app_user.user_id, 
            username, 
            email, 
            first_name, 
            last_name, 
            created_at, 
            updated_at, 
            is_active,
            token
        FROM app_user
        JOIN token ON token.user_id = app_user.user_id 
            AND token.token = %(token)s
            AND token.expires_at > %(expires_at)s
        ;
        ''', {
            'token': token,
            'expires_at': datetime.now(timezone.utc) + timedelta(minutes=1)
        })
        db.commit()
        user = cursor.fetchone()
        return user
コード例 #2
0
def log_in(username, password):
    db = get_db()
    with db.cursor() as cursor:
        query = '''
            SELECT user_id, is_active, password_hash
            FROM app_user
            WHERE username = %(username)s
            ;
        '''
        cursor.execute(query, {'username': username})

        user = cursor.fetchone()
        if user and not user.is_active:
            db.commit()
            raise UserIsNotActive()
        elif user and check_password(password, user.password_hash):
            token, expires_at = generate_auth_token_with_expiry_date()

            cursor.execute('''
            INSERT INTO token (user_id, token, expires_at)
            VALUES (%(user_id)s, %(token)s, %(expires_at)s);
            ''', {
                'user_id': user.user_id,
                'token': token,
                'expires_at': expires_at
            })
            db.commit()

            return token, expires_at

        raise BadCredentials()
コード例 #3
0
def register_new_user(username, email, password, is_activation_required=True):
    db = get_db()
    with db.cursor() as cursor:
        try:
            password_hash = hash_password(password)
            cursor.execute('''
            INSERT INTO app_user (username, email, password_hash, is_active)
            VALUES (%(username)s, %(email)s, %(password_hash)s, %(is_active)s)
            RETURNING *;
            ''', {
                'username': username,
                'email': email,
                'password_hash': password_hash,
                'is_active': not is_activation_required
            })
            db.commit()

            new_user = cursor.fetchone()

            if is_activation_required:
                token = create_activation_token(new_user.user_id).decode('utf-8')
                send_activation_link(new_user.email, token)

            return new_user

        except psycopg2.errors.UniqueViolation as error:
            # TODO: you have to look at the database to know which constraint to catch
            # https://www.psycopg.org/docs/extensions.html#psycopg2.extensions.Diagnostics
            db.rollback()
            constraint = getattr(error.diag, 'constraint_name')
            if constraint == 'app_user_username_key':
                raise DuplicateUsername()
            elif constraint == 'app_user_email_key':
                raise DuplicateEmail()
            raise error
コード例 #4
0
def reset_password(token, new_password):
    try:
        decoded = jwt.decode(
            token,
            os.getenv('TASKAFARIAN_SECRET_KEY'),
            algorithms=['HS256'],
            issuer=os.getenv('TASKAFARIAN_ENV')
        )

        if 'action' not in decoded or decoded['action'] != ActionType.PASSWORD_RESET.value:
            # unexpected action. maybe user tried to reuse token from other flow
            raise BadCredentials()

        password_hash = hash_password(new_password)

        db = get_db()
        with db.cursor() as cursor:
            cursor.execute('''
            UPDATE app_user
            SET password_hash = %(password_hash)s
            WHERE email = %(email)s
            ;
            ''', {'password_hash': password_hash, 'email': decoded['email']})
            db.commit()
    except jwt.exceptions.PyJWTError:
        raise BadCredentials()
コード例 #5
0
ファイル: conftest.py プロジェクト: kaijicode/taskafarian
def load_fixture(name):
    from chalicelib.core.database import get_db
    db = get_db()
    with db.cursor() as cursor:
        with (Path() / 'tests/fixtures' / name).open() as f:
            cursor.execute(f.read())
            db.commit()
    close_db()
コード例 #6
0
def log_out(token):
    db = get_db()
    with db.cursor() as cursor:
        cursor.execute('''
        DELETE
        FROM token
        WHERE token = %(token)s
        ''', {'token': token})
        db.commit()
コード例 #7
0
def activate_user(user_id):
    db = get_db()
    with db.cursor() as cursor:
        cursor.execute('''
        UPDATE app_user
        SET is_active = true
        WHERE user_id = %(user_id)s
        ;
        ''', {'user_id': user_id})
        db.commit()
コード例 #8
0
ファイル: user.py プロジェクト: kaijicode/taskafarian
def get_user_role_in_team(user_id: int, team_id: int):
    db = get_db()
    with db.cursor() as cursor:
        cursor.execute('''
        SELECT user_role
        FROM user_to_team
        WHERE user_id = %(user_id)s AND team_id = %(team_id)s
        ;
        ''', {'user_id': user_id, 'team_id': team_id})
        return cursor.fetchone()
コード例 #9
0
ファイル: user.py プロジェクト: kaijicode/taskafarian
def get_teams(user_id: int):
    db = get_db()
    with db.cursor() as cursor:
        cursor.execute('''
        SELECT team_id, user_role
        FROM user_to_team
        WHERE user_id = %(user_id)s
        ;
        ''', {'user_id': user_id})
        return cursor.fetchall()
コード例 #10
0
ファイル: exceptions.py プロジェクト: kaijicode/taskafarian
def handle_exception(exception):
    response = exception.get_response()
    response.data = json.dumps({
        "status": exception.code,
        "detail": exception.description
    })
    response.content_type = "application/json"

    if exception.code == 500:
        db = get_db()
        if db:
            db.rollback()

    return response
コード例 #11
0
def is_valid_token(token):
    db = get_db()
    with db.cursor() as cursor:
        cursor.execute('''
        SELECT expires_at
        FROM token
        WHERE token = %(token)s
        ''', {'token': token})
        db.commit()

        token = cursor.fetchone()
        if token.expires_at > datetime.now(timezone.utc) + timedelta(minutes=1):
            return True
        else:
            return False
コード例 #12
0
def update_task(user: namedtuple, task_id: int, details: dict) -> dict:
    """
    Update task details such as name, estimation and etc.
    """
    db = get_db()
    with db.cursor() as cursor:
        changes = [
            SQL('{field} = {value}').format(field=Identifier(field),
                                            value=Placeholder(field))
            for field in details.keys()
        ]

        query = SQL('''
        WITH prepare_task_for_update(task_id) as (
            SELECT task.task_id
            FROM task
            INNER JOIN user_to_team
                ON user_to_team.team_id = task.team_id
                AND user_to_team.user_id = %(user_id)s
            WHERE task.task_id = %(task_id)s
        )
        UPDATE task
        SET {changes}
        FROM prepare_task_for_update
        WHERE task.task_id = prepare_task_for_update.task_id
        RETURNING task.task_id, 
            task.project_id,
            task.team_id,
            task.name,
            task.description,
            task.estimation,
            task.status,
            task.created_at,
            task.created_by,
            task.due_date,
            task.assignee_id
        ;
        ''').format(changes=SQL(', ').join(changes))

        params = {**details, 'task_id': task_id, 'user_id': user.user_id}
        cursor.execute(query, params)
        db.commit()

        updated_task = cursor.fetchone()
        if not updated_task:
            raise EntityNotFound()

        return updated_task
コード例 #13
0
ファイル: conftest.py プロジェクト: kaijicode/taskafarian
def get_user(username):
    from chalicelib.core.database import get_db
    db = get_db()
    with db.cursor() as cursor:
        query = '''
        SELECT * 
        FROM app_user
        LEFT JOIN token using (user_id)
        WHERE username = %(username)s
        ;
        '''
        params = {'username': username}
        cursor.execute(query, params)
        db.commit()

        return cursor.fetchone()
コード例 #14
0
def create_task(user,
                name,
                status,
                created_by,
                assignee_id=None,
                due_date=None,
                estimation=None,
                description='',
                team_id=None,
                project_id=None):
    db = get_db()
    with db.cursor() as cursor:
        query = '''
        INSERT INTO task(name, status, created_by, assignee_id, due_date, estimation, description, team_id, project_id)
        VALUES (
            %(name)s,
            %(status)s,
            %(created_by)s,
            %(assignee_id)s,
            %(due_date)s,
            %(estimation)s,
            %(description)s,
            %(team_id)s,
            %(project_id)s
        )
        RETURNING task_id
        ;
        '''

        params = {
            'name': name,
            'status': status,
            'created_by': created_by,
            'assignee_id': assignee_id,
            'due_date': due_date,
            'estimation': estimation,
            'description': description,
            'team_id': team_id,
            'project_id': project_id
        }

        cursor.execute(query, params)

        insertion_result = cursor.fetchone()
        db.commit()

    return fetch(user, insertion_result.task_id)
コード例 #15
0
def request_password_reset(email: str):
    db = get_db()
    with db.cursor() as cursor:
        cursor.execute('''
        SELECT email
        FROM app_user
        WHERE email = %(email)s
        ;
        ''', {'email': email})
        db.commit()
        user = cursor.fetchone()

        if not user:
            # no user with such email
            raise UserNotFound()

    token = create_token_for_password_reset(email).decode('utf-8')
    send_password_reset_by_email(email, token)
コード例 #16
0
def fetch(user: namedtuple, task_id: int):
    db = get_db()
    with db.cursor() as cursor:
        query = '''
        SELECT
            task.task_id,
            task.project_id,
            task.team_id,
            task.name,
            task.description,
            task.estimation,
            task.status,
            task.created_at,
            task.due_date,
            jsonb_build_object(
                'username', creator.username,
                'user_id', creator.user_id,
                'first_name', creator.first_name,
                'last_name', creator.last_name
            ) as creator,
            jsonb_build_object(
                'username', assignee.username,
                'user_id', assignee.user_id,
                'first_name', assignee.first_name,
                'last_name', assignee.last_name
            ) as assignee
        FROM task
        LEFT JOIN user_to_team
            ON user_to_team.team_id = task.team_id AND user_to_team.user_id = %(user_id)s
        LEFT JOIN app_user AS creator
            ON creator.user_id = task.created_by
        LEFT JOIN app_user AS assignee
            ON assignee.user_id = task.assignee_id
        WHERE task.task_id = %(task_id)s
            AND (task.created_by = %(user_id)s OR user_to_team.user_role IS NOT NULL)
        ;
        '''

        params = {'task_id': task_id, 'user_id': user.user_id}

        cursor.execute(query, params)
        db.commit()

        return cursor.fetchone()
コード例 #17
0
def get_user_by_id(user_id):
    db = get_db()
    with db.cursor() as cursor:
        cursor.execute('''
        SELECT 
            user_id, 
            username, 
            email, 
            first_name, 
            last_name, 
            created_at, 
            updated_at, 
            is_active
        FROM app_user
        WHERE user_id = %(user_id)s
        ;
        ''', {'user_id': user_id})
        db.commit()
        return cursor.fetchone()
コード例 #18
0
def deactivate_user(user_id):
    """Deactivates user by setting the is_active flag to false and removing all tokens."""
    db = get_db()

    with db.cursor() as cursor:
        query = '''
        UPDATE app_user 
        SET is_active = true
        WHERE user_id = %(user_id)s
        ;
        
        DELETE
        FROM token
        WHERE user_id = %(user_id)s
        ; 
        '''
        params = {'user_id': user_id}
        cursor.execute(query, params)
        db.commit()
コード例 #19
0
def delete_tasks(user: namedtuple,
                 task_ids: Tuple[int, ...],
                 all_or_nothing=True) -> List[int]:
    """Delete tasks.
    all_or_nothing=True - commit if all tasks deleted successfully otherwise abort
    all_or_nothing=False - commit even if one or more tasks could not be deleted
    """
    db = get_db()
    with db.cursor() as cursor:
        query = '''
        with prepare_for_deletion(task_id) as (
            SELECT task_id
            FROM task
            INNER JOIN user_to_team 
                ON user_to_team.team_id = task.team_id 
                AND user_to_team.user_id = %(user_id)s
            WHERE task_id IN %(task_ids)s
        )
        DELETE
        FROM task
        WHERE task.task_id IN (SELECT task_id FROM prepare_for_deletion)
        RETURNING task.task_id
        ;
        '''
        params = {'task_ids': tuple(task_ids), 'user_id': user.user_id}

        cursor.execute(query, params)
        deleted = cursor.fetchall()
        deleted_task_ids = [task.task_id for task in deleted]

        if all_or_nothing and len(deleted_task_ids) != len(task_ids):
            # could not delete some of the tasks, aborting
            db.rollback()
            raise DeletionError(list(set(task_ids) - set(deleted_task_ids)))

        db.commit()

        return deleted_task_ids
コード例 #20
0
def fetch_many(user, offset: int = 0, limit: int = 20):

    params = {
        'user_id': user.user_id,
        'limit': limit,
        'offset': offset,
    }

    db = get_db()
    with db.cursor() as cursor:
        query = SQL('''
        WITH extended_task AS (
            SELECT task.task_id,
                   task.project_id,
                   task.team_id,
                   task.name,
                   task.description,
                   task.estimation,
                   task.status,
                   task.created_at,
                   task.due_date,
                   task.created_by,
                   task.assignee_id,
                   coalesce(jsonb_agg(time_entries) filter ( where time_entries.task_id is not null ), '[]'::jsonb) as time_entries
            FROM task
            LEFT JOIN LATERAL (
                SELECT task_time_entry.time_entry_id,
                       task_time_entry.task_id,
                       task_time_entry.assignee_id,
                       task_time_entry.start_datetime,
                       task_time_entry.end_datetime
                FROM task_time_entry
                WHERE task_time_entry.task_id = task.task_id
                ORDER BY task_time_entry.start_datetime DESC
            ) AS time_entries ON true
            WHERE task.created_by = %(user_id)s
            GROUP BY task.task_id
            OFFSET %(offset)s
            LIMIT %(limit)s
        ),
        tasks_with_user_and_time_info AS (
            SELECT extended_task.task_id,
                    extended_task.project_id,
                    extended_task.team_id,
                    extended_task.name,
                    extended_task.description,
                    extended_task.estimation,
                    extended_task.status,
                    extended_task.created_at,
                    extended_task.due_date,
                    extended_task.time_entries,
                jsonb_build_object(
                   'username', creator.username,
                   'user_id', creator.user_id,
                   'first_name', creator.first_name,
                   'last_name', creator.last_name
                ) as creator,
                jsonb_build_object(
                   'username', assignee.username,
                   'user_id', assignee.user_id,
                   'first_name', assignee.first_name,
                   'last_name', assignee.last_name
                ) as assignee
            FROM extended_task
            LEFT JOIN app_user AS creator
                ON creator.user_id = extended_task.created_by
            LEFT JOIN app_user AS assignee
                ON assignee.user_id = extended_task.assignee_id
        )
        SELECT *
        FROM tasks_with_user_and_time_info
        ORDER BY tasks_with_user_and_time_info.created_at DESC
        ;
        ''')

        cursor.execute(query, params)
        tasks = cursor.fetchall()

        return {
            'entities': tasks,
            'meta': {
                'count': len(tasks),
                'offset': offset,
                'limit': limit
            }
        }