Skip to content

Commit 2408d06

Browse files
committed
- Added few tests
- Added fields as asked
1 parent 8e92e7a commit 2408d06

File tree

7 files changed

+89
-22
lines changed

7 files changed

+89
-22
lines changed

lms/lmsdb/models.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
from lms.lmsdb import database_config
2424
from lms.models.errors import AlreadyExists
2525
from lms.utils import hashing
26+
from lms.utils.courses import generate_invite_code
2627
from lms.utils.log import log
2728

2829

@@ -137,6 +138,8 @@ class Course(BaseModel):
137138
due_date = DateTimeField(null=True)
138139
is_finished = BooleanField(default=False)
139140
close_registration_date = DateTimeField(default=datetime.now)
141+
invite_code = CharField(default=generate_invite_code, unique=True)
142+
is_public = BooleanField(default=False)
140143

141144
def __str__(self):
142145
return f'{self.name}: {self.date} - {self.due_date}'
@@ -230,11 +233,10 @@ def is_user_registered(cls, user_id: int, course_id: int) -> bool:
230233
return (
231234
cls.
232235
select()
233-
.join(User)
234-
.where(User.id == user_id)
235-
.switch()
236-
.join(Course)
237-
.where(Course.id == course_id)
236+
.where(
237+
cls.user == user_id,
238+
cls.course == course_id,
239+
)
238240
.exists()
239241
)
240242

lms/lmsweb/views.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,7 @@ def upload_page(course_id: int):
430430
return fail(422, 'No file was given.')
431431

432432
try:
433-
matches, misses = upload.new(user, file, course_id)
433+
matches, misses = upload.new(user, course_id, file)
434434
except UploadError as e:
435435
log.debug(e)
436436
return fail(400, str(e))

lms/models/upload.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ def _run_auto_checks(solution: Solution) -> None:
6464

6565

6666
def new(
67-
user: User, file: FileStorage, course_id: int,
67+
user: User, course_id: int, file: FileStorage,
6868
) -> Tuple[List[int], List[int]]:
6969
matches: List[int] = []
7070
misses: List[int] = []

lms/templates/user.html

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -27,18 +27,18 @@ <h2>{{ _('תרגילים שהוגשו:') }}</h2>
2727
</thead>
2828
<tbody>
2929
{%- for exercise in solutions.values() %}
30-
{% for solution in exercise.values() %}
31-
<tr>
32-
<th scope="row">{{ solution.exercise_number | e }}</th>
33-
<td>{{ solution.course_name | e }}</td>
34-
<td>{{ solution.exercise_name | e }}</td>
35-
<td>
36-
{{ _('נבדק') if solution.is_checked else _('הוגש') if solution.solution_id else _('לא הוגש') }}
37-
</td>
38-
<td><a href="/view/{{ solution.solution_id }}">{{ solution.solution_id }}</a></td>
39-
<td>{{ solution.get('checker', '') | e }}</a></td>
40-
</tr>
41-
{% endfor %}
30+
{% for solution in exercise.values() %}
31+
<tr>
32+
<th scope="row">{{ solution.exercise_number | e }}</th>
33+
<td>{{ solution.course_name | e }}</td>
34+
<td>{{ solution.exercise_name | e }}</td>
35+
<td>
36+
{{ _('נבדק') if solution.is_checked else _('הוגש') if solution.solution_id else _('לא הוגש') }}
37+
</td>
38+
<td><a href="/view/{{ solution.solution_id }}">{{ solution.solution_id }}</a></td>
39+
<td>{{ solution.get('checker', '') | e }}</a></td>
40+
</tr>
41+
{% endfor %}
4242
{% endfor -%}
4343
</tbody>
4444
</table>

lms/utils/courses.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import secrets
2+
import string
3+
4+
5+
def generate_invite_code(length: int = 10):
6+
return ''.join(
7+
secrets.SystemRandom().choices(
8+
string.ascii_letters + string.digits, k=10,
9+
),
10+
)

tests/test_exercises.py

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import datetime
22

3-
from lms.lmsdb.models import Course, Exercise, User
3+
from lms.lmsdb.models import Course, Exercise, Solution, User
44
from tests import conftest
55

66

@@ -31,3 +31,43 @@ def test_courses_exercises(course: Course, student_user: User):
3131

3232
conftest.create_exercise(course, 1, index=1)
3333
assert len(list(Exercise.get_objects(student_user.id))) == 1
34+
35+
@staticmethod
36+
def test_course_objects_structure(course: Course, student_user: User):
37+
# Create more courses
38+
course2 = conftest.create_course(index=1)
39+
course3 = conftest.create_course(index=2)
40+
41+
# Create another student user
42+
student_user2 = conftest.create_student_user(index=1)
43+
44+
# Assign users to courses
45+
conftest.create_usercourse(student_user, course)
46+
conftest.create_usercourse(student_user, course3)
47+
conftest.create_usercourse(student_user2, course2)
48+
49+
# Create exercises for the courses
50+
conftest.create_exercise(course, 1)
51+
ex2_c1 = conftest.create_exercise(course, 2)
52+
ex1_c2 = conftest.create_exercise(course2, 1)
53+
conftest.create_exercise(course2, 2)
54+
conftest.create_exercise(course3, 1)
55+
56+
# Create solutions
57+
conftest.create_solution(ex2_c1, student_user)
58+
conftest.create_solution(ex1_c2, student_user2)
59+
60+
# Dicts of dicts structures
61+
user_structure1 = Solution.of_user(student_user)
62+
user_structure2 = Solution.of_user(student_user2)
63+
64+
assert len(user_structure1) == 2
65+
assert len(user_structure2) == 1
66+
assert 'solution_id' in user_structure1.get('course 0').get(2)
67+
assert len(user_structure1.get('course 0')) == 2
68+
assert len(user_structure1.get('course 2')) == 1
69+
assert len(user_structure2.get('course 1')) == 2
70+
assert (
71+
user_structure2.get('course 1').get(4).get('exercise_number') == 2,
72+
)
73+
assert 'solution_id' in user_structure2.get('course 1').get(3)

tests/test_extractor.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ def setup(self):
3232
self.image_no_exercise_file = next(self.zip_files(
3333
(self.IMAGE_NO_EXERCISE,),
3434
))
35-
self.pyfile_different_course = self.get_bytes_io_py_file(
35+
self.image_bytes_io = self.get_bytes_io_file(self.IMAGE_NAME)
36+
self.pyfile_different_course = self.get_bytes_io_file(
3637
self.PY_DIFFERENT_COURSE,
3738
)
3839
self.pyfiles_files = list(self.py_files(self.PY_NAMES))
@@ -87,7 +88,7 @@ def py_files(filenames: Iterator[str]):
8788
yield open(f'{SAMPLES_DIR}/{file_name}')
8889

8990
@staticmethod
90-
def get_bytes_io_py_file(file_name) -> BytesIO:
91+
def get_bytes_io_file(file_name) -> BytesIO:
9192
with open(f'{SAMPLES_DIR}/{file_name}', 'br') as open_file:
9293
return BytesIO(open_file.read()), file_name
9394

@@ -225,6 +226,20 @@ def test_upload_another_course(
225226
})
226227
assert fail_upload_response.status_code == 400
227228

229+
def test_upload_invalid_exercise(
230+
self,
231+
course: Course,
232+
student_user: User,
233+
):
234+
conftest.create_usercourse(student_user, course)
235+
236+
client = conftest.get_logged_user(username=student_user.username)
237+
fail_upload_response = client.post(f'/upload/{course.id}', data={
238+
'file': self.image_bytes_io,
239+
})
240+
assert fail_upload_response.status_code == 400
241+
242+
228243
def test_upload_correct_course(
229244
self,
230245
course: Course,

0 commit comments

Comments
 (0)