Skip to content

Commit

Permalink
Add database models
Browse files Browse the repository at this point in the history
  • Loading branch information
Jackson Chadfield committed Jul 31, 2019
1 parent 82b29a9 commit d93d021
Show file tree
Hide file tree
Showing 10 changed files with 177 additions and 8 deletions.
7 changes: 7 additions & 0 deletions .idea/OpenLearn.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions .idea/dataSources.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 13 additions & 3 deletions OpenLearn/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@

from flask import Flask, render_template

from OpenLearn import extensions, database
from . import views
from . import settings


def create_app():
"""Create application factory, as explained here: http://flask.pocoo.org/docs/patterns/appfactories/.
"""
app = Flask(__name__.split(".")[0])
app = Flask(__name__.split(".")[0], instance_relative_config=True)

settings.configure_app(app)

Expand All @@ -29,7 +30,7 @@ def create_app():

def register_extensions(app):
"""Register Flask extensions."""
pass
extensions.db.init_app(app)


def register_blueprints(app):
Expand Down Expand Up @@ -58,7 +59,16 @@ def register_shellcontext(app):

def shell_context():
"""Shell context objects."""
return {}
return {
"db": extensions.db,
"User": database.User,
"Quiz": database.Quiz,
"Question": database.Question,
"NumericQuestion": database.NumericQuestion,
"TextQuestion": database.TextQuestion,
"QuestionType": database.QuestionType,
"Room": database.Room
}

app.shell_context_processor(shell_context)

Expand Down
126 changes: 126 additions & 0 deletions OpenLearn/database.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
# -*- coding: utf-8 -*-
import datetime
import enum
import random
import string
from decimal import Decimal
from typing import Union, List

from sqlalchemy import func

from .extensions import db

# Alias common SQLAlchemy names
Column = db.Column
relationship = db.relationship

# Type Declarations
MString = Union[str, db.Column]
MInteger = Union[int, db.Column]
MDecimal = Union[Decimal, db.Column]
MBoolean = Union[bool, db.Column]
MDateTime = Union[datetime.datetime, db.Column]
MDate = Union[datetime.date, db.Column]


class QuestionType(enum.Enum):
Numeric = 0
Text = 1

@property
def type(self):
return {
QuestionType.Numeric: NumericQuestion,
QuestionType.Text: TextQuestion
}[self]


class User(db.Model):
id: MInteger = db.Column(db.Integer, primary_key=True)
username: MString = db.Column(db.String(25), unique=True, nullable=False)
password = db.Column(db.Binary(60), nullable=False)

quizzes: List["Quiz"] = relationship("Quiz", back_populates="owner")

created_on: MDateTime = db.Column(db.DateTime(timezone=True), nullable=False, server_default=func.now())


class Quiz(db.Model):
id: MInteger = db.Column(db.Integer, primary_key=True)
name: MString = db.Column(db.String(30), unique=True, nullable=False)

questions: List[Union["Question", "QuestionABC"]] = db.relationship('Question', back_populates="quiz",
order_by="Question.sort_index")

owner_id = db.Column(db.Integer, db.ForeignKey('user.id'))
owner = db.relationship("User", back_populates="quizzes")

created_on: MDateTime = db.Column(db.DateTime(timezone=True), nullable=False, server_default=func.now())


class Question(db.Model):
__mapper_args__ = {'polymorphic_on': "type"}

id: MInteger = db.Column(db.Integer, primary_key=True)
text: MString = db.Column(db.Text, nullable=False)
sort_index = db.Column(db.Integer, nullable=False)

type: QuestionType = db.Column(db.Enum(QuestionType), nullable=False)

quiz_id = db.Column(db.Integer, db.ForeignKey('quiz.id'), nullable=False)
quiz: Quiz = db.relationship('Quiz', back_populates="questions")

def __init__(self, *args, **kwargs):
raise NotImplementedError

def __eq__(self, other):
raise NotImplementedError


class NumericQuestion(Question):
__tablename__ = "numericQuestion"
__mapper_args__ = {'polymorphic_identity': QuestionType.Numeric}

id = Column(db.Integer, db.ForeignKey('question.id'), primary_key=True)
answer = db.Column(db.Numeric(precision=12, scale=5)) # 0000000.00000

def __init__(self, *args, **kwargs):
super(Question, self).__init__(*args, **kwargs)

def __eq__(self, other):
return other == self.answer


class TextQuestion(Question):
__tablename__ = "textQuestion"
__mapper_args__ = {'polymorphic_identity': QuestionType.Text}

id = Column(db.Integer, db.ForeignKey('question.id'), primary_key=True)
answer = db.Column(db.Text)

def __init__(self, *args, **kwargs):
super(Question, self).__init__(*args, **kwargs)

def __eq__(self, other):
return other == self.answer


class Room(db.Model):
id: MInteger = db.Column(db.Integer, primary_key=True)
active: MBoolean = db.Column(db.Boolean, default=False)
key: MString = db.Column(db.String(8), default=lambda: Room.generate_key())

controller_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
controller = db.relationship("User")

quiz_id = db.Column(db.Integer, db.ForeignKey('quiz.id'), nullable=False)
quiz: Quiz = db.relationship('Quiz')

created_on: MDateTime = db.Column(db.DateTime(timezone=True), nullable=False, server_default=func.now())

@staticmethod
def generate_key():
while True:
temp_key = ''.join(random.choices(string.ascii_uppercase + string.digits, k=8))
if not db.session.query(db.exists().where(Room.active, Room.key == temp_key)).scalar():
return temp_key
5 changes: 5 additions & 0 deletions OpenLearn/extensions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-

from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()
6 changes: 4 additions & 2 deletions OpenLearn/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@ class BaseConfig(object):
TESTING = False
VERSION = OpenLearn.__version__

SQLALCHEMY_TRACK_MODIFICATIONS = False


class DevelopmentConfig(BaseConfig):
DEBUG = True
TESTING = True
TESTING = False
VERSION = f"{OpenLearn.__version__} dev"


Expand All @@ -34,4 +36,4 @@ class ProductionConfig(BaseConfig):
def configure_app(app):
config_name = os.getenv("FLASK_ENV", "default")
app.config.from_object(config[config_name])
app.config.from_pyfile('config.cfg', silent=True)
app.config.from_pyfile('config.cfg', silent=False)
2 changes: 1 addition & 1 deletion OpenLearn/templates/layout.html
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
</main>
{% block footer %}
<footer class="siimple-footer siimple-footer--{{footer_color|default("light")}} siimple--text-center">
Designed & Built by <strong><a class="siimple-footer-link siimple-footer-link--inline siimple--color-white"
Designed & Built by <strong><a class="siimple-footer-link siimple-footer-link--inline"
href="https://github.com/j-chad">Jackson Chadfield</a></strong>
</footer>
{% endblock %}
Expand Down
8 changes: 8 additions & 0 deletions OpenLearn/templates/student/join.html
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,14 @@
#room-code-input {
text-transform: uppercase;
}

.siimple-footer-link {
color: white;
}

.siimple-footer-link:hover {
color: rgba(255, 255, 255, 0.4) !important;
}
</style>
{% endblock %}

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
---

<p align="center">
A open source web application which will enable cooperative learning with students.
An open source platform for collaborative learning.
</p>

## Built Using <a name="built_using"></a>
Expand Down

0 comments on commit d93d021

Please sign in to comment.