[develop]: Add sortBy # of publicatiosn options in RFOs/RPOs. Add indicator caching option.

This commit is contained in:
Konstantinos Triantafyllou 2024-02-20 11:02:04 +02:00
parent f5d85aef86
commit 37a678d571
14 changed files with 140 additions and 38 deletions

View File

@ -31,6 +31,7 @@
"@angular/platform-server": "^16.2.0",
"@angular/router": "^16.2.0",
"@nguniversal/express-engine": "^16.2.0",
"axios": "^1.4.0",
"clipboard": "^1.5.16",
"express": "^4.15.2",
"jquery": "^3.4.1",

View File

@ -13,12 +13,18 @@ var jsonParser = bodyParser.json()
import * as fs from 'fs';
import {readFileSync} from "fs";
import {properties} from "./src/environments/environment";
import axios, {AxiosHeaders} from "axios";
import {CacheIndicators} from "./src/app/openaireLibrary/monitor-admin/utils/cache-indicators/cache-indicators";
import {UserManagementService} from "./src/app/openaireLibrary/services/user-management.service";
import {Session, User} from "./src/app/openaireLibrary/login/utils/helper.class";
import {Stakeholder} from "./src/app/openaireLibrary/monitor/entities/stakeholder";
// The Express app is exported so that it can be used by serverless Functions.
export function app(): express.Express {
const server = express();
server.use(compression());
const distFolder = join(process.cwd(), 'dist/irish-monitor/browser');
const indexHtml = existsSync(join(distFolder, 'index.original.html')) ? 'index.original.html' : 'index';
let cacheIndicators: CacheIndicators = new CacheIndicators();
// Our Universal express-engine (found @ https://github.com/angular/universal/tree/main/modules/express-engine)
server.engine('html', ngExpressEngine({
@ -67,6 +73,65 @@ export function app(): express.Express {
message: 'action received!'
});
});
server.post('/cache/:alias', jsonParser, async (req, res) => {
await checkPermissions(req, res, (stakeholder, user) => {
if (cacheIndicators.completed(stakeholder._id)) {
res.send({
id: stakeholder._id,
report: cacheIndicators.createReport(stakeholder._id, cacheIndicators.stakeholderToCacheItems(stakeholder), stakeholder.name, user.email)
});
} else {
res.status(409).send('There is another active caching process for this stakeholder');
}
});
});
server.get('/cache/:alias', async (req, res) => {
await checkPermissions(req, res, stakeholder => {
if (cacheIndicators.exists(stakeholder._id)) {
res.send({
id: stakeholder._id,
report: cacheIndicators.getReport(stakeholder._id)
});
} else {
res.status(404).send('There is not an active caching process for this stakeholder');
}
});
});
async function checkPermissions(req, res, access: (stakeholder, user) => void) {
let headers: AxiosHeaders = new AxiosHeaders();
headers.set('Cookie', req.headers.cookie);
let userinfoRes = (await axios.get<any>(UserManagementService.userInfoUrl(), {
withCredentials: true,
headers: headers
}).catch(error => {
return error.response;
}));
if (userinfoRes.status === 200) {
let user = new User(userinfoRes.data);
let stakeholderRes = (await axios.get<Stakeholder>(properties.monitorServiceAPIURL + '/stakeholder/' + encodeURIComponent(req.params.alias), {
withCredentials: true,
headers: headers
}).catch(error => {
return error.response;
}));
if (stakeholderRes.status === 200) {
let stakeholder = stakeholderRes.data;
if (Session.isPortalAdministrator(user) || Session.isCurator(stakeholder.type, user)) {
access(stakeholder, user);
} else {
res.status(403).send('You are forbidden to access this resource');
}
} else {
res.status(stakeholderRes.status).send(stakeholderRes.statusText);
}
} else {
res.status(userinfoRes.status).send(userinfoRes.data.message);
}
}
server.get('*.*', express.static(distFolder, {
maxAge: '1y'
}));

View File

@ -27,6 +27,7 @@ import {Irish} from "../shared/irish";
<router-outlet></router-outlet>
</div>
</div>
<cache-indicators *ngIf="stakeholder && isAdmin" [alias]="stakeholder.alias"></cache-indicators>
</div>
`
})

View File

@ -9,6 +9,7 @@ import {LogoUrlPipeModule} from "../openaireLibrary/utils/pipes/logoUrlPipe.modu
import {AdminLoginGuard} from "../openaireLibrary/login/adminLoginGuard.guard";
import {LoginGuard} from "../openaireLibrary/login/loginGuard.guard";
import {AdminDashboardGuard} from "../openaireLibrary/monitor-admin/utils/adminDashboard.guard";
import {CacheIndicatorsModule} from "../openaireLibrary/monitor-admin/utils/cache-indicators/cache-indicators.module";
@NgModule({
imports: [CommonModule, RouterModule.forChild([
@ -59,7 +60,7 @@ import {AdminDashboardGuard} from "../openaireLibrary/monitor-admin/utils/adminD
}
]
}
]), SideBarModule, LoadingModule, LogoUrlPipeModule],
]), SideBarModule, LoadingModule, LogoUrlPipeModule, CacheIndicatorsModule],
declarations: [AdminComponent],
exports: [AdminComponent]
})

@ -1 +1 @@
Subproject commit 368ef1aba443cc94d1e95b95c237d3ef2d67e906
Subproject commit 35323bd7441d7d21ce785aade0002ee02fdc402a

View File

@ -2,32 +2,30 @@ import {ChangeDetectorRef, Component} from "@angular/core";
import {ActivatedRoute, Router} from "@angular/router";
import {FormBuilder} from "@angular/forms";
import {BrowseStakeholderBaseComponent} from "../../shared/browse-stakeholder-base.component";
import {StakeholderService} from "../../openaireLibrary/monitor/services/stakeholder.service";
import {LayoutService} from "../../openaireLibrary/dashboard/sharedComponents/sidebar/layout.service";
import {Option} from "../../openaireLibrary/sharedComponents/input/input.component";
import {Stakeholder} from "../../openaireLibrary/monitor/entities/stakeholder";
import {SearchDataprovidersService} from "../../openaireLibrary/services/searchDataproviders.service";
import {SearchResult} from "../../openaireLibrary/utils/entities/searchResult";
import {ResultPreview} from "../../openaireLibrary/utils/result-preview/result-preview";
import {Observable, forkJoin, of} from "rxjs";
import {forkJoin, Observable, of} from "rxjs";
import {catchError} from "rxjs/operators";
import {StakeholderPublication} from "../../shared/irish";
import {IrishMonitorService} from "../../shared/irish-monitor.service";
@Component({
selector: 'browse-repository',
templateUrl: 'browse-repositories.component.html'
})
export class BrowseRepositoriesComponent extends BrowseStakeholderBaseComponent {
filteredStakeholders: StakeholderRepository[];
sortBy = 'alphAsc';
sortOptions: Option[] = [
{value: 'alphAsc', label: 'Alphabetically Asc. (A-Z)'},
{value: 'alphDsc', label: 'Alphabetically Dsc. (Z-A)'},
{value: 'mostRecent', label: 'Most recent'},
{value: 'leastRecent', label: 'Least recent'},
{value: 'alphDsc', label: 'Alphabetically Dsc. (Z-A)'}
]
constructor(protected _route: ActivatedRoute,
protected _router: Router,
protected stakeholderService: StakeholderService,
protected irishMonitorService: IrishMonitorService,
protected layoutService: LayoutService,
protected cdr: ChangeDetectorRef,
protected fb: FormBuilder,
@ -46,15 +44,6 @@ export class BrowseRepositoriesComponent extends BrowseStakeholderBaseComponent
this.stakeholders = this.stakeholders.sort((a, b) => b['index_name'].localeCompare(a['index_name']));
this.afterStakeholdersInitialized();
break;
case 'mostRecent':
// compare creationDate?
this.stakeholders = this.stakeholders.sort((a, b) => Number(b['creationDate']) - Number(a['creationDate']));
this.afterStakeholdersInitialized();
break;
case 'leastRecent':
this.stakeholders = this.stakeholders.sort((a, b) => Number(a['creationDate']) - Number(b['creationDate']));
this.afterStakeholdersInitialized();
break;
default:
break;
}
@ -95,6 +84,7 @@ export class BrowseRepositoriesComponent extends BrowseStakeholderBaseComponent
return ResultPreview.searchResultConvert(result, (result.entityType) ? result.entityType : this.typeAsLabel);
}
}
export class StakeholderRepository extends Stakeholder {
export class StakeholderRepository extends StakeholderPublication {
details: any;
}
}

View File

@ -35,7 +35,7 @@ import {OpenaireEntities} from "../openaireLibrary/utils/properties/searchFields
<div class="uk-width-expand uk-margin-small-left">
<div class="uk-h4 uk-margin-xsmall-bottom uk-text-truncate">{{author.authorGivenName}} {{author.authorFamilyName}}</div>
<div class="uk-text-xsmall uk-text-bold uk-margin-bottom">
<div *ngIf="totalResults > 0">{{totalResults}} research outcomes</div>
<div *ngIf="totalResults > 0">{{totalResults}} {{openaireEntities.RESULTS}}</div>
<div *ngIf="author.institutions" class="uk-text-truncate">{{author.institutions.join(", ")}} </div>
</div>
<div class="uk-flex uk-flex-middle uk-text-small uk-text-italic">
@ -90,6 +90,7 @@ export class ResearcherComponent extends ResearcherBaseComponent implements OnI
stakeholder;
isSearch: boolean = false;
openaireEntities = OpenaireEntities;
constructor(protected _router: Router,
protected _route: ActivatedRoute,
protected seoService: SEOService,

View File

@ -41,7 +41,7 @@
<div class="uk-padding-remove-left uk-width-expand">
<div class="uk-h6 uk-margin-xsmall-bottom uk-text-truncate">{{author.authorGivenName}} {{author.authorFamilyName}}</div>
<div class="uk-text-primary uk-text-xsmall uk-text-bold">
<div *ngIf="author.resultsCount && author.resultsCount > 0">{{author.resultsCount}} research outcomes</div>
<div *ngIf="author.resultsCount && author.resultsCount > 0">{{author.resultsCount}} {{openaireEntities.RESULTS}}</div>
<div class="uk-text-truncate" *ngIf="author.institutions">{{author.institutions.join(", ")}}</div>
</div>
</div>
@ -59,7 +59,7 @@
<div *ngIf="orcidStatus == errorCodes.LOADING" class="uk-height-medium uk-position-relative" role="alert">
<loading class="uk-position-center"></loading>
</div>
<div class="uk-flex uk-flex-center">
<div class="uk-flex uk-flex-center uk-margin-medium-top">
<button *ngIf="authorsToShow.length > 0 && orcidStatus != errorCodes.LOADING && (authorsToShow.length > page*size || authors.length > authorsRendered)" class="uk-button uk-button-default" [class.uk-disabled]="orcidStatus == errorCodes.LOADING" (click)="loadMore()" >Load more</button>
</div>
</div>

View File

@ -12,12 +12,14 @@ import {SEOService} from "../../openaireLibrary/sharedComponents/SEO/SEO.service
import {PiwikService} from "../../openaireLibrary/utils/piwik/piwik.service";
import {Meta, Title} from "@angular/platform-browser";
import {map} from "rxjs/operators";
import {OpenaireEntities} from "../../openaireLibrary/utils/properties/searchFields";
@Component({
selector: 'search-researcher',
templateUrl: './search-researcher.component.html',
})
export class SearchResearcherComponent extends BaseComponent implements OnInit {
openaireEntities = OpenaireEntities;
page: number = 1;
size: number = 10;
public keyword: string = "";//"paolo manghi";//'0000-0001-7291-3210';

View File

@ -7,30 +7,35 @@ import {debounceTime, distinctUntilChanged} from "rxjs/operators";
import {HelperFunctions} from "../openaireLibrary/utils/HelperFunctions.class";
import {StakeholderService} from "../openaireLibrary/monitor/services/stakeholder.service";
import {LayoutService} from "../openaireLibrary/dashboard/sharedComponents/sidebar/layout.service";
import {IrishMonitorService} from "./irish-monitor.service";
import {StakeholderPublication} from "./irish";
import {OpenaireEntities} from "../openaireLibrary/utils/properties/searchFields";
@Directive()
export class BrowseStakeholderBaseComponent extends StakeholderBaseComponent implements OnInit {
openaireEntities = OpenaireEntities;
stakeholderType: StakeholderType;
stakeholders: Stakeholder[] = [];
filteredStakeholders: Stakeholder[] = [];
stakeholders: StakeholderPublication[] = [];
filteredStakeholders: StakeholderPublication[] = [];
showLoading: boolean = true;
isMobile: boolean = false;
gridView: boolean = true;
sortOptions: Option[] = [
{value: null, label: 'Number of Publications'},
{value: 'alphAsc', label: 'Alphabetically Asc. (A-Z)'},
{value: 'alphDsc', label: 'Alphabetically Dsc. (Z-A)'},
/*{value: 'oaDsc', label: '"Open Access %" Dsc.'}*/
];
pageOptions: number[] = [10, 20, 30, 40];
sortBy: string = 'alphAsc';
sortBy: string = null;
currentPage: number = 1;
pageSize: number = 10;
parameters = {};
keywordControl: FormControl;
/* Services */
protected stakeholderService: StakeholderService;
protected irishMonitorService: IrishMonitorService;
protected layoutService: LayoutService;
protected cdr: ChangeDetectorRef;
protected fb: FormBuilder;
@ -49,10 +54,10 @@ export class BrowseStakeholderBaseComponent extends StakeholderBaseComponent imp
if(!this.stakeholderType) {
this.navigateToError();
}
this.subscriptions.push(this.stakeholderService.getStakeholders(this.properties.monitorServiceAPIURL, this.stakeholderType).subscribe(stakeholders => {
this.subscriptions.push(this.irishMonitorService.getStakeholdersWithPublications(this.stakeholderType).subscribe(stakeholders => {
this.stakeholders = stakeholders;
this.filteredStakeholders = stakeholders;
this.filteredStakeholders.sort((a, b) => a['name'].localeCompare(b['name']));
this.sortByChanged();
this.filtering(this.keywordControl.value);
}));
this.subscriptions.push(this.keywordControl.valueChanges.pipe(debounceTime(200), distinctUntilChanged()).subscribe(value => {
@ -84,11 +89,8 @@ export class BrowseStakeholderBaseComponent extends StakeholderBaseComponent imp
case 'alphDsc':
this.stakeholders = this.stakeholders.sort((a, b) => b['name'].localeCompare(a['name']));
break;
case 'oaDsc':
// TODO: dont have an OA percentage yet
// this.stakeholders = this.stakeholders.sort((a, b) => b['openAccessPercentage'] - a['openAccessPercentage']);
break;
default:
this.stakeholders = this.stakeholders.sort((a, b) => b.publications - a.publications);
break;
}
}

View File

@ -25,7 +25,7 @@
</div>
<div class="uk-flex uk-flex-middle uk-flex-between uk-margin-large-top">
<div class="uk-flex uk-flex-middle">
<div class="uk-width-small uk-margin-medium-right">
<div *ngIf="sortOptions?.length > 0" class="uk-width-small uk-margin-medium-right">
<div input
type="select" placeholder="Sort by" inputClass="border-bottom"
[options]="sortOptions" [(value)]="sortBy" (valueChange)="sortByChanged()">
@ -75,6 +75,9 @@
{{item.name}}
</div>
</div>
<div *ngIf="item.publications" class="uk-margin-small-top uk-text-xsmall uk-text-center">
{{openaireEntities.PUBLICATIONS}}: {{item.publications | number}}
</div>
</div>
<!-- when OA badges are re-introduced, the below if-statement will have to be moved on its correct div -->
<div *ngIf="item.funderType" class="uk-card-footer uk-padding-small uk-background-muted">
@ -114,6 +117,7 @@
<tr>
<th>Logo</th>
<th>Name</th>
<th># of Publications</th>
<th *ngIf="stakeholderType === 'funder'">Type</th>
<!-- <th class="uk-flex uk-flex-middle">
<icon [name]="'open_access'" [flex]="true" [ratio]="0.8" class="open-access"></icon>
@ -138,6 +142,11 @@
{{item.name}}
</div>
</td>
<td>
<div class="uk-text-truncate uk-text-capitalize uk-text-italic uk-text-small uk-text-bold" [title]="item.name">
{{item.publications | number}}
</div>
</td>
<td *ngIf="stakeholderType === 'funder'">
<div *ngIf="item.funderType" class="uk-text-small uk-text-bold uk-text-capitalize">
{{getFunderTypeLabel(item.funderType)}}

View File

@ -1,9 +1,9 @@
import {ChangeDetectorRef, Component} from "@angular/core";
import {ActivatedRoute, Router} from "@angular/router";
import {StakeholderService} from "../../openaireLibrary/monitor/services/stakeholder.service";
import {LayoutService} from "src/app/openaireLibrary/dashboard/sharedComponents/sidebar/layout.service";
import {FormBuilder} from "@angular/forms";
import {BrowseStakeholderBaseComponent} from "../browse-stakeholder-base.component";
import {IrishMonitorService} from "../irish-monitor.service";
@Component({
selector: 'browse-stakeholder',
@ -13,7 +13,7 @@ export class BrowseStakeholdersComponent extends BrowseStakeholderBaseComponent
constructor(protected _route: ActivatedRoute,
protected _router: Router,
protected stakeholderService: StakeholderService,
protected irishMonitorService: IrishMonitorService,
protected layoutService: LayoutService,
protected cdr: ChangeDetectorRef,
protected fb: FormBuilder) {

View File

@ -0,0 +1,25 @@
import {Injectable} from "@angular/core";
import {HttpClient} from "@angular/common/http";
import {Observable} from "rxjs";
import {StakeholderPublication} from "./irish";
import {properties} from "../../environments/environment";
import {Stakeholder, StakeholderType} from "../openaireLibrary/monitor/entities/stakeholder";
import {CustomOptions} from "../openaireLibrary/services/servicesUtils/customOptions.class";
import {map} from "rxjs/operators";
import {HelperFunctions} from "../openaireLibrary/utils/HelperFunctions.class";
@Injectable({
providedIn: 'root'
})
export class IrishMonitorService {
constructor(private http: HttpClient) {
}
public getStakeholdersWithPublications(type: StakeholderType): Observable<StakeholderPublication[]> {
return this.http.get<StakeholderPublication[]>(properties.monitorServiceAPIURL + '/publications/' + type, CustomOptions.registryOptions()).pipe(map(stakeholders => {
return HelperFunctions.copy(Stakeholder.checkIsUpload(stakeholders));
}));
}
}

View File

@ -2,6 +2,7 @@ import {Portal} from "../openaireLibrary/utils/entities/adminTool/portal";
import {StakeholderConfiguration} from "../openaireLibrary/monitor-admin/utils/indicator-utils";
import {LayoutService} from "../openaireLibrary/dashboard/sharedComponents/sidebar/layout.service";
import {Role} from "../openaireLibrary/login/utils/helper.class";
import {Stakeholder} from "../openaireLibrary/monitor/entities/stakeholder";
export class Irish {
public static irishAdminToolsPortalType = "country";
@ -42,7 +43,7 @@ export class Irish {
{icon: 'earth', value: "PUBLIC", label: 'Public'},
];
StakeholderConfiguration.CACHE_INDICATORS = false;
StakeholderConfiguration.CACHE_INDICATORS = true;
LayoutService.HEADER_HEIGHT = '60px';
@ -50,3 +51,7 @@ export class Irish {
}
}
export class StakeholderPublication extends Stakeholder {
publications: number;
}