diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0eebfc0f9b8fa4a114826e30b8c3877168bd8a2d..c5048cadca89397b43402858564b02a6692a8e2e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,7 +1,8 @@ stages: - - build - Static analysis - + - build + - deploy + variables: SONAR_PROJECTKEY: "$CI_PROJECT_NAME" SONAR_HOST_URL: "https://sonarqube.neogeo.fr" @@ -23,6 +24,17 @@ build testing docker image: - /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --destination neogeo/geocontrib-front:testing - echo Image docker neogeo/geocontrib-front:testing livrée +deploy testing docker image: + stage: deploy + only: + - develop + tags: + - build + image: + name: curlimages/curl + script: + - curl -X POST -F token=$TRIGGER_TOKEN -F ref=main https://git.neogeo.fr/api/v4/projects/226/trigger/pipeline + build stable docker image: stage: build only: diff --git a/Dockerfile b/Dockerfile index 307c845f6c400793a1dab711dd633c2842587108..cc27e038c58e349e28dccf75daccde01322bb594 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,5 +16,14 @@ RUN mkdir /usr/share/nginx/html/geocontrib COPY --from=builder /app/dist /usr/share/nginx/html/geocontrib COPY nginx.conf /etc/nginx/conf.d/default.conf +RUN useradd -r -m apprunner + +RUN mkdir -p /opt/geocontrib/media /opt/geocontrib/static /opt/geocontrib/config/ && \ + chown -R apprunner /opt/geocontrib/ && \ + rm -Rf /usr/share/nginx/html/geocontrib/config/ && \ + ln -s /opt/geocontrib/config/ /usr/share/nginx/html/geocontrib/config + +VOLUME /opt/geocontrib/media /opt/geocontrib/static /opt/geocontrib/config/ + EXPOSE 80 CMD ["nginx", "-g", "daemon off;"] diff --git a/src/views/NotFound.vue b/src/views/NotFound.vue index 45383de0811961bfbe763d28584eecabf24efc8b..57d7e54f229a9ed836f9de938c0265bbb4dfb6d6 100644 --- a/src/views/NotFound.vue +++ b/src/views/NotFound.vue @@ -2,8 +2,8 @@ <div> <h1>Not Found</h1> <p> - Oups, la page demandée n'a pas été trouvé. Essayez de retourner à la - <router-link to="/">page d'acceuil</router-link> + Oups, la page demandée n'a pas été trouvée. Essayez de retourner à la + <router-link to="/">page d'accueil</router-link> </p> </div> -</template> \ No newline at end of file +</template> diff --git a/src/views/feature/Feature_edit.vue b/src/views/feature/Feature_edit.vue index 4916b6ba1b3aa8553eecadc15f864b3503aab495..6502947fcb45afe9ab0a5c2c4d9af894cf95884e 100644 --- a/src/views/feature/Feature_edit.vue +++ b/src/views/feature/Feature_edit.vue @@ -346,7 +346,7 @@ export default { }, computed: { - ...mapGetters(["project"]), + ...mapGetters(["project", "permissions"]), ...mapGetters("feature_type", ["feature_type"]), ...mapState(["user", "USER_LEVEL_PROJECTS"]), ...mapState("map", ["basemaps"]), @@ -689,6 +689,15 @@ export default { } if (is_valid) { + //* if moderate project modified by someone else than admin or moderator, switch status to pending + if ( + this.project.moderation && + !this.permissions.is_project_administrator && + !this.permissions.is_project_moderator + ) { + this.form.status.value = { name: "Brouillon", value: "draft" }; + this.updateStore(); + } this.$store.dispatch("feature/SEND_FEATURE", this.currentRouteName); } }, @@ -921,7 +930,7 @@ export default { setTimeout( function () { let project_id = this.$route.params.slug.split("-")[0]; - const mvtUrl = `${this.$store.state.configuration.VUE_APP_DJANGO_API_BASE}/features.mvt/?tile={z}/{x}/{y}&project_id=${project_id}`; + const mvtUrl = `${this.$store.state.configuration.VUE_APP_DJANGO_API_BASE}features.mvt/?tile={z}/{x}/{y}&project_id=${project_id}`; mapUtil.addVectorTileLayer( mvtUrl, diff --git a/src/views/feature/Feature_list.vue b/src/views/feature/Feature_list.vue index b86b137acf5366c17f40509a440b35c175c9e64f..a9f9fb4a9e67a2fe57881e470d1cbdbd2dda80cf 100644 --- a/src/views/feature/Feature_list.vue +++ b/src/views/feature/Feature_list.vue @@ -313,7 +313,7 @@ export default { .dispatch("feature/GET_PROJECT_FEATURES", this.project.slug) .then(() => { this.getNloadGeojsonFeatures(); - this.checkedFeatures.splice(feature_id) + this.checkedFeatures.splice(feature_id); }); } }) @@ -384,7 +384,7 @@ export default { setTimeout( function () { let project_id = this.$route.params.slug.split("-")[0]; - const mvtUrl = `${this.$store.state.configuration.VUE_APP_DJANGO_API_BASE}/features.mvt/?tile={z}/{x}/{y}&project_id=${project_id}`; + const mvtUrl = `${this.$store.state.configuration.VUE_APP_DJANGO_API_BASE}features.mvt/?tile={z}/{x}/{y}&project_id=${project_id}`; mapUtil.addVectorTileLayer( mvtUrl, this.$route.params.slug, diff --git a/src/views/project/Project_detail.vue b/src/views/project/Project_detail.vue index 84888b12a4054e5fe90f51046cb8e55d1516b00c..ee2ea87f07ed1227a706d0385ace4f0890eda9c6 100644 --- a/src/views/project/Project_detail.vue +++ b/src/views/project/Project_detail.vue @@ -52,19 +52,24 @@ <h1 class="ui header"> <div class="content"> {{ project.title }} - <div v-if="arraysOffline.length>0">{{arraysOffline.length}} modifications en attente + <div v-if="arraysOffline.length > 0"> + {{ arraysOffline.length }} modifications en attente <button - :disabled="isOffline()" - @click="sendOfflineFeatures()" - class="ui fluid teal icon button" - > - <i class="upload icon"></i> Envoyer au serveur - </button> - + :disabled="isOffline()" + @click="sendOfflineFeatures()" + class="ui fluid teal icon button" + > + <i class="upload icon"></i> Envoyer au serveur + </button> </div> <div class="ui icon right floated compact buttons"> <a - v-if="user && permissions && permissions.can_view_project && isOffline()!=true" + v-if=" + user && + permissions && + permissions.can_view_project && + isOffline() != true + " id="subscribe-button" class="ui button button-hover-green" data-tooltip="S'abonner au projet" @@ -75,7 +80,11 @@ <i class="inverted grey envelope icon"></i> </a> <router-link - v-if="permissions && permissions.can_update_project && isOffline()!=true" + v-if=" + permissions && + permissions.can_update_project && + isOffline() != true + " :to="{ name: 'project_edit', params: { slug: project.slug } }" class="ui button button-hover-orange" data-tooltip="Modifier le projet" @@ -166,7 +175,8 @@ v-if=" project && permissions && - permissions.can_create_feature_type && isOffline()!=true + permissions.can_create_feature_type && + isOffline() != true " class=" ui @@ -192,7 +202,8 @@ project && type.is_editable && permissions && - permissions.can_create_feature_type && isOffline()!=true + permissions.can_create_feature_type && + isOffline() != true " class=" ui @@ -218,7 +229,11 @@ <div class="nouveau-type-signalement"> <router-link - v-if="permissions && permissions.can_update_project && isOffline()!=true" + v-if=" + permissions && + permissions.can_update_project && + isOffline() != true + " :to="{ name: 'ajouter-type-signalement', params: { slug: project.slug }, @@ -230,7 +245,11 @@ </div> <div class="nouveau-type-signalement"> <a - v-if="permissions && permissions.can_update_project && isOffline()!=true" + v-if=" + permissions && + permissions.can_update_project && + isOffline() != true + " class=" ui compact @@ -531,67 +550,75 @@ export default { refreshId() { return "?ver=" + Math.random(); }, - isOffline(){ - return navigator.onLine==false; + isOffline() { + return navigator.onLine == false; }, - checkForOfflineFeature(){ - let arraysOffline=[]; - let localStorageArray=localStorage.getItem("geocontrib_offline"); - if(localStorageArray){ - arraysOffline=JSON.parse(localStorageArray); - this.arraysOffline=arraysOffline.filter(x=>x.project==this.project.slug); + checkForOfflineFeature() { + let arraysOffline = []; + let localStorageArray = localStorage.getItem("geocontrib_offline"); + if (localStorageArray) { + arraysOffline = JSON.parse(localStorageArray); + this.arraysOffline = arraysOffline.filter( + (x) => x.project == this.project.slug + ); } }, - sendOfflineFeatures(){ + sendOfflineFeatures() { var promises = []; - this.arraysOffline.forEach((feature, index, object)=>{ + this.arraysOffline.forEach((feature, index, object) => { console.log(feature); - if(feature.type=='post') { + if (feature.type == "post") { promises.push( - axios - .post(`${this.$store.state.configuration.VUE_APP_DJANGO_API_BASE}features/`, feature.geojson) - .then((response) => { - console.log(response) - if (response.status === 201 && response.data) { - object.splice(index, 1); - } - }) - .catch((error) => { - console.log(error); - })); - } - else if(feature.type=='put') { + axios + .post( + `${this.$store.state.configuration.VUE_APP_DJANGO_API_BASE}features/`, + feature.geojson + ) + .then((response) => { + console.log(response); + if (response.status === 201 && response.data) { + object.splice(index, 1); + } + }) + .catch((error) => { + console.log(error); + }) + ); + } else if (feature.type == "put") { promises.push( - axios - .put(`${this.$store.state.configuration.VUE_APP_DJANGO_API_BASE}features/${feature.featureId}`, feature.geojson) - .then((response) => { - console.log(response) - if (response.status === 200 && response.data) { - object.splice(index, 1); - } - }) - .catch((error) => { - console.log(error); - })); + axios + .put( + `${this.$store.state.configuration.VUE_APP_DJANGO_API_BASE}features/${feature.featureId}`, + feature.geojson + ) + .then((response) => { + console.log(response); + if (response.status === 200 && response.data) { + object.splice(index, 1); + } + }) + .catch((error) => { + console.log(error); + }) + ); } }); Promise.all(promises).then(() => { - this.updateLocalStorage(); - window.location.reload(); - } - - ); - + this.updateLocalStorage(); + window.location.reload(); + }); }, - updateLocalStorage(){ - let arraysOffline=[]; - let localStorageArray=localStorage.getItem("geocontrib_offline"); - if(localStorageArray){ - arraysOffline=JSON.parse(localStorageArray); + updateLocalStorage() { + let arraysOffline = []; + let localStorageArray = localStorage.getItem("geocontrib_offline"); + if (localStorageArray) { + arraysOffline = JSON.parse(localStorageArray); } - let arraysOfflineOtherProject = arraysOffline.filter(x=>x.project!=this.project.slug); - arraysOffline=arraysOfflineOtherProject.concat(this.arraysOffline); - localStorage.setItem("geocontrib_offline",JSON.stringify(arraysOffline)); + let arraysOfflineOtherProject = arraysOffline.filter( + (x) => x.project != this.project.slug + ); + arraysOffline = arraysOfflineOtherProject.concat(this.arraysOffline); + localStorage.setItem("geocontrib_offline", JSON.stringify(arraysOffline)); }, toNewFeatureType() { this.$router.push({ @@ -642,54 +669,65 @@ export default { setTimeout(() => (this.infoMessage = ""), 3000); }); }, - initMap(){ - if (this.project && this.permissions.can_view_project) { - this.$store.dispatch("map/INITIATE_MAP"); - const url = `${this.$store.state.configuration.VUE_APP_DJANGO_API_BASE}projects/${this.$route.params.slug}/feature/?output=geojson`; - let self = this; - this.checkForOfflineFeature(); - let project_id=this.$route.params.slug.split('-')[0]; - const mvtUrl = `${this.$store.state.configuration.VUE_APP_DJANGO_API_BASE}/features.mvt/?tile={z}/{x}/{y}&project_id=${project_id}`; - mapUtil.addVectorTileLayer(mvtUrl,this.$route.params.slug,this.$store.state.feature_type.feature_types); - axios - .get(url) - .then((response) => { - let features = response.data.features; - self.arraysOffline.forEach(x=>x.geojson.properties.color="red"); - features=response.data.features.concat(self.arraysOffline.map(x=>x.geojson)); - const featureGroup = mapUtil.addFeatures(features,{},false,this.$store.state.feature_type.feature_types); + initMap() { + if (this.project && this.permissions.can_view_project) { + this.$store.dispatch("map/INITIATE_MAP"); + const url = `${this.$store.state.configuration.VUE_APP_DJANGO_API_BASE}projects/${this.$route.params.slug}/feature/?output=geojson`; + let self = this; + this.checkForOfflineFeature(); + let project_id = this.$route.params.slug.split("-")[0]; + const mvtUrl = `${this.$store.state.configuration.VUE_APP_DJANGO_API_BASE}features.mvt/?tile={z}/{x}/{y}&project_id=${project_id}`; + mapUtil.addVectorTileLayer( + mvtUrl, + this.$route.params.slug, + this.$store.state.feature_type.feature_types + ); + axios + .get(url) + .then((response) => { + let features = response.data.features; + self.arraysOffline.forEach( + (x) => (x.geojson.properties.color = "red") + ); + features = response.data.features.concat( + self.arraysOffline.map((x) => x.geojson) + ); + const featureGroup = mapUtil.addFeatures( + features, + {}, + false, + this.$store.state.feature_type.feature_types + ); - if (featureGroup && featureGroup.getLayers().length > 0) { - mapUtil - .getMap() - .fitBounds(featureGroup.getBounds(), { padding: [25, 25] }); - this.$store.commit("map/SET_GEOJSON_FEATURES", features); - } else { - this.$store.commit("map/SET_GEOJSON_FEATURES", []); - } - }) - .catch((error) => { - throw error; - }); - - } - }, + if (featureGroup && featureGroup.getLayers().length > 0) { + mapUtil + .getMap() + .fitBounds(featureGroup.getBounds(), { padding: [25, 25] }); + this.$store.commit("map/SET_GEOJSON_FEATURES", features); + } else { + this.$store.commit("map/SET_GEOJSON_FEATURES", []); + } + }) + .catch((error) => { + throw error; + }); + } + }, }, created() { - - if (this.user) { projectAPI .getProjectSubscription({ projectSlug: this.$route.params.slug }) .then((data) => (this.is_suscriber = data.is_suscriber)); } }, - mounted() { - let self=this; - this.$store.dispatch("GET_PROJECT_INFO", this.slug).then(setTimeout(self.initMap,1000)); + let self = this; + this.$store + .dispatch("GET_PROJECT_INFO", this.slug) + .then(setTimeout(self.initMap, 1000)); if (this.message) { this.tempMessage = this.message; document