Beispiel #1
0
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)
Beispiel #2
0
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)
Beispiel #3
0
 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)
Beispiel #4
0
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({})
Beispiel #5
0
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)
Beispiel #6
0
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)
Beispiel #7
0
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
Beispiel #8
0
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)
Beispiel #9
0
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)
Beispiel #10
0
 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)
Beispiel #11
0
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({})