def create_repo_card(): schema = { Required('repository_id'): int, Required('side_a'): Any(str, None), Required('side_b'): Any(str, None), Required('side_c'): Any(str, None), Required('side_d'): Any(str, None), Required('side_e'): Any(str, None), Required('side_f'): Any(str, None), } payload = retrieve_payload(schema) repo = Repository.query.get(payload['repository_id']) if not repo: raise NotFoundError if repo.user_id != g.user.id: raise SignatureError card = Card(**payload) with db.auto_commit(): db.session.add(card) courses = Course.query \ .filter_by(repository_id=payload['repository_id']) \ .all() with db.auto_commit(): for course in courses: progress = CourseCardProgress(course_id=course.id, card_id=card.id) db.session.add(progress) return jsonify(card)
def create_course(): schema = { Required('repository_id'): int, Required('name'): str, Required('daily_new'): int, Required('daily_review'): int, Required('q_sides'): str, Required('a_sides'): str, } payload = retrieve_payload(schema) repo = Repository.query.get(payload['repository_id']) if not repo: raise NotFoundError if repo.private and g.user.id != repo.user_id: raise NotFoundError q_sides = payload['q_sides'] a_sides = payload['a_sides'] if not q_sides or not a_sides: raise BadRequestError(desc='Q&A should both has values') # todo: q_sides, a_sides more validation course = Course(**payload, user_id=g.user.id) # todo: make it transaction with db.auto_commit(): db.session.add(course) cards = Card.query.filter_by(repository_id=repo.id).all() with db.auto_commit(): for card in cards: progress = CourseCardProgress(course_id=course.id, card_id=card.id) db.session.add(progress) course.refresh_progress() return jsonify(course)
def refresh_progress(self): from morio.model import CourseCardProgress # clear status with db.auto_commit(): for row in CourseCardProgress.query.filter_by(course_id=self.id): row.today_status = None row.now_status = None # map hard feeling to last_time_grasped = None, hits = 0 last_feeling_hard = CourseCardProgress.query \ .filter_by(course_id=self.id, last_feel=CourseCardProgress.FEEL_HARD) \ .all() with db.auto_commit(): for item in last_feeling_hard: item.hits = 0 item.last_time_grasped = None db.session.add(item) # to learn to_learn_max = 30 progresses = CourseCardProgress.query \ .filter_by(course_id=self.id, last_time_grasped=None) \ .limit(to_learn_max) with db.auto_commit(): for progress in progresses: progress.today_status = CourseCardProgress.STATUS_TO_LEARN progress.now_status = CourseCardProgress.STATUS_TO_LEARN db.session.add(progress) # to review to_review_max = to_learn_max * 6 to_review = CourseCardProgress.query \ .filter_by(course_id=self.id) \ .filter(CourseCardProgress.last_time_grasped.isnot(None)) \ .all() to_review_measurements = list() for item in to_review: delta_day = (datetime.now() - item.last_time_grasped).days feel = item.last_feel or CourseCardProgress.FEEL_HARD m = score_for_feel(feel) \ * math.exp(-delta_day / memory_stability(item.hits - 1)) to_review_measurements.append((m, item)) to_review_measurements.sort(key=lambda x: x[0]) to_review = [x[1] for x in to_review_measurements if x[0] < 50] to_review = to_review[:to_review_max] for item in to_review: with db.auto_commit(): item.today_status = CourseCardProgress.STATUS_TO_REVIEW item.now_status = CourseCardProgress.STATUS_TO_REVIEW db.session.add(item)
def delete_repo_card(card_id): card = Card.query.get(card_id) if not card: raise NotFoundError if card.repository.user_id != g.user.id: raise SignatureError(desc='Permission denied') with db.auto_commit(): CourseCardProgress.query.filter_by(card_id=card.id).delete() db.session.delete(card) return jsonify({})
def update_repo(id_): payload = retrieve_payload(common_repo_schema) src = Repository.query.filter_by(id=id_, user_id=g.user.id) \ .first() if not src: raise NotFoundError(desc='Repo not found') with db.auto_commit(): for key, value in payload.items(): setattr(src, key, value) return jsonify(src)
def confirm_email(): schema = { Required('token'): str, } payload = retrieve_payload(schema) user = User.verify_email_token(payload['token']) if not user: raise NotFoundError(desc='Token invalid') with db.auto_commit(): user.email_confirmed = True db.session.add(user) return jsonify(user)
def register(): schema = { Required('name'): All(Match(r'^[a-zA-Z0-9_.-]+$', msg='username has invalid symbol'), Length(min=1, max=30, msg='username too long')), Required('nickname'): All( str, Length(min=1, max=30, msg='nickname too long'), ), Required('email'): All(Email(), msg='bad email format'), Required('password'): All( str, Length(min=6, msg='password less then 6 letters'), ), } payload = retrieve_payload(schema) user = User.query.filter_by(name=payload['name']).first() if user: raise ConflictException(desc='username already used') user = User.query.filter_by(email=payload['email']).first() if user: raise ConflictException(desc='email already used') avatar = pagan.Avatar(payload['name'], pagan.SHA512) upload_folder = current_app.config['UPLOAD_FOLDER'] filepath = os.path.join('avatar', uuid4().hex[:8]) avatar.save(os.path.join(upload_folder, filepath), '_.png') avatar_path = '/' + os.path.join('upload', filepath, '_.png') user = User( role=User.ROLE_USER, name=payload['name'], nickname=payload['nickname'], email=payload['email'], avatar=avatar_path, ) user.password = payload['password'] with db.auto_commit(): db.session.add(user) confirm_url = 'https://morio.cc/confirm?token={}'.format( user.gen_email_token()) mailgun.send_mail.delay( user.email, 'Welcome to Morio', html=render_template('email/confirm.html', url=confirm_url), ) resp = jsonify(user) resp.headers['Authorization'] = user.gen_auth_token() return resp
def update_me(): schema = { Optional('nickname'): All( str, Length(min=1, max=30, msg='nickname too long'), ), Optional('avatar'): All(Url, msg='invalid avatar url') } payload = retrieve_payload(schema) user = g.user for key, value in payload.items(): setattr(user, key, value) with db.auto_commit(): db.session.add(user) return jsonify(user)
def create_repo(): schema = { Required('name'): All( Match(r'^[a-zA-Z0-9_.-]+$', msg='repository name has invalid symbol'), Length(min=1, max=30, msg='repository name too long') ), **common_repo_schema, } payload = retrieve_payload(schema) src = Repository.query \ .filter_by(user_id=g.user.id, name=payload['name']) \ .first() if src: raise ConflictException(desc='repo already exist') repo = Repository(user_id=g.user.id, **payload) with db.auto_commit(): db.session.add(repo) return jsonify(repo)
def record(course_id, card_id, feel): progress = CourseCardProgress.query \ .filter_by(course_id=course_id, card_id=card_id).first() if not progress: return if feel == CourseCardProgress.FEEL_HARD: progress.now_status = CourseCardProgress.STATUS_TO_LEARN elif feel == CourseCardProgress.FEEL_EASY: progress.now_status = CourseCardProgress.STATUS_FINISHED progress.hits += 1 progress.last_time_grasped = datetime.now() elif feel == CourseCardProgress.FEEL_MEDIUM: if progress.now_status == CourseCardProgress.STATUS_TO_REVIEW: progress.now_status = CourseCardProgress.STATUS_FINISHED progress.hits += 1 progress.last_time_grasped = datetime.now() else: progress.now_status = CourseCardProgress.STATUS_TO_REVIEW progress.last_feel = feel with db.auto_commit(): db.session.add(progress)
def update_course(course_id): course = retrieve_course(course_id) with db.auto_commit(): CourseCardProgress.query.filter_by(course_id=course_id).delete() db.session.delete(course) return jsonify({})