Beispiel #1
0
def legacy_get_ics(student_id, semester_str):
    """
    legacy iCalendar endpoint

    query the student first, if the student is not privacy protected, redirect to new ics. else return 401.

    this route is bad. however, many users have already been using it. breaking experience is bad. so we have
    to keep the route here for now. and (maybe) remove it in the future.
    """
    from flask import current_app as app, abort, redirect, url_for

    from everyclass.server.db.dao import PrivacySettingsDAO, CalendarTokenDAO
    from everyclass.server.utils.rpc import HttpRpc
    from everyclass.server.db.model import Semester

    # fix parameters
    place = student_id.find('-')
    semester_str = student_id[place + 1:len(student_id)] + '-' + semester_str
    student_id = student_id[:place]

    semester = Semester(semester_str)

    with elasticapm.capture_span('rpc_search'):
        rpc_result = HttpRpc.call_with_error_page('{}/v1/search/{}'.format(
            app.config['API_SERVER_BASE_URL'], student_id),
                                                  retry=True)
        if isinstance(rpc_result, str):
            return rpc_result
        api_response = rpc_result

    if len(api_response['student']) != 1:
        # bad request
        return abort(400)

    if semester.to_str() not in api_response['student'][0]['semester']:
        return abort(400)

    with elasticapm.capture_span('get_privacy_settings'):
        privacy_settings = PrivacySettingsDAO.get_level(
            api_response['student'][0]['sid_orig'])

    if privacy_settings != 0:
        # force user to get a calendar token when the user is privacy-protected but accessed through legacy interface
        return "Visit {} to get your calendar".format(
            url_for("main.main")), 401
    else:
        token = CalendarTokenDAO.get_or_set_calendar_token(
            resource_type="student",
            identifier=api_response['student'][0]['sid_orig'],
            semester=semester.to_str())
        return redirect(url_for('calendar.ics_download', calendar_token=token))
Beispiel #2
0
def generate(name: str, courses: Dict[Tuple[int, int], List[Dict]],
             semester: Semester, ics_token: str):
    """
    生成 ics 文件并保存到目录

    :param name: 姓名
    :param courses: 参与的课程
    :param semester: 当前导出的学期
    :param ics_token: ics 令牌
    :return: None
    """
    semester_string = semester.to_str(simplify=True)
    semester = semester.to_tuple()

    # 创建 calender 对象
    cal = Calendar()
    cal.add('prodid', '-//Admirable//EveryClass//EN')
    cal.add('version', '2.0')
    cal.add('calscale', 'GREGORIAN')
    cal.add('method', 'PUBLISH')
    cal.add('X-WR-CALNAME', name + '的' + semester_string + '课表')
    cal.add('X-WR-TIMEZONE', 'Asia/Shanghai')

    # 时区
    tzc.add_component(tzs)
    cal.add_component(tzc)

    # 创建 events
    for time in range(1, 7):
        for day in range(1, 8):
            if (day, time) in courses:
                for course in courses[(day, time)]:
                    for week in course['week']:
                        dtstart = _get_datetime(week, day,
                                                get_time(time)[0], semester)
                        dtend = _get_datetime(week, day,
                                              get_time(time)[1], semester)

                        if dtstart.year == 1984:
                            continue

                        cal.add_component(
                            _build_event(course_name=course['name'],
                                         times=(dtstart, dtend),
                                         classroom=course['classroom'],
                                         teacher=course['teacher'],
                                         week_string=course['week_string'],
                                         current_week=week,
                                         cid=course['cid']))

    # 写入文件
    import os

    with open(
            os.path.join(os.path.dirname(__file__),
                         '../../../calendar_files/{}.ics'.format(ics_token)),
            'w') as f:
        f.write(cal.to_ical().decode(encoding='utf-8'))
Beispiel #3
0
def get_ics(student_id, semester_str):
    """
    iCalendar service
    """
    from everyclass.server.calendar import ics_generator
    from everyclass.server.db.dao import check_if_stu_exist, get_my_semesters, get_classes_for_student
    from everyclass.server.db.model import Semester
    from everyclass.server.exceptions import IllegalSemesterException
    from everyclass.server import logger

    # TODO: generate ics here and return it to user, instead of generating .ics files in other places.
    # 临时 fix
    place = student_id.find('-')
    semester_str = student_id[place + 1:len(student_id)] + '-' + semester_str
    student_id = student_id[:place]

    # 学号检测
    if not check_if_stu_exist(student_id):
        flash("{} 学号不存在".format(student_id))
        logger.warning("[ics] {} 学号不存在".format(student_id))
        return redirect(url_for("main.main"))

    # 学期检测
    my_available_semesters, student_name = get_my_semesters(student_id)
    try:
        semester = Semester(semester_str)
    except IllegalSemesterException:
        flash("{} 学期格式错误".format(semester_str))
        logger.warning("{} 学期格式错误".format(semester_str))
        return redirect(url_for("main.main"))
    if semester not in my_available_semesters:
        flash("{} 学期不适用于此学生".format(semester_str))
        logger.warning("{} 学期不适用于此学生".format(semester_str))
        return redirect(url_for("main.main"))

    student_classes = get_classes_for_student(student_id, semester)
    ics_generator.generate(student_id, student_name, student_classes,
                           semester.to_str(simplify=True), semester.to_tuple())

    return send_from_directory("../../calendar_files",
                               student_id + "-" + semester_str + ".ics",
                               as_attachment=True,
                               mimetype='text/calendar')
def batch_generate():
    """生成当前学期所有学生的 ics 文件,每次更新当前学期数据后使用"""
    from everyclass.server import create_app
    from everyclass.server.db.dao import get_all_students, get_classes_for_student
    from everyclass.server.db.model import Semester

    config = get_config()
    now_semester = Semester(config.DEFAULT_SEMESTER)
    now_semester_str = str(now_semester)

    with create_app(offline=True).app_context():
        students = get_all_students()
        print("Total {} students".format(len(students)))
        for each in students:
            if now_semester_str in each[2]:
                print("Generate .ics for [{}]{}...".format(each[0], each[1]))
                student_classes = get_classes_for_student(
                    each[0], now_semester)
                generate(student_id=each[0],
                         student_name=each[1],
                         student_classes=student_classes,
                         semester_string=now_semester.to_str(simplify=True),
                         semester=now_semester.to_tuple())
        print("Done.")