Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions web-app/adapters/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
# static analysis: ignore[import_failed]
from . import orm, repository
65 changes: 22 additions & 43 deletions web-app/adapters/orm.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
# static analysis: ignore[import_failed]
from sqlalchemy import Column, MetaData, Integer, String, ForeignKey, Text, Enum, Table, Boolean
from sqlalchemy.orm import registry
from sqlalchemy.orm import mapper
from sqlalchemy.orm import mapper, relationship

from domain import model

# Заглушка
# To distinguish between question types
# class QuestionTypes:
# pass


# Base = declarative_base()
mapper_registry = registry()
Expand All @@ -24,65 +20,48 @@
# Table for users
user_table = Table("users", metadata,
Column('id', Integer, primary_key=True, autoincrement=True),
Column('nickname', Text, unique=True),
Column('name', Text),
Column('surname', Text),
Column('email', Text, unique=True),
Column('password', Text))

# Table for quizzes
quiz_table = Table("quizzes", metadata,
Column('user_id', Integer, ForeignKey('user.id')),
Column('id', Integer, primary_key=True, autoincrement=True),
Column('user_id', Integer, ForeignKey('users.id', ondelete="CASCADE")),
Column('name', Text))

# Table for questions
question_table = Table("questions", metadata,
Column('id', Integer, primary_key=True, autoincrement=True),
Column('quiz_id', Integer, ForeignKey('quiz.id')),
Column('type', Enum(model.QuestionTypes)),
Column('description', Text))
Column('quiz_id', Integer, ForeignKey('quizzes.id', ondelete="CASCADE")),
Column('question_type', Text),
Column('text', Text),
Column('time', Integer))

# Table for answers
answer_table = Table("answers", metadata,
Column('id', Integer, primary_key=True, autoincrement=True),
Column('question_id', ForeignKey('question.id')),
Column('question_id', Integer, ForeignKey('questions.id', ondelete="CASCADE")),
Column('text', Text),
Column('correct_answer', Boolean))


def start_mappers():
user_mapper = mapper_registry.map_imperatively(model.User, user_table)
question_mapper = mapper_registry.map_imperatively(model.Question, question_table)
user_mapper = mapper_registry.map_imperatively(model.User, user_table)
answer_mapper = mapper_registry.map_imperatively(model.Answer, answer_table)
quiz_mapper = mapper_registry.map_imperatively(model.Quiz, quiz_table)


def create_all(engine):
metadata.bind = engine
metadata.create_all()


def delete_all(engine):
metadata.drop_all(engine)


if __name__ == '__main__':
start_mappers()
# Draft
# class User(Base):
# __tablename__ = 'user'
#
# id = Column(Integer, primary_key=True, autoincrement=True)
# nickname = Column(Text, unique=True)
# email = Column(Text, unique=True)
# password = Column(Text)
#
#
# class Quiz(Base):
# __tablename__ = 'quiz'
#
# id = Column(Integer, primary_key=True, autoincrement=True)
# user_id = Column(Integer, ForeignKey('user.id'))
# quiz_name = Column(Text)
#
#
# class Question(Base):
# __tablename__ = 'question'
#
# id = Column(Integer, primary_key=True, autoincrement=True)
# quiz_id = Column(Integer, ForeignKey('quiz.id'))
# type = Column(Enum(QuestionTypes))
# description = Column(Text)
# possible_answers = ()
#
#
# class Answers(Base):
# pass
50 changes: 40 additions & 10 deletions web-app/adapters/repository.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# from abc import ABC, abstractmethod
# static analysis: ignore[import_failed]

from domain import model

Expand All @@ -24,17 +24,25 @@ class SqlAlchemyRepository:
def __init__(self, session):
self.session = session

def add_user(self, user: model.Quiz):
def add_user(self, user: model.User):
self.session.add(user)
self.session.commit()

def get_user(self, user_id):
def get_user_by_id(self, user_id):
return self.session.query(model.User).filter_by(id=user_id).one()

def get_user_by_email(self, email):
return self.session.query(model.User).filter_by(email=email).one()

def delete_user(self, user: model.User):
self.session.delete(user)
self.session.commit()

# Working with quizzes
def add_quiz(self, quiz: model.Quiz):
def add_quiz(self, quiz: model.Quiz) -> int:
self.session.add(quiz)
self.session.commit()
return quiz.id

def get_quiz(self, quiz_id):
return self.session.query(model.Quiz).filter_by(id=quiz_id).one()
Expand All @@ -43,35 +51,57 @@ def put_quiz(self, quiz: model.Quiz):
# self.session.query(model.Quiz).f
raise NotImplemented

def delete_quiz(self, quiz_id):
self.session.query(model.Quiz).filter_by(id=quiz_id).delete(synchronize_session=False)
# TODO: deletion of questions and answers
def delete_quiz(self, quiz: model.Quiz):
self.session.delete(quiz)
self.session.commit()

def list_quizzes(self, user_id):
return self.session.query(model.User).filter_by(user_id=user_id).all()
return self.session.query(model.Quiz).filter_by(user_id=user_id).all()

# Working with questions
def add_question(self, question: model.Question):
self.session.add(question)
self.session.commit()
return question.id

def get_question(self, question_id):
return self.session.query(model.Question).filter_by(id=question_id).one()

def delete_question(self, question: model.Question):
self.session.delete(question)
self.session.commit()

def list_questions(self, quiz_id):
return self.session.query(model.Question).filter_by(quiz_id=quiz_id).all()

# Working with answers
def add_answer(self, answer: model.Answer):
self.session.add(answer)
self.session.commit()
return answer.id

def get_answer(self, answer_id):
return self.session.query(model.Answer).filter_by(id=answer_id)
return self.session.query(model.Answer).filter_by(id=answer_id).one()

def delete_answer(self, answer: model.Answer):
self.session.delete(answer)
self.session.commit()

def list_answers(self, question_id):
return self.session.query(model.Answer).filter_by(question_id=question_id)
return self.session.query(model.Answer).filter_by(question_id=question_id).all()

# -- for test
def get_users(self):
return self.session.query(model.User).all()

def get_quizzes(self):
return self.session.query(model.Quiz).all()

def get_answers(self):
return self.session.query(model.Answer).all()

def get_questions(self):
return self.session.query(model.Question).all()


# Testing Repository
Expand Down
1 change: 1 addition & 0 deletions web-app/app_start.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# static analysis: ignore[import_failed]
from entrypoints.flask_app import app

if __name__ == "__main__":
Expand Down
2 changes: 2 additions & 0 deletions web-app/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
def get_postgres_uri():
return "postgresql://test:test@postgres_db:5432/test"
1 change: 1 addition & 0 deletions web-app/domain/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
# static analysis: ignore[import_failed]
from . import model
52 changes: 40 additions & 12 deletions web-app/domain/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
# Types declaration

# For user
NickName = NewType('NickName', str)
Name = NewType('Name', str)
Surname = NewType('Surname', str)
Email = NewType('Email', str)
Password = NewType('Password', str)

Expand All @@ -18,41 +19,68 @@


class Answer:
def __init__(self, text: QuestionAnswer, is_correct: bool):
def __init__(self, question_id: int, text: QuestionAnswer, correct_answer: bool):
self.text = text
self.is_correct = is_correct
self.correct_answer = correct_answer
self.question_id = question_id

def to_dict(self):
return {
"text": self.text,
"correct_answer": self.correct_answer,
"question_id": self.question_id
}


# Possible types of question in a quiz
class QuestionTypes(enum.Enum):
poll = "polls"
poll = "poll"
quiz = "quiz"


# Question class, to store information about question:
# question type, description, possible answers, and correct answers
class Question:
def __init__(self, question_type: QuestionTypes, text: QuestionDescription, quiz_id: int):
def __init__(self, question_type: str, text: QuestionDescription, quiz_id: int, time_limit: int):
self.question_type = question_type
self.text = text
self.quiz_id = quiz_id
self.time = time_limit

# [maybe deleted]
# return next question
def next(self):
pass
def to_dict(self):
return {
"quiz_id": self.quiz_id,
"text": self.text,
"question_type": self.question_type,
"time": self.time
}


# Quiz class,
class Quiz:
def __init__(self, quiz_name: QuizName, user_id: int = 0):
self.quiz_name = quiz_name
self.name = quiz_name
self.user_id = user_id

def to_dict(self):
return {
"user_id": self.user_id,
"name": self.name
}


# User class, to manage stored in db information through nickname/email
class User:
def __init__(self, nickname: NickName, email: Email, password: Password):
self.nickname = nickname
def __init__(self, name: Name, surname: Surname, email: Email, password: Password):
self.name = name
self.surname = surname
self.email = email
self.password = password

def to_dict(self):
return {
"name": self.name,
"surname": self.surname,
"email": self.email,
"password": self.password
}
1 change: 1 addition & 0 deletions web-app/entrypoints/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# static analysis: ignore[import_failed]
1 change: 1 addition & 0 deletions web-app/entrypoints/api/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# static analysis: ignore[import_failed]
8 changes: 6 additions & 2 deletions web-app/entrypoints/api/api_initialization.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
# static analysis: ignore[import_failed]
from entrypoints.api.resource import AnswerResource, QuizResource, QuestionResource, UserResource

from flask_restful import Api


def api_initialization(app) -> Api:
api = Api(app)
api.add_resource(UserResource.UserResource, '/api/user/<int:user_id>')
api.add_resource(UserResource.UserRegistrationResource, '/api/user')
api.add_resource(UserResource.UserLoginResource, '/api/user/login')
api.add_resource(UserResource.UserRegistrationResource, '/api/user/register')

api.add_resource(QuizResource.QuizResource, '/api/user/<int:user_id>/quiz/<int:quiz_id>')
api.add_resource(QuizResource.QuizListResource, '/api/user/<int:user_id>/quiz')

api.add_resource(QuestionResource.QuestionResource, '/api/quiz/<int:quiz_id>/question/<int:question_id>')

return api
1 change: 1 addition & 0 deletions web-app/entrypoints/api/resource/AnswerResource.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# static analysis: ignore[import_failed]
from flask import jsonify
from flask_restful import reqparse, abort, Resource
from adapters.repository import SqlAlchemyRepository, get_repo
Expand Down
1 change: 1 addition & 0 deletions web-app/entrypoints/api/resource/QuestionResource.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# static analysis: ignore[import_failed]
from flask import jsonify
from flask_restful import reqparse, abort, Resource
from adapters.repository import SqlAlchemyRepository, get_repo
Expand Down
Loading