Skip to content

Commit

Permalink
feat: setup tab-observers with paginated content
Browse files Browse the repository at this point in the history
  • Loading branch information
edelclaux committed Sep 26, 2024
1 parent d5cca73 commit 913306c
Show file tree
Hide file tree
Showing 10 changed files with 219 additions and 24 deletions.
66 changes: 42 additions & 24 deletions backend/geonature/core/gn_synthese/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
SyntheseLogEntry,
)
from geonature.core.gn_synthese.synthese_config import MANDATORY_COLUMNS
from geonature.core.gn_synthese.utils.species_sheet import SpeciesSheetUtils

from geonature.core.gn_synthese.utils.blurring import (
build_allowed_geom_cte,
Expand All @@ -66,7 +67,6 @@
from geonature.core.gn_permissions.decorators import login_required, permissions_required
from geonature.core.gn_permissions.tools import get_scopes_by_action, get_permissions
from geonature.core.sensitivity.models import cor_sensitivity_area_type

from ref_geo.models import LAreas, BibAreasTypes

from apptax.taxonomie.models import (
Expand All @@ -81,6 +81,8 @@
VMTaxrefListForautocomplete,
)

from geonature import app


routes = Blueprint("gn_synthese", __name__)

Expand Down Expand Up @@ -965,28 +967,11 @@ def species_stats(scope, cd_ref):

area_type = request.args.get("area_type")

if not area_type:
if not SpeciesSheetUtils.is_valid_area_type(area_type):
raise BadRequest("Missing area_type parameter")

# Ensure area_type is valid
valid_area_types = (
db.session.query(BibAreasTypes.type_code)
.distinct()
.filter(BibAreasTypes.type_code == area_type)
.scalar()
)
if not valid_area_types:
raise BadRequest("Invalid area_type")

# Subquery to fetch areas based on area_type
areas_subquery = (
select([LAreas.id_area])
.where(LAreas.id_type == BibAreasTypes.id_type)
.where(BibAreasTypes.type_code == area_type)
.alias("areas")
)

taxref_cd_nom_list = db.session.scalars(select(Taxref.cd_nom).where(Taxref.cd_ref == cd_ref))
areas_subquery = SpeciesSheetUtils.get_area_subquery(area_type)
taxref_cd_nom_list = SpeciesSheetUtils.get_cd_nom_list_from_cd_ref(cd_ref)

# Main query to fetch stats
query = (
Expand Down Expand Up @@ -1014,9 +999,8 @@ def species_stats(scope, cd_ref):
.where(Synthese.cd_nom.in_(taxref_cd_nom_list))
)

synthese_query_obj = SyntheseQuery(Synthese, query, {})
synthese_query_obj.filter_query_with_cruved(g.current_user, scope)
result = DB.session.execute(synthese_query_obj.query)
synthese_query = SpeciesSheetUtils.get_synthese_query_with_scope(g.current_user, scope, query)
result = DB.session.execute(synthese_query)
synthese_stats = result.fetchone()

data = {
Expand All @@ -1033,6 +1017,40 @@ def species_stats(scope, cd_ref):
return data


if app.config["SYNTHESE"]["SPECIES_SHEET"]["OBSERVERS"]["ENABLED"]:

@routes.route("/species_observers/<int:cd_ref>", methods=["GET"])
@permissions.check_cruved_scope("R", get_scope=True, module_code="SYNTHESE")
# @json_resp
def species_observers(scope, cd_ref):
per_page = int(request.args.get("per_page", 1))
page = request.args.get("page", 1, int)

# taxref_cd_nom_list = SpeciesSheetUtils.get_cd_nom_list_from_cd_ref(cd_ref)
query = (
db.session.query(
func.trim(func.unnest(func.string_to_array(Synthese.observers, ","))).label(
"observer"
),
func.min(Synthese.date_min).label("date_min"),
func.max(Synthese.date_max).label("date_max"),
func.count(Synthese.observers).label("count"),
).group_by("observer")
# .where(Synthese.cd_nom.in_(taxref_cd_nom_list))
)
query = SpeciesSheetUtils.get_synthese_query_with_scope(g.current_user, scope, query)

results = query.paginate(page=page, per_page=per_page, error_out=False)
return jsonify(
{
"items": results.items,
"total": results.total,
"per_page": per_page,
"page": page,
}
)


@routes.route("/taxons_tree", methods=["GET"])
@login_required
@json_resp
Expand Down
5 changes: 5 additions & 0 deletions backend/geonature/core/gn_synthese/synthese_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,11 @@ class DefaultGeographicOverview:
pass


class DefaultObservers:
ENABLED = True
pass


class DefaultSpeciesSheet:
## DEFAULT SPECIES SHEET INDICATORS
LIST_INDICATORS = [
Expand Down
44 changes: 44 additions & 0 deletions backend/geonature/core/gn_synthese/utils/species_sheet.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import typing
from geonature.utils.env import db
from ref_geo.models import LAreas, BibAreasTypes

from geonature.core.gn_synthese.models import Synthese
from sqlalchemy import select
from apptax.taxonomie.models import Taxref
from geonature.core.gn_synthese.utils.query_select_sqla import SyntheseQuery


class SpeciesSheetUtils:

@staticmethod
def get_cd_nom_list_from_cd_ref(cd_ref: int) -> typing.List[int]:
return db.session.scalars(select(Taxref.cd_nom).where(Taxref.cd_ref == cd_ref))

@staticmethod
def get_synthese_query_with_scope(current_user, scope: int, query) -> any:
synthese_query_obj = SyntheseQuery(Synthese, query, {})
synthese_query_obj.filter_query_with_cruved(current_user, scope)
return synthese_query_obj.query

@staticmethod
def is_valid_area_type(area_type: str) -> bool:
# Ensure area_type is valid
valid_area_types = (
db.session.query(BibAreasTypes.type_code)
.distinct()
.filter(BibAreasTypes.type_code == area_type)
.scalar()
)

return valid_area_types

@staticmethod
def get_area_subquery(area_type: str) -> any:

# Subquery to fetch areas based on area_type
return (
select([LAreas.id_area])
.where(LAreas.id_type == BibAreasTypes.id_type)
.where(BibAreasTypes.type_code == area_type)
.alias("areas")
)
6 changes: 6 additions & 0 deletions backend/geonature/utils/config_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
DEFAULT_EXPORT_COLUMNS,
DEFAULT_LIST_COLUMN,
DefaultGeographicOverview,
DefaultObservers,
DefaultProfile,
DefaultSpeciesSheet,
)
Expand Down Expand Up @@ -282,6 +283,10 @@ class SpeciesSheetProfile(Schema):
LIST_INDICATORS = fields.List(fields.Dict, load_default=DefaultProfile.LIST_INDICATORS)


class SpeciesSheetObservers(Schema):
ENABLED = fields.Boolean(load_default=DefaultObservers.ENABLED)


class SpeciesSheetGeographicOverview(Schema):
pass

Expand All @@ -295,6 +300,7 @@ class SpeciesSheet(Schema):
load_default=SpeciesSheetGeographicOverview().load({})
) # rename
PROFILE = fields.Nested(SpeciesSheetProfile, load_default=SpeciesSheetProfile().load({}))
OBSERVERS = fields.Dict(load_default=SpeciesSheetObservers().load({}))


class Synthese(Schema):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export interface SyntheseDataPaginationItem {
totalItems: number;
currentPage: number;
perPage: number;
}

export const DEFAULT_PAGINATION: SyntheseDataPaginationItem = {
totalItems: 0,
currentPage: 1,
perPage: 10,
};
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { BehaviorSubject } from 'rxjs';
import { CommonService } from '@geonature_common/service/common.service';
import { Observable } from 'rxjs';
import { ConfigService } from '@geonature/services/config.service';
import { DEFAULT_PAGINATION, SyntheseDataPaginationItem } from './synthese-data-pagination-item';

export const FormatMapMime = new Map([
['csv', 'text/csv'],
Expand Down Expand Up @@ -61,6 +62,18 @@ export class SyntheseDataService {
});
}

getSyntheseSpeciesSheetObservers(
cd_ref: number,
pagination: SyntheseDataPaginationItem = DEFAULT_PAGINATION
) {
return this._api.get<any>(`${this.config.API_ENDPOINT}/synthese/species_observers/${cd_ref}`, {
params: {
per_page: pagination.perPage,
page: pagination.currentPage,
},
});
}

getTaxaCount(params = {}) {
let queryString = new HttpParams();
for (let key in params) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<div class="Observers">
<ngx-datatable
class="Observers__table material striped"
[rows]="items"
[columns]="columns"
columnMode="force"
[draggable]="false"
[externalPaging]="true"
[count]="pagination.totalItems"
(page)="onChangePage($event)"
footerHeight="auto"
headerHeight="auto"
rowHeight="auto"
></ngx-datatable>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.Observers {
&__table {
box-shadow: none;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { Component, OnInit } from '@angular/core';
import { GN2CommonModule } from '@geonature_common/GN2Common.module';
import { CommonModule } from '@angular/common';
import { ConfigService } from '@geonature/services/config.service';
import { Taxon } from '@geonature_common/form/taxonomy/taxonomy.component';
import { TaxonSheetService } from '../taxon-sheet.service';
import { SyntheseDataService } from '@geonature_common/form/synthese-form/synthese-data.service';
import {
DEFAULT_PAGINATION,
SyntheseDataPaginationItem,
} from '@geonature_common/form/synthese-form/synthese-data-pagination-item';
@Component({
standalone: true,
selector: 'tab-observers',
templateUrl: 'tab-observers.component.html',
styleUrls: ['tab-observers.component.scss'],
imports: [GN2CommonModule, CommonModule],
})
export class TabObserversComponent implements OnInit {
items: any[] = [];
pagination: SyntheseDataPaginationItem = DEFAULT_PAGINATION;

readonly columns = [
{ prop: 'observer', name: 'Observateur' },
{ prop: 'date_min', name: 'Plus ancienne' },
{ prop: 'date_max', name: 'Plus récente' },
{ prop: 'count', name: "Nombre d'observations" },
];

constructor(
private _syntheseDataService: SyntheseDataService,
private _config: ConfigService,
private _tss: TaxonSheetService
) {}

ngOnInit() {
this._tss.taxon.subscribe((taxon: Taxon | null) => {
this.fetchObservers();
});
}

onChangePage(event) {
this.pagination.currentPage = event.offset + 1;
this.fetchObservers();
}

fetchObservers() {
const taxon = this._tss.taxon.getValue();
if (!taxon) {
console.log('taxon is undefined');
return;
}
this._syntheseDataService
.getSyntheseSpeciesSheetObservers(taxon.cd_ref, this.pagination)
.subscribe((data) => {
// Store result
this.items = data.items;
this.pagination = {
totalItems: data.total,
currentPage: data.page,
perPage: data.per_page,
};
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { ConfigService } from '@geonature/services/config.service';
import { Observable } from 'rxjs';
import { TabGeographicOverviewComponent } from './tab-geographic-overview/tab-geographic-overview.component';
import { TabProfileComponent } from './tab-profile/tab-profile.component';
import { TabObserversComponent } from './tab-observers/tab-observers.component';

interface Tab {
label: string;
Expand All @@ -35,9 +36,17 @@ const ROUTE_PROFILE: Tab = {
component: TabProfileComponent,
};

const ROUTE_OBSERVERS: Tab = {
label: 'Observateurs',
path: 'observers',
configEntry: 'OBSERVERS',
component: TabObserversComponent,
};

export const ALL_TAXON_SHEET_ADVANCED_INFOS_ROUTES: Array<Tab> = [
ROUTE_GEOGRAPHIC_OVERVIEW,
ROUTE_PROFILE,
ROUTE_OBSERVERS,
];

@Injectable({
Expand All @@ -53,9 +62,13 @@ export class RouteService implements CanActivateChild {
this.TAB_LINKS.push(ROUTE_MANDATORY);
if (this._config && this._config['SYNTHESE'] && this._config['SYNTHESE']['SPECIES_SHEET']) {
const config = this._config['SYNTHESE']['SPECIES_SHEET'];
console.log(config);
if (config['PROFILE'] && config['PROFILE']['ENABLED']) {
this.TAB_LINKS.push(ROUTE_PROFILE);
}
if (config['OBSERVERS'] && config['OBSERVERS']['ENABLED']) {
this.TAB_LINKS.push(ROUTE_OBSERVERS);
}
}
}

Expand Down

0 comments on commit 913306c

Please sign in to comment.