Coverage for postrfp/buyer/api/endpoints/reports/qtextxlsx.py: 100%

37 statements  

« prev     ^ index     » next       coverage.py v7.11.0, created at 2025-10-22 21:34 +0000

1from io import BytesIO 

2 

3from sqlalchemy.orm import subqueryload 

4from sqlalchemy.orm.session import Session 

5import xlsxwriter # type: ignore[import] 

6 

7from postrfp.authorisation import perms 

8from postrfp.shared import fetch 

9from postrfp.shared.decorators import http 

10from postrfp.model.project import Project 

11from postrfp.model import QuestionInstance, Label, User 

12from postrfp.buyer.api import authorise 

13from postrfp.shared.constants import MimeTypes 

14from postrfp.shared.response import XAccelResponse 

15 

16from .responses import attachment 

17 

18 

19def _generate_xlsx(session: Session, project: Project) -> BytesIO: 

20 q = ( 

21 session.query(QuestionInstance) 

22 .filter(QuestionInstance.project == project) 

23 .options(subqueryload(QuestionInstance.question_def)) 

24 .order_by(QuestionInstance.b36_number) 

25 ) 

26 

27 buff = BytesIO() 

28 workbook = xlsxwriter.Workbook(buff, {"in_memory": True}) 

29 worksheet = workbook.add_worksheet() 

30 

31 for idx, qi in enumerate(q): 

32 worksheet.write(idx, 0, qi.number) 

33 worksheet.write(idx, 1, qi.question_def.title) 

34 elements = qi.question_def.elements 

35 col = 2 

36 for element in elements: 

37 if isinstance(element, Label): 

38 worksheet.write(idx, col, element.label) 

39 col = col + 1 

40 workbook.close() 

41 buff.seek(0) 

42 return buff 

43 

44 

45@http 

46def get_project_report_qtext( 

47 session: Session, user: User, project_id: int 

48) -> XAccelResponse: 

49 """ 

50 Generate a spreadsheet with one row for each question and one column for title and then each 

51 Label (question text) element in the question. 

52 

53 Useful for checking all the text in a questionnaire. 

54 """ 

55 project = fetch.project(session, project_id) 

56 authorise.check(user, perms.PROJECT_ACCESS, project=project, deny_restricted=True) 

57 buff = _generate_xlsx(session, project) 

58 buff.seek(0) 

59 return attachment(buff.read(), MimeTypes.XLSX.value, f"{project.title[:25]}.xlsx")