Loading front/src/ReplaceStrengthenPerson.vue +181 −73 Changes for front/src/ReplaceStrengthenPerson.vue: 181 added lines, 73 removed lines. Original line number Diff line number Diff line <template> <div> <div class="overlay" v-if="mode != ''"> <div class="overlay-content" style="overflow: scroll"> <div class="overlay-content" :style="step == 1 ? 'overflow: visible;' : 'overflow: scroll;'"> <a href="#" @click.prevent="handlerCancel()" class="overlay-closer">X</a> <h1> {{ mode }} <strong>{{ person.displayname }}</strong> </h1> <div class="alert-info alert"> Remplacer <strong>{{ person.displayname }}</strong> par une autre personnes <div class="steps-bar"> <div class="step" :class="{'current': step == 1, 'done': step > 1}"> Choisir une personne </div> <div class="step" :class="{'current': step == 2, 'done': step > 2, 'futur': step < 2}"> Vérifier les affectations </div> <div class="step" :class="{'current': step == 3, 'futur': step < 3}"> Finalisation </div> </div> <div class="step-content"> <div v-if="recapPending"> <i class="icon-spinner animate-spin"></i> {{ recapPending }} <!-- Messages --> <div class="alert-info alert" v-if="pendingMessage"> <i class="animate-spin icon-spinner"></i> {{ pendingMessage }} </div> <div v-else-if="errorRecap" class="alert-danger alert"> <div v-if="errorMessage" class="alert-danger alert"> <i class="icon-attention-1"></i> <strong>Erreur</strong> : {{ errorRecap }} {{ errorMessage }} </div> <div v-else> <p>Choisissez une personne pour {{ mode }}</p> <div v-if="step == 1"> <div v-if="!replacer_id"> <p>Choisissez une personne :</p> <person-auto-completer @change="handlerSelectPerson" style="z-index: 10"/> </div> </div> <div class="alert alert-info" v-if="step1info"> {{ step1info }} </div> <nav class="buttons text-center" v-if="step == 1"> <button class="btn btn-success" @click="handlerConfirmStep1()" :class="{ 'disabled': !replacer_id }" > <i class="icon-spinner animate-spin" v-if="pendingMessage"></i> <i class="icon-angle-right" v-else></i> Vérifier les affectations </button> </nav> <section class=""> <!-- <h2>INFOS : {{ recap.infos }}</h2> --> <section class="affectations" v-if="affectations"> <section class="affectations" v-if="step == 2"> <section> <h2> <i class="icon-beaker"></i> Loading @@ -39,43 +69,41 @@ <h4><i class="icon-cubes"></i> Projets</h4> <p v-if="replacer_id"> <strong>{{ replacer }}</strong> va être ajouté dans le(s) <strong>{{ affectations.projects.length }}</strong> projet(s) suivant : va être ajouté dans le(s) <strong>{{ projects.length }}</strong> projet(s) suivant : </p> <div class="columns-3"> <div class="card xs applyable" @click="handlerSwitchApply(p)" v-for="p in affectations.projects" :class="{ 'apply': p.apply }"> v-for="p in projects" :class="{ 'apply': p.apply, 'active': p.active }"> <div class=""> <strong> <i class="icon-cubes"></i> {{ p.acronym }} {{ p.label }} </strong> <small>{{ p.label }}</small> <span class="badge bg-info on-right">{{ p.activities_count }}</span> </div> HHH <span class="cartouche xs"> {{ p.roles.join(', ') }} <span class="cartouche xs" v-for="role in p.roles" :class="{'past obsolete': !role.active, 'success': p.apply}"> {{ role.roleId }} </span> </div> </div> </section> <h3><i class="icon-cube"></i> Activités</h3> <div style="columns: 3"> <div v-for="p in activities" class="card xs applyable" <h4><i class="icon-cube"></i> Activités</h4> <div class="columns-3"> <div class="card xs applyable" @click="handlerSwitchApply(p)" :class="{ 'active': p.active, 'disabled': !p.active, 'apply': p.apply }"> <div style="border-bottom: solid thin #ccc"> v-for="p in activities" :class="{ 'apply': p.apply, 'active': p.active }"> <div class=""> <strong> <i class="icon-cube"></i> {{ p.acronym }} {{ p.label }} </strong> <em>{{ p.label }}</em> <i class="on-right" :class="'icon-status-' + p.status" :title="p.status_text"></i> </div> <small>({{ p.roles.join(', ') }})</small> <span class="cartouche xs" v-for="role in p.roles" :class="{'past obsolete': !role.active, 'success': p.apply}"> {{ role.roleId }} </span> </div> </div> </section> Loading @@ -85,14 +113,15 @@ <i class="icon-building-filled"></i> Structure </h2> <div v-for="p in structures" class="card xs applyable" @click="handlerSwitchApply(p)" :class="{'apply': p.apply }"> <strong>{{ p.label }}</strong> <small>({{ p.roles.join(', ') }})</small> <span class="cartouche xs" v-for="role in p.roles" :class="{'past obsolete': !role.active, 'success': p.apply}"> {{ role.roleId }} </span> </div> </section> <section> Loading @@ -101,54 +130,105 @@ Validation </h2> <div v-if="affectations.validations.prj"> <div v-if="validations.prj"> <h4><i class="icon-cube"></i>Validation projet</h4> <div class="card xs applyable" @click="v.apply = !v.apply; console.log('OK')" v-for="v in affectations.validations.prj" v-for="v in validations.prj" :class="{'apply': v.apply }"> <strong>{{ v.acronym }}</strong> <em>{{ v.label }}</em> </div> </div> <div v-if="affectations.validations.sci"> <div v-if="validations.sci"> <h4><i class="icon-beaker"></i>Validation scientifique</h4> <div class="card xs applyable" @click="v.apply = !v.apply" v-for="v in affectations.validations.sci" v-for="v in validations.sci" :class="{'apply': v.apply }"> <strong>{{ v.acronym }}</strong> <em>{{ v.label }}</em> </div> </div> <div v-if="affectations.validations.adm"> <div v-if="validations.adm"> <h4><i class="icon-book"></i>Validation administratif</h4> <div class="card xs applyable" @click="v.apply = !v.apply" v-for="v in affectations.validations.adm" v-for="v in validations.adm" :class="{'apply': v.apply }"> <strong>{{ v.acronym }}</strong> <em>{{ v.label }}</em> </div> </div> </section> <section> <h2> <i class="icon-calendar"></i> Hiérarchie </h2> <div> <h4><i class="icon-book"></i>Reférent(s)</h4> <p> <i class="icon-info-circled"></i> Personnes qui seront chargées de valider les déclaration <strong>Hors-lot</strong> de {{ person.displayname }}. </p> <div class="card xs person-card" v-for="p in subordinates" :class="{'apply': p.apply}"> <div class="card-title"> <img :src="'//www.gravatar.com/avatar/' +p.mailmd5 +'&s=20'" alt="" class="gravatar" width="20"> <strong> <i class="icon-user"></i> {{ p.label }} </strong> </div> <small> <i class="icon-mail"></i> {{ p.mail }} </small> </div> </div> <div> <h4><i class="icon-beaker"></i>Subordonné(s)</h4> <p> <i class="icon-info-circled"></i> Personnes pour qui <strong>{{ person.displayname }}</strong> devra valider les déclarations <strong>Hors-lot</strong> </p> <div class="card xs person-card" v-for="p in referents" :class="{'apply': p.apply}"> <div class="card-title"> <img :src="'//www.gravatar.com/avatar/' +p.mailmd5 +'&s=20'" alt="" class="gravatar" width="20"> <strong> <i class="icon-user"></i> {{ p.label }} </strong> </div> <small> <i class="icon-mail"></i> {{ p.mail }} </small> </div> </div> </section> <hr> <nav class="buttons text-center"> <button class="btn btn-success" @click="handlerConfirmReplace()"> Confirmer <nav class="buttons"> <button class="btn btn-success" @click="handlerConfirmReplace"> Terminé </button> </nav> </section> </section> </div> </div> </div> <div class="replace-strengthen-person actions text-center"> <div class="alert alert-danger"> {{ error }} </div> <button @click="handlerReplace"> <i class="icon-rewind-outline"></i> Remplacer </button> Loading @@ -161,7 +241,8 @@ <script> // MANUAL COMPILATION // node node_modules/.bin/vue-cli-service build --name ReplaceStrengthenPerson --dest ../public/js/oscar/dist/ReplaceStrengthenPerson --no-clean --formats umd,umd-min --target lib src/ReplaceStrengthenPerson.vue; // node node_modules/.bin/vue-cli-service build --name ReplaceStrengthenPerson --dest ../public/js/oscar/dist/ --no-clean --formats umd,umd-min --target lib src/ReplaceStrengthenPerson.vue import PersonAutoCompleter from "./components/PersonAutoCompleter"; export default { Loading @@ -178,10 +259,10 @@ export default { urlReplace: { required: true }, urlStrengthen: { urlAffectation: { required: true }, affectations: { urlStrengthen: { required: true } }, Loading @@ -193,19 +274,29 @@ export default { recapPending: "", errorRecap: "", error: "", step: 1, pendingMessage: "", errorMessage: "", replacer: "", replacer_id: null, step1info: "", projects: {}, activities: {}, structures: {}, validations: {} validations: {}, referents: {}, subordinates: {} } }, methods: { handlerReplace() { this.mode = 'Remplacer'; this.loadingMessage = "Chargement de l'aperçu"; }, handlerSwitchApply(item) { Loading @@ -219,17 +310,30 @@ export default { * @param e */ handlerSelectPerson(e) { console.log("handlerSelectPerson"); this.replacer = e.displayname; this.replacer_id = e.id; this.step1info = "Remplacer " + this.person.displayname + " par " + this.replacer; }, this.recap = { "replacer_id": e.id, "infos": "Remplacer " + this.person.displayname + " par " + e.displayname, "dump": this.person }; console.log(e); handlerConfirmStep1(){ this.pendingMessage = "Chargement des affectations..."; this.$http.get(this.urlAffectation+"?person=" + this.replacer_id).then( ok => { this.step = 2; this.projects = ok.body.affectations.projects; this.activities = ok.body.affectations.activities; this.structures = ok.body.affectations.structures; this.validations = ok.body.affectations.validations; this.referents = ok.body.affectations.referents; this.subordinates = ok.body.affectations.subordinates; }, ko => { this.errorMessage = ko.body; } ).then( () => { this.pendingMessage = ""; }); }, handlerConfirmReplace() { Loading @@ -239,45 +343,49 @@ export default { 'activities': this.activities, 'structures': this.structures, 'validations': this.validations, 'subordinates': this.subordinates, 'referents': this.referents, 'replacer_id': this.replacer_id }; console.log('OUT', out); this.recapPending = "Remplacement..."; this.pendingMessage = "Remplacement..."; this.step = 3; data.append("out", JSON.stringify(out)); this.$http.post(this.urlReplace, data).then( this.$http.post(this.urlAffectation, data).then( ok => { document.location.refresh(); document.location.reload(); }, ko => { if (ko.status == 403) { this.errorRecap = "Non-autorisé"; this.errorMessage = "Non-autorisé"; } else { if (ko.body.error) { this.errorRecap = "Erreur : " + ko.body.error; this.errorMessage = "Erreur : " + ko.body.error; } else { this.errorRecap = ko.body; this.errorMessage = ko.body; } } } ).then( foo => this.recapPending = ""); ).then( foo => { this.pendingMessage = ""; }) }, handlerCancel() { this.recapPending = ""; this.errorRecap = ""; this.recap = ""; this.step = 1; this.errorMessage = ""; this.mode = ""; this.replacer_id = null; this.replacer = ""; this.step1info = ""; }, }, // Lifecycle mounted() { console.log("mounted"); this.projects = this.affectations.projects; this.activities = this.affectations.activities; this.structures = this.affectations.structures; this.validations = this.affectations.validations; // amazing void content } } </script> No newline at end of file module/Oscar/config/module.config.php +1 −1 Changes for module/Oscar/config/module.config.php: 1 added line, 1 removed line. Original line number Diff line number Diff line Loading @@ -248,7 +248,7 @@ return array( 'privileges' => \Oscar\Provider\Privileges::PERSON_INDEX ], [ 'controller' => 'Person', 'action' => ['edit', 'new', 'merge', 'organizationRole', 'notificationPerson', 'notificationPersonGenerate'], 'action' => ['edit', 'new', 'merge', 'organizationRole', 'notificationPerson', 'notificationPersonGenerate', 'affectation'], 'privileges' => \Oscar\Provider\Privileges::PERSON_EDIT ], Loading module/Oscar/config/routes.yml +7 −0 Changes for module/Oscar/config/routes.yml: 7 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -605,6 +605,13 @@ person: defaults: action: access affectation: type: segment options: route: '/affectation/:id' defaults: action: affectation notification: type: segment options: Loading module/Oscar/src/Oscar/Controller/PersonController.php +64 −2 Changes for module/Oscar/src/Oscar/Controller/PersonController.php: 64 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -452,8 +452,7 @@ class PersonController extends AbstractOscarController implements UsePersonServi if ( !$this->getOscarUserContextService()->hasPrivilegeDeep(Privileges::ACTIVITY_PERSON_MANAGE) && !$this->getOscarUserContextService()->hasPrivilegeDeep(Privileges::PROJECT_PERSON_MANAGE) && !$this->getOscarUserContextService()->hasPrivilegeDeep(Privileges::ORGANIZATION_EDIT) && !$this->getOscarUserContextService()->hasPrivilegeDeep(Privileges::ACTIVITY_INDEX) !$this->getOscarUserContextService()->hasPrivilegeDeep(Privileges::ORGANIZATION_EDIT) ) return $this->getResponseUnauthorized("Vous n'avez pas accès à la liste des personnes"); Loading Loading @@ -902,6 +901,69 @@ class PersonController extends AbstractOscarController implements UsePersonServi ]; } /** * @param string $idPersonKey * @return Person * @throws OscarException */ protected function getRoutePerson(string $idPersonKey = 'id'): Person { $id = $this->params()->fromRoute($idPersonKey); return $this->getPersonService()->getPersonById($id, true); } /** * */ public function affectationAction() { try { $person = $this->getRoutePerson(); $manage = $this->getOscarUserContextService()->hasPrivileges(Privileges::PERSON_EDIT); if (!$manage) { throw new OscarException("Accès interdit"); } // TRAITEMENT if ($this->getRequest()->isPost()) { try { $out = $this->params()->fromPost('out', ""); $this->getPersonService()->affectationsReplace($person, json_decode($out, true)); return $this->getResponseOk("done"); } catch (\Exception $e) { return $this->getResponseInternalError($e->getMessage()); } } // Récupération des affectations if ($this->params()->fromQuery('f') == 'json' || $this->isAjax()) { try { $replacerId = $this->params()->fromQuery('person'); $replacer = $this->getPersonService()->getPersonById($replacerId, true); } catch (\Exception $e) { return $this->getResponseInternalError( sprintf( "Impossible de traver le remplaçant : %s", $e->getMessage() ) ); } $out = [ 'affectations' => $this->getPersonService()->getPersonAffectationsArray($person, $replacer) ]; return $this->ajaxResponse($out); } throw new OscarException("Mauvaise utilisation de l'API"); } catch (\Exception $e) { return $this->getResponseInternalError( sprintf( "Gestion des affectations impossible : %s", $e->getMessage() ) ); } } public function mergeAction() { Loading module/Oscar/src/Oscar/Controller/ProjectGrantController.php +1 −1 Changes for module/Oscar/src/Oscar/Controller/ProjectGrantController.php: 1 added line, 1 removed line. Original line number Diff line number Diff line Loading @@ -1946,7 +1946,6 @@ class ProjectGrantController extends AbstractOscarController implements UseNotif // Récupération de l'activités $activity = $this->getProjectGrantService()->getGrant($this->params()->fromRoute('id')); $this->getOscarUserContextService()->check(Privileges::ACTIVITY_PERSON_SHOW, $activity); $out = []; Loading Loading @@ -2010,6 +2009,7 @@ class ProjectGrantController extends AbstractOscarController implements UseNotif 'context' => $context, 'urlEdit' => $urlEdit, 'urlShow' => $urlShow, 'past' => $activityPerson->isPast(), 'enroller' => $idEnroller, 'enrollerLabel' => $activity->getLabel(), 'editable' => $editable, Loading Loading
front/src/ReplaceStrengthenPerson.vue +181 −73 Changes for front/src/ReplaceStrengthenPerson.vue: 181 added lines, 73 removed lines. Original line number Diff line number Diff line <template> <div> <div class="overlay" v-if="mode != ''"> <div class="overlay-content" style="overflow: scroll"> <div class="overlay-content" :style="step == 1 ? 'overflow: visible;' : 'overflow: scroll;'"> <a href="#" @click.prevent="handlerCancel()" class="overlay-closer">X</a> <h1> {{ mode }} <strong>{{ person.displayname }}</strong> </h1> <div class="alert-info alert"> Remplacer <strong>{{ person.displayname }}</strong> par une autre personnes <div class="steps-bar"> <div class="step" :class="{'current': step == 1, 'done': step > 1}"> Choisir une personne </div> <div class="step" :class="{'current': step == 2, 'done': step > 2, 'futur': step < 2}"> Vérifier les affectations </div> <div class="step" :class="{'current': step == 3, 'futur': step < 3}"> Finalisation </div> </div> <div class="step-content"> <div v-if="recapPending"> <i class="icon-spinner animate-spin"></i> {{ recapPending }} <!-- Messages --> <div class="alert-info alert" v-if="pendingMessage"> <i class="animate-spin icon-spinner"></i> {{ pendingMessage }} </div> <div v-else-if="errorRecap" class="alert-danger alert"> <div v-if="errorMessage" class="alert-danger alert"> <i class="icon-attention-1"></i> <strong>Erreur</strong> : {{ errorRecap }} {{ errorMessage }} </div> <div v-else> <p>Choisissez une personne pour {{ mode }}</p> <div v-if="step == 1"> <div v-if="!replacer_id"> <p>Choisissez une personne :</p> <person-auto-completer @change="handlerSelectPerson" style="z-index: 10"/> </div> </div> <div class="alert alert-info" v-if="step1info"> {{ step1info }} </div> <nav class="buttons text-center" v-if="step == 1"> <button class="btn btn-success" @click="handlerConfirmStep1()" :class="{ 'disabled': !replacer_id }" > <i class="icon-spinner animate-spin" v-if="pendingMessage"></i> <i class="icon-angle-right" v-else></i> Vérifier les affectations </button> </nav> <section class=""> <!-- <h2>INFOS : {{ recap.infos }}</h2> --> <section class="affectations" v-if="affectations"> <section class="affectations" v-if="step == 2"> <section> <h2> <i class="icon-beaker"></i> Loading @@ -39,43 +69,41 @@ <h4><i class="icon-cubes"></i> Projets</h4> <p v-if="replacer_id"> <strong>{{ replacer }}</strong> va être ajouté dans le(s) <strong>{{ affectations.projects.length }}</strong> projet(s) suivant : va être ajouté dans le(s) <strong>{{ projects.length }}</strong> projet(s) suivant : </p> <div class="columns-3"> <div class="card xs applyable" @click="handlerSwitchApply(p)" v-for="p in affectations.projects" :class="{ 'apply': p.apply }"> v-for="p in projects" :class="{ 'apply': p.apply, 'active': p.active }"> <div class=""> <strong> <i class="icon-cubes"></i> {{ p.acronym }} {{ p.label }} </strong> <small>{{ p.label }}</small> <span class="badge bg-info on-right">{{ p.activities_count }}</span> </div> HHH <span class="cartouche xs"> {{ p.roles.join(', ') }} <span class="cartouche xs" v-for="role in p.roles" :class="{'past obsolete': !role.active, 'success': p.apply}"> {{ role.roleId }} </span> </div> </div> </section> <h3><i class="icon-cube"></i> Activités</h3> <div style="columns: 3"> <div v-for="p in activities" class="card xs applyable" <h4><i class="icon-cube"></i> Activités</h4> <div class="columns-3"> <div class="card xs applyable" @click="handlerSwitchApply(p)" :class="{ 'active': p.active, 'disabled': !p.active, 'apply': p.apply }"> <div style="border-bottom: solid thin #ccc"> v-for="p in activities" :class="{ 'apply': p.apply, 'active': p.active }"> <div class=""> <strong> <i class="icon-cube"></i> {{ p.acronym }} {{ p.label }} </strong> <em>{{ p.label }}</em> <i class="on-right" :class="'icon-status-' + p.status" :title="p.status_text"></i> </div> <small>({{ p.roles.join(', ') }})</small> <span class="cartouche xs" v-for="role in p.roles" :class="{'past obsolete': !role.active, 'success': p.apply}"> {{ role.roleId }} </span> </div> </div> </section> Loading @@ -85,14 +113,15 @@ <i class="icon-building-filled"></i> Structure </h2> <div v-for="p in structures" class="card xs applyable" @click="handlerSwitchApply(p)" :class="{'apply': p.apply }"> <strong>{{ p.label }}</strong> <small>({{ p.roles.join(', ') }})</small> <span class="cartouche xs" v-for="role in p.roles" :class="{'past obsolete': !role.active, 'success': p.apply}"> {{ role.roleId }} </span> </div> </section> <section> Loading @@ -101,54 +130,105 @@ Validation </h2> <div v-if="affectations.validations.prj"> <div v-if="validations.prj"> <h4><i class="icon-cube"></i>Validation projet</h4> <div class="card xs applyable" @click="v.apply = !v.apply; console.log('OK')" v-for="v in affectations.validations.prj" v-for="v in validations.prj" :class="{'apply': v.apply }"> <strong>{{ v.acronym }}</strong> <em>{{ v.label }}</em> </div> </div> <div v-if="affectations.validations.sci"> <div v-if="validations.sci"> <h4><i class="icon-beaker"></i>Validation scientifique</h4> <div class="card xs applyable" @click="v.apply = !v.apply" v-for="v in affectations.validations.sci" v-for="v in validations.sci" :class="{'apply': v.apply }"> <strong>{{ v.acronym }}</strong> <em>{{ v.label }}</em> </div> </div> <div v-if="affectations.validations.adm"> <div v-if="validations.adm"> <h4><i class="icon-book"></i>Validation administratif</h4> <div class="card xs applyable" @click="v.apply = !v.apply" v-for="v in affectations.validations.adm" v-for="v in validations.adm" :class="{'apply': v.apply }"> <strong>{{ v.acronym }}</strong> <em>{{ v.label }}</em> </div> </div> </section> <section> <h2> <i class="icon-calendar"></i> Hiérarchie </h2> <div> <h4><i class="icon-book"></i>Reférent(s)</h4> <p> <i class="icon-info-circled"></i> Personnes qui seront chargées de valider les déclaration <strong>Hors-lot</strong> de {{ person.displayname }}. </p> <div class="card xs person-card" v-for="p in subordinates" :class="{'apply': p.apply}"> <div class="card-title"> <img :src="'//www.gravatar.com/avatar/' +p.mailmd5 +'&s=20'" alt="" class="gravatar" width="20"> <strong> <i class="icon-user"></i> {{ p.label }} </strong> </div> <small> <i class="icon-mail"></i> {{ p.mail }} </small> </div> </div> <div> <h4><i class="icon-beaker"></i>Subordonné(s)</h4> <p> <i class="icon-info-circled"></i> Personnes pour qui <strong>{{ person.displayname }}</strong> devra valider les déclarations <strong>Hors-lot</strong> </p> <div class="card xs person-card" v-for="p in referents" :class="{'apply': p.apply}"> <div class="card-title"> <img :src="'//www.gravatar.com/avatar/' +p.mailmd5 +'&s=20'" alt="" class="gravatar" width="20"> <strong> <i class="icon-user"></i> {{ p.label }} </strong> </div> <small> <i class="icon-mail"></i> {{ p.mail }} </small> </div> </div> </section> <hr> <nav class="buttons text-center"> <button class="btn btn-success" @click="handlerConfirmReplace()"> Confirmer <nav class="buttons"> <button class="btn btn-success" @click="handlerConfirmReplace"> Terminé </button> </nav> </section> </section> </div> </div> </div> <div class="replace-strengthen-person actions text-center"> <div class="alert alert-danger"> {{ error }} </div> <button @click="handlerReplace"> <i class="icon-rewind-outline"></i> Remplacer </button> Loading @@ -161,7 +241,8 @@ <script> // MANUAL COMPILATION // node node_modules/.bin/vue-cli-service build --name ReplaceStrengthenPerson --dest ../public/js/oscar/dist/ReplaceStrengthenPerson --no-clean --formats umd,umd-min --target lib src/ReplaceStrengthenPerson.vue; // node node_modules/.bin/vue-cli-service build --name ReplaceStrengthenPerson --dest ../public/js/oscar/dist/ --no-clean --formats umd,umd-min --target lib src/ReplaceStrengthenPerson.vue import PersonAutoCompleter from "./components/PersonAutoCompleter"; export default { Loading @@ -178,10 +259,10 @@ export default { urlReplace: { required: true }, urlStrengthen: { urlAffectation: { required: true }, affectations: { urlStrengthen: { required: true } }, Loading @@ -193,19 +274,29 @@ export default { recapPending: "", errorRecap: "", error: "", step: 1, pendingMessage: "", errorMessage: "", replacer: "", replacer_id: null, step1info: "", projects: {}, activities: {}, structures: {}, validations: {} validations: {}, referents: {}, subordinates: {} } }, methods: { handlerReplace() { this.mode = 'Remplacer'; this.loadingMessage = "Chargement de l'aperçu"; }, handlerSwitchApply(item) { Loading @@ -219,17 +310,30 @@ export default { * @param e */ handlerSelectPerson(e) { console.log("handlerSelectPerson"); this.replacer = e.displayname; this.replacer_id = e.id; this.step1info = "Remplacer " + this.person.displayname + " par " + this.replacer; }, this.recap = { "replacer_id": e.id, "infos": "Remplacer " + this.person.displayname + " par " + e.displayname, "dump": this.person }; console.log(e); handlerConfirmStep1(){ this.pendingMessage = "Chargement des affectations..."; this.$http.get(this.urlAffectation+"?person=" + this.replacer_id).then( ok => { this.step = 2; this.projects = ok.body.affectations.projects; this.activities = ok.body.affectations.activities; this.structures = ok.body.affectations.structures; this.validations = ok.body.affectations.validations; this.referents = ok.body.affectations.referents; this.subordinates = ok.body.affectations.subordinates; }, ko => { this.errorMessage = ko.body; } ).then( () => { this.pendingMessage = ""; }); }, handlerConfirmReplace() { Loading @@ -239,45 +343,49 @@ export default { 'activities': this.activities, 'structures': this.structures, 'validations': this.validations, 'subordinates': this.subordinates, 'referents': this.referents, 'replacer_id': this.replacer_id }; console.log('OUT', out); this.recapPending = "Remplacement..."; this.pendingMessage = "Remplacement..."; this.step = 3; data.append("out", JSON.stringify(out)); this.$http.post(this.urlReplace, data).then( this.$http.post(this.urlAffectation, data).then( ok => { document.location.refresh(); document.location.reload(); }, ko => { if (ko.status == 403) { this.errorRecap = "Non-autorisé"; this.errorMessage = "Non-autorisé"; } else { if (ko.body.error) { this.errorRecap = "Erreur : " + ko.body.error; this.errorMessage = "Erreur : " + ko.body.error; } else { this.errorRecap = ko.body; this.errorMessage = ko.body; } } } ).then( foo => this.recapPending = ""); ).then( foo => { this.pendingMessage = ""; }) }, handlerCancel() { this.recapPending = ""; this.errorRecap = ""; this.recap = ""; this.step = 1; this.errorMessage = ""; this.mode = ""; this.replacer_id = null; this.replacer = ""; this.step1info = ""; }, }, // Lifecycle mounted() { console.log("mounted"); this.projects = this.affectations.projects; this.activities = this.affectations.activities; this.structures = this.affectations.structures; this.validations = this.affectations.validations; // amazing void content } } </script> No newline at end of file
module/Oscar/config/module.config.php +1 −1 Changes for module/Oscar/config/module.config.php: 1 added line, 1 removed line. Original line number Diff line number Diff line Loading @@ -248,7 +248,7 @@ return array( 'privileges' => \Oscar\Provider\Privileges::PERSON_INDEX ], [ 'controller' => 'Person', 'action' => ['edit', 'new', 'merge', 'organizationRole', 'notificationPerson', 'notificationPersonGenerate'], 'action' => ['edit', 'new', 'merge', 'organizationRole', 'notificationPerson', 'notificationPersonGenerate', 'affectation'], 'privileges' => \Oscar\Provider\Privileges::PERSON_EDIT ], Loading
module/Oscar/config/routes.yml +7 −0 Changes for module/Oscar/config/routes.yml: 7 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -605,6 +605,13 @@ person: defaults: action: access affectation: type: segment options: route: '/affectation/:id' defaults: action: affectation notification: type: segment options: Loading
module/Oscar/src/Oscar/Controller/PersonController.php +64 −2 Changes for module/Oscar/src/Oscar/Controller/PersonController.php: 64 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -452,8 +452,7 @@ class PersonController extends AbstractOscarController implements UsePersonServi if ( !$this->getOscarUserContextService()->hasPrivilegeDeep(Privileges::ACTIVITY_PERSON_MANAGE) && !$this->getOscarUserContextService()->hasPrivilegeDeep(Privileges::PROJECT_PERSON_MANAGE) && !$this->getOscarUserContextService()->hasPrivilegeDeep(Privileges::ORGANIZATION_EDIT) && !$this->getOscarUserContextService()->hasPrivilegeDeep(Privileges::ACTIVITY_INDEX) !$this->getOscarUserContextService()->hasPrivilegeDeep(Privileges::ORGANIZATION_EDIT) ) return $this->getResponseUnauthorized("Vous n'avez pas accès à la liste des personnes"); Loading Loading @@ -902,6 +901,69 @@ class PersonController extends AbstractOscarController implements UsePersonServi ]; } /** * @param string $idPersonKey * @return Person * @throws OscarException */ protected function getRoutePerson(string $idPersonKey = 'id'): Person { $id = $this->params()->fromRoute($idPersonKey); return $this->getPersonService()->getPersonById($id, true); } /** * */ public function affectationAction() { try { $person = $this->getRoutePerson(); $manage = $this->getOscarUserContextService()->hasPrivileges(Privileges::PERSON_EDIT); if (!$manage) { throw new OscarException("Accès interdit"); } // TRAITEMENT if ($this->getRequest()->isPost()) { try { $out = $this->params()->fromPost('out', ""); $this->getPersonService()->affectationsReplace($person, json_decode($out, true)); return $this->getResponseOk("done"); } catch (\Exception $e) { return $this->getResponseInternalError($e->getMessage()); } } // Récupération des affectations if ($this->params()->fromQuery('f') == 'json' || $this->isAjax()) { try { $replacerId = $this->params()->fromQuery('person'); $replacer = $this->getPersonService()->getPersonById($replacerId, true); } catch (\Exception $e) { return $this->getResponseInternalError( sprintf( "Impossible de traver le remplaçant : %s", $e->getMessage() ) ); } $out = [ 'affectations' => $this->getPersonService()->getPersonAffectationsArray($person, $replacer) ]; return $this->ajaxResponse($out); } throw new OscarException("Mauvaise utilisation de l'API"); } catch (\Exception $e) { return $this->getResponseInternalError( sprintf( "Gestion des affectations impossible : %s", $e->getMessage() ) ); } } public function mergeAction() { Loading
module/Oscar/src/Oscar/Controller/ProjectGrantController.php +1 −1 Changes for module/Oscar/src/Oscar/Controller/ProjectGrantController.php: 1 added line, 1 removed line. Original line number Diff line number Diff line Loading @@ -1946,7 +1946,6 @@ class ProjectGrantController extends AbstractOscarController implements UseNotif // Récupération de l'activités $activity = $this->getProjectGrantService()->getGrant($this->params()->fromRoute('id')); $this->getOscarUserContextService()->check(Privileges::ACTIVITY_PERSON_SHOW, $activity); $out = []; Loading Loading @@ -2010,6 +2009,7 @@ class ProjectGrantController extends AbstractOscarController implements UseNotif 'context' => $context, 'urlEdit' => $urlEdit, 'urlShow' => $urlShow, 'past' => $activityPerson->isPast(), 'enroller' => $idEnroller, 'enrollerLabel' => $activity->getLabel(), 'editable' => $editable, Loading