Esempio n. 1
0
def android_client_get_ics(resource_type, identifier, semester):
    """
    android client get a student or teacher's ics file

    If the student does not have privacy mode, anyone can use student number to subscribe his calendar.
    If the privacy mode is on and there is no HTTP basic authentication, return a 401(unauthorized)
    status code and the Android client ask user for password to try again.
    """
    from flask import redirect, url_for, request

    from everyclass.server.db.dao import PrivacySettings, CalendarToken, User
    from everyclass.server.rpc.api_server import APIServer
    from everyclass.server.utils.resource_identifier_encrypt import decrypt

    # 检查 URL 参数
    try:
        res_type, res_id = decrypt(identifier)
    except ValueError:
        return "Invalid identifier", 400
    if resource_type not in ('student',
                             'teacher') or resource_type != res_type:
        return "Unknown resource type", 400

    if resource_type == 'teacher':
        try:
            teacher = APIServer.get_teacher_timetable(res_id, semester)
        except Exception as e:
            return handle_exception_with_error_page(e)

        cal_token = CalendarToken.get_or_set_calendar_token(
            resource_type=resource_type,
            identifier=teacher.teacher_id,
            semester=semester)
        return redirect(
            url_for('calendar.ics_download', calendar_token=cal_token))
    else:  # student
        try:
            student = APIServer.get_student_timetable(res_id, semester)
        except Exception as e:
            return handle_exception_with_error_page(e)

        with elasticapm.capture_span('get_privacy_settings'):
            privacy_level = PrivacySettings.get_level(student.student_id)

        # get authorization from HTTP header and verify password if privacy is on
        if privacy_level != 0:
            if not request.authorization:
                return "Unauthorized (privacy on)", 401
            username, password = request.authorization
            if not User.check_password(username, password):
                return "Unauthorized (password wrong)", 401
            if student.student_id != username:
                return "Unauthorized (username mismatch)", 401

        cal_token = CalendarToken.get_or_set_calendar_token(
            resource_type=resource_type,
            identifier=student.student_id,
            semester=semester)
        return redirect(
            url_for('calendar.ics_download', calendar_token=cal_token))
Esempio n. 2
0
def cal_page(url_res_type: str, url_res_identifier: str, url_semester: str):
    """课表导出页面视图函数"""
    from flask import current_app as app, render_template, url_for, session

    from everyclass.server.db.dao import CalendarToken, PrivacySettings
    from everyclass.server.consts import MSG_400, SESSION_CURRENT_USER, MSG_401
    from everyclass.server.rpc.api_server import APIServer
    from everyclass.server.utils.resource_identifier_encrypt import decrypt
    from everyclass.server.consts import MSG_INVALID_IDENTIFIER

    # 检查 URL 参数
    try:
        res_type, res_id = decrypt(url_res_identifier)
    except ValueError:
        return render_template("common/error.html",
                               message=MSG_INVALID_IDENTIFIER)
    if url_res_type not in ('student', 'teacher') or url_res_type != res_type:
        return render_template("common/error.html", message=MSG_400)

    if url_res_type == 'student':
        try:
            student = APIServer.get_student_timetable(res_id, url_semester)
        except Exception as e:
            return handle_exception_with_error_page(e)

        # 检查是否有权限访问日历订阅页面
        with elasticapm.capture_span('get_privacy_settings'):
            privacy_level = PrivacySettings.get_level(student.student_id)
        if privacy_level != 0:
            if not (session.get(SESSION_CURRENT_USER, None)
                    and session[SESSION_CURRENT_USER].sid_orig
                    == student.student_id):
                return render_template("common/error.html", message=MSG_401)

        token = CalendarToken.get_or_set_calendar_token(
            resource_type=url_res_type,
            identifier=student.student_id,
            semester=url_semester)
    else:
        try:
            teacher = APIServer.get_teacher_timetable(res_id, url_semester)
        except Exception as e:
            return handle_exception_with_error_page(e)

        token = CalendarToken.get_or_set_calendar_token(
            resource_type=url_res_type,
            identifier=teacher.teacher_id,
            semester=url_semester)

    ics_url = url_for('calendar.ics_download',
                      calendar_token=token,
                      _external=True)
    ics_webcal = ics_url.replace('https', 'webcal').replace('http', 'webcal')

    return render_template('calendarSubscribe.html',
                           ics_url=ics_url,
                           ics_webcal=ics_webcal,
                           android_client_url=app.config['ANDROID_CLIENT_URL'])
Esempio n. 3
0
def ics_download(calendar_token: str):
    """
    iCalendar ics file download

    因为课表会更新,所以 ics 文件只能在这里动态生成,不能在日历订阅页面就生成
    """
    from collections import defaultdict

    from flask import send_from_directory
    from everyclass.server.db.dao import CalendarToken
    from everyclass.server.models import Semester
    from everyclass.server.calendar import ics_generator
    from everyclass.server.rpc.api_server import APIServer, teacher_list_to_name_str
    from everyclass.server.utils import lesson_string_to_tuple

    result = CalendarToken.find_calendar_token(token=calendar_token)
    if not result:
        return 'invalid calendar token', 404

    CalendarToken.update_last_used_time(calendar_token)

    # 获得原始学号或教工号
    if result['type'] == 'student':
        rpc_result = APIServer.get_student_timetable(result['identifier'],
                                                     result['semester'])
    else:
        # teacher
        rpc_result = APIServer.get_teacher_timetable(result['identifier'],
                                                     result['semester'])

    with elasticapm.capture_span('process_rpc_result'):
        semester = Semester(result['semester'])

        cards: Dict[Tuple[int, int], List[Dict]] = defaultdict(list)
        for card in rpc_result.cards:
            day, time = lesson_string_to_tuple(card.lesson)
            cards[(day, time)].append(
                dict(name=card.name,
                     teacher=teacher_list_to_name_str(card.teachers),
                     week=card.weeks,
                     week_string=card.week_string,
                     classroom=card.room,
                     cid=card.card_id_encoded))

    ics_generator.generate(name=rpc_result.name,
                           cards=cards,
                           semester=semester,
                           ics_token=calendar_token)

    return send_from_directory("../../calendar_files",
                               calendar_token + ".ics",
                               as_attachment=True,
                               mimetype='text/calendar')
Esempio n. 4
0
def cal_page(url_res_type: str, url_res_identifier: str, url_semester: str):
    """课表导出页面视图函数"""
    from flask import current_app as app, render_template, url_for

    from everyclass.server.db.dao import CalendarToken
    from everyclass.server.consts import MSG_400
    from everyclass.server.rpc.api_server import APIServer
    from everyclass.server.utils.resource_identifier_encrypt import decrypt
    from everyclass.server.consts import MSG_INVALID_IDENTIFIER

    # 检查 URL 参数
    try:
        res_type, res_id = decrypt(url_res_identifier)
    except ValueError:
        return render_template("common/error.html", message=MSG_INVALID_IDENTIFIER)
    if url_res_type not in ('student', 'teacher') or url_res_type != res_type:
        return render_template("common/error.html", message=MSG_400)

    if url_res_type == 'student':
        try:
            student = APIServer.get_student_timetable(res_id, url_semester)
        except Exception as e:
            return handle_exception_with_error_page(e)

        # 权限检查,如果没有权限则返回
        has_permission, return_val = check_permission(student)
        if not has_permission:
            return return_val

        token = CalendarToken.get_or_set_calendar_token(resource_type=url_res_type,
                                                        identifier=student.student_id,
                                                        semester=url_semester)
    else:
        try:
            teacher = APIServer.get_teacher_timetable(res_id, url_semester)
        except Exception as e:
            return handle_exception_with_error_page(e)

        token = CalendarToken.get_or_set_calendar_token(resource_type=url_res_type,
                                                        identifier=teacher.teacher_id,
                                                        semester=url_semester)

    ics_url = url_for('calendar.ics_download', calendar_token=token, _external=True)
    ics_webcal = ics_url.replace('https', 'webcal').replace('http', 'webcal')

    return render_template('calendarSubscribe.html',
                           ics_url=ics_url,
                           ics_webcal=ics_webcal,
                           android_client_url=app.config['ANDROID_CLIENT_URL'])
Esempio n. 5
0
def get_teacher(url_tid, url_semester):
    """老师查询"""
    from collections import defaultdict

    from everyclass.server.utils import lesson_string_to_tuple
    from everyclass.server.utils import semester_calculate
    from everyclass.server.rpc.api_server import APIServer
    from everyclass.server.utils.resource_identifier_encrypt import decrypt
    from everyclass.server.consts import MSG_INVALID_IDENTIFIER

    # decrypt identifier in URL
    try:
        _, teacher_id = decrypt(url_tid, resource_type='teacher')
    except ValueError:
        return render_template("common/error.html",
                               message=MSG_INVALID_IDENTIFIER)

    # RPC to get teacher timetable
    with elasticapm.capture_span('rpc_get_teacher_timetable'):
        try:
            teacher = APIServer.get_teacher_timetable(teacher_id, url_semester)
        except Exception as e:
            return handle_exception_with_error_page(e)

    with elasticapm.capture_span('process_rpc_result'):
        cards = defaultdict(list)
        for card in teacher.cards:
            day, time = lesson_string_to_tuple(card.lesson)
            if (day, time) not in cards:
                cards[(day, time)] = list()
            cards[(day, time)].append(card)

    empty_5, empty_6, empty_sat, empty_sun = _empty_column_check(cards)

    available_semesters = semester_calculate(url_semester, teacher.semesters)

    return render_template('query/teacher.html',
                           teacher=teacher,
                           cards=cards,
                           empty_sat=empty_sat,
                           empty_sun=empty_sun,
                           empty_6=empty_6,
                           empty_5=empty_5,
                           available_semesters=available_semesters,
                           current_semester=url_semester)