From 7fea3dac33d9be540fd938729101381fd5161278 Mon Sep 17 00:00:00 2001 From: Mike Risher Date: Tue, 24 Sep 2019 17:41:27 +0000 Subject: [PATCH] lp1845240 port of Surveys UI from DOJO to Angular idlClass asv holds the surveys, asvq holds their questions, and asva holds the answers to those questions. The surveys are in their own module and are lazy loaded Signed-off-by: Mike Risher Modernize the survey create API by migrating it to cstore. Additionally, make it possible to modify an existing survey top-level object by setting 'ischanged' to the inbound survey. Signed-off-by: Bill Erickson LP1845240 Migrate survey create API to cstore Modernize the survey create API by migrating it to cstore. New API supports full range of isnew / ischanged / isdeleted actions on the survey, questions, and answers. Signed-off-by: Bill Erickson LP1845240 Survey API returns updated fleshed survey Signed-off-by: Bill Erickson Changes to be committed: modified: Open-ILS/src/eg2/src/app/staff/admin/local/admin-local-splash.component.html modified: Open-ILS/src/eg2/src/app/staff/admin/local/routing.module.ts new file: Open-ILS/src/eg2/src/app/staff/admin/local/survey/survey-edit.component.html new file: Open-ILS/src/eg2/src/app/staff/admin/local/survey/survey-edit.component.ts new file: Open-ILS/src/eg2/src/app/staff/admin/local/survey/survey-routing.module.ts new file: Open-ILS/src/eg2/src/app/staff/admin/local/survey/survey.component.html new file: Open-ILS/src/eg2/src/app/staff/admin/local/survey/survey.component.ts new file: Open-ILS/src/eg2/src/app/staff/admin/local/survey/survey.module.ts modified: Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Survey.pm modified: Open-ILS/tests/datasets/sql/surveys.sql Signed-off-by: Bill Erickson --- .../local/admin-local-splash.component.html | 3 +- .../app/staff/admin/local/routing.module.ts | 3 + .../local/survey/survey-edit.component.html | 124 +++++++ .../local/survey/survey-edit.component.ts | 307 ++++++++++++++++++ .../local/survey/survey-routing.module.ts | 22 ++ .../admin/local/survey/survey.component.html | 37 +++ .../admin/local/survey/survey.component.ts | 122 +++++++ .../staff/admin/local/survey/survey.module.ts | 25 ++ .../lib/OpenILS/Application/Circ/Survey.pm | 152 ++++++++- 9 files changed, 788 insertions(+), 7 deletions(-) create mode 100644 Open-ILS/src/eg2/src/app/staff/admin/local/survey/survey-edit.component.html create mode 100644 Open-ILS/src/eg2/src/app/staff/admin/local/survey/survey-edit.component.ts create mode 100644 Open-ILS/src/eg2/src/app/staff/admin/local/survey/survey-routing.module.ts create mode 100644 Open-ILS/src/eg2/src/app/staff/admin/local/survey/survey.component.html create mode 100644 Open-ILS/src/eg2/src/app/staff/admin/local/survey/survey.component.ts create mode 100644 Open-ILS/src/eg2/src/app/staff/admin/local/survey/survey.module.ts diff --git a/Open-ILS/src/eg2/src/app/staff/admin/local/admin-local-splash.component.html b/Open-ILS/src/eg2/src/app/staff/admin/local/admin-local-splash.component.html index e051d37c42..223d1817cc 100644 --- a/Open-ILS/src/eg2/src/app/staff/admin/local/admin-local-splash.component.html +++ b/Open-ILS/src/eg2/src/app/staff/admin/local/admin-local-splash.component.html @@ -63,11 +63,10 @@ + routerLink="/staff/admin/local/action/survey"> - diff --git a/Open-ILS/src/eg2/src/app/staff/admin/local/routing.module.ts b/Open-ILS/src/eg2/src/app/staff/admin/local/routing.module.ts index 39c6be7179..15a9153201 100644 --- a/Open-ILS/src/eg2/src/app/staff/admin/local/routing.module.ts +++ b/Open-ILS/src/eg2/src/app/staff/admin/local/routing.module.ts @@ -22,6 +22,9 @@ const routes: Routes = [{ }, { path: 'config/standing_penalty', component: StandingPenaltyComponent +}, { + path: 'action/survey', + loadChildren: '@eg/staff/admin/local/survey/survey.module#SurveyModule' }, { path: ':schema/:table', component: BasicAdminPageComponent diff --git a/Open-ILS/src/eg2/src/app/staff/admin/local/survey/survey-edit.component.html b/Open-ILS/src/eg2/src/app/staff/admin/local/survey/survey-edit.component.html new file mode 100644 index 0000000000..86f2f20d81 --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/admin/local/survey/survey-edit.component.html @@ -0,0 +1,124 @@ + + + + +
+
+ +
+ + +
+
+
+ + +
+ + +
+
+ + + + + + +
+
+ + + + + +
+
+ + + + +
+
+
+ + + + + +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Open-ILS/src/eg2/src/app/staff/admin/local/survey/survey-edit.component.ts b/Open-ILS/src/eg2/src/app/staff/admin/local/survey/survey-edit.component.ts new file mode 100644 index 0000000000..73b3a7bca6 --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/admin/local/survey/survey-edit.component.ts @@ -0,0 +1,307 @@ +import {Component, OnInit, ViewChild} from '@angular/core'; +import {ActivatedRoute} from '@angular/router'; +import {FmRecordEditorComponent} from '@eg/share/fm-editor/fm-editor.component'; +import {StringComponent} from '@eg/share/string/string.component'; +import {ToastService} from '@eg/share/toast/toast.service'; +import {NetService} from '@eg/core/net.service'; +import {AuthService} from '@eg/core/auth.service'; +import {IdlObject, IdlService } from '@eg/core/idl.service'; +import {NgbTabset, NgbTabChangeEvent} from '@ng-bootstrap/ng-bootstrap'; + +@Component({ + templateUrl: './survey-edit.component.html' +}) + +export class SurveyEditComponent implements OnInit { + surveyId: number; + surveyObj: IdlObject; + localArray: any; + newAnswerArray: object[]; + newQuestionText: string; + surveyTab: string; + + @ViewChild('editDialog', { static: true }) editDialog: FmRecordEditorComponent; + + @ViewChild('createAnswerString', { static: true }) + createAnswerString: StringComponent; + @ViewChild('createAnswerErrString', { static: true }) + createAnswerErrString: StringComponent; + @ViewChild('createQuestionString', { static: true }) + createQuestionString: StringComponent; + @ViewChild('createQuestionErrString', { static: true }) + createQuestionErrString: StringComponent; + + @ViewChild('updateQuestionSuccessStr', { static: true }) + updateQuestionSuccessStr: StringComponent; + @ViewChild('updateQuestionFailStr', { static: true }) + updateQuestionFailStr: StringComponent; + @ViewChild('updateAnswerSuccessStr', { static: true }) + updateAnswerSuccessStr: StringComponent; + @ViewChild('updateAnswerFailStr', { static: true }) + updateAnswerFailStr: StringComponent; + + @ViewChild('delAnswerSuccessStr', { static: true }) + delAnswerSuccessStr: StringComponent; + @ViewChild('delAnswerFailStr', { static: true }) + delAnswerFailStr: StringComponent; + @ViewChild('delQuestionSuccessStr', { static: true }) + delQuestionSuccessStr: StringComponent; + @ViewChild('delQuestionFailStr', { static: true }) + delQuestionFailStr: StringComponent; + + @ViewChild('endSurveyFailedString', { static: true }) + endSurveyFailedString: StringComponent; + @ViewChild('endSurveySuccessString', { static: true }) + endSurveySuccessString: StringComponent; + @ViewChild('questionAlreadyStartedErrString', { static: true }) + questionAlreadyStartedErrString: StringComponent; + + constructor( + private auth: AuthService, + private net: NetService, + private route: ActivatedRoute, + private toast: ToastService, + private idl: IdlService, + ) { + } + + ngOnInit() { + this.surveyId = parseInt(this.route.snapshot.paramMap.get('id'), 10); + this.updateData(); + } + + updateData() { + this.newQuestionText = ''; + this.net.request( + 'open-ils.circ', + 'open-ils.circ.survey.fleshed.retrieve', + this.surveyId + ).subscribe(res => { + this.surveyObj = res; + this.buildLocalArray(res); + return res; + }); + } + + onTabChange(event: NgbTabChangeEvent) { + this.surveyTab = event.nextId; + } + + buildLocalArray(res) { + this.localArray = []; + this.newAnswerArray = []; + const allQuestions = res.questions(); + allQuestions.forEach((question, index) => { + this.newAnswerArray.push({inputText: ''}); + question.words = question.question(); + question.answers = question.answers(); + this.localArray.push(question); + question.answers.forEach(answer => { + answer.words = answer.answer(); + }); + this.sortAnswers(index); + }); + this.sortQuestions(); + } + + sortQuestions() { + this.localArray.sort(function(a, b) { + const q1 = a.question().toUpperCase(); + const q2 = b.question().toUpperCase(); + return (q1 < q2) ? -1 : (q1 > q2) ? 1 : 0; + }); + } + + sortAnswers(questionIndex) { + this.localArray[questionIndex].answers.sort(function(a, b) { + const a1 = a.answer().toUpperCase(); + const a2 = b.answer().toUpperCase(); + return (a1 < a2) ? -1 : (a1 > a2) ? 1 : 0; + }); + } + + updateQuestion(questionToChange) { + if (this.surveyHasBegun()) { + return; + } + questionToChange.question(questionToChange.words); + questionToChange.ischanged(true); + this.net.request( + 'open-ils.circ', + 'open-ils.circ.survey.update', + this.auth.token(), this.surveyObj + ).subscribe(res => { + if (res.debug) { + this.updateQuestionFailStr.current().then(msg => this.toast.warning(msg)); + return res; + } else { + this.surveyObj = res; + this.buildLocalArray(this.surveyObj); + this.updateQuestionSuccessStr.current().then(msg => this.toast.success(msg)); + return res; + } + }); + } + + deleteQuestion(questionToDelete) { + if (this.surveyHasBegun()) { + return; + } + questionToDelete.isdeleted(true); + this.net.request( + 'open-ils.circ', + 'open-ils.circ.survey.update', + this.auth.token(), this.surveyObj + ).subscribe(res => { + if (res.debug) { + this.delQuestionFailStr.current().then(msg => this.toast.warning(msg)); + return res; + } else { + this.surveyObj = res; + this.buildLocalArray(this.surveyObj); + this.delQuestionSuccessStr.current().then(msg => this.toast.success(msg)); + return res; + } + + }); + } + + createQuestion(newQuestionText) { + if (this.surveyHasBegun()) { + return; + } + const newQuestion = this.idl.create('asvq'); + newQuestion.question(newQuestionText); + newQuestion.isnew(true); + let questionObjects = []; + questionObjects = this.surveyObj.questions(); + questionObjects.push(newQuestion); + this.surveyObj.questions(questionObjects); + this.net.request( + 'open-ils.circ', + 'open-ils.circ.survey.update', + this.auth.token(), this.surveyObj + ).subscribe(res => { + if (res.debug) { + this.newQuestionText = ''; + this.createQuestionErrString.current().then(msg => this.toast.warning(msg)); + return res; + } else { + this.surveyObj = res; + this.buildLocalArray(this.surveyObj); + this.newQuestionText = ''; + this.createQuestionString.current().then(msg => this.toast.success(msg)); + return res; + } + + }); + } + + deleteAnswer(answerObj) { + if (this.surveyHasBegun()) { + return; + } + answerObj.isdeleted(true); + this.net.request( + 'open-ils.circ', + 'open-ils.circ.survey.update', + this.auth.token(), this.surveyObj + ).subscribe(res => { + if (res.debug) { + this.delAnswerFailStr.current().then(msg => this.toast.warning(msg)); + return res; + } else { + this.surveyObj = res; + this.buildLocalArray(this.surveyObj); + this.delAnswerSuccessStr.current().then(msg => this.toast.success(msg)); + return res; + } + }); + } + + updateAnswer(answerObj) { + if (this.surveyHasBegun()) { + return; + } + answerObj.answer(answerObj.words); + answerObj.ischanged(true); + this.net.request( + 'open-ils.circ', + 'open-ils.circ.survey.update', + this.auth.token(), this.surveyObj + ).subscribe(res => { + if (res.debug) { + this.updateAnswerFailStr.current().then(msg => this.toast.warning(msg)); + return res; + } else { + this.surveyObj = res; + this.buildLocalArray(this.surveyObj); + this.updateAnswerSuccessStr.current().then(msg => this.toast.success(msg)); + return res; + } + }); + } + + createAnswer(newAnswerText, questionObj) { + // Create answer *is* allowed if survey has already begun + const questionId = questionObj.id(); + const newAnswer = this.idl.create('asva'); + newAnswer.answer(newAnswerText); + newAnswer.question(questionId); + newAnswer.isnew(true); + questionObj.answers.push(newAnswer); + this.net.request( + 'open-ils.circ', + 'open-ils.circ.survey.update', + this.auth.token(), this.surveyObj + ).subscribe(res => { + if (res.debug) { + this.createAnswerErrString.current().then(msg => this.toast.warning(msg)); + return res; + } else { + this.surveyObj = res; + this.buildLocalArray(this.surveyObj); + this.createAnswerString.current().then(msg => this.toast.success(msg)); + return res; + } + }); + } + + endSurvey() { + const today = new Date().toISOString(); + this.surveyObj.end_date(today); + this.surveyObj.ischanged(true); + // to get fm-editor to display changed date we need to set + // this.surveyObj to null temporarily + const surveyClone = this.idl.clone(this.surveyObj); + this.surveyObj = null; + this.net.request( + 'open-ils.circ', + 'open-ils.circ.survey.update', + this.auth.token(), surveyClone + ).subscribe(res => { + if (res.debug) { + this.endSurveyFailedString.current().then(msg => this.toast.warning(msg)); + return res; + } else { + this.surveyObj = res; + this.surveyObj.ischanged(false); + this.buildLocalArray(this.surveyObj); + this.endSurveySuccessString.current().then(msg => this.toast.success(msg)); + return res; + } + }); + } + + surveyHasBegun() { + const surveyStartDate = new Date(this.surveyObj.start_date()); + const now = new Date(); + if (surveyStartDate <= now) { + this.questionAlreadyStartedErrString.current().then(msg => + this.toast.warning(msg)); + return true; + } + return false; + } +} + diff --git a/Open-ILS/src/eg2/src/app/staff/admin/local/survey/survey-routing.module.ts b/Open-ILS/src/eg2/src/app/staff/admin/local/survey/survey-routing.module.ts new file mode 100644 index 0000000000..cd36869e70 --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/admin/local/survey/survey-routing.module.ts @@ -0,0 +1,22 @@ +import {NgModule} from '@angular/core'; +import {RouterModule, Routes} from '@angular/router'; +import {SurveyComponent} from './survey.component'; +import {SurveyEditComponent} from './survey-edit.component'; + +const routes: Routes = [{ + path: '', + component: SurveyComponent +}, { + path: ':id', + component: SurveyEditComponent +}]; + + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) + +export class SurveyRoutingModule {} + + diff --git a/Open-ILS/src/eg2/src/app/staff/admin/local/survey/survey.component.html b/Open-ILS/src/eg2/src/app/staff/admin/local/survey/survey.component.html new file mode 100644 index 0000000000..394d837c16 --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/admin/local/survey/survey.component.html @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Open-ILS/src/eg2/src/app/staff/admin/local/survey/survey.component.ts b/Open-ILS/src/eg2/src/app/staff/admin/local/survey/survey.component.ts new file mode 100644 index 0000000000..9865a4b3e6 --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/admin/local/survey/survey.component.ts @@ -0,0 +1,122 @@ +import {Pager} from '@eg/share/util/pager'; +import {Component, OnInit, Input, ViewChild} from '@angular/core'; +import {GridComponent} from '@eg/share/grid/grid.component'; +import {GridDataSource} from '@eg/share/grid/grid'; +import {Router} from '@angular/router'; +import {IdlObject} from '@eg/core/idl.service'; +import {PcrudService} from '@eg/core/pcrud.service'; +import {FmRecordEditorComponent} from '@eg/share/fm-editor/fm-editor.component'; +import {StringComponent} from '@eg/share/string/string.component'; +import {ToastService} from '@eg/share/toast/toast.service'; +import {NetService} from '@eg/core/net.service'; +import {AuthService} from '@eg/core/auth.service'; + +@Component({ + templateUrl: './survey.component.html' +}) + +export class SurveyComponent implements OnInit { + + gridDataSource: GridDataSource; + + @ViewChild('editDialog', { static: true }) editDialog: FmRecordEditorComponent; + @ViewChild('grid', { static: true }) grid: GridComponent; + @ViewChild('successString', { static: true }) successString: StringComponent; + @ViewChild('createString', { static: true }) createString: StringComponent; + @ViewChild('createErrString', { static: true }) createErrString: StringComponent; + @ViewChild('updateFailedString', { static: true }) updateFailedString: StringComponent; + @ViewChild('deleteFailedString', { static: true }) deleteFailedString: StringComponent; + @ViewChild('deleteSuccessString', { static: true }) deleteSuccessString: StringComponent; + @ViewChild('endSurveyFailedString', { static: true }) endSurveyFailedString: StringComponent; + @ViewChild('endSurveySuccessString', { static: true }) endSurveySuccessString: StringComponent; + + @Input() dialogSize: 'sm' | 'lg' = 'lg'; + + constructor( + private auth: AuthService, + private net: NetService, + private pcrud: PcrudService, + private toast: ToastService, + private router: Router + ) { + this.gridDataSource = new GridDataSource(); + } + + ngOnInit() { + this.gridDataSource.getRows = (pager: Pager, sort: any[]) => { + return this.pcrud.retrieveAll('asv', {}); + }; + + this.grid.onRowActivate.subscribe( + (idlThing: IdlObject) => { + const idToEdit = idlThing.id(); + this.navigateToEditPage(idToEdit); + } + ); + } + + showEditDialog(idlThing: IdlObject): Promise { + return; + } + + editSelected = (surveys: IdlObject[]) => { + const idToEdit = surveys[0].id(); + this.navigateToEditPage(idToEdit); + } + + endSurvey = (surveys: IdlObject[]) => { + const today = new Date().toISOString(); + for (let i = 0; i < surveys.length; i++) { + surveys[i].end_date(today); + this.pcrud.update(surveys[i]).toPromise().then( + async (ok) => { + this.toast.success(await this.endSurveySuccessString.current()); + }, + async (err) => { + this.toast.warning(await this.endSurveyFailedString.current()); + } + ); + } + } + + deleteSelected = (surveys: IdlObject[]) => { + for (let i = 0; i < surveys.length; i++) { + const idToDelete = surveys[i].id(); + this.net.request( + 'open-ils.circ', + 'open-ils.circ.survey.delete.cascade.override', + this.auth.token(), idToDelete + ).subscribe(res => { + this.deleteSuccessString.current() + .then(str => this.toast.success(str)); + this.grid.reload(); + return res; + }, (err) => { + this.deleteFailedString.current() + .then(str => this.toast.success(str)); + }); + } + } + + navigateToEditPage(id: any) { + this.router.navigate(['/staff/admin/local/action/survey/' + id]); + } + + createNew = () => { + this.editDialog.mode = 'create'; + this.editDialog.datetimeFields = 'start_date,end_date'; + this.editDialog.open({size: this.dialogSize}).subscribe( + ok => { + this.createString.current() + .then(str => this.toast.success(str)); + this.grid.reload(); + }, + rejection => { + if (!rejection.dismissed) { + this.createErrString.current() + .then(str => this.toast.danger(str)); + } + } + ); + } +} diff --git a/Open-ILS/src/eg2/src/app/staff/admin/local/survey/survey.module.ts b/Open-ILS/src/eg2/src/app/staff/admin/local/survey/survey.module.ts new file mode 100644 index 0000000000..21ba53f64e --- /dev/null +++ b/Open-ILS/src/eg2/src/app/staff/admin/local/survey/survey.module.ts @@ -0,0 +1,25 @@ +import {NgModule} from '@angular/core'; +import {AdminCommonModule} from '@eg/staff/admin/common.module'; +import {SurveyComponent} from './survey.component'; +import {FormsModule} from '@angular/forms'; +import {SurveyEditComponent} from './survey-edit.component'; +import {SurveyRoutingModule} from './survey-routing.module'; + +@NgModule({ + declarations: [ + SurveyComponent, + SurveyEditComponent + ], + imports: [ + AdminCommonModule, + SurveyRoutingModule, + FormsModule, + ], + exports: [ + ], + providers: [ + ] +}) + +export class SurveyModule { +} diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Survey.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Survey.pm index 3b83e36a2b..2f684c4b32 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Survey.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Survey.pm @@ -22,9 +22,155 @@ use Data::Dumper; use OpenILS::Event; use Time::HiRes qw(time); use OpenILS::Utils::CStoreEditor qw/:funcs/; +use OpenSRF::Utils::Logger qw/$logger/; my $apputils = "OpenILS::Application::AppUtils"; +__PACKAGE__->register_method( + method => "update_survey", + api_name => "open-ils.circ.survey.update", + signature => { + desc => q/Create, update, delete surveys, survey questions, and + survey answers. Relies on isnew ; isnchanged ; isdeleted + attributes of provided objects to determine outcome. + /, + params => [ + {desc => 'Authtoken', type => 'string'}, + {desc => 'Fleshed survey (asv) object', type => 'object'} + ], + return => '1 on success, event on error' + } +); + + +sub update_survey { + my ($self, $client, $auth, $survey) = @_; + + my $e = new_editor(authtoken => $auth, xact => 1); + return $e->die_event unless $e->checkauth; + return $e->die_event unless $e->allowed('ADMIN_SURVEY', $survey->owner); + + my $questions = $survey->questions || []; + + if ($survey->isdeleted) { + + $questions = $e->search_action_survey_question({survey => $survey->id}); + $_->isdeleted(1) for @$questions; + $survey->questions($questions); + + # Remove dependent data first. + return $e->die_event if update_questions($e, $survey); + return $e->die_event unless $e->delete_action_survey($survey); + + } else { + + if ($survey->isnew) { + + $survey->clear_id; + return $e->die_event unless $e->create_action_survey($survey); + + $_->isnew(1) for @$questions; + + } elsif ($survey->ischanged) { + + return $e->die_event unless $e->update_action_survey($survey); + } + + return $e->die_event if update_questions($e, $survey); + } + + $e->commit; + + $e->xact_begin; + $survey = $e->retrieve_action_survey([ + $survey->id, + { flesh => 2, + flesh_fields => {asv => ['questions'], 'asvq' => ['answers']} + } + ]); + $e->rollback; + + return $survey; +} + +# returns undef on success, event on error +sub update_questions { + my ($e, $survey) = @_; + + for my $question (@{$survey->questions}) { + + if ($question->isdeleted) { + + # Get the full set + my $answers = + $e->search_action_survey_answer({question => $question->id}); + $_->isdeleted(1) for @$answers; + $question->answers($answers); + + # Delete linked objects first. + return 1 if update_answers($e, $question); + return $e->die_event + unless $e->delete_action_survey_question($question); + + } else { + + if ($question->ischanged) { + + return $e->die_event + unless $e->update_action_survey_question($question); + + } elsif ($question->isnew) { + + $question->survey($survey->id); + $question->clear_id; + + return $e->die_event unless $e->create_action_survey_question($question); + } + + return 1 if update_answers($e, $question); + } + } + + return undef; +} + +sub update_answers { + my ($e, $question) = @_; + + return undef unless $question->answers; + + for my $answer (@{$question->answers}) { + + if ($answer->isdeleted) { + my $responses = + $e->search_action_survey_response({answer => $answer->id}); + + for my $response (@$responses) { + return $e->die_event unless + $e->delete_action_survey_response($response); + } + + return $e->die_event unless $e->delete_action_survey_answer($answer); + + } elsif ($answer->isnew) { + + $answer->clear_id; + $answer->question($question->id); + + return $e->die_event + unless $e->create_action_survey_answer($answer); + + } elsif ($answer->ischanged) { + return $e->die_event + unless $e->update_action_survey_answer($answer); + } + } + + return undef; +} + + + # - creates a new survey # expects a survey complete with questions and answers __PACKAGE__->register_method( @@ -78,10 +224,6 @@ sub _add_survey { return $survey; } -sub _update_survey { - my($session, $survey) = @_; -} - sub _add_questions { my($session, $survey) = @_; @@ -423,4 +565,4 @@ sub delete_survey { -1; +1; \ No newline at end of file -- 2.43.2