Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add possibility to edit and delete site visits #333

Merged
merged 13 commits into from
Feb 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 63 additions & 1 deletion backend/gncitizen/core/sites/routes.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import io
import uuid
import json

import xlwt
from flask import Blueprint, current_app, make_response, request
Expand Down Expand Up @@ -113,6 +114,8 @@ def get_site_photos(site_id):
"url": "/media/{}".format(p.MediaModel.filename),
"date": p.VisitModel.as_dict()["date"],
"author": p.VisitModel.obs_txt,
"visit_id": p.VisitModel.id_visit,
"id_media": p.MediaModel.id_media
}
for p in photos
]
Expand Down Expand Up @@ -406,6 +409,44 @@ def post_visit(site_id):
return {"error_message": str(e)}, 400


@sites_api.route("/visits/<int:visit_id>", methods=["PATCH"])
@json_resp
@jwt_required()
def update_visit(visit_id):
try:
current_user = get_user_if_exists()
update_data = dict(request.get_json())
visit = VisitModel.query.filter_by(id_visit=visit_id).first()
if current_user.id_user != visit.id_role:
return ("unauthorized"), 403

try:
# Delete selected existing media
id_media_to_delete = json.loads(update_data.get("delete_media"))
if len(id_media_to_delete):
db.session.query(MediaOnVisitModel).filter(
MediaOnVisitModel.id_media.in_(
tuple(id_media_to_delete)
),
MediaOnVisitModel.id_data_source
== visit_id,
).delete(synchronize_session="fetch")
db.session.query(MediaModel).filter(
MediaModel.id_media.in_(tuple(id_media_to_delete))
).delete(synchronize_session="fetch")
except Exception as e:
current_app.logger.warning("[update_visit] delete media ", e)
raise GeonatureApiError(e)

visit.date = update_data.get("date")
visit.json_data = update_data.get("data")
db.session.commit()
return ("Visit updated successfully"), 200
except Exception as e:
current_app.logger.critical("[update_visit] Error: %s", str(e))
return {"message": str(e)}, 400


@sites_api.route(
"/<int:site_id>/visits/<int:visit_id>/photos", methods=["POST"]
)
Expand Down Expand Up @@ -442,7 +483,7 @@ def delete_site(site_id):
.join(UserModel, SiteModel.id_role == UserModel.id_user, full=True)
.first()
)
if current_user.id_user == site.id_role:
if current_user.id_user == site.SiteModel.id_role:
SiteModel.query.filter_by(id_site=site_id).delete()
db.session.commit()
return ("Site deleted successfully"), 200
Expand All @@ -452,6 +493,27 @@ def delete_site(site_id):
return {"message": str(e)}, 500


@sites_api.route("/visit/<int:visit_id>", methods=["DELETE"])
@json_resp
@jwt_required()
def delete_visit(visit_id):
current_user = get_user_if_exists()
# try:
visit = (
db.session.query(VisitModel)
.filter(VisitModel.id_visit == visit_id)
.first()
)
if current_user.id_user == visit.id_role:
VisitModel.query.filter_by(id_visit=visit_id).delete()
db.session.commit()
return ("Site deleted successfully"), 200
else:
return ("delete unauthorized"), 403
# except Exception as e:
# return {"message": str(e)}, 500


@sites_api.route("/export/<int:user_id>", methods=["GET"])
@jwt_required()
def export_sites_xls(user_id):
Expand Down
2 changes: 1 addition & 1 deletion backend/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ sqlalchemy==1.4.15; (python_version >= "2.7" and python_full_version < "3.0.0")
toml==0.10.2; (python_version >= "2.6" and python_full_version < "3.0.0") or (python_full_version >= "3.3.0")
typing-extensions==3.10.0.0; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "3.8" or python_full_version >= "3.6.0" and python_version < "3.8" and python_version >= "3.6"
urllib3==1.26.4; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version < "4"
utils-flask-sqlalchemy @ git+https://github.com/hypsug0/Utils-Flask-SQLAlchemy@master
utils-flask-sqlalchemy @ git+https://github.com/PnX-SI/Utils-Flask-SQLAlchemy@master
utils-flask-sqlalchemy-geo @ git+https://github.com/PnX-SI/[email protected]
werkzeug==2.0.0; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4" or python_full_version >= "3.5.0" and python_version >= "3.6" and python_version < "4"
wtforms==2.3.3
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,9 @@ export class UserDashboardComponent implements OnInit {
// this.rowData(obs, coords);
// this.obsExport(obs);
});
if (this.observations.length === 0 && this.mysites.features.length > 0) {
this.tab = 'sites'
}
} else {
this.observations = data[0].features;
this.observations.forEach((obs) => {
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/app/auth/user-dashboard/user.service.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@ export class UserService {
);
}

deleteSiteVisit(idVisit: number) {
return this.http.delete<Object>(
`${AppConfig.API_ENDPOINT}/sites/visit/${idVisit}`
);
}

ConvertToCSV(objArray, headerList) {
let array =
typeof objArray != 'object' ? JSON.parse(objArray) : objArray;
Expand Down
8 changes: 8 additions & 0 deletions frontend/src/app/home/home.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,14 @@ export class HomeComponent implements OnInit, AfterViewChecked {
this.observationsService
.getStat()
.subscribe((stats) => (this.stats = stats));
if (this.programs.length === 1) {
const p = this.programs[0]
this.router.navigate([
'/programs',
p.id_program,
p.module.name
]);
}
});
this.route.fragment.subscribe((fragment) => {
this.fragment = fragment;
Expand Down
41 changes: 41 additions & 0 deletions frontend/src/app/programs/base/detail/detail.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -121,10 +121,26 @@ <h2 class="mt-4 mb-4">Photos</h2>
<div *ngIf="attributes.length > 0" class="row">
<h2 class="my-4">Description</h2>
</div>
<!-- {{ attributes|json }} -->
<!-- <span *ngIf="site">{{ site.properties.visits|json }}</span> -->
<div *ngFor="let a of attributes" class="row bg-light my-3">
<h5>
<i class="fa fa-calendar"></i>
{{ a.date | date: 'longDate' }} par {{ a.author }}
<i
class="fa fa-edit text-primary"
ngbTooltip="Editer"
(click)="editSiteVisit(a);"
*ngIf="a.author === username"
></i>
&nbsp;
<!-- {{ a|json }} deleteSiteVisit(a.id)-->
<i
class="fa fa-trash text-danger"
ngbTooltip="Supprimer"
(click)="openDelVisitModal(a.id)"
*ngIf="a.author === username"
></i>
</h5>
<table class="table table-striped table-sm table-hover">
<tbody>
Expand Down Expand Up @@ -196,3 +212,28 @@ <h5 class="modal-title" id="exampleModalLabel">
</div>
</div>
</div>

<ng-template #visitDeleteModal let-modal>
<div class="modal-delete-header">
<h5 class="modal-delete-title"><i class="fa fa-trash"></i></h5>
</div>
<div class="modal-delete-body">
Êtes-vous sûr de vouloir supprimer cette visite et toutes les informations
qui y sont rattachées ?
<br />
La suppression sera définitive
</div>
<div class="modal-delete-footer">
<button
type="button"
class="cancel-btn"
style="margin-right: 15px"
(click)="visitDeleteModalClose()"
>
ANNULER
</button>
<button type="button" class="green-btn" (click)="deleteSiteVisit(idVisitToDelete); visitDeleteModalClose();">
OUI
</button>
</div>
</ng-template>
1 change: 1 addition & 0 deletions frontend/src/app/programs/base/detail/detail.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export abstract class BaseDetailComponent {
obs: any;
site_id: any;
site: any;
username = null;

showPhoto(photo) {
console.log('opening photo:');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export const MODAL_DEFAULTS: NgbModalOptions = {
})
export class ModalFlowService extends FlowService {
modalRef: NgbModalRef;
private modalCloseStatus: BehaviorSubject<string> = new BehaviorSubject(
public modalCloseStatus: BehaviorSubject<string> = new BehaviorSubject(
null
);
display: boolean = false;
Expand Down Expand Up @@ -89,7 +89,7 @@ export class ModalFlowService extends FlowService {
return this.modalCloseStatus.asObservable();
}

setModalCloseSatus(type: 'updateObs' | 'newObs' | null) {
setModalCloseSatus(type: 'updateObs' | 'newObs' | 'visitPosted' | null) {
this.modalCloseStatus.next(type);
}

Expand Down
Loading