diff --git a/backend/gncitizen/core/sites/routes.py b/backend/gncitizen/core/sites/routes.py index 133e1cb8..76d7c5e6 100644 --- a/backend/gncitizen/core/sites/routes.py +++ b/backend/gncitizen/core/sites/routes.py @@ -1,5 +1,6 @@ import io import uuid +import json import xlwt from flask import Blueprint, current_app, make_response, request @@ -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 ] @@ -406,6 +409,44 @@ def post_visit(site_id): return {"error_message": str(e)}, 400 +@sites_api.route("/visits/", 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( "//visits//photos", methods=["POST"] ) @@ -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 @@ -452,6 +493,27 @@ def delete_site(site_id): return {"message": str(e)}, 500 +@sites_api.route("/visit/", 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/", methods=["GET"]) @jwt_required() def export_sites_xls(user_id): diff --git a/backend/requirements.txt b/backend/requirements.txt index 4d3d73f0..99570476 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -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/Utils-Flask-SQLAlchemy-Geo@0.2.1 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 diff --git a/frontend/src/app/auth/user-dashboard/user-dashboard.component.ts b/frontend/src/app/auth/user-dashboard/user-dashboard.component.ts index ad27c0cb..6e7d477e 100644 --- a/frontend/src/app/auth/user-dashboard/user-dashboard.component.ts +++ b/frontend/src/app/auth/user-dashboard/user-dashboard.component.ts @@ -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) => { diff --git a/frontend/src/app/auth/user-dashboard/user.service.service.ts b/frontend/src/app/auth/user-dashboard/user.service.service.ts index 168aeef4..9bc65315 100644 --- a/frontend/src/app/auth/user-dashboard/user.service.service.ts +++ b/frontend/src/app/auth/user-dashboard/user.service.service.ts @@ -65,6 +65,12 @@ export class UserService { ); } + deleteSiteVisit(idVisit: number) { + return this.http.delete( + `${AppConfig.API_ENDPOINT}/sites/visit/${idVisit}` + ); + } + ConvertToCSV(objArray, headerList) { let array = typeof objArray != 'object' ? JSON.parse(objArray) : objArray; diff --git a/frontend/src/app/home/home.component.ts b/frontend/src/app/home/home.component.ts index 430b4a63..994cb594 100644 --- a/frontend/src/app/home/home.component.ts +++ b/frontend/src/app/home/home.component.ts @@ -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; diff --git a/frontend/src/app/programs/base/detail/detail.component.html b/frontend/src/app/programs/base/detail/detail.component.html index e9ab192e..f5d71a18 100644 --- a/frontend/src/app/programs/base/detail/detail.component.html +++ b/frontend/src/app/programs/base/detail/detail.component.html @@ -121,10 +121,26 @@

Photos

Description

+ +
{{ a.date | date: 'longDate' }} par {{ a.author }} + +   + +
@@ -196,3 +212,28 @@