예제 #1
0
def get_courses(major_id):
    active_period = get_app_config("ACTIVE_PERIOD")
    period = Period.objects(major_id=major_id,
                            name=active_period,
                            is_detail=True).first()

    if period is None:
        period = Period.objects(major_id=major_id,
                                name=active_period,
                                is_detail=False).first()
    return (jsonify(period.serialize()), 200)
예제 #2
0
def list_timetable(bot, message: Message):
    # Fetch all periods collection
    unsorted_periods = Period().all()
    sorted_periods = Period().sort_by_weekday(unsorted_periods)
    periods_output = ""
    # foreach group in grouped results
    for weekday in sorted_periods:
        periods = sorted_periods[weekday]
        period_table = format_periods(periods, weekday)
        periods_output += f"```{period_table.get_string()}```"

    message.reply_text(periods_output,parse_mode='markdown')
예제 #3
0
    def test_serialize_with_empty_courses(self):
        period = Period(
            major_id=None,
            name="Period B",
            is_detail=True,
            courses=[],
        )

        serialized_period = period.serialize()

        assert serialized_period["name"] == period.name
        assert serialized_period["is_detail"] == period.is_detail
        assert serialized_period["courses"] == []
예제 #4
0
    def test_serialization_contains_required_keys(self):
        period = Period(
            major_id=None,
            name="Period A",
            is_detail=True,
            courses=[],
        )

        serialized_period = period.serialize()

        self.assert_serialization_contains_keys(
            keys=["name", "is_detail", "courses"], serialized_object=serialized_period
        )
예제 #5
0
    def test_serialize_with_courses(self):
        period = Period(
            major_id=None,
            name="Period C",
            is_detail=True,
            courses=[self.generate_random_course_item() for _ in range(5)],
        )

        serialized_period = period.serialize()

        assert serialized_period["name"] == period.name
        assert serialized_period["is_detail"] == period.is_detail
        for i in range(len(serialized_period["courses"])):
            assert serialized_period["courses"][i] == period.courses[i].serialize()
예제 #6
0
    def create_period(self, major_id):
        """Create dummy period with its course and class"""

        class_obj = Class(
            name='Anum - A',
            schedule_items=[
                ScheduleItem(
                    day='Senin',
                    start='09.40',
                    end='08.00',
                    room='A6.09 (Ged Baru)',
                ),
            ],
            lecturer=['Nama Dosen 1', 'Nama Dosen 2'],
        )

        course = Course(
            name=self.COURSE['name'],
            credit=self.COURSE['credit'],
            term=self.COURSE['term'],
            classes=[class_obj],
        )

        period = Period.objects().create(
            major_id=major_id,
            name=app.config["ACTIVE_PERIOD"],
            is_detail=True,
            courses=[course],
        )

        return period
예제 #7
0
    def process_sso_auth(cls, sso_profile) -> Tuple[dict, int]:
        user_name = sso_profile["username"]
        period_name = get_app_config("ACTIVE_PERIOD")
        user = User.objects(username=user_name).first()
        if user is None:
            full_name = sso_profile['attributes']['ldap_cn']
            user = User(name=full_name, username=user_name)
            try:
                user_npm = sso_profile["attributes"]["npm"]
                major_name = sso_profile["attributes"]["study_program"]
                major_kd_org = sso_profile["attributes"]["kd_org"]
            except KeyError:
                completion_id = uuid.uuid4()
                user.completion_id = completion_id
                user.save()
                return {
                    'user_name': user_name,
                    'full_name': full_name,
                    'completion_id': str(completion_id)
                }, 201
            user.npm = user_npm
            user.batch = f"20{user_npm[:2]}"
            major = Major.objects(kd_org=major_kd_org).first()
            if major is None:
                major = Major(name=major_name, kd_org=major_kd_org)
                major.save()

            user.major = major
            user.save()

        if user.completion_id is not None:
            return {
                'user_name': user.username,
                'full_name': user.name,
                'completion_id': str(user.completion_id)
            }, 201

        major = user.major

        period = Period.objects(major_id=major.id,
                                name=period_name,
                                is_detail=True).first()

        token = generate_token(user.id, user.major.id)

        result = {
            "user_id": str(user.id),
            "major_id": str(user.major.id),
            "token": token
        }

        if period is None:
            result = {**result, "err": True, "major_name": major.name}
        return result, 200
예제 #8
0
def process_sso_profile(sso_profile):
    period_name = app.config["ACTIVE_PERIOD"]

    user_npm = sso_profile["attributes"]["npm"]
    major_name = sso_profile["attributes"]["study_program"]
    major_kd_org = sso_profile["attributes"]["kd_org"]

    major = Major.objects(kd_org=major_kd_org).first()
    if major is None:
        major = Major(name=major_name, kd_org=major_kd_org)
        major.save()

    period_detail = Period.objects(
        major_id=major.id, name=period_name, is_detail=True).first()
    period_not_detail = Period.objects(
        major_id=major.id, name=period_name, is_detail=False).first()

    if period_detail is None:
        if period_not_detail is None:
            courses, is_detail = scrape_courses(major_kd_org, period_name)

            if not courses:
                result = {
                    "err": True,
                    "major_name": major_name
                }
                return result
        else:
            courses, is_detail = scrape_courses(
                major_kd_org, period_name, skip_not_detail=True)

        if courses:
            period = Period(
                major_id=major.id,
                name=period_name,
                courses=courses,
                is_detail=is_detail
            )
            period.save()

    user = User.objects(npm=user_npm).first()
    if user is None:
        user = User(
            name=sso_profile["attributes"]["ldap_cn"],
            username=sso_profile["username"],
            npm=user_npm,
            batch=f"20{user_npm[:2]}",
            major=major,
        )
        user.save()

    token = generate_token(user.id, user.major.id)
    result = {
        "user_id": str(user.id),
        "major_id": str(user.major.id),
        "token": token
    }

    return result
예제 #9
0
    def test_period_deletion(self):
        period = Period.objects().create(
            major_id=self.generate_random_major_item().save(),
            name="Period Name Old",
            is_detail=True,
            courses=[self.generate_random_course_item()],
        )

        assert len(Period.objects) == 1
        assert period in Period.objects

        period.delete()
        assert len(Period.objects) == 0
        assert period not in Period.objects
예제 #10
0
    def test_period_fields_validation(self):
        course = self.generate_random_course_item()
        test_cases = [
            {"major_id": course, "name": "Name", "courses": [course]},
            {"major_id": course, "name": "Name" * 10, "courses": [course]},
            {"major_id": course, "name": "Name" * 10, "courses": [course]},
            {"major_id": course, "name": "Name" * 10, "courses": "Courses"},
        ]

        for case in test_cases:
            with pytest.raises(ValidationError):
                Period(
                    major_id=case["major_id"],
                    name=case["name"],
                    courses=case["courses"],
                ).save()
예제 #11
0
    def test_period_creation(self):
        period = Period.objects().create(
            major_id=self.generate_random_major_item().save(),
            name="Period",
            is_detail=True,
            courses=[self.generate_random_course_item()],
        )

        periods = Period.objects
        assert len(periods) == 1

        fetched_period = periods().first()
        assert fetched_period.major_id == period.major_id
        assert fetched_period.name == "Period"
        assert fetched_period.is_detail
        assert fetched_period.courses == period.courses

        fetched_period.delete()
예제 #12
0
    def test_period_update(self):
        period = Period.objects().create(
            major_id=self.generate_random_major_item().save(),
            name="Period Name Old",
            is_detail=True,
            courses=[self.generate_random_course_item()],
        )

        new_major = self.generate_random_major_item().save()
        period.major_id = new_major
        period.name = "New Name"
        period.is_detail = False
        period.courses = []
        period.save()
        period.reload()

        assert period.major_id == new_major
        assert period.name == "New Name"
        assert not period.is_detail
        assert period.courses == []

        period.delete()
예제 #13
0
 def callback(ch, method, properties, body):
     data = json.loads(body)
     now = datetime.datetime.utcnow()
     username = data['username']
     password = data['password']
     major_id = data['major_id']
     period = Period.objects(major_id=major_id, name=active_period, is_detail=True).first()
     if period is None:
         period = Period(
             major_id=major_id,
             is_detail=True,
             name=active_period,
         )
     if period.last_update_at:
         time_difference = now - period.last_update_at
         if time_difference.seconds < 300:
             return
     courses = scrape_courses_with_credentials(active_period, username, password)
     period.courses = courses
     period.last_update_at = now
     period.save()
     app.logger.info(f"Done scrapping kd_org: {method.routing_key}; period: {active_period}; at: {now} UTC")
예제 #14
0
    def process_auth_completion(cls, data: AuthCompletionData) -> dict:
        user = User.objects(completion_id=data.completion_id).first()
        period_name = get_app_config("ACTIVE_PERIOD")
        if user is None:
            raise UserNotFound()
        base_kd_org_data = get_app_config("BASE_KD_ORG")
        try:
            kd_org_data = base_kd_org_data[data.kd_org]
        except KeyError:
            raise KdOrgNotFound()

        major = Major.objects(kd_org=data.kd_org).first()
        if major is None:
            major = Major(name=kd_org_data["study_program"],
                          kd_org=data.kd_org)
            major.save()

        user.npm = data.npm
        user.major = major
        user.completion_id = None
        user.batch = f"20{data.npm[:2]}"
        user.save()

        period = Period.objects(major_id=major.id,
                                name=period_name,
                                is_detail=True).first()

        token = generate_token(user.id, user.major.id)
        result = {
            "user_id": str(user.id),
            "major_id": str(major.id),
            "token": token
        }
        if period is None:
            result = {**result, "err": True, "major_name": major.name}
        return result
예제 #15
0
def update_courses():
    period_name = app.config["ACTIVE_PERIOD"]
    majors = Major.objects.all()
    for major in majors:
        major_kd_org = major.kd_org
        period_detail = Period.objects(major_id=major.id,
                                       name=period_name,
                                       is_detail=True).first()

        if period_detail is None:
            period_not_detail = Period.objects(major_id=major.id,
                                               name=period_name,
                                               is_detail=False).first()

            if period_not_detail is None:
                continue

            courses, is_detail = scrape_courses(major_kd_org, period_name)
            if courses:
                if is_detail:
                    period = Period(major_id=major.id,
                                    name=period_name,
                                    courses=courses,
                                    is_detail=True)
                    period.save()
                else:
                    period_not_detail.courses = courses
                    period_not_detail.save()
            continue

        courses, is_detail = scrape_courses(major_kd_org,
                                            period_name,
                                            skip_not_detail=True)

        if courses:
            period_detail.courses = courses
            period_detail.save()
예제 #16
0
def upload(profile):
    if request.method == "POST":
        if "file" not in request.files:
            flash("File error.")
            return redirect(url_for_custom("router_uploader.upload"))

        file_ = request.files["file"]

        if file_.filename == "":
            flash("File kosong.")
            return redirect(url_for_custom("router_uploader.upload"))

        if file_ and allowed_file(file_.filename):

            if not os.path.isdir(app.config["UPLOAD_FOLDER"]):
                os.mkdir(app.config["UPLOAD_FOLDER"])

            html = file_.read()
            period, kd_org = get_period_and_kd_org(html)
            role = check_uploader(profile["npm"])

            if (period == app.config["ACTIVE_PERIOD"]) and (
                    kd_org == profile["kd_org"] or role == "admin"):
                courses = create_courses(html, is_detail=True)
                if not courses:
                    flash("Error, hubungi admin. Sertakan file ini.")
                    return redirect(url_for_custom("router_uploader.upload"))

                major = Major.objects(kd_org=kd_org).first()
                if major is None:
                    flash("Login susun jadwal beneran dulu ya.")
                    return redirect(url_for_custom("router_uploader.upload"))

                instance = Period.objects(major_id=major.id,
                                          name=period,
                                          is_detail=True).first()

                if instance:
                    instance.courses = courses
                else:
                    instance = Period(major_id=major.id,
                                      name=period,
                                      courses=courses,
                                      is_detail=True)
                instance.save()

                timestamp = int(time.time())
                filename = f"{kd_org}_{timestamp}_{secure_filename(file_.filename)}"
                file_.save(os.path.join(app.config["UPLOAD_FOLDER"], filename))

            else:
                flash("Periode salah atau jurusan tidak sesuai.")
                return redirect(url_for_custom("router_uploader.upload"))

            flash("Berhasil..!!")
            return redirect(url_for_custom("router_uploader.upload"))

        flash("Gagal. File salah atau hubungi admin.")
        return redirect(url_for_custom("router_uploader.upload"))

    return render_template("upload.html", profile=profile)
예제 #17
0
def list_today_timetable(bot, message: Message):
    today = date.today().strftime('%A')
    periods = Period().today()
    period_table = format_periods(periods, today)
    message.reply_text(f"```{period_table.get_string()}```",parse_mode='markdown')