Ejemplo n.º 1
0
def _login_user(user_id, redirect_path=None, tool_id=None):
    app.logger.info(f'_login_user: user_id={user_id}, redirect_path={redirect_path}, tool_id={tool_id}')
    authenticated = login_user(LoginSession(user_id), remember=True) and current_user.is_authenticated
    if authenticated:
        if redirect_path:
            response = redirect(location=f"{app.config['VUE_LOCALHOST_BASE_URL'] or ''}{redirect_path}")
        else:
            response = tolerant_jsonify(current_user.to_api_json())

        canvas_api_domain = current_user.course.canvas_api_domain
        canvas = Canvas.find_by_domain(canvas_api_domain)
        canvas_course_id = current_user.course.canvas_course_id
        # Yummy cookies!
        key = f'{canvas_api_domain}|{canvas_course_id}'
        value = str(current_user.user_id)
        response.set_cookie(
            key=key,
            value=value,
            samesite='None',
            secure=True,
        )
        app.logger.info(f'_login_user cookie: key={key} value={str(current_user.user_id)}')

        response.set_cookie(
            key=f'{canvas_api_domain}_supports_custom_messaging',
            value=str(canvas.supports_custom_messaging),
            samesite='None',
            secure=True,
        )
        return response
    elif tool_id:
        raise UnauthorizedRequestError(f'Unauthorized user during {tool_id} LTI launch (user_id = {user_id})')
    else:
        return tolerant_jsonify({'message': f'User {user_id} failed to authenticate.'}, 403)
Ejemplo n.º 2
0
def app_status():
    resp = {
        'app': True,
        'canvas': _ping_canvas(),
        'db': _db_status(),
    }
    return tolerant_jsonify(resp)
Ejemplo n.º 3
0
def previews_callback():
    if not verify_preview_service_authorization(
            request.headers.get('authorization')):
        raise UnauthorizedRequestError(
            'Missing or invalid authorization header.')

    params = request.form
    if not (params.get('id', None) and params.get('status', None)):
        raise BadRequestError('Id and status fields required.')
    metadata = None
    try:
        if params.get('metadata'):
            metadata = json.loads(params['metadata'])
    except Exception as e:
        app.logger.error('Failed to parse JSON preview metadata.')
        app.logger.exception(e)
        raise BadRequestError('Could not parse JSON metadata.')

    asset = Asset.find_by_id(params['id'])
    if not asset:
        raise BadRequestError(f"Asset {params['id']} not found.")

    if asset.update_preview(
            preview_status=params.get('status'),
            thumbnail_url=params.get('thumbnail'),
            image_url=params.get('image'),
            pdf_url=params.get('pdf'),
            metadata=metadata,
    ):
        return tolerant_jsonify({'status': 'success'})
    else:
        raise InternalServerError(
            f"Unable to update preview data (asset_id={params['id']}.")
Ejemplo n.º 4
0
def get_categories():
    include_hidden = to_bool_or_none(request.args.get('includeHidden'))
    categories = Category.get_categories_by_course_id(
        course_id=current_user.course.id,
        include_hidden=include_hidden,
    )
    return tolerant_jsonify(Category.to_decorated_json(categories))
Ejemplo n.º 5
0
def get_comments(asset_id):
    asset = Asset.find_by_id(asset_id=asset_id)
    if asset and can_view_asset(asset=asset, user=current_user):
        return tolerant_jsonify(
            _decorate_comments(Comment.get_comments(asset.id)))
    else:
        raise ResourceNotFoundError(
            'Asset is either unavailable or non-existent.')
Ejemplo n.º 6
0
def get_asset(asset_id):
    asset = Asset.find_by_id(asset_id=asset_id)
    if asset and can_view_asset(asset=asset, user=current_user):
        if current_user.user not in asset.users:
            asset.increment_views(current_user.user)
        return tolerant_jsonify(
            asset.to_api_json(user_id=current_user.get_id()))
    else:
        raise ResourceNotFoundError(f'No asset found with id: {asset_id}')
Ejemplo n.º 7
0
def delete_comment(comment_id):
    comment = Comment.find_by_id(comment_id=comment_id)
    if comment and can_delete_comment(comment=comment, user=current_user):
        Comment.delete(comment_id=comment_id)
        return tolerant_jsonify({'message':
                                 f'Comment {comment_id} deleted'}), 200
    else:
        raise ResourceNotFoundError(
            'Comment is either unavailable or non-existent.')
Ejemplo n.º 8
0
def delete_asset(asset_id):
    asset = Asset.find_by_id(asset_id) if asset_id else None
    if not asset:
        raise ResourceNotFoundError('Asset not found.')
    if not can_update_asset(asset=asset, user=current_user):
        raise BadRequestError(
            'To delete this asset you must own it or be a teacher in the course.'
        )
    Asset.delete(asset_id=asset_id)
    return tolerant_jsonify({'message': f'Asset {asset_id} deleted'}), 200
Ejemplo n.º 9
0
def app_config():
    return tolerant_jsonify({
        'squiggyEnv':
        app.config['SQUIGGY_ENV'],
        'ebEnvironment':
        app.config['EB_ENVIRONMENT']
        if 'EB_ENVIRONMENT' in app.config else None,
        'timezone':
        app.config['TIMEZONE'],
    })
Ejemplo n.º 10
0
def create_category():
    params = request.get_json() or request.form
    title = params.get('title')
    if not title:
        raise BadRequestError('Category creation requires title.')
    category = Category.create(
        canvas_assignment_name=title,
        course_id=current_user.course.id,
        title=title,
    )
    return tolerant_jsonify(category.to_api_json())
Ejemplo n.º 11
0
def update_comment(comment_id):
    params = request.get_json()
    comment = Comment.find_by_id(comment_id=comment_id)
    if comment and can_update_comment(comment=comment, user=current_user):
        body = params.get('body', '').strip()
        if not body:
            raise BadRequestError('Comment body is required.')
        comment = Comment.update(body=body, comment_id=comment.id)
        return tolerant_jsonify(_decorate_comments([comment.to_api_json()])[0])
    else:
        raise ResourceNotFoundError(
            'Asset is either unavailable or non-existent.')
Ejemplo n.º 12
0
def app_version():
    v = {
        'version': version,
    }
    build_stats = load_json('config/build-summary.json')
    if build_stats:
        v.update(build_stats)
    else:
        v.update({
            'build': None,
        })
    return tolerant_jsonify(v)
Ejemplo n.º 13
0
def app_config():
    return tolerant_jsonify({
        'assetTypes': assets_type.enums,
        'ebEnvironment': app.config['EB_ENVIRONMENT'] if 'EB_ENVIRONMENT' in app.config else None,
        'emailAddressSupport': '*****@*****.**',  # TODO: get email address
        'canvasApiUrl': app.config['CANVAS_API_URL'],
        'canvasBaseUrl': app.config['CANVAS_BASE_URL'],
        'orderByOptions': assets_sort_by_options,
        'squiggyEnv': app.config['SQUIGGY_ENV'],
        'staticPath': app.config['STATIC_PATH'],
        'timezone': app.config['TIMEZONE'],
    })
Ejemplo n.º 14
0
def logout():
    response = tolerant_jsonify(current_user.to_api_json())
    # Delete our custom cookies
    canvas_api_domain = current_user.course.canvas_api_domain
    keys = [
        f'{canvas_api_domain}|{current_user.course.canvas_course_id}',
        f'{canvas_api_domain}_supports_custom_messaging',
    ]
    for key in keys:
        response.set_cookie(key, '', samesite='None', secure=True, expires=0)

    logout_user()
    return response
Ejemplo n.º 15
0
def dev_auth_login():
    params = request.get_json() or {}
    if app.config['DEVELOPER_AUTH_ENABLED']:
        user_id = to_int(params.get('userId'))
        password = params.get('password')
        logger = app.logger

        if password != app.config['DEVELOPER_AUTH_PASSWORD']:
            logger.error('Dev auth: Wrong password')
            return tolerant_jsonify({'message': 'Invalid credentials'}, 401)
        return _login_user(user_id)
    else:
        raise ResourceNotFoundError('Unknown path')
Ejemplo n.º 16
0
def update_category():
    params = request.get_json()
    category_id = params.get('categoryId')
    title = params.get('title')
    visible = to_bool_or_none(params.get('visible'))
    category = Category.find_by_id(category_id) if category_id else None
    if not category or not title:
        raise BadRequestError('Category update requires categoryId and title.')
    category = Category.update(
        category_id=category_id,
        title=title,
        visible=category.visible if visible is None else visible,
    )
    return tolerant_jsonify(category.to_api_json())
Ejemplo n.º 17
0
def app_status():
    def db_status():
        try:
            db.session.execute('SELECT 1')
            return True
        except SQLAlchemyError:
            app.logger.exception('Database connection error')
            return False

    resp = {
        'app': True,
        'db': db_status(),
    }
    return tolerant_jsonify(resp)
Ejemplo n.º 18
0
def create_comment():
    params = request.get_json()
    asset_id = params.get('assetId')
    asset = Asset.find_by_id(asset_id=asset_id)
    if asset and can_view_asset(asset=asset, user=current_user):
        body = params.get('body', '').strip()
        if not body:
            raise BadRequestError('Comment body is required.')
        parent_id = params.get('parentId')
        comment = Comment.create(
            asset=asset,
            user_id=current_user.user_id,
            body=body,
            parent_id=parent_id and int(parent_id),
        )
        return tolerant_jsonify(_decorate_comments([comment.to_api_json()])[0])
    else:
        raise ResourceNotFoundError(
            'Asset is either unavailable or non-existent.')
Ejemplo n.º 19
0
def update_asset():
    params = request.get_json()
    asset_id = params.get('assetId')
    category_id = params.get('categoryId')
    description = params.get('description')
    title = params.get('title')
    asset = Asset.find_by_id(asset_id) if asset_id else None
    if not asset or not title:
        raise BadRequestError('Asset update requires a valid ID and title.')
    if not can_update_asset(asset=asset, user=current_user):
        raise BadRequestError(
            'To update an asset you must own it or be a teacher in the course.'
        )
    asset = Asset.update(
        asset_id=asset_id,
        categories=category_id and [Category.find_by_id(category_id)],
        description=description,
        title=title,
    )
    return tolerant_jsonify(asset.to_api_json(user_id=current_user.get_id()))
Ejemplo n.º 20
0
def create_asset():
    params = request.get_json() or request.form
    asset_type = params.get('type')
    category_id = params.get('categoryId')
    description = params.get('description')
    source = params.get('source')
    url = params.get('url')
    title = params.get('title', url)
    visible = params.get('visible', True)
    if not asset_type or not title:
        raise BadRequestError('Asset creation requires title and type.')

    if asset_type == 'link' and not url:
        raise BadRequestError('Link asset creation requires url.')

    if not current_user.course:
        raise BadRequestError('Course data not found')

    s3_attrs = {}
    if asset_type == 'file':
        file_upload = _get_upload_from_http_post()
        s3_attrs = Asset.upload_to_s3(
            filename=file_upload['name'],
            byte_stream=file_upload['byte_stream'],
            course_id=current_user.course.id,
        )

    asset = Asset.create(
        asset_type=asset_type,
        categories=category_id and [Category.find_by_id(category_id)],
        course_id=current_user.course.id,
        description=description,
        download_url=s3_attrs.get('download_url', None),
        mime=s3_attrs.get('content_type', None),
        source=source,
        title=title,
        url=url,
        users=[User.find_by_id(current_user.get_id())],
        visible=visible,
    )
    return tolerant_jsonify(asset.to_api_json())
Ejemplo n.º 21
0
def get_assets():
    params = request.get_json()
    sort = _get(params, 'sort', None)
    offset = params.get('offset')
    limit = params.get('limit')
    filters = {
        'asset_type': _get(params, 'assetType', None),
        'category_id': _get(params, 'categoryId', None),
        'has_comments': _get(params, 'hasComments', None),
        'has_likes': _get(params, 'hasLikes', None),
        'has_views': _get(params, 'hasViews', None),
        'keywords': _get(params, 'keywords', None),
        'order_by': _get(params, 'orderBy', 'recent'),
        'owner_id': _get(params, 'userId', None),
        'section_id': _get(params, 'sectionId', None),
    }
    results = Asset.get_assets(session=current_user,
                               sort=sort,
                               offset=offset,
                               limit=limit,
                               filters=filters)
    return tolerant_jsonify(results)
Ejemplo n.º 22
0
def delete(category_id):
    Category.delete(category_id)
    return tolerant_jsonify({'message':
                             f'Category {category_id} deleted'}), 200
Ejemplo n.º 23
0
def remove_like_asset(asset_id):
    asset = _get_asset_for_like(asset_id)
    asset.remove_like(user=current_user)
    return tolerant_jsonify(asset.to_api_json(user_id=current_user.get_id()))
Ejemplo n.º 24
0
def get_users():
    return tolerant_jsonify([
        u.to_api_json()
        for u in User.get_users_by_course_id(course_id=current_user.course.id)
    ])
Ejemplo n.º 25
0
def my_profile():
    return tolerant_jsonify(current_user.to_api_json())
Ejemplo n.º 26
0
def logout():
    _logout_user()
    return tolerant_jsonify(current_user.to_api_json())
Ejemplo n.º 27
0
 def to_json(self):
     if self.message:
         return tolerant_jsonify({'message': self.message})
     else:
         return ''
Ejemplo n.º 28
0
def handle_unexpected_error(error):
    app.logger.exception(error)
    return tolerant_jsonify(
        {'message': 'An unexpected server error occurred.'}), 500