mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-07 18:44:08 +00:00
Merge branch 'issue511_document_evaluations' into 'master'
AccompanyingCourseWorkEdit: replace document by a new one, fix deleting See merge request Chill-Projet/chill-bundles!384
This commit is contained in:
commit
0a0243eb85
@ -11,6 +11,9 @@ and this project adheres to
|
||||
## Unreleased
|
||||
|
||||
<!-- write down unreleased development here -->
|
||||
* [person] AccompanyingCourseWorkEdit: fix deleting evaluation documents (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/546)
|
||||
* [person] AccompanyingCourseWorkEdit: download existing documents (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/512)
|
||||
* [person] AccompanyingCourseWorkEdit: replace document by a new one (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/511)
|
||||
* [person] AccompanyingPeriodWork: add referrers to work, add doctrine event listener to add logged user to referrers collection and display a referrers list in work list (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/502)
|
||||
* [person] AccompanyingPeriodWorkEvaluation: fix circular reference when serialising (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/495)
|
||||
* [person] order accompanying period by opening date in search persons, person and household period lists (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/493)
|
||||
|
@ -61,13 +61,13 @@ class StoredObject implements AsyncFileInterface, Document
|
||||
/**
|
||||
* @var int[]
|
||||
* @ORM\Column(type="json", name="iv")
|
||||
* @Serializer\Groups({"write"})
|
||||
* @Serializer\Groups({"read", "write"})
|
||||
*/
|
||||
private array $iv = [];
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="json", name="key")
|
||||
* @Serializer\Groups({"write"})
|
||||
* @Serializer\Groups({"read", "write"})
|
||||
*/
|
||||
private array $keyInfos = [];
|
||||
|
||||
|
@ -73,6 +73,7 @@ var download = (button) => {
|
||||
button.type = mimeType;
|
||||
button.textContent = labelReady;
|
||||
if (hasFilename) {
|
||||
|
||||
button.download = filename;
|
||||
if (extension !== false) {
|
||||
button.download = button.download + '.' + extension;
|
||||
@ -92,4 +93,4 @@ window.addEventListener('load', function(e) {
|
||||
initializeButtons(e.target);
|
||||
});
|
||||
|
||||
module.exports = initializeButtons;
|
||||
export { initializeButtons, download };
|
@ -1,6 +1,6 @@
|
||||
var algo = 'AES-CBC';
|
||||
import Dropzone from 'dropzone';
|
||||
var initializeDownload = require('./downloader.js');
|
||||
import { initializeButtons } from './downloader.js';
|
||||
|
||||
|
||||
/**
|
||||
@ -359,7 +359,7 @@ var insertDownloadButton = (zone, zoneData) => {
|
||||
|
||||
addBelowButton(newButton, zone, zoneData);
|
||||
//zone.appendChild(newButton);
|
||||
initializeDownload(zone);
|
||||
initializeButtons(zone);
|
||||
};
|
||||
|
||||
window.addEventListener('load', function(e) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<a class="btn btn-create" :title="$t(buttonTitle)" @click="openModal">
|
||||
<a :class="btnClasses" :title="$t(buttonTitle)" @click="openModal">
|
||||
<span>{{ $t(buttonTitle) }}</span>
|
||||
</a>
|
||||
<teleport to="body">
|
||||
@ -96,10 +96,27 @@ export default {
|
||||
Modal
|
||||
},
|
||||
i18n,
|
||||
props: [
|
||||
'buttonTitle',
|
||||
'options'
|
||||
],
|
||||
props: {
|
||||
buttonTitle: {
|
||||
type: String,
|
||||
default: 'Ajouter un document',
|
||||
},
|
||||
options: {
|
||||
type: Object,
|
||||
default: {
|
||||
maxFiles: 1,
|
||||
maxPostSize: 262144000, // 250MB
|
||||
required: false,
|
||||
}
|
||||
},
|
||||
btnClasses: {
|
||||
type: Object,
|
||||
default: {
|
||||
btn: true,
|
||||
'btn-create': true
|
||||
}
|
||||
}
|
||||
},
|
||||
emits: ['addDocument'],
|
||||
data() {
|
||||
return {
|
||||
|
@ -0,0 +1,45 @@
|
||||
<template>
|
||||
<a
|
||||
class="btn btn-download"
|
||||
:title="$t(buttonTitle)"
|
||||
:data-key=JSON.stringify(storedObject.keyInfos)
|
||||
:data-iv=JSON.stringify(storedObject.iv)
|
||||
:data-mime-type=storedObject.type
|
||||
:data-label-preparing="$t('dataLabelPreparing')"
|
||||
:data-label-ready="$t('dataLabelReady')"
|
||||
:data-temp-url-get-generator="url"
|
||||
@click.once="downloadDocument">
|
||||
</a>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { download } from '../../module/async_upload/downloader';
|
||||
|
||||
const i18n = {
|
||||
messages: {
|
||||
fr: {
|
||||
dataLabelPreparing: "Chargement...",
|
||||
dataLabelReady: "",
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default {
|
||||
name: "AddAsyncUploadDownloader",
|
||||
i18n,
|
||||
props: [
|
||||
'buttonTitle',
|
||||
'storedObject'
|
||||
],
|
||||
computed: {
|
||||
url() {
|
||||
return `/asyncupload/temp_url/generate/GET?object_name=${this.storedObject.filename}`;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
downloadDocument(e) {
|
||||
download(e.target);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -100,10 +100,8 @@ final class UserControllerTest extends WebTestCase
|
||||
$crawler = $this->client->followRedirect();
|
||||
|
||||
// Check data in the show view
|
||||
$this->assertGreaterThan(
|
||||
0,
|
||||
$crawler->filter('td:contains("Test_user")')->count(),
|
||||
'Missing element td:contains("Test user")'
|
||||
$this->assertStringContainsString(
|
||||
"Test_user", $crawler->text(), "page contains the name of the user"
|
||||
);
|
||||
|
||||
//test the auth of the new client
|
||||
@ -125,11 +123,7 @@ final class UserControllerTest extends WebTestCase
|
||||
$this->client->submit($form);
|
||||
$crawler = $this->client->followRedirect();
|
||||
// Check the element contains an attribute with value equals "Foo"
|
||||
$this->assertGreaterThan(
|
||||
0,
|
||||
$crawler->filter('[data-username="' . $username . '"]')->count(),
|
||||
'Missing element [data-username="Foo bar"]'
|
||||
);
|
||||
$this->assertResponseIsSuccessful();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -15,7 +15,6 @@ use Chill\MainBundle\Entity\User;
|
||||
use Chill\MainBundle\Pagination\PaginatorFactory;
|
||||
use Chill\MainBundle\Repository\UserRepository;
|
||||
use Chill\MainBundle\Templating\Entity\UserRender;
|
||||
use Chill\PersonBundle\Repository\AccompanyingPeriodACLAwareRepository;
|
||||
use Chill\PersonBundle\Repository\AccompanyingPeriodACLAwareRepositoryInterface;
|
||||
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
|
@ -11,6 +11,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Chill\PersonBundle\EventListener;
|
||||
|
||||
use Chill\MainBundle\Entity\User;
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork;
|
||||
use Symfony\Component\Security\Core\Security;
|
||||
|
||||
@ -25,6 +26,8 @@ class AccompanyingPeriodWorkEventListener
|
||||
|
||||
public function prePersistAccompanyingPeriodWork(AccompanyingPeriodWork $work): void
|
||||
{
|
||||
$work->addReferrer($this->security->getUser());
|
||||
if ($this->security->getUser() instanceof User) {
|
||||
$work->addReferrer($this->security->getUser());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,8 +16,9 @@ use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
|
||||
use Chill\MainBundle\Security\Resolver\CenterResolverDispatcherInterface;
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
use Symfony\Component\Security\Core\Security;
|
||||
use DateTime;
|
||||
|
||||
use Symfony\Component\Security\Core\Security;
|
||||
use function count;
|
||||
|
||||
final class AccompanyingPeriodACLAwareRepository implements AccompanyingPeriodACLAwareRepositoryInterface
|
||||
@ -55,7 +56,7 @@ final class AccompanyingPeriodACLAwareRepository implements AccompanyingPeriodAC
|
||||
)
|
||||
)
|
||||
->setParameter('user', $user)
|
||||
->setParameter('now', new \DateTime('now'))
|
||||
->setParameter('now', new DateTime('now'))
|
||||
->setParameter('draft', AccompanyingPeriod::STEP_DRAFT);
|
||||
|
||||
return $qb;
|
||||
@ -140,7 +141,7 @@ final class AccompanyingPeriodACLAwareRepository implements AccompanyingPeriodAC
|
||||
->setMaxResults($limit);
|
||||
|
||||
foreach ($orderBy as $field => $direction) {
|
||||
$qb->addOrderBy('ap.'.$field, $direction);
|
||||
$qb->addOrderBy('ap.' . $field, $direction);
|
||||
}
|
||||
|
||||
return $qb->getQuery()->getResult();
|
||||
|
@ -16,6 +16,8 @@ use Chill\PersonBundle\Entity\Person;
|
||||
|
||||
interface AccompanyingPeriodACLAwareRepositoryInterface
|
||||
{
|
||||
public function countByUserOpenedAccompanyingPeriod(?User $user): int;
|
||||
|
||||
public function findByPerson(
|
||||
Person $person,
|
||||
string $role,
|
||||
@ -25,6 +27,4 @@ interface AccompanyingPeriodACLAwareRepositoryInterface
|
||||
): array;
|
||||
|
||||
public function findByUserOpenedAccompanyingPeriod(?User $user, array $orderBy = [], int $limit = 0, int $offset = 50): array;
|
||||
|
||||
public function countByUserOpenedAccompanyingPeriod(?User $user): int;
|
||||
}
|
||||
|
@ -127,7 +127,7 @@
|
||||
</div>
|
||||
<ul class="record_actions" v-if="evaluationsForAction.length > 0">
|
||||
<li>
|
||||
<button :title="$t('add_an_evaluation')" class="btn btn-create" @click="toggleAddEvaluation"></button>
|
||||
<button :title="$t('add_an_evaluation')" class="btn btn-create" @click="toggleAddEvaluation">{{ $t('add_an_evaluation') }}</button>
|
||||
</li>
|
||||
</ul>
|
||||
<div v-else>
|
||||
|
@ -27,7 +27,7 @@
|
||||
|
||||
</li>
|
||||
<li v-if="canDelete">
|
||||
<a class="btn btn-delete" @click="modal.showModal = true" :title="$t('action.delete')"></a>
|
||||
<a class="btn btn-delete" @click="modal.showModal = true" :title="$t('action.delete')">{{ $t('delete_evaluation')}}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@ -72,7 +72,8 @@ const i18n = {
|
||||
sure: "Êtes-vous sûr?",
|
||||
sure_description: "Cette évaluation sera supprimée de cette action d'accompagnement",
|
||||
ok: "Supprimer"
|
||||
}
|
||||
},
|
||||
delete_evaluation: "Supprimer l'évaluation",
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -65,7 +65,7 @@
|
||||
<h5>{{ $t('Documents') }} :</h5>
|
||||
|
||||
<div class="flex-table">
|
||||
<div class="item-bloc" v-for="(d, i) in evaluation.documents" :key="d.key">
|
||||
<div class="item-bloc" v-for="(d, i) in evaluation.documents" :key="d.id">
|
||||
<div class="item-row">
|
||||
<div class="input-group input-group-lg mb-3">
|
||||
<div>
|
||||
@ -75,6 +75,7 @@
|
||||
type="text"
|
||||
:value="d.title"
|
||||
:id="d.id"
|
||||
:data-key="i"
|
||||
@input="onInputDocumentTitle"/>
|
||||
</div>
|
||||
</div>
|
||||
@ -84,6 +85,8 @@
|
||||
<p v-if="d.createdBy" class="createdBy">Créé par {{ d.createdBy.text }}<br/>
|
||||
Le {{ $d(ISOToDatetime(d.createdAt.datetime), 'long') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item-row">
|
||||
<div class="item-col">
|
||||
<ul class="record_actions" >
|
||||
<li v-if="d.workflows_availables.length > 0">
|
||||
@ -98,6 +101,23 @@
|
||||
@go-to-generate-workflow="goToGenerateWorkflowEvaluationDocument"
|
||||
></list-workflow-modal>
|
||||
</li>
|
||||
<li>
|
||||
<add-async-upload
|
||||
:buttonTitle="$t('replace')"
|
||||
:options="asyncUploadOptions"
|
||||
:btnClasses="{'btn': true, 'btn-edit': true}"
|
||||
@addDocument="(arg) => replaceDocument(d, arg)"
|
||||
>
|
||||
</add-async-upload>
|
||||
</li>
|
||||
<li>
|
||||
<add-async-upload-downloader
|
||||
:buttonTitle="$t('download')"
|
||||
:storedObject="d.storedObject"
|
||||
>
|
||||
</add-async-upload-downloader>
|
||||
|
||||
</li>
|
||||
<li>
|
||||
<a :href="buildEditLink(d.storedObject)" class="btn btn-wopilink"></a>
|
||||
</li>
|
||||
@ -152,6 +172,7 @@ import { mapGetters, mapState } from 'vuex';
|
||||
import PickTemplate from 'ChillDocGeneratorAssets/vuejs/_components/PickTemplate.vue';
|
||||
import {buildLink} from 'ChillDocGeneratorAssets/lib/document-generator';
|
||||
import AddAsyncUpload from 'ChillDocStoreAssets/vuejs/_components/AddAsyncUpload.vue';
|
||||
import AddAsyncUploadDownloader from 'ChillDocStoreAssets/vuejs/_components/AddAsyncUploadDownloader.vue';
|
||||
import ListWorkflowModal from 'ChillMainAssets/vuejs/_components/EntityWorkflow/ListWorkflowModal.vue';
|
||||
import {buildLinkCreate} from 'ChillMainAssets/lib/entity-workflow/api.js';
|
||||
|
||||
@ -176,7 +197,9 @@ const i18n = {
|
||||
document_upload: "Téléverser un document",
|
||||
document_title: "Titre du document",
|
||||
template_title: "Nom du template",
|
||||
browse: "Ajouter un document"
|
||||
browse: "Ajouter un document",
|
||||
replace: "Remplacer",
|
||||
download: "Télécharger le fichier existant"
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -188,6 +211,7 @@ export default {
|
||||
ckeditor: CKEditor.component,
|
||||
PickTemplate,
|
||||
AddAsyncUpload,
|
||||
AddAsyncUploadDownloader,
|
||||
ListWorkflowModal,
|
||||
},
|
||||
i18n,
|
||||
@ -274,8 +298,9 @@ export default {
|
||||
},
|
||||
onInputDocumentTitle(event) {
|
||||
const id = Number(event.target.id);
|
||||
const key = Number(event.target.dataset.key) + 1;
|
||||
const title = event.target.value;
|
||||
this.$store.commit('updateDocumentTitle', {id: id, evaluationKey: this.evaluation.key, title: title});
|
||||
this.$store.commit('updateDocumentTitle', {id: id, key: key, evaluationKey: this.evaluation.key, title: title});
|
||||
},
|
||||
addDocument(storedObject) {
|
||||
let document = {
|
||||
@ -285,6 +310,14 @@ export default {
|
||||
};
|
||||
this.$store.commit('addDocument', {key: this.evaluation.key, document: document});
|
||||
},
|
||||
replaceDocument(oldDocument, storedObject) {
|
||||
let document = {
|
||||
type: 'accompanying_period_work_evaluation_document',
|
||||
storedObject: storedObject,
|
||||
title: oldDocument.title
|
||||
};
|
||||
this.$store.commit('replaceDocument', {key: this.evaluation.key, document: document, oldDocument: oldDocument});
|
||||
},
|
||||
removeDocument(document) {
|
||||
if (window.confirm("Êtes-vous sûr·e de vouloir supprimer le document qui a pour titre \"" + document.title +"\" ?")) {
|
||||
this.$store.commit('removeDocument', {key: this.evaluation.key, document: document});
|
||||
|
@ -136,9 +136,9 @@ const store = createStore({
|
||||
endDate: e.endDate !== null ? ISOToDatetime(e.endDate.datetime) : null,
|
||||
maxDate: e.maxDate !== null ? ISOToDatetime(e.maxDate.datetime) : null,
|
||||
warningInterval: e.warningInterval !== null ? intervalISOToDays(e.warningInterval) : null,
|
||||
documents: e.documents.map((d, dindex) => {
|
||||
documents: e.documents.map((d, docIndex) => {
|
||||
return Object.assign(d, {
|
||||
key: index
|
||||
key: docIndex
|
||||
});
|
||||
}),
|
||||
});
|
||||
@ -218,13 +218,26 @@ const store = createStore({
|
||||
}));
|
||||
},
|
||||
removeDocument(state, {key, document}) {
|
||||
let evaluations = state.evaluationsPicked.find(e => e.key === key);
|
||||
|
||||
if (evaluations === undefined) {
|
||||
let evaluation = state.evaluationsPicked.find(e => e.key === key);
|
||||
if (evaluation === undefined) {
|
||||
return;
|
||||
}
|
||||
evaluation.documents = evaluation.documents.filter(d => d.key !== document.key);
|
||||
},
|
||||
replaceDocument(state, payload) {
|
||||
let evaluation = state.evaluationsPicked.find(e => e.key === payload.key);
|
||||
if (evaluation === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
evaluations.documents = evaluations.documents.filter(d => d.key !== document.key);
|
||||
let newDocument = Object.assign(
|
||||
payload.document, {
|
||||
key: evaluation.documents.length + 1,
|
||||
workflows_availables: state.work.workflows_availables_evaluation_documents,
|
||||
workflows: [],
|
||||
}
|
||||
);
|
||||
evaluation.documents = evaluation.documents.map(d => d.id === payload.oldDocument.id ? newDocument : d);
|
||||
},
|
||||
addEvaluation(state, evaluation) {
|
||||
let e = {
|
||||
@ -326,8 +339,13 @@ const store = createStore({
|
||||
state.isPosting = st;
|
||||
},
|
||||
updateDocumentTitle(state, payload) {
|
||||
state.evaluationsPicked.find(e => e.key === payload.evaluationKey)
|
||||
if (payload.id === 0) {
|
||||
state.evaluationsPicked.find(e => e.key === payload.evaluationKey)
|
||||
.documents.find(d => d.key === payload.key).title = payload.title;
|
||||
} else {
|
||||
state.evaluationsPicked.find(e => e.key === payload.evaluationKey)
|
||||
.documents.find(d => d.id === payload.id).title = payload.title;
|
||||
}
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
@ -424,6 +442,9 @@ const store = createStore({
|
||||
removeDocument({commit}, payload) {
|
||||
commit('removeDocument', payload);
|
||||
},
|
||||
replaceDocument({commit}, payload) {
|
||||
commit('replaceDocument', payload);
|
||||
},
|
||||
submit({ getters, state, commit }, callback) {
|
||||
let
|
||||
payload = getters.buildPayload,
|
||||
|
Loading…
x
Reference in New Issue
Block a user