Skip to content

Commit

Permalink
feat: Edit group site new component
Browse files Browse the repository at this point in the history
Handle error when "Edit" path method
Create class of invalid request to manage return erreor
Create function to handle type of field (wip)

Reviewed-by:andriacap
[Refs_ticket]:#4
  • Loading branch information
andriacap committed Jan 24, 2023
1 parent 9e089c1 commit dd3755f
Show file tree
Hide file tree
Showing 14 changed files with 613 additions and 6 deletions.
8 changes: 8 additions & 0 deletions backend/gn_module_monitoring/monitoring/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ def attribute_names(cls):
if isinstance(prop, sqlalchemy.orm.ColumnProperty)
]

@classmethod
def get_type_fields(cls):
structure_data = {prop.key:type(prop.expression.type).__name__ for prop in class_mapper(cls).iterate_properties
if isinstance(prop, sqlalchemy.orm.ColumnProperty)}
for prop in class_mapper(cls).iterate_properties:
if isinstance(prop, sqlalchemy.orm.RelationshipProperty) and prop.backref is not None:
structure_data[prop.key] = "Select"
return structure_data
# __table_args__ = {'mysql_engine': 'InnoDB'}
# id = DB.Column(Integer, primary_key=True)

Expand Down
6 changes: 5 additions & 1 deletion backend/gn_module_monitoring/monitoring/schemas.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import json

import geojson
from marshmallow import Schema, fields
from marshmallow import Schema, fields, validate
from marshmallow_sqlalchemy import SQLAlchemyAutoSchema
from pypnnomenclature.schemas import NomenclatureSchema

Expand All @@ -23,6 +23,10 @@ class PaginationSchema(Schema):


class MonitoringSitesGroupsSchema(SQLAlchemyAutoSchema):

sites_group_name = fields.String(
validate=validate.Length(min=3,error="Length must be greater than 3"),)

class Meta:
model = TMonitoringSitesGroups
exclude = ("geom_geojson",)
Expand Down
23 changes: 18 additions & 5 deletions backend/gn_module_monitoring/routes/sites_groups.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from flask import jsonify, request
from geonature.utils.env import db
from gn_module_monitoring.utils.strings.strings import gettext
from sqlalchemy import func
from werkzeug.datastructures import MultiDict

Expand All @@ -15,7 +16,8 @@
sort,
)
from gn_module_monitoring.monitoring.schemas import MonitoringSitesGroupsSchema
from geonature.utils.env import DB
from marshmallow import ValidationError
from gn_module_monitoring.utils.errors.errorHandler import InvalidUsage


@blueprint.route("/sites_groups", methods=["GET"])
Expand Down Expand Up @@ -70,15 +72,26 @@ def patch(_id):
setattr(item, field, item_json[field])
else:
# return {"message": gettext("field_not_valid").format(field,item.__str__())}, 404
raise "field_not_valid"
return InvalidUsage(
gettext("field_not_valid").format(field, item.__tablename__),
status_code=404,
payload=item_json,
)
# item.ab_base = item_json["ab_base"]
else:
item = item_schema.load(item_json)

# TODO: check why there is no select inside fields
structure_data = TMonitoringSitesGroups.get_type_fields()
try:
DB.session.add(item)
DB.session.commit()
item_schema.load(item_json)
db.session.add(item)
db.session.commit()
except ValidationError as err:
return InvalidUsage(
gettext("item_not_validated").format(err.messages), status_code=422, payload=item_json
).to_dict()
except:
return {"message": "item_error_inserting"}, 500
return InvalidUsage("Internal Error", status_code=500).to_dict()

return item_schema.dump(item), 201
Empty file.
30 changes: 30 additions & 0 deletions backend/gn_module_monitoring/utils/errors/errorHandler.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# class APIError(Exception):
# """All custom API Exceptions"""
# pass


class InvalidUsage(Exception):
status_code = 400

def __init__(self, message, status_code=None, payload=None):
Exception.__init__(self)
self.message = message
if status_code is not None:
self.status_code = status_code
self.payload = payload


def to_dict(self):
rv = {}
# rv['payload'] = dict(self.payload or ())
rv["payload"] = self.payload
rv["message"] = self.message
rv["status_code"] = self.status_code
return (rv,self.status_code)


class APIAuthError(Exception):
"""Custom Authentication Error Class."""

code = 403
description = "Authentication Error"
Empty file.
8 changes: 8 additions & 0 deletions backend/gn_module_monitoring/utils/strings/en-gb.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"item_name_exists": "An item with name '{}' already exists.",
"item_error_inserting": "An error occurred while inserting the item.",
"item_not_found": "An item <id='{}'> cannot be found.",
"item_deleted": "Item deleted.",
"item_not_validated" :"Validation fields not pass , message : {}",
"field_not_valid":"The field '{}' from request body is not valid see the model {} '"
}
25 changes: 25 additions & 0 deletions backend/gn_module_monitoring/utils/strings/strings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
"""
libs.strings
By default, uses `en-gb.json` file inside the `strings` top-level folder.
If language changes, set `libs.strings.default_locale` and run `libs.strings.refresh()`.
"""
import json,os

default_locale = "en-gb"
cached_strings = {}
dir = os.path.dirname(os.path.realpath(__file__))
# parent_dir = os.path.abspath(os.path.join(dir, os.pardir))
def refresh():
print("Refreshing...")
global cached_strings
with open(os.path.join(dir,f"{default_locale}.json")) as f:
cached_strings = json.load(f)


def gettext(name):
return cached_strings[name]


refresh()
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
:host ::ng-deep .obj-form {
margin: 0;
margin-bottom: 10px;
padding: 0;
}

.hide-spinner {
display: none;
}

.btn-height {
height: 39px;
}

.float-right {
margin-left: 5px;
}


.float-left {
margin-right: 10px;
float: left;
}

form:invalid {
outline: none;
}

form.ng-invalid {
border: 0px !important;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
<pnx-modal-msg [bDisplayModal]="bDeleteModal" *ngIf="obj && obj.bIsInitialized">
<h2>Attention</h2>
<p>
<!-- TODO: voir pour améliorer le passage d'informations ici -->
Vous êtes sur le point de supprimer le groupe de site
<b>Description du groupe de site</b>
</p>
<button class="btn btn-danger float-right" (click)="onDelete()">
<span
[ngClass]="{ 'hide-spinner': !bDeleteSpinner }"
class="spinner-border spinner-border-sm"
role="status"
aria-hidden="true"
></span>
Confirmer la suppression
</button>
<button class="btn btn-primary" (click)="bDeleteModal = false">
Annuler
</button>
</pnx-modal-msg>

<div>
<div
id="properties-form"
class="cadre"
>
<!-- TODO: voir pour intiialisation si nécessaire à remettre dans la div du dessus -->
<!-- *ngIf="obj.bIsInitialized && objFormsDefinition" -->


<!-- TODO: Voir pour l'enchainement des saisies -->
<!-- <span
*ngIf="!obj.id && obj.config['chained']"
id="toggle-btn"
class="float-right"
matTooltip="Enchainer les saisies"
matTooltipPosition="left"
>
<i class="fa fa-repeat" aria-hidden="true"></i>
<mat-slide-toggle
color="primary"
[(ngModel)]="bChainInput"
(change)="bChainInputChanged($event)"
>
</mat-slide-toggle>
</span> -->

<form [formGroup]="objForm">

<!-- TODO: Gérer la saisie de géometrie -->
<!-- <p
class="alert alert-warning"
style="display:inline-block;"
*ngIf="obj.config['geometry_type'] && !objForm.value.geometry"
>
<span> Veuillez saisir une géométrie sur la carte </span>
</p> -->

<!-- composant choix de site select + filtre -->

<!-- <pnx-dynamic-form-generator
class="obj-form"
#dynamicForm
[autoGenerated]="true"
[myFormGroup]="objForm"
[formsDefinition]="objFormsDefinition"
(myFormGroupChange)="initForm()"
(change)="onObjFormValueChange($event)"
></pnx-dynamic-form-generator> -->

<div>
<!-- <button
*ngIf="!bChainInput && !obj.id && obj.uniqueChildrenName()"
class="btn btn-success float-right"
(click)="bSaveAndAddChildrenSpinner = bAddChildren = true; onSubmit()"
[disabled]="!objForm.valid"
>
<span
[ngClass]="{ 'hide-spinner': !bSaveAndAddChildrenSpinner }"
class="spinner-border spinner-border-sm float-right"
role="status"
aria-hidden="true"
></span>
<span
>Valider et saisir des {{obj.uniqueChildrenName()}}</span
>
</button> -->

<button
class="btn btn-success float-right"
(click)="bSaveSpinner = true; onSubmit()"
[disabled]="!objForm.valid"
>
<span
[ngClass]="{ 'hide-spinner': !bSaveSpinner }"
class="spinner-border spinner-border-sm float-right"
role="status"
aria-hidden="true"
></span>

<!-- <span *ngIf="bChainInput && !obj.id"
>Valider et enchainer les saisies</span
> -->
<!-- <span *ngIf="!bChainInput || obj.id">Valider</span>
</button> -->
<span >Valider</span>
</button>

<button class="btn btn-primary float-left" (click)="onCancelEdit()">
Annuler
</button>
<button
class="btn btn-danger float-left"
(click)="bDeleteModal = true"
*ngIf="obj.id && (currentUser['cruved_object'][obj.objectType] || currentUser['cruved']).D >= obj.cruved('D')"
>
Supprimer
</button>
</div>
<div class="btn-height"></div>
</form>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';

import { MonitoringFormComponent } from './monitoring-form.component';

describe('MonitoringFormComponent', () => {
let component: MonitoringFormComponent;
let fixture: ComponentFixture<MonitoringFormComponent>;

beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ MonitoringFormComponent ]
})
.compileComponents();
}));

beforeEach(() => {
fixture = TestBed.createComponent(MonitoringFormComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
Loading

0 comments on commit dd3755f

Please sign in to comment.