removing hard-coded constants and refactoring

alex 8th May 2024 at 11:13am

I'm not sure where to head next. I know there are a few problems I must solve when porting to the raspberry. Here's one, for example:

@login_required
def serve_student_files(request, student_code: str, stint_code: str,
                        doc_type: str, doc_filename: str,
                        document_root=None, show_indexes=False):
    document_root = '/home/apinto/prog/tutogarden/tutogarden/throve/mock_student_dir/'
		[...]

This was obviously hardcoded for testing purposes, and doesn't stand a chance out of my local computer. Something like this, on the new settings configuration, could work:

STUDENTS_THROVE_DIR = str(BASE_DIR) + '/throve/mock_student_dir/'

...but, of course, this is still a test directory: I should link to the proper one. But that raises another possible problem: if the STUDENTS_THROVE_DIR is defined in Django settings, in the case I must use another directory for testing purposes — which I do — would it be possible to override it?

# this function retrieves a path from the settings
def get_path_to_student_dir(student: Student, stint: Stint = None) -> str:
    BASE = f"{settings.STUDENTS_THROVE_DIR}{student.student_code}/"
    if stint:
        return f"{BASE}{stint.stint_code}/"
    else:
        return f"{BASE}"

In fact, it is possible:

@override_settings(STUDENTS_THROVE_DIR=MOCK_EXP_DIR)
class TestGetListOfFilesInPath(TestCase):
    def setUp(self):
        self.student = Student.objects.create(student_code='le_math')
        self.stint = Stint.objects.create(student_id=self.student, stint_code='econstant_exam')

    def test_get_dict_of_files_in_stint_with_valid_files(self):
        # Assuming get_path_to_student_dir returns the correct path
        files_dict = get_dict_of_files_in_stint(self.student, self.stint)
				[...]

And I had used something similar in some other tests:

    @patch('throve.utils.get_dict_of_files_in_stint')
    def test_stint_files_view_with_valid_files(self, mock_get_dict_of_files_in_stint):
        # Mock the get_dict_of_files_in_stint function to return a predefined dictionary
        mock_get_dict_of_files_in_stint.return_value = {
            'apontamentos': ['apontamento1.pdf', 'apontamento2.PDF'],
            'exames': ['exame1.pdf'],
            'exercicios': ['exercicio1.pdf']
        }

Now, I must hook up the real tutoring content throve to the code — using the aforementioned STUDENTS_THROVE_DIR — and refactor many functions that were driven by having just one test user.

First, I'll create a new page: a proper landing page for a Student. It should list all current or past Stints. I'm keeping in mind that I'll eventually transition into a proper front-end, and so the views will be built API first.

class TestStudentStintsPageTest(TestCase):
    def setUp(self):
        self.user = User.objects.create_user(username='testuser', password='12345', first_name='Leonard', last_name='Euler')
        self.student = Student.objects.create(student_code='le_math', user=self.user)

    def test_student_stints_api_get(self):
        # Create an instance of the StintFilesView
        self.stint = Stint.objects.create(student_id=self.student, stint_code='econstant_exam')
        view = StudentStintsView()

        # Call the get method of the view with the student_code and stint_code
        response = view.get(None, student_code=self.student.student_code)

        # Assert that the response data contains the expected stints information
        self.assertEqual(response.status_code, 200)
        self.assertEqual(json.loads(response.content), {
            'student_name': 'Leonard',
            'student_code': 'le_math',
            'stints': ['econstant_exam']
            })

Something like this quickly tests the API response without necessarily tying it to a route in the back-end. After some quick templating and view generation, I managed to quickly create a User, Student, and a Stint, and all went very nicely. So I'd say this refactor is done.

With this in mind, I'd say the next step is to have a first soft-launch on the Raspberry. I wonder if that entails much work — off the top of my head, there's only some nginx to handle (wsgi deployment will be done later).