Skip to content

Commit

Permalink
feat: setup tab for media in taxon sheet
Browse files Browse the repository at this point in the history
  • Loading branch information
edelclaux committed Oct 24, 2024
1 parent 46ecee3 commit e702a5a
Show file tree
Hide file tree
Showing 10 changed files with 255 additions and 2 deletions.
23 changes: 23 additions & 0 deletions backend/geonature/core/gn_synthese/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
jsonify,
g,
)
from geonature.core.gn_commons.schemas import TMedias
from geonature.core.gn_synthese.schemas import ReportSchema, SyntheseSchema
from geonature.core.gn_synthese.synthese_config import MANDATORY_COLUMNS
from pypnusershub.db.models import User
Expand Down Expand Up @@ -1466,6 +1467,28 @@ def notify_new_report_change(synthese, user, id_roles, content):
)


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

query = select(TMedias).join(Synthese.medias).order_by(TMedias.meta_create_date.desc())

taxref_cd_nom_list = db.session.scalars(select(Taxref.cd_nom).where(Taxref.cd_ref == cd_ref))
query = query.where(Synthese.cd_nom.in_(taxref_cd_nom_list))

pagination = DB.paginate(query, page=page, per_page=per_page)
return {
"total": pagination.total,
"page": pagination.page,
"per_page": pagination.per_page,
"items": [media.as_dict() for media in pagination.items],
}


@routes.route("/reports/<int:id_report>", methods=["PUT"])
@login_required
@json_resp
Expand Down
14 changes: 14 additions & 0 deletions backend/geonature/tests/test_synthese.py
Original file line number Diff line number Diff line change
Expand Up @@ -1836,3 +1836,17 @@ def test_export_observations_sensitive_excluded(
# No feature accessible because sensitive data excluded if
# the user has no right to see it
assert len(response.json["features"]) == 0


@pytest.mark.usefixtures("client_class", "temporary_transaction")
class TestMediaTaxon:
def test_taxon_medias(self, synthese_read_permissions, users):
set_logged_user(self.client, users["self_user"])
synthese_read_permissions(users["self_user"], None, sensitivity_filter=True)

cd_ref = db.session.scalar(select(Taxref.cd_ref))

response = self.client.get(url_for("gn_synthese.taxon_medias", cd_ref=cd_ref))

assert response.status_code == 200
assert isinstance(response.json["items"], list)
1 change: 1 addition & 0 deletions backend/geonature/utils/config_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ class TaxonSheet(Schema):
# --------------------------------------------------------------------
# SYNTHESE - TAXON_SHEET
ENABLE_PROFILE = fields.Boolean(load_default=True)
ENABLE_MEDIA = fields.Boolean(load_default=True)


class Synthese(Schema):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
<div class="flex-container">
<ng-container *ngIf="ms.typeMedia(media) === 'PDF'">
<embed
[src]="media.safeUrl"
[src]="media.safeEmbedUrl"
width="100%"
[height]="height"
type="application/pdf"
Expand Down Expand Up @@ -68,7 +68,7 @@
</ng-container>
<ng-container *ngIf="ms.typeMedia(media) === 'Photo'">
<img
*ngIf="['medium', 'small'].includes(display)"
*ngIf="['medium', 'small', 'xlarge', 'xxlarge'].includes(display)"
class="media-center"
[src]="media.href(config.API_ENDPOINT, config.MEDIA_URL, thumbnailHeight)"
[ngClass]="{ 'media-diapo-link': !!diaporama }"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ export class DisplayMediasComponent {
mini: 50,
small: 100,
medium: 200,
large: 300,
xlarge: 400,
xxlarge: 500,
};

this.height = heights[this.display] ? `${heights[this.display]}px` : '100%';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@ export class SyntheseDataService {
});
}

getTaxonMedias(cdRef: number, params?: {}): Observable<any> {
return this._api.get(`${this.config.API_ENDPOINT}/synthese/taxon_medias/${cdRef}`, {
params,
});
}

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,55 @@
<div
class="MediaContainer MediaContainer--empty"
*ngIf="medias.length === 0"
>
<p class="no-media">No media</p>
</div>
<div
class="MediaContainer"
*ngIf="medias.length !== 0"
>
<div class="MediaContainer__list">
<div class="List">
<ng-container *ngFor="let media of medias">
<div
class="List__item"
(click)="selectMedia(media)"
>
<img
*ngIf="ms.typeMedia(media) === 'Photo'"
[src]="ms.href(media, 100)"
alt="Miniature"
[ngClass]="
media.id_media == selectedMedia.id_media
? 'Media Media--thumbnail Media--selected'
: 'Media Media--thumbnail'
"
/>
<div
*ngIf="ms.typeMedia(media) !== 'Photo'"
[ngClass]="media.id_media == selectedMedia.id_media ? 'Media Media--selected' : 'Media'"
>
<mat-icon>{{ ms.icon(media) }}</mat-icon>
</div>
</div>
</ng-container>
</div>

<mat-paginator
[pageSizeOptions]="[10, 25, 50, 100]"
[pageSize]="pagination.perPage"
[length]="pagination.totalItems"
[pageIndex]="pagination.currentPage"
(page)="onPageChange($event)"
></mat-paginator>
</div>

<div class="MediaContainer__view">
<pnx-display-medias
[medias]="[selectedMedia]"
[index]="0"
display="xxlarge"
diaporama="false"
></pnx-display-medias>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
.MediaContainer {
display: flex;
justify-content: space-between;
width: 100%;

&--empty {
flex: 1;
justify-content: center;
align-items: center;
}

&__view,
&__list {
width: 50%;
}

&__view {
overflow: hidden;
align-content: center;
}

&__list {
display: flex;
flex-direction: column;
justify-content: space-between;
// flex: 1;
min-width: 0;

.List {
display: flex;
flex-flow: row wrap;
gap: 2rem;
margin: 1rem;
justify-content: start;
&__item {
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;

.Media {
width: 5rem;
height: 5rem;
color: rgba(0, 0, 0, 0.87);
display: flex;
justify-content: center;
align-items: center;
border: 3px solid rgba(0, 0, 0, 0.125);
border-radius: 8px;
&--thumbnail {
height: 7rem;
width: auto;
border-color: rgba(0, 0, 0, 0);
}
&--selected {
border-color: var(--purple) !important;
}
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { Component, OnInit } from '@angular/core';
import { Taxon } from '@geonature_common/form/taxonomy/taxonomy.component';
import { MediaService } from '@geonature_common/service/media.service';
import { TaxonSheetService } from '../taxon-sheet.service';
import { GN2CommonModule } from '@geonature_common/GN2Common.module';
import { CommonModule } from '@angular/common';
import { PageEvent } from '@angular/material/paginator';
import { SyntheseDataService } from '@geonature_common/form/synthese-form/synthese-data.service';

export interface Pagination {
totalItems: number;
currentPage: number;
perPage: number;
}

export const DEFAULT_PAGINATION: Pagination = {
totalItems: 0,
currentPage: 0,
perPage: 10,
};

@Component({
standalone: true,
selector: 'pnx-tab-media',
templateUrl: './tab-media.component.html',
styleUrls: ['./tab-media.component.scss'],
imports: [GN2CommonModule, CommonModule],
})
export class TabMediaComponent implements OnInit {
public medias: any[] = [];
public selectedMedia: any = {};
taxon: Taxon | null = null;
pagination: Pagination = DEFAULT_PAGINATION;

constructor(
public ms: MediaService,
private _tss: TaxonSheetService,
private _syntheseDataService: SyntheseDataService
) {}

ngOnInit() {
this._tss.taxon.subscribe((taxon) => {
this.taxon = taxon;
if (!this.taxon) {
this.medias = [];
this.selectedMedia = {};
this.pagination = DEFAULT_PAGINATION;
return;
}
this.loadMedias();
});
}

loadMedias() {
this._syntheseDataService
.getTaxonMedias(this.taxon.cd_ref, {
page: this.pagination.currentPage + 1,
per_page: this.pagination.perPage,
})
.subscribe((response) => {
this.medias = response.items;
this.pagination = {
totalItems: response.total,
currentPage: response.page - 1,
perPage: response.per_page,
};
if (!this.medias.some((media) => media.id_media == this.selectedMedia.id_media)) {
this.selectedMedia = this.medias[0];
}
});
}

selectMedia(media: any) {
this.selectedMedia = media;
}

onPageChange(event: PageEvent) {
this.pagination.currentPage = event.pageIndex;
this.pagination.perPage = event.pageSize;
this.loadMedias();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,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 { TabMediaComponent } from './tab-media/tab-media.component';

interface Tab {
label: string;
Expand All @@ -30,6 +31,12 @@ export const ALL_TAXON_SHEET_ADVANCED_INFOS_ROUTES: Array<Tab> = [
configEnabledField: 'ENABLE_PROFILE',
component: TabProfileComponent,
},
{
label: 'Médias',
path: 'media',
configEnabledField: 'ENABLE_MEDIA',
component: TabMediaComponent,
},
];

@Injectable({
Expand Down

0 comments on commit e702a5a

Please sign in to comment.