Commit e375ce64 authored by Anton Akhmerov's avatar Anton Akhmerov
Browse files

Merge branch '518-duplicate-page-entries' into 'master'

Resolve "Duplicate page entries"

Closes #518

See merge request zesje/zesje!308
parents d9e84339 cb8c84f6
......@@ -3,10 +3,11 @@ import zipfile
from io import BytesIO
from PIL import Image
from pathlib import Path
from zesje.raw_scans import create_copy
from zesje.scans import _process_scan
from zesje.database import db, Exam, Student, Submission, Scan, Problem, ProblemWidget, ExamLayout
from zesje.raw_scans import create_copy, process_page
from zesje.scans import _process_scan, exam_metadata
from zesje.database import db, Exam, Student, Submission, Scan, Problem, ProblemWidget, ExamLayout, Copy, Page
......@@ -72,3 +73,34 @@ def test_zip_process(app_with_data, zip_file):
assert len(copy.pages) == 1
page = copy.pages[0]
assert page.number == 0
def test_reupload_page(app_with_data, zip_file):
app, exam, students = app_with_data
student = students[0]
file_name = 'old.txt'
sub = Submission(exam=exam,, validated=True)
copy = Copy(submission=sub, number=1)
page = Page(copy=copy, number=0, path=file_name)
db.session.add_all([sub, copy, page])
old_path = Path(app.config['DATA_DIRECTORY']) / file_name
old_path.write_text('old image data')
image ='RGB', (10, 10))
page_info = (, page.number, copy.number)
file_info = [f'{}-{page.number+1}-{page.copy.number}.jpg']
exam_config = exam_metadata(exam)
output_directory = app.config['DATA_DIRECTORY']
process_page(image, page_info, file_info, exam_config, output_directory)
# Only a single page entry
assert Page.query.filter(Page.copy == copy, Page.number == page.number).one()
# Path was updated and only new image still exists
assert page.path != file_name
assert not old_path.exists()
assert Path(page.abs_path).exists()
......@@ -144,6 +144,12 @@ class Page(db.Model):
def abs_path(self):
return os.path.join(current_app.config['DATA_DIRECTORY'], self.path)
def retrieve(cls, copy, page_number):
"""Retrieve an existing page or create a new one"""
return (cls.query.filter(cls.copy == copy, cls.number == page_number).one_or_none() or
cls(copy=copy, number=page_number))
Enum for the grading policy of a problem
from flask import current_app
from pathlib import Path
from .database import db, Exam, Page, Submission, Solution, Student, Copy
from .database import db, Exam, Submission, Solution, Student, Copy, Page
def process_page(image, page_info, file_info, exam_config, output_directory):
......@@ -24,13 +24,18 @@ def process_page(image, page_info, file_info, exam_config, output_directory):
image_dir = Path(output_directory) / 'submissions' / f'{copy.number}'
image_dir.mkdir(exist_ok=True, parents=True)
path = image_dir / f'page{page:02d}.jpg'
page = Page.retrieve(copy, page)
# Delete old image of this page if it exists
if page.path:
old_path = Path(page.abs_path)
if old_path.exists():
old_path.unlink() # Remove file
path = image_dir / f'page{page.number:02d}.jpg'
page.path = str(path.relative_to(current_app.config['DATA_DIRECTORY']))
return True, 'success'
......@@ -333,9 +333,10 @@ def add_to_correct_copy(image_path, barcode):
# We may have added this page in previous uploads but we only want a single
# 'Page' entry regardless
if Page.query.filter(Page.copy == copy, Page.number == is None:
rel_path = os.path.relpath(image_path, start=current_app.config['DATA_DIRECTORY'])
db.session.add(Page(path=rel_path, copy=copy,
page = Page.retrieve(copy,
if not page.path:
page.path = os.path.relpath(image_path, start=current_app.config['DATA_DIRECTORY'])
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment