Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
SIGPUBLIC
unantes-orientation-active
Commits
fc891225
Commit
fc891225
authored
Sep 27, 2021
by
Kevin Robert
Browse files
UNAPLLYREC-7 : Ajout de la question ouverte.
parent
a58061e6
Changes
13
Hide whitespace changes
Inline
Side-by-side
src/main/java/com/unantes/orientactive/converter/bean/Item.java
View file @
fc891225
...
...
@@ -20,7 +20,8 @@ import java.util.UUID;
@JsonSubTypes
.
Type
(
value
=
MultipleChoiceItem
.
class
,
name
=
"radio"
),
@JsonSubTypes
.
Type
(
value
=
MultipleChoiceItem
.
class
,
name
=
"checkbox"
),
@JsonSubTypes
.
Type
(
value
=
PictureItem
.
class
,
name
=
"picture"
),
@JsonSubTypes
.
Type
(
value
=
ButtonItem
.
class
,
name
=
"button"
)
@JsonSubTypes
.
Type
(
value
=
ButtonItem
.
class
,
name
=
"button"
),
@JsonSubTypes
.
Type
(
value
=
OpenQuestion
.
class
,
name
=
"openquestion"
)
})
// @formatter:on
public
abstract
class
Item
implements
ApiConvertible
{
...
...
src/main/java/com/unantes/orientactive/navigation/ScreenNavigationService.java
View file @
fc891225
...
...
@@ -83,10 +83,10 @@ public class ScreenNavigationService {
final
ScreenDTO
nextScreen
;
if
(
CollectionUtils
.
isEmpty
(
screen
.
getNextScreenExpressions
()))
{
nextScreen
=
getDefaultNextScreen
(
screen
);
LOGGER
.
debug
(
"Prochain écran (valeur par défaut) : {}"
,
nextScreen
.
getReference
());
LOGGER
.
debug
(
"Prochain écran (valeur par défaut) :
'
{}
'
"
,
nextScreen
.
getReference
());
}
else
{
nextScreen
=
getNextScreenFromExpressions
(
expression
,
screen
);
LOGGER
.
debug
(
"Prochain écran (à partir des expressions) : {}"
,
nextScreen
.
getReference
());
LOGGER
.
debug
(
"Prochain écran (à partir des expressions) :
'
{}
'
"
,
nextScreen
.
getReference
());
}
filterScreenItems
(
nextScreen
,
expression
);
return
nextScreen
;
...
...
src/main/java/com/unantes/orientactive/repository/FormRepository.java
View file @
fc891225
...
...
@@ -33,7 +33,7 @@ public interface FormRepository extends JpaRepository<Form, Long>, RoleRepositor
* @param id id du formulaire
* @return La liste des références des questions.
*/
@Query
(
value
=
"select screenitems ->> 'reference' reference from screen sc cross join lateral json_array_elements(sc.items) screenitems where sc.form_id = :formId and screenitems ->> 'type' in ('radio', 'checkbox')"
,
nativeQuery
=
true
)
@Query
(
value
=
"select screenitems ->> 'reference' reference from screen sc cross join lateral json_array_elements(sc.items) screenitems where sc.form_id = :formId and screenitems ->> 'type' in ('radio', 'checkbox'
, 'openquestion'
)"
,
nativeQuery
=
true
)
List
<
String
>
getFormQuestionReferences
(
@Param
(
"formId"
)
Long
id
);
/**
...
...
src/main/java/com/unantes/orientactive/web/api/FormApiDelegateImpl.java
View file @
fc891225
package
com.unantes.orientactive.web.api
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Optional
;
import
java.util.UUID
;
import
java.util.stream.Collectors
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.springframework.http.HttpStatus
;
import
org.springframework.http.ResponseEntity
;
import
org.springframework.stereotype.Service
;
import
org.springframework.transaction.annotation.Transactional
;
import
org.springframework.web.context.request.NativeWebRequest
;
import
com.unantes.orientactive.converter.ServiceConverter
;
import
com.unantes.orientactive.converter.bean.AnswerElements
;
import
com.unantes.orientactive.navigation.NavigationService
;
...
...
@@ -22,9 +8,24 @@ import com.unantes.orientactive.service.dto.FormDTO;
import
com.unantes.orientactive.service.dto.ScreenDTO
;
import
com.unantes.orientactive.web.api.model.AnswersAPI
;
import
com.unantes.orientactive.web.api.model.FormAPI
;
import
com.unantes.orientactive.web.api.model.ItemAPI
;
import
com.unantes.orientactive.web.api.model.MultipleChoiceItemAPI
;
import
com.unantes.orientactive.web.api.model.OpenQuestionItemAPI
;
import
com.unantes.orientactive.web.api.model.ProgressAPI
;
import
com.unantes.orientactive.web.api.model.ScreenAPI
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.springframework.http.HttpStatus
;
import
org.springframework.http.ResponseEntity
;
import
org.springframework.stereotype.Service
;
import
org.springframework.transaction.annotation.Transactional
;
import
org.springframework.web.context.request.NativeWebRequest
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Optional
;
import
java.util.UUID
;
import
java.util.stream.Collectors
;
/**
* Implementation du delegate chargé de répondre aux requêtes via l'API des formulaires.
...
...
@@ -162,37 +163,59 @@ public class FormApiDelegateImpl implements FormApiDelegate {
private
void
addAnswers
(
final
String
sessionId
,
final
Long
screenId
,
final
FormAPI
formAPI
)
{
AnswerDTO
answer
=
navigationService
.
retrieveAnswerForScreen
(
sessionId
,
screenId
);
List
<
AnswerElements
>
answers
=
answer
.
getAnswerElements
();
valuate
Selected
Answer
(
formAPI
.
getScreen
(),
answers
);
valuateAnswer
s
(
formAPI
.
getScreen
(),
answers
);
}
/**
* Value l
a propriété de sélection des différents items ayant des choix en fonction des réponses saisies par l'utilisateur
.
* Value l
es réponses de l'utilisateur aux différents items de l'écran.
.
*
* @param screenAPI Le modèle d'API de l'écran.
* @param answers Les réponses.
*/
private
void
valuateSelectedAnswer
(
final
ScreenAPI
screenAPI
,
final
List
<
AnswerElements
>
answers
)
{
// @formatter:off
private
void
valuateAnswers
(
final
ScreenAPI
screenAPI
,
final
List
<
AnswerElements
>
answers
)
{
final
Map
<
String
,
List
<
String
>>
questionsAnswers
=
answers
.
stream
()
.
filter
(
answerElements
->
answerElements
.
getAnswer
()
!=
null
)
.
collect
(
Collectors
.
toMap
(
AnswerElements:
:
getQuestionReference
,
AnswerElements:
:
getAnswer
));
// @formatter:on
//TODO : code déjà présent dans ScreenNavigationService
// @formatter:off
final
List
<
MultipleChoiceItemAPI
>
questions
=
screenAPI
.
getItems
()
.
stream
()
.
collect
(
Collectors
.
toMap
(
AnswerElements:
:
getQuestionReference
,
AnswerElements:
:
getAnswer
));
valuateSelectedAnswer
(
screenAPI
.
getItems
(),
questionsAnswers
);
valuateOpenQuestionAnswers
(
screenAPI
.
getItems
(),
questionsAnswers
);
}
/**
* Sélectionne les cases à cauchées saisies par l'utilisateur.
*
* @param items Les items de l'écran.
* @param answers Les réponses de l'utilisateur.
*/
public
void
valuateSelectedAnswer
(
final
List
<
ItemAPI
>
items
,
final
Map
<
String
,
List
<
String
>>
answers
)
{
final
List
<
MultipleChoiceItemAPI
>
questions
=
items
.
stream
()
.
filter
(
MultipleChoiceItemAPI
.
class
::
isInstance
)
.
map
(
MultipleChoiceItemAPI
.
class
::
cast
)
.
collect
(
Collectors
.
toList
());
// @formatter:on
//TODO : il faut utiliser MultipleChoiceItem; lui ajouter une abstraction Question et une méthode qui permet de traiter une réponse
for
(
MultipleChoiceItemAPI
question
:
questions
)
{
if
(
questionsA
nswers
.
containsKey
(
question
.
getReference
()))
{
List
<
String
>
questionAnswers
=
questionsA
nswers
.
get
(
question
.
getReference
());
if
(
a
nswers
.
containsKey
(
question
.
getReference
()))
{
List
<
String
>
questionAnswers
=
a
nswers
.
get
(
question
.
getReference
());
question
.
getChoices
().
stream
().
filter
(
choice
->
questionAnswers
.
contains
(
choice
.
getValue
())).
forEach
(
choice
->
choice
.
setSelected
(
true
));
}
}
}
/**
* Ajout des réponses apportées aux questions ouvertes par l'utilisateur.
*
* @param items Les items de l'écran.
* @param answers Les réponses de l'utilisateur.
*/
public
void
valuateOpenQuestionAnswers
(
final
List
<
ItemAPI
>
items
,
final
Map
<
String
,
List
<
String
>>
answers
)
{
final
List
<
OpenQuestionItemAPI
>
openQuestions
=
items
.
stream
()
.
filter
(
OpenQuestionItemAPI
.
class
::
isInstance
)
.
map
(
OpenQuestionItemAPI
.
class
::
cast
)
.
collect
(
Collectors
.
toList
());
for
(
OpenQuestionItemAPI
question
:
openQuestions
)
{
if
(
answers
.
containsKey
(
question
.
getReference
()))
{
final
List
<
String
>
questionAnswers
=
answers
.
get
(
question
.
getReference
());
question
.
setAnswer
(
questionAnswers
.
get
(
0
));
}
}
}
}
src/main/resources/swagger/api.yml
View file @
fc891225
...
...
@@ -309,6 +309,19 @@ components:
type
:
string
description
:
Style du bouton.
example
:
btn--medium
OpenQuestionItemAPI
:
allOf
:
-
$ref
:
'
#/components/schemas/ItemAPI'
-
type
:
object
properties
:
question
:
type
:
string
description
:
La question ouverte.
example
:
Est-ce que ce questionnaire vous a été utile ?
answer
:
type
:
string
description
:
La réponse.
example
:
Oui.
ChoiceAPI
:
properties
:
label
:
...
...
src/main/webapp/app/components/screen-item/item-edit.component.ts
View file @
fc891225
...
...
@@ -8,6 +8,7 @@ import Button from '@/components/screen-item/items/button/button-edit.vue';
import
Choices
from
'
@/components/screen-item/items/choices/choices-edit.vue
'
;
import
Message
from
'
@/components/screen-item/items/message/message-edit.vue
'
;
import
Picture
from
'
@/components/screen-item/items/picture/picture-edit.vue
'
;
import
OpenQuestion
from
'
@/components/screen-item/items/openquestion/openquestion-edit.vue
'
;
import
OaInput
from
'
@/components/forms/input/oa-input.vue
'
;
import
OaCheckbox
from
'
@/components/forms/checkbox/oa-checkbox.vue
'
;
...
...
@@ -58,7 +59,7 @@ export default class ItemEdit extends Vue {
let
title
:
string
;
if
(
this
.
item
.
type
===
'
button
'
)
{
title
=
this
.
item
.
text
;
}
else
if
(
this
.
item
.
type
===
'
radio
'
||
this
.
item
.
type
===
'
checkbox
'
)
{
}
else
if
(
this
.
item
.
type
===
'
radio
'
||
this
.
item
.
type
===
'
checkbox
'
||
this
.
item
.
type
===
'
openquestion
'
)
{
title
=
this
.
item
.
question
;
}
else
if
(
this
.
item
.
type
===
'
message
'
)
{
title
=
this
.
removeTags
(
this
.
item
.
content
);
...
...
@@ -95,6 +96,8 @@ export default class ItemEdit extends Vue {
return
Message
;
}
else
if
(
this
.
item
.
type
===
'
picture
'
)
{
return
Picture
;
}
else
if
(
this
.
item
.
type
===
'
openquestion
'
)
{
return
OpenQuestion
;
}
else
{
return
null
;
}
...
...
src/main/webapp/app/components/screen-item/items/openquestion/openquestion-edit.component.ts
0 → 100644
View file @
fc891225
import
{
Component
}
from
'
vue-property-decorator
'
;
import
{
mixins
}
from
'
vue-class-component
'
;
import
ItemMixin
from
'
@/components/screen-item/items/item-edit.mixin
'
;
import
OaInput
from
'
@/components/forms/input/oa-input.vue
'
;
@
Component
({
components
:
{
OaInput
,
}
})
export
default
class
OpenQuestionEdit
extends
mixins
(
ItemMixin
)
{
}
src/main/webapp/app/components/screen-item/items/openquestion/openquestion-edit.vue
0 → 100644
View file @
fc891225
<
template
>
<div>
<oa-input
:label=
"$t('screen.item.openquestion.label')"
:value=
"item.question"
required=
"true"
@
update=
"editItem(
{ question: $event })" />
</div>
</
template
>
<
script
lang=
"ts"
src=
"./openquestion-edit.component.ts"
></
script
>
src/main/webapp/app/components/screen-toolbar/screen-toolbar.vue
View file @
fc891225
...
...
@@ -23,6 +23,12 @@
@
click=
"addNewItem('button')"
:title=
"$t('screen.toolbar.buttons.button')"
></oa-button>
<oa-button
variant=
"icon"
icon-name=
"text-box"
@
click=
"addNewItem('openquestion')"
:title=
"$t('screen.toolbar.buttons.button')"
></oa-button>
<!-- Dropdown-->
<!--
<div
class=
"relative group ml-4"
>
-->
<!--
<button-->
...
...
src/main/webapp/app/front/components/openquestion/openquestion.component.ts
0 → 100644
View file @
fc891225
import
AbstractFrontComponent
from
'
@/front/components/common/abstract-front.component
'
;
import
Component
from
'
vue-class-component
'
;
import
{
OpenAnswer
}
from
"
@/front/model/answer-front.model
"
;
@
Component
export
default
class
OpenQuestion
extends
AbstractFrontComponent
{
constructor
()
{
super
();
let
initValue
=
this
.
item
.
answer
?
this
.
item
.
answer
:
''
;
this
.
$store
.
commit
(
'
addAnswer
'
,
new
OpenAnswer
(
this
.
item
.
reference
,
[
initValue
]));
}
public
get
question
():
any
{
return
this
.
item
.
question
;
}
public
updateAnswer
(
event
):
void
{
let
value
=
event
.
target
.
value
;
if
(
value
)
{
this
.
$store
.
commit
(
'
updateAnswer
'
,
{
questionReference
:
this
.
item
.
reference
,
answer
:
[
value
]
});
}
}
}
src/main/webapp/app/front/components/openquestion/openquestion.vue
0 → 100644
View file @
fc891225
<
template
>
<div>
<fieldset
id=
"question-0"
class=
"form__fieldset"
>
<legend
class=
"form__legend"
>
{{
item
.
question
}}
</legend>
<textarea
@
change=
"updateAnswer"
:value=
"item.answer"
></textarea>
</fieldset>
</div>
</
template
>
<
script
lang=
"ts"
src=
"./openquestion.component.ts"
></
script
>
src/main/webapp/app/front/model/answer-front.model.ts
View file @
fc891225
...
...
@@ -13,3 +13,11 @@ export class SelectAnswer implements IAnswerFront {
return
!
this
.
required
||
(
this
.
required
&&
this
.
answer
.
length
>
0
);
}
}
export
class
OpenAnswer
implements
IAnswerFront
{
constructor
(
public
questionReference
:
string
,
public
answer
?:
string
[])
{}
validate
():
boolean
{
return
true
;
}
}
src/main/webapp/app/front/model/item-front.model.ts
View file @
fc891225
...
...
@@ -20,6 +20,8 @@ export class ItemFront implements IItemFront {
public
content
?:
string
,
public
text
?:
string
,
public
url
?:
string
,
public
style
?:
string
public
style
?:
string
,
public
question
?:
string
,
public
answer
?:
string
)
{}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment