예제 #1
0
class CanvasPollerApiKey(Base):
    __tablename__ = 'canvas_poller_api_keys'

    canvas_api_domain = db.Column(db.String(255), nullable=False, primary_key=True)
    api_key = db.Column(db.String(255), nullable=False, primary_key=True)

    def __init__(
        self,
        canvas_api_domain,
        api_key,
    ):
        self.api_key = api_key
        self.canvas_api_domain = canvas_api_domain

    def __repr__(self):
        return f"""<Course
                    api_key={self.api_key},
                    canvas_api_domain={self.canvas_api_domain}
                """

    @classmethod
    def create(cls, canvas_api_domain, api_key):
        api_key = cls(
            canvas_api_domain=canvas_api_domain,
            api_key=api_key,
        )
        db.session.add(api_key)
        std_commit()
        return api_key

    @classmethod
    def find_by_domain(cls, canvas_api_domain):
        return cls.query.filter_by(canvas_api_domain=canvas_api_domain).all()
예제 #2
0
class AuthorizedUser(Base):
    __tablename__ = 'authorized_users'

    id = db.Column(db.Integer, nullable=False, primary_key=True)  # noqa: A003
    is_admin = True
    uid = db.Column(db.String(255), nullable=False, unique=True)

    def __init__(self, uid):
        self.uid = uid

    def __repr__(self):
        return f"""<AuthorizedUser
                    uid={self.uid},
                    created_at={self.created_at},
                    updated_at={self.updated_at}>
                """

    @classmethod
    def find_by_id(cls, db_id, include_deleted=False):
        return cls.query.filter_by(id=db_id).first()

    @classmethod
    def find_by_uid(cls, uid):
        return cls.query.filter_by(uid=uid).first()

    @classmethod
    def get_id_per_uid(cls, uid):
        query = text('SELECT id FROM authorized_users WHERE uid = :uid')
        result = db.session.execute(query, {'uid': uid}).first()
        return result and result['id']
예제 #3
0
class Base(db.Model):
    __abstract__ = True

    created_at = db.Column(db.DateTime, nullable=False, default=datetime.now)
    updated_at = db.Column(db.DateTime,
                           nullable=False,
                           default=datetime.now,
                           onupdate=datetime.now)
예제 #4
0
class ActivityType(Base):
    __tablename__ = 'activity_types'

    id = db.Column(db.Integer, nullable=False, primary_key=True)  # noqa: A003
    activity_type = db.Column('type', activities_type, nullable=False)
    course_id = db.Column(db.Integer, nullable=False)
    enabled = db.Column(db.Boolean, default=True, nullable=False)
    points = db.Column(db.Integer)

    def __init__(
        self,
        activity_type,
        course_id,
        enabled=True,
        points=None,
    ):
        self.activity_type = activity_type
        self.course_id = course_id
        self.enabled = enabled
        self.points = points

    def __repr__(self):
        return f"""<ActivityType
                    type={self.activity_type},
                    course_id={self.course_id},
                    enabled={self.enabled},
                    points={self.points}>
                """

    @classmethod
    def create(cls, activity_type, course_id, enabled=True, points=None):
        activity_type_instance = cls(
            activity_type=activity_type,
            course_id=course_id,
            enabled=enabled,
            points=points,
        )
        db.session.add(activity_type_instance)
        std_commit()
        return activity_type_instance

    def to_api_json(self):
        return {
            'id': self.id,
            'type': self.activity_type,
            'courseId': self.course_id,
            'enabled': self.enabled,
            'points': self.points,
            'createdAt': isoformat(self.created_at),
            'updatedAt': isoformat(self.updated_at),
        }
예제 #5
0
class User(Base):
    __tablename__ = 'users'

    id = db.Column(db.Integer, nullable=False, primary_key=True)  # noqa: A003
    canvas_course_role = db.Column(db.String(255), nullable=False)
    canvas_course_sections = db.Column(ARRAY(db.String(255)))
    canvas_email = db.Column(db.String(255))
    canvas_enrollment_state = db.Column('canvas_enrollment_state',
                                        canvas_enrollment_state_type,
                                        nullable=False)
    canvas_full_name = db.Column(db.String(255), nullable=False)
    canvas_image = db.Column(db.String(255))
    canvas_user_id = db.Column(db.Integer, nullable=False)
    course_id = db.Column(db.Integer,
                          db.ForeignKey('courses.id'),
                          nullable=False)
    points = db.Column(db.Integer, default=0, nullable=False)
    share_points = db.Column(db.Boolean, default=False)
    last_activity = db.Column(db.DateTime,
                              nullable=False,
                              default=datetime.now)

    assets = db.relationship(
        'Asset',
        secondary=asset_user_table,
        backref='users',
        lazy='dynamic',
    )
    course = db.relationship(Course.__name__, back_populates='users')

    def __init__(
        self,
        canvas_course_role,
        canvas_enrollment_state,
        canvas_full_name,
        canvas_user_id,
        course_id,
        canvas_course_sections=None,
        canvas_email=None,
        canvas_image=None,
        points=0,
        share_points=False,
    ):
        self.canvas_course_role = canvas_course_role
        self.canvas_course_sections = canvas_course_sections
        self.canvas_email = canvas_email
        self.canvas_enrollment_state = canvas_enrollment_state
        self.canvas_full_name = canvas_full_name
        self.canvas_image = canvas_image
        self.canvas_user_id = canvas_user_id
        self.course_id = course_id
        self.points = points
        self.share_points = share_points

    def __repr__(self):
        return f"""<User
                    canvas_course_role={self.canvas_course_role},
                    canvas_course_sections={self.canvas_course_sections},
                    canvas_email={self.canvas_email},
                    canvas_enrollment_state={self.canvas_enrollment_state},
                    canvas_full_name={self.canvas_full_name},
                    canvas_user_id={self.canvas_user_id},
                    course_id={self.course_id},
                    last_activity={self.last_activity},
                    points={self.points},
                    share_points={self.share_points},
                    created_at={self.created_at},
                    updated_at={self.updated_at}>
                """

    @classmethod
    def create(
        cls,
        canvas_course_role,
        canvas_enrollment_state,
        canvas_full_name,
        canvas_user_id,
        course_id,
        canvas_course_sections=None,
        canvas_email=None,
        canvas_image=None,
    ):
        user = cls(
            canvas_course_role=canvas_course_role,
            canvas_course_sections=canvas_course_sections,
            canvas_email=canvas_email,
            canvas_enrollment_state=canvas_enrollment_state,
            canvas_full_name=canvas_full_name,
            canvas_image=canvas_image,
            canvas_user_id=canvas_user_id,
            course_id=course_id,
        )
        db.session.add(user)
        std_commit()
        return user

    @classmethod
    def find_by_course_id(cls, canvas_user_id, course_id):
        where_clause = and_(cls.course_id == course_id,
                            cls.canvas_user_id == canvas_user_id)
        return cls.query.filter(where_clause).one_or_none()

    @classmethod
    def get_users_by_course_id(cls, course_id):
        return cls.query.filter_by(course_id=course_id).order_by(
            cls.canvas_full_name).all()

    @classmethod
    def find_by_canvas_user_id(cls, canvas_user_id):
        return cls.query.filter_by(canvas_user_id=canvas_user_id).first()

    @classmethod
    def find_by_id(cls, user_id):
        user_id = to_int(user_id)
        if not user_id:
            return None
        return cls.query.filter_by(id=user_id).first()

    @classmethod
    def find_by_ids(cls, user_ids):
        return cls.query.filter(cls.id.in_(user_ids)).all()

    def to_api_json(self):
        return {
            'id': self.id,
            'canvasApiDomain': self.course.canvas_api_domain,
            'canvasCourseId': self.course.canvas_course_id,
            'canvasCourseRole': self.canvas_course_role,
            'canvasCourseSections': self.canvas_course_sections,
            'canvasEmail': self.canvas_email,
            'canvasFullName': self.canvas_full_name,
            'canvasImage': self.canvas_image,
            'canvasUserId': self.canvas_user_id,
            'lastActivity': isoformat(self.last_activity),
            'points': self.points,
            'sharePoints': self.share_points,
            'createdAt': isoformat(self.created_at),
            'updatedAt': isoformat(self.updated_at),
        }
예제 #6
0
class Category(Base):
    __tablename__ = 'categories'

    id = db.Column(db.Integer, nullable=False, primary_key=True)  # noqa: A003
    canvas_assignment_id = db.Column(db.Integer)
    canvas_assignment_name = db.Column(db.String(255), nullable=False)
    course_id = db.Column(db.Integer, db.ForeignKey('courses.id'))
    deleted_at = db.Column(db.DateTime)
    title = db.Column(db.String(255), nullable=False)
    visible = db.Column(db.Boolean, nullable=True)

    def __init__(
        self,
        canvas_assignment_name,
        course_id,
        title,
        canvas_assignment_id=None,
        visible=True,
    ):
        self.canvas_assignment_id = canvas_assignment_id
        self.canvas_assignment_name = canvas_assignment_name
        self.course_id = course_id
        self.title = title
        self.visible = visible

    def __repr__(self):
        return f"""<Category
                    id={self.id},
                    canvas_assignment_id={self.canvas_assignment_id},
                    canvas_assignment_name={self.canvas_assignment_name},
                    course_id={self.course_id},
                    deleted_at={self.deleted_at},
                    title={self.title},
                    visible={self.visible},
                    created_at={self.created_at},
                    updated_at={self.updated_at}>
                """

    @classmethod
    def create(
        cls,
        canvas_assignment_name,
        course_id,
        title,
        canvas_assignment_id=None,
        visible=True,
    ):
        category = cls(
            canvas_assignment_id=canvas_assignment_id,
            canvas_assignment_name=canvas_assignment_name,
            course_id=course_id,
            title=title,
            visible=visible,
        )
        db.session.add(category)
        std_commit()
        return category

    @classmethod
    def delete(cls, category_id):
        category = cls.query.filter_by(id=category_id).first()
        if category:
            db.session.delete(category)
            std_commit()

    @classmethod
    def find_by_id(cls, category_id):
        return cls.query.filter_by(id=category_id).first()

    @classmethod
    def get_categories_by_course_id(cls, course_id, include_hidden=False):
        query = cls.query.filter_by(
            course_id=course_id) if include_hidden else cls.query.filter_by(
                course_id=course_id, visible=True)
        return query.order_by(cls.title, cls.created_at).all()

    @classmethod
    def update(
        cls,
        category_id,
        title,
        visible,
    ):
        category = cls.find_by_id(category_id)
        category.title = title
        category.visible = visible
        db.session.add(category)
        std_commit()
        return category

    @classmethod
    def to_decorated_json(cls, categories):
        sql = """SELECT
            c.id, (SELECT COUNT(*)::int FROM asset_categories WHERE category_id = c.id) AS asset_count
            FROM categories AS c
            WHERE c.id =  ANY(:category_ids)
        """
        results = db.session.execute(
            sql, {'category_ids': [c.id for c in categories]})
        asset_count_lookup = dict(
            (row['id'], row['asset_count']) for row in results)

        def _decorated_json(c):
            return {
                **c.to_api_json(),
                **{
                    'assetCount': asset_count_lookup.get(c.id, None),
                },
            }

        return [_decorated_json(category) for category in categories]

    def to_api_json(self):
        return {
            'id': self.id,
            'canvasAssignmentId': self.canvas_assignment_id,
            'canvasAssignmentName': self.canvas_assignment_name,
            'courseId': self.course_id,
            'deletedAt': _isoformat(self.deleted_at),
            'title': self.title,
            'visible': self.visible,
            'createdAt': _isoformat(self.created_at),
            'updatedAt': _isoformat(self.updated_at),
        }
예제 #7
0
class Asset(Base):
    __tablename__ = 'assets'

    id = db.Column(db.Integer, nullable=False, primary_key=True)  # noqa: A003
    asset_type = db.Column('type', assets_type, nullable=False)
    body = db.Column(db.Text)
    canvas_assignment_id = db.Column(db.Integer)
    comment_count = db.Column(db.Integer, nullable=False, default=0)
    course_id = db.Column(db.Integer, nullable=False)
    deleted_at = db.Column(db.DateTime)
    description = db.Column(db.Text)
    dislikes = db.Column(db.Integer, nullable=False, default=0)
    download_url = db.Column(db.String(255))
    image_url = db.Column(db.String(255))
    likes = db.Column(db.Integer, nullable=False, default=0)
    mime = db.Column(db.String(255))
    pdf_url = db.Column(db.String(255))
    preview_metadata = db.Column(JSON)
    preview_status = db.Column(db.String(255),
                               nullable=False,
                               default='pending')
    source = db.Column(db.String(255))
    thumbnail_url = db.Column(db.String(255))
    title = db.Column(db.String(255))
    url = db.Column(db.String(255))
    views = db.Column(db.Integer, nullable=False, default=0)
    visible = db.Column(db.Boolean, nullable=False, default=True)
    categories = db.relationship(
        'Category',
        secondary=asset_category_table,
        backref='assets',
    )

    comments = db.relationship('Comment',
                               back_populates='asset',
                               cascade='all, delete-orphan')

    def __init__(
        self,
        asset_type,
        course_id,
        canvas_assignment_id=None,
        categories=None,
        description=None,
        download_url=None,
        mime=None,
        source=None,
        title=None,
        url=None,
        users=None,
        visible=True,
    ):
        self.asset_type = asset_type
        self.canvas_assignment_id = canvas_assignment_id
        self.categories = categories or []
        self.course_id = course_id
        self.description = description
        self.download_url = download_url
        self.mime = mime
        self.source = source
        self.title = title
        self.url = url
        self.users = users or []
        self.visible = visible

    def __repr__(self):
        return f"""<Asset
                    asset_type={self.asset_type},
                    categories={self.categories},
                    users={self.users},
                    course_id={self.course_id},
                    canvas_assignment_id={self.canvas_assignment_id},
                    description={self.description},
                    source={self.source},
                    title={self.title},
                    url={self.url},
                    visible={self.visible},
                    created_at={self.created_at},
                    updated_at={self.updated_at}>,
                    deleted_at={self.deleted_at}>
                """

    @classmethod
    def find_by_id(cls, asset_id):
        return cls.query.filter_by(id=asset_id, deleted_at=None).first()

    @classmethod
    def create(
        cls,
        asset_type,
        course_id,
        title,
        users,
        canvas_assignment_id=None,
        categories=None,
        description=None,
        download_url=None,
        mime=None,
        source=None,
        url=None,
        visible=True,
        create_activity=True,
    ):
        asset = cls(
            asset_type=asset_type,
            canvas_assignment_id=canvas_assignment_id,
            categories=categories,
            course_id=course_id,
            description=description,
            download_url=download_url,
            mime=mime,
            source=source,
            title=title,
            url=url,
            users=users,
            visible=visible,
        )
        db.session.add(asset)
        std_commit()

        preview_url = download_url if asset_type == 'file' else url
        generate_previews(asset.id, preview_url)

        # Invisible assets generate no activities.
        if visible and create_activity is not False:
            for user in users:
                Activity.create(
                    activity_type='asset_add',
                    course_id=course_id,
                    user_id=user.id,
                    object_type='asset',
                    object_id=asset.id,
                    asset_id=asset.id,
                )

        return asset

    @classmethod
    def delete(cls, asset_id):
        asset = cls.find_by_id(asset_id)
        if asset:
            asset.deleted_at = utc_now()
            std_commit()

    @classmethod
    def update(
        cls,
        asset_id,
        title,
        categories=None,
        description=None,
    ):
        asset = Asset.find_by_id(asset_id)
        asset.title = title
        asset.description = description
        asset.categories = categories
        db.session.add(asset)
        std_commit()
        return asset

    @classmethod
    def get_assets(cls, session, sort, offset, limit, filters):
        params = {
            'course_id': session.course.id,
            'user_id': session.user.id,
            'asset_types': filters.get('asset_type'),
            'category_id': filters.get('category_id'),
            'owner_id': filters.get('owner_id'),
            'section_id': filters.get('section_id'),
            'offset': offset,
            'limit': limit,
        }

        from_clause = """FROM assets a
            LEFT JOIN asset_categories ac ON a.id = ac.asset_id
            LEFT JOIN categories c ON c.id = ac.category_id
            LEFT JOIN asset_users au ON a.id = au.asset_id
            LEFT JOIN users u ON au.user_id = u.id
            LEFT JOIN activities act ON a.id = act.asset_id
                AND act.course_id = :course_id
                AND act.user_id = :user_id
                AND act.object_type = 'asset'
                AND act.type = 'asset_like'"""

        where_clause = _build_where_clause(filters, params)
        order_clause = _build_order_clause(sort)

        assets_query = text(
            f"""SELECT DISTINCT ON (a.id, a.likes, a.views, a.comment_count) a.*, act.type AS activity_type
            {from_clause} {where_clause} {order_clause}
            LIMIT :limit OFFSET :offset""")
        assets_result = list(db.session.execute(assets_query, params))

        count_query = text(
            f'SELECT COUNT(DISTINCT(a.id))::int AS count {from_clause} {where_clause}'
        )
        count_result = db.session.execute(count_query, params).fetchone()
        total = (count_result and count_result[0]) or 0

        asset_ids = [r['id'] for r in assets_result]

        users_query = text("""SELECT au.asset_id,
            u.id, u.canvas_user_id, u.canvas_course_role, u.canvas_course_sections, u.canvas_enrollment_state, u.canvas_full_name, u.canvas_image
            FROM users u JOIN asset_users au
            ON au.user_id = u.id AND au.asset_id = ANY(:asset_ids)
            ORDER BY au.asset_id""")
        users_result = db.session.execute(users_query,
                                          {'asset_ids': asset_ids})

        def _row_to_json_obj(row):
            d = dict(row)
            json_obj = dict()
            for key in d.keys():
                if key.endswith('_at'):
                    json_obj[camelize(key)] = isoformat(d[key])
                elif isinstance(d[key], dict):
                    json_obj[camelize(key)] = _row_to_json_obj(d[key])
                else:
                    json_obj[camelize(key)] = d[key]
            return json_obj

        users_by_asset = dict()
        for asset_id, user_rows in groupby(users_result,
                                           lambda r: r['asset_id']):
            users_by_asset[asset_id] = [_row_to_json_obj(r) for r in user_rows]

        def _row_to_json_asset(row):
            json_asset = _row_to_json_obj(row)

            # Has the current user liked the asset?
            json_asset['liked'] = (json_asset['activityType'] == 'asset_like')

            if json_asset['id'] in users_by_asset:
                json_asset['users'] = users_by_asset[json_asset['id']]
            json_asset['thumbnailUrl'] = get_s3_signed_url(
                json_asset['thumbnailUrl'])

            return json_asset

        results = {
            'offset': offset,
            'total': total,
            'results': [_row_to_json_asset(r) for r in assets_result],
        }

        return results

    @classmethod
    def upload_to_s3(cls, filename, byte_stream, course_id):
        bucket = app.config['S3_BUCKET']
        # S3 key begins with course id, reversed for performant key distribution, padded for readability.
        reverse_course = str(course_id)[::-1].rjust(7, '0')
        (basename, extension) = os.path.splitext(filename)
        # Truncate file basename if longer than 170 characters; the complete constructed S3 URI must come in under 255.
        key = f"{reverse_course}/assets/{datetime.now().strftime('%Y-%m-%d_%H%M%S')}-{basename[0:170]}{extension}"
        content_type = magic.from_buffer(byte_stream, mime=True)
        if put_binary_data_to_s3(bucket, key, byte_stream, content_type):
            return {
                'content_type': content_type,
                'download_url': f's3://{bucket}/{key}',
            }
        else:
            raise InternalServerError('Could not upload file.')

    def add_like(self, user):
        like_activity = Activity.create_unless_exists(
            activity_type='asset_like',
            course_id=self.course_id,
            user_id=user.get_id(),
            object_type='asset',
            object_id=self.id,
            asset_id=self.id,
        )
        if like_activity:
            for asset_owner in self.users:
                Activity.create_unless_exists(
                    activity_type='get_asset_like',
                    course_id=self.course_id,
                    user_id=asset_owner.id,
                    object_type='asset',
                    object_id=self.id,
                    asset_id=self.id,
                    actor_id=user.get_id(),
                    reciprocal_id=like_activity.id,
                )
        self.likes = Activity.query.filter_by(
            asset_id=self.id, activity_type='asset_like').count()
        db.session.add(self)
        std_commit()
        return True

    def remove_like(self, user):
        db.session.query(Activity).filter_by(
            object_id=self.id,
            object_type='asset',
            activity_type='asset_like',
            user_id=user.get_id(),
        ).delete()
        db.session.query(Activity).filter_by(
            object_id=self.id,
            object_type='asset',
            activity_type='get_asset_like',
            actor_id=user.get_id(),
        ).delete()
        self.likes = Activity.query.filter_by(
            object_id=self.id, object_type='asset',
            activity_type='asset_like').count()
        db.session.add(self)
        std_commit()
        return True

    def increment_views(self, user):
        view_activity = Activity.create_unless_exists(
            activity_type='asset_view',
            course_id=self.course_id,
            user_id=user.id,
            object_type='asset',
            object_id=self.id,
            asset_id=self.id,
        )
        if view_activity:
            for asset_owner in self.users:
                Activity.create_unless_exists(
                    activity_type='get_asset_view',
                    course_id=self.course_id,
                    user_id=asset_owner.id,
                    object_type='asset',
                    object_id=self.id,
                    asset_id=self.id,
                    actor_id=user.id,
                    reciprocal_id=view_activity.id,
                )
        self.views = Activity.query.filter_by(
            asset_id=self.id, activity_type='asset_view').count()
        db.session.add(self)
        std_commit()
        return True

    def refresh_comments_count(self):
        self.comment_count = len(self.comments)
        db.session.add(self)
        std_commit()
        return self.comment_count

    def update_preview(self, **kwargs):
        if kwargs.get('preview_status'):
            self.preview_status = kwargs['preview_status']
        if kwargs.get('thumbnail_url'):
            self.thumbnail_url = kwargs['thumbnail_url']
        if kwargs.get('image_url'):
            self.image_url = kwargs['image_url']
        if kwargs.get('pdf_url'):
            self.pdf_url = kwargs['pdf_url']
        if kwargs.get('metadata'):
            self.preview_metadata = kwargs['metadata']
        db.session.add(self)
        std_commit()
        return True

    def to_api_json(self, user_id=None):
        image_url = get_s3_signed_url(self.image_url)
        pdf_url = get_s3_signed_url(self.pdf_url)

        liked = False
        if user_id:
            like_query = Activity.query.filter_by(
                object_id=self.id,
                object_type='asset',
                activity_type='asset_like',
                user_id=user_id,
            )
            if like_query.first() is not None:
                liked = True

        return {
            'id': self.id,
            'assetType': self.asset_type,
            'body': self.body,
            'canvasAssignment_id': self.canvas_assignment_id,
            'categories': [c.to_api_json() for c in self.categories],
            'commentCount': self.comment_count,
            'courseId': self.course_id,
            'description': self.description,
            'dislikes': self.dislikes,
            'downloadUrl': self.download_url,
            'imageUrl': image_url,
            'liked': liked,
            'likes': self.likes,
            'mime': self.mime,
            'pdfUrl': pdf_url,
            'previewMetadata': self.preview_metadata,
            'previewStatus': self.preview_status,
            'source': self.source,
            'title': self.title,
            'url': self.url,
            'users': [u.to_api_json() for u in self.users],
            'views': self.views,
            'visible': self.visible,
            'createdAt': isoformat(self.created_at),
            'deletedAt': isoformat(self.deleted_at),
            'updatedAt': isoformat(self.updated_at),
        }
예제 #8
0
class Canvas(Base):
    __tablename__ = 'canvas'

    canvas_api_domain = db.Column(db.String(255),
                                  nullable=False,
                                  primary_key=True)
    api_key = db.Column(db.String(255), nullable=False)
    logo = db.Column(db.String(255))
    lti_key = db.Column(db.String(255), nullable=False)
    lti_secret = db.Column(db.String(255), nullable=False)
    name = db.Column(db.String(255), nullable=False)
    supports_custom_messaging = db.Column(db.Boolean,
                                          default=False,
                                          nullable=False)
    use_https = db.Column(db.Boolean, default=True, nullable=False)

    def __init__(
        self,
        canvas_api_domain,
        api_key,
        lti_key,
        lti_secret,
        name,
        logo=None,
        supports_custom_messaging=False,
        use_https=True,
    ):
        self.api_key = api_key
        self.canvas_api_domain = canvas_api_domain
        self.lti_key = lti_key
        self.lti_secret = lti_secret
        self.name = name
        self.logo = logo
        self.supports_custom_messaging = supports_custom_messaging
        self.use_https = use_https

    def __repr__(self):
        return f"""<Course
                    api_key={self.api_key},
                    canvas_api_domain={self.canvas_api_domain},
                    lti_key={self.lti_key},
                    lti_secret={self.lti_secret},
                    name={self.name},
                    logo={self.logo},
                    supports_custom_messaging={self.supports_custom_messaging},
                    use_https={self.use_https},
                    created_at={self.created_at},
                    updated_at={self.updated_at}>
                """

    @classmethod
    def find_by_domain(cls, canvas_api_domain):
        return cls.query.filter_by(canvas_api_domain=canvas_api_domain).first()

    @classmethod
    def get_all(cls):
        return cls.query.order_by(cls.name).all()

    def to_api_json(self):
        return {
            'apiKey': self.api_key,
            'canvasApiDomain': self.canvas_api_domain,
            'ltiKey': self.lti_key,
            'ltiSecret': self.lti_secret,
            'logo': self.logo,
            'name': self.name,
            'supportsCustomMessaging': self.supports_custom_messaging,
            'useHttps': self.use_https,
            'createdAt': _isoformat(self.created_at),
            'updatedAt': _isoformat(self.updated_at),
        }
예제 #9
0
class Comment(Base):
    __tablename__ = 'comments'

    id = db.Column(db.Integer, nullable=False, primary_key=True)  # noqa: A003
    asset_id = db.Column(db.Integer,
                         db.ForeignKey('assets.id'),
                         nullable=False)
    user_id = db.Column(db.Integer)
    body = db.Column(db.Text, nullable=False)
    parent_id = db.Column(db.Integer)

    asset = db.relationship('Asset', back_populates='comments')

    def __init__(
        self,
        asset_id,
        user_id,
        body,
        parent_id=None,
    ):
        self.body = body
        self.asset_id = asset_id
        self.user_id = user_id
        self.parent_id = parent_id

    def __repr__(self):
        return f"""<Comment
                    asset_id={self.asset_id},
                    user_id={self.user_id},
                    parent_id={self.parent_id},
                    body={self.body}>
                """

    @classmethod
    def delete(cls, comment_id):
        comment = cls.query.filter_by(id=comment_id).first()
        if comment:
            asset = comment.asset
            db.session.delete(comment)
            Activity.delete_by_object_id(object_type='comment',
                                         object_id=comment_id)
            std_commit(allow_test_environment=True)
            if asset:
                asset.refresh_comments_count()

    @classmethod
    def find_by_id(cls, comment_id):
        return cls.query.filter_by(id=comment_id).first()

    @classmethod
    def create(cls, asset, user_id, body, parent_id=None):
        comment = cls(
            asset_id=asset.id,
            user_id=user_id,
            body=body,
            parent_id=parent_id,
        )
        db.session.add(comment)
        std_commit(allow_test_environment=True)
        _create_activities_per_new_comment(asset=asset, comment=comment)
        asset.refresh_comments_count()
        return comment

    @classmethod
    def update(cls, body, comment_id):
        comment = cls.find_by_id(comment_id)
        comment.body = body
        db.session.add(comment)
        std_commit()
        return comment

    @classmethod
    def get_comments(cls, asset_id):
        orphans = []
        parents = []
        # Sort reverse chronological
        order_by = desc(cls.created_at)
        for row in cls.query.filter_by(
                asset_id=asset_id).order_by(order_by).all():
            comment = row.to_api_json()
            (orphans if row.parent_id else parents).append(comment)
            comment['replies'] = []
        while len(orphans):
            orphan = orphans.pop(0)
            # Find the child's parent
            parent = next((c for c in (parents + orphans)
                           if orphan['parentId'] == c['id']), None)
            if parent:
                parent['replies'].insert(0, orphan)
        return parents

    def to_api_json(self):
        return {
            'id': self.id,
            'userId': self.user_id,
            'parentId': self.parent_id,
            'body': self.body,
            'createdAt': isoformat(self.created_at),
            'updatedAt': isoformat(self.updated_at),
        }
예제 #10
0
class Course(Base):
    __tablename__ = 'courses'

    id = db.Column(db.Integer, nullable=False, primary_key=True)  # noqa: A003
    active = db.Column(db.Boolean, nullable=False)
    asset_library_url = db.Column(db.String(255))
    canvas_api_domain = db.Column(db.String(255), nullable=False)
    canvas_course_id = db.Column(db.Integer, nullable=False)
    enable_daily_notifications = db.Column(db.Boolean,
                                           default=True,
                                           nullable=False)
    enable_upload = db.Column(db.Boolean, default=True, nullable=False)
    enable_weekly_notifications = db.Column(db.Boolean,
                                            default=True,
                                            nullable=False)
    engagement_index_url = db.Column(db.String(255))
    name = db.Column(db.String(255))
    last_polled = db.Column(db.DateTime)

    users = db.relationship('User', back_populates='course')

    def __init__(
        self,
        active,
        canvas_api_domain,
        canvas_course_id,
        asset_library_url=None,
        enable_daily_notifications=True,
        enable_upload=True,
        enable_weekly_notifications=True,
        engagement_index_url=None,
        name=None,
    ):
        self.active = active
        self.asset_library_url = asset_library_url
        self.canvas_api_domain = canvas_api_domain
        self.canvas_course_id = canvas_course_id
        self.enable_daily_notifications = enable_daily_notifications
        self.enable_upload = enable_upload
        self.enable_weekly_notifications = enable_weekly_notifications
        self.engagement_index_url = engagement_index_url
        self.name = name

    def __repr__(self):
        return f"""<Course
                    active={self.active},
                    asset_library_url={self.asset_library_url},
                    canvas_api_domain={self.canvas_api_domain},
                    canvas_course_id={self.canvas_course_id},
                    enable_daily_notifications={self.enable_daily_notifications},
                    enable_upload={self.enable_upload},
                    enable_weekly_notifications={self.enable_weekly_notifications},
                    engagement_index_url={self.engagement_index_url},
                    id={self.id},
                    name={self.name},
                    created_at={self.created_at},
                    updated_at={self.updated_at}>
                """

    @classmethod
    def find_by_id(cls, course_id):
        return cls.query.filter_by(id=course_id).first()

    @classmethod
    def find_by_canvas_course_id(cls, canvas_api_domain, canvas_course_id):
        return cls.query.filter_by(canvas_api_domain=canvas_api_domain,
                                   canvas_course_id=canvas_course_id).first()

    @classmethod
    def create(
        cls,
        canvas_api_domain,
        canvas_course_id,
        asset_library_url=None,
        engagement_index_url=None,
        name=None,
    ):
        course = cls(
            active=True,
            asset_library_url=asset_library_url,
            canvas_api_domain=canvas_api_domain,
            canvas_course_id=canvas_course_id,
            engagement_index_url=engagement_index_url,
            name=name,
        )
        db.session.add(course)
        std_commit()
        return course

    @classmethod
    def update(
        cls,
        asset_library_url,
        course_id,
        engagement_index_url,
    ):
        course = cls.find_by_id(course_id=course_id)
        course.asset_library_url = asset_library_url
        course.engagement_index_url = engagement_index_url
        db.session.add(course)
        std_commit()
        return course

    def to_api_json(self):
        canvas = Canvas.find_by_domain(
            canvas_api_domain=self.canvas_api_domain)
        return {
            'active': self.active,
            'assetLibraryUrl': self.asset_library_url,
            'canvas': canvas.to_api_json(),
            'canvasApiDomain': self.canvas_api_domain,
            'canvasCourseId': self.canvas_course_id,
            'enableDailyNotifications': self.enable_daily_notifications,
            'enableUpload': self.enable_upload,
            'enableWeeklyNotifications': self.enable_weekly_notifications,
            'engagementIndexUrl': self.engagement_index_url,
            'id': self.id,
            'name': self.name,
            'lastPolled': _isoformat(self.last_polled),
            'createdAt': _isoformat(self.created_at),
            'updatedAt': _isoformat(self.updated_at),
        }
예제 #11
0
class Activity(Base):
    __tablename__ = 'activities'

    id = db.Column(db.Integer, nullable=False, primary_key=True)  # noqa: A003
    activity_type = db.Column('type', activities_type, nullable=False)
    object_id = db.Column(db.Integer)
    object_type = db.Column('object_type', activities_object_type, nullable=False)
    activity_metadata = db.Column('metadata', JSON)
    asset_id = db.Column(db.Integer)
    course_id = db.Column(db.Integer, nullable=False)
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
    actor_id = db.Column(db.Integer)
    reciprocal_id = db.Column(db.Integer)

    user = db.relationship('User')

    def __init__(
        self,
        activity_type,
        course_id,
        user_id,
        object_type,
        object_id=None,
        asset_id=None,
        actor_id=None,
        reciprocal_id=None,
        activity_metadata=None,
    ):
        self.activity_type = activity_type
        self.course_id = course_id
        self.user_id = user_id
        self.object_type = object_type
        self.object_id = object_id
        self.asset_id = asset_id
        self.actor_id = actor_id
        self.reciprocal_id = reciprocal_id
        self.activity_metadata = activity_metadata

    def __repr__(self):
        return f"""<Activity
                    type={self.activity_type},
                    course_id={self.course_id},
                    user_id={self.user_id},
                    object_type={self.object_type}
                    object_id={self.object_id}
                    asset_id={self.asset_id}
                    actor_id={self.actor_id}
                    reciprocal_id={self.reciprocal_id}
                    metadata={self.activity_metadata}>
                """

    @classmethod
    def create(
        cls,
        activity_type,
        course_id,
        user_id,
        object_type,
        object_id=None,
        asset_id=None,
        actor_id=None,
        reciprocal_id=None,
        activity_metadata=None,
    ):
        activity = cls(
            activity_type=activity_type,
            course_id=course_id,
            user_id=user_id,
            object_type=object_type,
            object_id=object_id,
            asset_id=asset_id,
            actor_id=actor_id,
            reciprocal_id=reciprocal_id,
            activity_metadata=activity_metadata,
        )
        db.session.add(activity)
        std_commit()
        return activity

    @classmethod
    def create_unless_exists(cls, **kwargs):
        if cls.query.filter_by(**kwargs).count() == 0:
            return cls.create(**kwargs)

    @classmethod
    def delete_by_object_id(cls, object_type, object_id):
        cls.query.filter(and_(cls.object_type == object_type, cls.object_id == object_id)).delete()

    @classmethod
    def find_by_object_id(cls, object_type, object_id):
        return cls.query.filter(and_(cls.object_type == object_type, cls.object_id == object_id)).all()

    def to_api_json(self):
        return {
            'id': self.id,
            'activityType': self.activity_type,
            'courseId': self.course_id,
            'userId': self.user_id,
            'objectType': self.object_type,
            'objectId': self.object_id,
            'assetId': self.asset_id,
            'actorId': self.actor_id,
            'reciprocalId': self.reciprocal_id,
            'metadata': self.activity_metadata,
            'createdAt': isoformat(self.created_at),
            'updatedAt': isoformat(self.updated_at),
        }