Skip to content
Snippets Groups Projects
Commit f1140d54 authored by Remco Tukker's avatar Remco Tukker
Browse files

first version of saving and retrieving answers from the database

parent 2ef109e2
No related branches found
No related tags found
1 merge request!43Feature/comp 205 create survey datamodel
import logging
#from typing import Optional
from typing import Dict, Any
from typing_extensions import Annotated
#from sqlalchemy import String
from sqlalchemy.orm import Mapped, mapped_column, relationship
from sqlalchemy.schema import ForeignKey
from sqlalchemy.types import JSON
......@@ -41,4 +39,4 @@ class Answers(db.Model):
question_year: Mapped[int_pk_fkQuestions]
question: Mapped[Questions] = relationship(lazy='joined')
answers: Mapped[json]
# completed column?? I think we need that..
\ No newline at end of file
# completed column?? I think we need that..
import json
import logging
from pathlib import Path
from typing import Any, List, Optional
from flask import Blueprint, jsonify, request
from sqlalchemy import select
from compendium_v2.db import db
from compendium_v2.db.model import NREN
from compendium_v2.db.survey_model import Questions, Answers
from compendium_v2.routes import common
from typing import Any
routes = Blueprint('survey', __name__)
......@@ -20,31 +23,77 @@ logger = logging.getLogger(__name__)
@common.require_accepts_json
def open_survey() -> Any:
entries = [entry for entry in db.session.scalars(select(Questions))]
entries2 = [entry for entry in db.session.scalars(select(Answers))]
# TODO check if the survey was already started, if so, continue with that survey:
# survey_continue = {
# "questions": entries,
# "data": "TODO",
# # TODO page number
# "unvalidated": ["TODO also take this from the db"] # TODO or maybe do it in another way..
# }
survey_start = {
"questions": entries,
"data": "TODO take from db last year",
"unvalidated": ["TODO list question names from last_year_data"] # TODO or maybe do it in another way..
# just a hardcoded year and nren for development for now
nren = db.session.execute(select(NREN).order_by(NREN.id).limit(1)).scalar_one()
year = 1988
questions = db.session.scalar(select(Questions).where(Questions.year == year))
if questions is None or questions.survey == {}:
# TODO remove this at some point, its just convenient for now while we are changing the survey model a lot
p = Path(__file__).with_name('survey_model.json')
with p.open('r') as f:
questions = json.load(f)
# TODO add some magic strings in the json (like the year) and interpolate them here
data: Optional[dict] = None
page = 0
unvalidated: List[str] = [] # or should we keep track of what _was_ validated?
answers = db.session.scalar(
select(Answers).where(Answers.question_year == year).where(Answers.nren_id == nren.id)
)
previous_answers = db.session.scalar(
select(Answers).where(Answers.question_year == year - 1).where(Answers.nren_id == nren.id)
)
if answers:
data = answers.answers["data"]
page = answers.answers["page"]
unvalidated = answers.answers["unvalidated"]
elif previous_answers:
data = previous_answers.answers["data"]
unvalidated = ["TODO everything?"]
open_survey: dict = {
"model": questions,
"data": data,
"page": page,
"unvalidated": unvalidated
}
return jsonify(survey_start)
return jsonify(open_survey)
@routes.route('/save', methods=['POST'])
@common.require_accepts_json
def save_survey() -> Any:
data = request.json
# TODO store stuff in db
# just a hardcoded year and nren for development for now
nren = db.session.execute(select(NREN).order_by(NREN.id).limit(1)).scalar_one()
year = 1988
questions = db.session.scalar(select(Questions).where(Questions.year == year))
if questions is None:
questions = Questions(year=year, survey={})
db.session.add(questions)
answers = db.session.scalar(
select(Answers).where(Answers.question_year == year).where(Answers.nren_id == nren.id)
)
if answers is None:
answers = Answers(question_year=year, nren_id=nren.id)
db.session.add(answers)
save_survey = request.json
if not save_survey:
raise Exception("Invalid format")
answers.answers = {
"data": save_survey["data"],
"page": save_survey["page"],
"unvalidated": save_survey["unvalidated"]
}
db.session.commit()
return jsonify(data), 201
return {'success': True}
import React, { useState, useEffect } from "react";
import { Model } from "survey-core";
import { Survey } from "survey-react-ui";
import "survey-core/modern.min.css";
function SurveyComponent() {
const [surveyModel, setSurveyModel] = useState<Model>();
// const surveyComplete = useCallback((sender) => {
// console.log(sender.data);
// }, []);
async function getModel()
{
const response = await fetch('/api/survey/open');
const json = await response.json();
const survey = new Model(json['model']);
if (json['data'] !== null)
{
survey.data = json['data'];
}
// survey.onComplete.add((sender, options) => {
// console.log(JSON.stringify(sender.data, null, 3));
// });
// TODO also use data and page info
// TODO also manage the list of (un)validated answers from last year
survey.onComplete.add((sender, options) => {
console.log(sender.data)
options.showSaveInProgress();
const xhr = new XMLHttpRequest();
xhr.open("POST", "/api/survey/save");
xhr.setRequestHeader("Content-Type", "application/json; charset=utf-8");
xhr.onload = xhr.onerror = function () {
if (xhr.status == 200) {
// Display the "Success" message (pass a string value to display a custom message)
options.showSaveSuccess();
// Alternatively, you can clear all messages:
// options.clearSaveMessages();
} else {
// Display the "Error" message (pass a string value to display a custom message)
options.showSaveError();
}
};
const saveData = {
data: sender.data,
page: 2,
unvalidated: []
}
xhr.send(JSON.stringify(saveData));
});
survey.onPartialSend.add((sender, options) => {
console.log(sender.data)
// TODO same as above
});
survey.onGetQuestionTitleActions.add((_, opt) => {
// opt.question TODO check what we can do with this..
console.log(opt.question.title, opt.question.value, opt.question.validators);
opt.titleActions = [
{
title: 'Validate pre-filled value',
innerCss: 'validate-pre-filled-value',
action: () => {
console.log('verified!')
},
},
];
});
setSurveyModel(survey);
}
useEffect(() => {
getModel();
}, []);
if (surveyModel)
{
return (<Survey model={surveyModel} />);
}
else
{
return (<span>loading...</span>);
}
}
export default SurveyComponent;
\ No newline at end of file
import React, { useCallback } from 'react';
import React from 'react';
import { createRoot } from 'react-dom/client';
import SurveyComponent from './SurveyComponent';
//import 'bootstrap/dist/css/bootstrap.min.css';
import 'survey-core/modern.min.css';
import surveyJson from './survey_model.json';
import { Model } from 'survey-core';
import { Survey } from 'survey-react-ui';
const container = document.getElementById('root') as HTMLElement;
const root = createRoot(container);
const survey = new Model(surveyJson);
// const surveyComplete = useCallback((sender) => {
// console.log(sender.data);
// }, []);
survey.onComplete.add((sender) => { console.log(sender.data) });
root.render(
<React.StrictMode>
<Survey model={survey} />
<SurveyComponent />
</React.StrictMode>
)
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment