Exemple #1
0
class StudyPlan(TimestampedModel):
    """Study plan model class"""

    __tablename__ = "study_plans"

    name = db.Column(db.String(100), nullable=False)
    description = db.Column(db.String)
    order = db.Column(
        db.Enum(OrderTypeEnum), default=OrderTypeEnum.oldest, nullable=False
    )
    see_solved = db.Column(db.Boolean(), default=False)
    user_id = db.Column(db.Integer, db.ForeignKey("users.id"))

    user = db.relationship(User, backref=backref("study_plans", cascade="all,delete"))

    def __init__(self, **kwargs):
        """Initialize a study plan"""
        user = False
        for k, v in kwargs.items():
            if k == "user":
                user = True
        if user and "user_id" in kwargs:
            kwargs.pop("user_id")
        if "order" not in kwargs:
            kwargs["order"] = OrderTypeEnum.oldest
        super(StudyPlan, self).__init__(**kwargs)

    def __repr__(self):
        return f"<StudyPlan: {self.name} - {self.state}>"

    @property
    def to_json(self):
        return dict(
            id=self.id,
            name=self.name,
            description=self.description,
            user=self.user_id,
            order=self.order.value,
        )

    @classmethod
    def create_default_study_plan(cls, user_id):
        user = User.query.get_or_404(user_id)
        default_plan = StudyPlan(
            name="Default", description="Default Study Plan", user=user
        )
        default_plan.save()
        return default_plan

    def delete(self):
        create_default = False
        user = User.query.filter_by(id=self.user_id).first()
        if user and len(user.study_plans) < 2:
            create_default = True
        db.session.delete(self.query.filter_by(id=self.id).first())
        db.session.commit()
        if create_default:
            self.create_default_study_plan(user_id=user.id)
Exemple #2
0
class StudySessionLog(TimestampedModel):
    """
    Tracks a study session. Records each card as a study session progresses
    """

    __tablename__ = "study_session_logs"

    study_session_id = db.Column(
        db.Integer, db.ForeignKey("study_sessions.id"), nullable=False
    )
    card_id = db.Column(db.Integer, db.ForeignKey("cards.id"), nullable=False)
    study_session = db.relationship(
        StudySession, backref=backref("study_session_logs", cascade="all,delete")
    )

    def __init__(self, **kwargs):
        """Initialize a Study Session Log"""
        super(StudySessionLog, self).__init__(**kwargs)

    def __repr__(self):
        return f"<StudySessionLog: {self.study_session.deck.name} - {self.state}>"
Exemple #3
0
class StudySession(TimestampedModel):
    """
    Represents a study session. Keeps track of deck study progress
    """

    __tablename__ = "study_sessions"

    deck_id = db.Column(db.Integer, db.ForeignKey("decks.id"), nullable=False)
    user_id = db.Column(db.Integer, db.ForeignKey("users.id"), nullable=False)
    known = db.Column(db.Integer, nullable=True, default=0)
    unknown = db.Column(db.Integer, nullable=True, default=0)

    deck = db.relationship(
        Deck, backref=backref("study_sessions", cascade="all,delete")
    )
    user = db.relationship(
        User, backref=backref("study_sessions", cascade="all,delete")
    )

    def __init__(self, **kwargs):
        """Initialize a Study Session"""
        super(StudySession, self).__init__(**kwargs)

    def save(self):
        db.session.add(self)
        db.session.commit()

    @property
    def to_json(self):
        return dict(
            id=self.id,
            state=self.state,
            deck_id=self.deck_id,
            user_id=self.user_id,
            known=self.known,
            unknown=self.unknown,
        )

    def __repr__(self):
        return f"<StudySession: {self.deck.name} - {self.state}>"
Exemple #4
0
class Card(TimestampedModel):
    """Card model class"""

    __tablename__ = "cards"

    front = db.Column(db.Text(), nullable=False)
    back = db.Column(db.Text(), nullable=False)
    user_id = db.Column(db.Integer, db.ForeignKey("users.id"), nullable=False)
    deck_id = db.Column(db.Integer, db.ForeignKey("decks.id"), nullable=False)

    user = db.relationship(User, backref=backref("cards", cascade="all,delete"))
    deck = db.relationship(Deck, backref=backref("cards", cascade="all,delete"))

    def __init__(self, **kwargs):
        """Initialize a card"""
        super(Card, self).__init__(**kwargs)

    @property
    def short_front(self):
        return self.front[:50] if len(self.front) > 50 else self.front

    def __repr__(self):
        return (
            f"<Card: {self.short_front} - {self.user.username}" f" - {self.deck.name}>"
        )

    @property
    def to_json(self):
        return dict(
            id=self.id,
            state=self.state,
            front=self.front,
            back=self.back,
            short_front=self.short_front,
            user_id=self.user_id,
            deck_id=self.deck_id,
        )

    @classmethod
    def get_next_card(cls, study_session_id, deck_id):
        session = StudySession.query.filter_by(
            id=study_session_id, user_id=g.user.id, deck_id=deck_id, state="Studying"
        ).first()
        if session is None:
            abort(404)
        study_logs = db.session.query(StudySessionLog.card_id).filter_by(
            study_session_id=session.id
        )
        study_plan = db.session.query(StudyPlan).filter_by(user_id=g.user.id).first()
        ordering = func.random()
        if study_plan:
            if study_plan.order.value == "latest":
                ordering = Card.date_created.desc()
            elif study_plan.order.value == "oldest":
                ordering = Card.date_created.asc()
        card = (
            db.session.query(Card)
            .filter(
                Card.state == "Active",
                Card.user_id == g.user.id,
                Card.deck_id == session.deck_id,
                ~(Card.id.in_(study_logs)),
            )
            .order_by(ordering)
            .first()
        )
        return card
Exemple #5
0
class Deck(TimestampedModel):
    """Deck model class"""

    __tablename__ = "decks"

    name = db.Column(db.String(100), nullable=False)
    description = db.Column(db.String)
    user_id = db.Column(db.Integer, db.ForeignKey("users.id"))
    parent_id = db.Column(db.Integer, db.ForeignKey("decks.id"))

    user = db.relationship(User, backref=backref("decks", cascade="all,delete"))
    children = db.relationship("Deck", cascade="all,delete")

    def __init__(self, **kwargs):
        """Initialize a Deck"""
        user = False
        for k, v in kwargs.items():
            if k == "user":
                user = True
        if user and "user_id" in kwargs:
            kwargs.pop("user_id")
        super(Deck, self).__init__(**kwargs)

    def save(self):
        if self.parent_id and Deck.query.filter_by(id=self.parent_id).first() is None:
            raise ValueError("Parent does not exist")
        db.session.add(self)
        db.session.commit()

    @property
    def to_json(self):
        return dict(
            id=self.id,
            name=self.name,
            state=self.state,
            description=self.description,
            user=self.user_id,
            parent=self.parent_id,
            child_count=self.child_count,
            card_count=self.card_count,
            stats=self.quick_stats,
            date_created=self.date_created,
            date_updated=self.date_updated,
        )

    @property
    def children_to_json(self):
        return dict([child.to_json for child in self.children])

    @property
    def child_count(self):
        return len(self.children)

    @property
    def card_count(self):
        return len(self.cards)

    @property
    def quick_stats(self):
        stats = {
            "progress": 0,
            "known": 0,
            "unknown": 0,
            "remaining": self.card_count,
            "last_studied": "",
        }
        if self.state != "New":
            study_session = (
                StudySession.query.filter_by(deck_id=self.id, user_id=g.user.id)
                .order_by(StudySession.date_updated.desc())
                .first()
            )
            if study_session:
                known, unknown = study_session.known, study_session.unknown
                stats["known"] = known
                stats["unknown"] = unknown
                stats["remaining"] = self.card_count - (known + unknown)
                stats["last_studied"] = study_session.date_updated
                if all([known + unknown > 0, self.card_count > 0]):
                    stats["progress"] = int(((known + unknown) / self.card_count) * 100)
        return stats

    @classmethod
    def create_default_deck(cls, user_id):
        user = User.query.get_or_404(user_id)
        default_deck = Deck(
            name="Default", description="Default Deck", user=user, state="New"
        )
        default_deck.save()
        return default_deck

    def delete(self):
        create_default = False
        user = User.query.filter_by(id=self.user_id).first()
        if user and len(user.decks) < 2:
            create_default = True
        db.session.delete(self.query.filter_by(id=self.id).first())
        db.session.commit()
        if create_default:
            self.create_default_deck(user_id=user.id)

    def __repr__(self):
        return f"<Deck: {self.name}>"