Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove ProgramsView from students learning menu; Add autofail_ungraded functional and tests #800

Merged
merged 24 commits into from
Feb 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions apps/projects/management/commands/autofail_ungraded.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import logging

from django.core.management import BaseCommand

from courses.constants import SemesterTypes
from courses.models import Semester
from learning.models import Enrollment
from learning.settings import GradeTypes

logger = logging.getLogger(__name__)

class Command(BaseCommand):
help = """
Set grade to fail for all ungraded students. Only in courses of current semester by default.
Set --prev-sem flag to apply for courses from Autumn 2020 till previous semester.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Зачем реализована такая странная логика? Почему в этом случае явно не запрашивать указание семестра?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

По аналогии с автоматическим выставлением оценок по проектам, по дефолту изменяется действующий сем. Сделано, как я понимаю, в основном в качестве защиты от дурака, чтобы невозможно было поменять наследие. Флаг придуман, чтобы можно было единократно запустить этот скрипт на проде и почистить все оценки до 2020 года. Доступа к нему нет из UI сайта.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Осень 2020 года выбран как последний важный сем. Предполагается, что не существует действующих студентов, поступивших раньше.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Если нужно запустить один раз, то это не должно потом храниться вечно в репозитории.

"""

def add_arguments(self, parser):
parser.add_argument("site", type=str, help='Site to search for enrollments')
parser.add_argument('--prev-sem', action='store_true', help='If flag is true, script works for previous '
'semesters')

def handle(self, *args, **options):
site = options["site"]
enrollments = Enrollment.objects.select_related("student_profile__branch__site", "course__semester")
current_term = Semester.get_current()
if options['prev_sem']:
term = Semester.objects.get(year=2020, type=SemesterTypes.AUTUMN)
enrollments = enrollments.filter(grade=GradeTypes.NOT_GRADED,
course__semester__lte=term,
course__semester__gt=current_term,
student_profile__branch__site__domain=site)
else:
enrollments = enrollments.filter(grade=GradeTypes.NOT_GRADED,
course__semester=current_term,
student_profile__branch__site__domain=site)
logger.info(f"Change grades of {current_term} enrollments from Not Graded to Unsatisfactory")
graded = enrollments.update(grade=GradeTypes.UNSATISFACTORY)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Хорошо бы записать куда-то в лог, что было изменено. Пусть даже операция без отката, но у тебя хоть какой-то будет механизм восстановления.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Логировать все измененные enrollments не вариант, поскольку писать в консоль 6000+ записей это не только долго, но и бессмысленно. Ибо неясно каким образом это хоть как-то использовать. Добавлю логирование семестра измененных отметок.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

логирование оно же не только в консоль, но и в файл должно быть

return str(graded)
45 changes: 45 additions & 0 deletions apps/projects/tests/test_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@
from django.core import management
from django.core.management import CommandError

from courses.constants import SemesterTypes
from courses.tests.factories import SemesterFactory
from learning.settings import GradeTypes
from learning.tests.factories import EnrollmentFactory
from notifications import NotificationTypes
from notifications.models import Notification
from projects.constants import (
Expand All @@ -17,6 +20,7 @@
from projects.tests.factories import (
ProjectFactory, ProjectStudentFactory, ReportingPeriodFactory
)
from core.tests.factories import SiteFactory


@pytest.mark.django_db
Expand Down Expand Up @@ -49,6 +53,47 @@ def test_autograde_projects(settings):
assert project_student.final_grade == ProjectStudent.GRADES.CREDIT


@pytest.mark.django_db
@pytest.mark.parametrize("prev_sem, current_grade, previous_grade, enrollment_2020_grade, enrollment_2018_grade",
[(False, GradeTypes.UNSATISFACTORY, GradeTypes.NOT_GRADED, GradeTypes.NOT_GRADED,
GradeTypes.NOT_GRADED),
(True, GradeTypes.NOT_GRADED, GradeTypes.UNSATISFACTORY, GradeTypes.UNSATISFACTORY,
GradeTypes.NOT_GRADED)])
def test_autofail_ungraded(settings, prev_sem, current_grade, previous_grade, enrollment_2020_grade,
enrollment_2018_grade):
settings.LANGUAGE_CODE = 'ru'
current_term = SemesterFactory.create_current()
previous_term = SemesterFactory.create_prev(current_term)
term_2020_autumn = SemesterFactory(year=2020, type=SemesterTypes.AUTUMN)
term_2018_autumn = SemesterFactory(year=2018, type=SemesterTypes.AUTUMN)
site = SiteFactory()
out = StringIO()

current_enrollment = EnrollmentFactory(course__semester=current_term)
previous_enrollment = EnrollmentFactory(course__semester=previous_term)
enrollment_2020 = EnrollmentFactory(course__semester=term_2020_autumn)
enrollment_2018 = EnrollmentFactory(course__semester=term_2018_autumn)

assert current_enrollment.grade == GradeTypes.NOT_GRADED
assert previous_enrollment.grade == GradeTypes.NOT_GRADED
assert enrollment_2020.grade == GradeTypes.NOT_GRADED
assert enrollment_2018.grade == GradeTypes.NOT_GRADED

management.call_command("autofail_ungraded", site, prev_sem=prev_sem, stdout=out)

assert out.getvalue().strip() != "0"

current_enrollment.refresh_from_db()
previous_enrollment.refresh_from_db()
enrollment_2020.refresh_from_db()
enrollment_2018.refresh_from_db()

assert current_enrollment.grade == current_grade
assert previous_enrollment.grade == previous_grade
assert enrollment_2020.grade == enrollment_2020_grade
assert enrollment_2018.grade == enrollment_2018_grade


@pytest.mark.django_db
def test_projects_notifications(settings, mocker):
settings.LANGUAGE_CODE = 'ru'
Expand Down
8 changes: 8 additions & 0 deletions apps/staff/templates/staff/exports.html
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,14 @@ <h4 class="list-group-item-heading">Оценки по проектам, {% trans
</ul>
</div>
</div>
<h2>Незачеты</h2>
<div class="list-group">
<div class="list-group-item">
<h4 class="list-group-item-heading">Невыставленные оценки по курсам, {% trans current_term.type %} {{ current_term.year }}</h4>
<p><a href="{% url 'staff:autofail_ungraded' %}" class="btn btn-primary btn-wide"
onclick="return confirm('Вы уверены? Это действие нельзя обратить')">Превратить в незачеты </a></p>
</div>
</div>
<a name="will-graduate"></a>
<h2 class="content-title">Будущий выпуск</h2>
<div class="list-group">
Expand Down
6 changes: 4 additions & 2 deletions apps/staff/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@
OfficialDiplomasCSVView, OfficialDiplomasListView, OfficialDiplomasTeXView,
ProgressReportForSemesterView, ProgressReportFullView, StudentFacesView,
StudentSearchCSVView, StudentSearchView, SurveySubmissionsReportView,
SurveySubmissionsStatsView, WillGraduateStatsReportView, autograde_projects,
create_alumni_profiles
SurveySubmissionsStatsView, WillGraduateStatsReportView
)

from staff.views import autograde_projects, autofail_ungraded, create_alumni_profiles

app_name = 'staff'


Expand Down Expand Up @@ -64,6 +65,7 @@ def to_url(self, value):

path('commands/create-alumni-profiles/', create_alumni_profiles, name='create_alumni_profiles'), # deprecated
path('commands/autograde-projects/', autograde_projects, name='autograde_projects'),
path('commands/autofail_ungraded/', autofail_ungraded, name='autofail_ungraded'),

path('course-participants/', CourseParticipantsIntersectionView.as_view(), name='course_participants_intersection'),

Expand Down
12 changes: 12 additions & 0 deletions apps/staff/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,18 @@ def autograde_projects(request):
messages.error(request, str(e))
return HttpResponseRedirect(reverse("staff:exports"))

def autofail_ungraded(request):
if not request.user.is_curator:
return HttpResponseForbidden()
try:
graded = call_command("autofail_ungraded", request.site)
messages.success(
request, f"Операция выполнена успешно.<br>" f"Выставлено незачетов: {graded}"
atolstikov marked this conversation as resolved.
Show resolved Hide resolved
)
except CommandError as e:
messages.error(request, str(e))
return HttpResponseRedirect(reverse("staff:exports"))


# FIXME: replace with staff.api.views.CreateAlumniProfiles (already tested) - needs to write js part
def create_alumni_profiles(request: HttpRequest):
Expand Down
3 changes: 2 additions & 1 deletion lk_yandexdataschool_ru/menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@
MenuItem(pgettext_lazy("menu", "Полезное"), '/learning/useful/', weight=60),
MenuItem(pgettext_lazy("menu", "Кодекс чести"), '/learning/hc/', weight=70),
MenuItem(pgettext_lazy("menu", "Программы обучения"), '/learning/programs/', weight=70),
MenuItem(pgettext_lazy("menu", "Проекты организаторов"), '/learning/internships/', weight=80),
# Commented to return fast in autumn semester
# MenuItem(pgettext_lazy("menu", "Проекты организаторов"), '/learning/internships/', weight=80),
Dmi4er4 marked this conversation as resolved.
Show resolved Hide resolved
],
permissions=(
"learning.view_study_menu",
Expand Down
1 change: 1 addition & 0 deletions lk_yandexdataschool_ru/pytest.ini
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@ filterwarnings =
ignore:smart_text\(\) is deprecated in favor:PendingDeprecationWarning
ignore:The providing_args argument is deprecated:PendingDeprecationWarning
ignore:'.*' defines default_app_config = '.*':PendingDeprecationWarning
ignore::DeprecationWarning