Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add statistics pages #851

Merged
merged 5 commits into from Oct 7, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
18 changes: 17 additions & 1 deletion src/app/+collection-page/collection-page-routing.module.ts
Expand Up @@ -20,6 +20,8 @@ import {
COLLECTION_CREATE_PATH
} from './collection-page-routing-paths';
import { CollectionPageAdministratorGuard } from './collection-page-administrator.guard';
import { MenuItemType } from '../shared/menu/initial-menus-state';
import { LinkMenuItemModel } from '../shared/menu/menu-item/models/link.model';

@NgModule({
imports: [
Expand Down Expand Up @@ -69,7 +71,21 @@ import { CollectionPageAdministratorGuard } from './collection-page-administrato
pathMatch: 'full',
canActivate: [AuthenticatedGuard]
}
]
],
data: {
menu: {
public: [{
id: 'statistics_collection_:id',
active: true,
visible: true,
model: {
type: MenuItemType.LINK,
text: 'menu.section.statistics',
link: 'statistics/collections/:id/',
} as LinkMenuItemModel,
}],
},
},
},
])
],
Expand Down
18 changes: 17 additions & 1 deletion src/app/+community-page/community-page-routing.module.ts
Expand Up @@ -12,6 +12,8 @@ import { DSOBreadcrumbsService } from '../core/breadcrumbs/dso-breadcrumbs.servi
import { LinkService } from '../core/cache/builders/link.service';
import { COMMUNITY_EDIT_PATH, COMMUNITY_CREATE_PATH } from './community-page-routing-paths';
import { CommunityPageAdministratorGuard } from './community-page-administrator.guard';
import { MenuItemType } from '../shared/menu/initial-menus-state';
import { LinkMenuItemModel } from '../shared/menu/menu-item/models/link.model';

@NgModule({
imports: [
Expand Down Expand Up @@ -45,7 +47,21 @@ import { CommunityPageAdministratorGuard } from './community-page-administrator.
component: CommunityPageComponent,
pathMatch: 'full',
}
]
],
data: {
menu: {
public: [{
id: 'statistics_community_:id',
active: true,
visible: true,
model: {
type: MenuItemType.LINK,
text: 'menu.section.statistics',
link: 'statistics/communities/:id/',
} as LinkMenuItemModel,
}],
},
},
},
])
],
Expand Down
18 changes: 17 additions & 1 deletion src/app/+home-page/home-page-routing.module.ts
Expand Up @@ -3,6 +3,8 @@ import { RouterModule } from '@angular/router';

import { HomePageComponent } from './home-page.component';
import { HomePageResolver } from './home-page.resolver';
import { MenuItemType } from '../shared/menu/initial-menus-state';
import { LinkMenuItemModel } from '../shared/menu/menu-item/models/link.model';

@NgModule({
imports: [
Expand All @@ -11,7 +13,21 @@ import { HomePageResolver } from './home-page.resolver';
path: '',
component: HomePageComponent,
pathMatch: 'full',
data: {title: 'home.title'},
data: {
title: 'home.title',
menu: {
public: [{
id: 'statistics_site',
active: true,
visible: true,
model: {
type: MenuItemType.LINK,
text: 'menu.section.statistics',
link: 'statistics',
} as LinkMenuItemModel,
}],
},
},
resolve: {
site: HomePageResolver
}
Expand Down
16 changes: 16 additions & 0 deletions src/app/+item-page/item-page-routing.module.ts
Expand Up @@ -11,6 +11,8 @@ import { LinkService } from '../core/cache/builders/link.service';
import { UploadBitstreamComponent } from './bitstreams/upload/upload-bitstream.component';
import { UPLOAD_BITSTREAM_PATH, ITEM_EDIT_PATH } from './item-page-routing-paths';
import { ItemPageAdministratorGuard } from './item-page-administrator.guard';
import { MenuItemType } from '../shared/menu/initial-menus-state';
import { LinkMenuItemModel } from '../shared/menu/menu-item/models/link.model';

@NgModule({
imports: [
Expand Down Expand Up @@ -43,6 +45,20 @@ import { ItemPageAdministratorGuard } from './item-page-administrator.guard';
canActivate: [AuthenticatedGuard]
}
],
data: {
menu: {
public: [{
id: 'statistics_item_:id',
active: true,
visible: true,
model: {
type: MenuItemType.LINK,
text: 'menu.section.statistics',
link: 'statistics/items/:id/',
} as LinkMenuItemModel,
}],
},
},
}
])
],
Expand Down
4 changes: 4 additions & 0 deletions src/app/app-routing.module.ts
Expand Up @@ -69,6 +69,10 @@ import { SiteRegisterGuard } from './core/data/feature-authorization/feature-aut
{ path: 'processes', loadChildren: './process-page/process-page.module#ProcessPageModule', canActivate: [AuthenticatedGuard, EndUserAgreementCurrentUserGuard] },
{ path: INFO_MODULE_PATH, loadChildren: './info/info.module#InfoModule' },
{ path: UNAUTHORIZED_PATH, component: UnauthorizedComponent },
{
path: 'statistics',
loadChildren: './statistics-page/statistics-page-routing.module#StatisticsPageRoutingModule',
},
{ path: '**', pathMatch: 'full', component: PageNotFoundComponent },
]}
],
Expand Down
4 changes: 3 additions & 1 deletion src/app/core/core.module.ts
Expand Up @@ -171,6 +171,7 @@ import { EndUserAgreementCurrentUserGuard } from './end-user-agreement/end-user-
import { EndUserAgreementCookieGuard } from './end-user-agreement/end-user-agreement-cookie.guard';
import { EndUserAgreementService } from './end-user-agreement/end-user-agreement.service';
import { SiteRegisterGuard } from './data/feature-authorization/feature-authorization-guard/site-register.guard';
import { UsageReport } from './statistics/models/usage-report.model';

/**
* When not in production, endpoint responses can be mocked for testing purposes
Expand Down Expand Up @@ -371,7 +372,8 @@ export const models =
Vocabulary,
VocabularyEntry,
VocabularyEntryDetail,
ConfigurationProperty
ConfigurationProperty,
UsageReport,
];

@NgModule({
Expand Down
51 changes: 51 additions & 0 deletions src/app/core/statistics/models/usage-report.model.ts
@@ -0,0 +1,51 @@
import { autoserialize, inheritSerialization } from 'cerialize';
import { typedObject } from '../../cache/builders/build-decorators';
import { excludeFromEquals } from '../../utilities/equals.decorators';
import { ResourceType } from '../../shared/resource-type';
import { HALResource } from '../../shared/hal-resource.model';
import { USAGE_REPORT } from './usage-report.resource-type';
import { HALLink } from '../../shared/hal-link.model';
import { deserialize, autoserializeAs } from 'cerialize';

/**
* A usage report.
*/
@typedObject
@inheritSerialization(HALResource)
export class UsageReport extends HALResource {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add TypeDocs for this new class, and the Point interface in this same file

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added typedocs


static type = USAGE_REPORT;

/**
* The object type
*/
@excludeFromEquals
@autoserialize
type: ResourceType;

@autoserialize
id: string;

@autoserializeAs('report-type')
reportType: string;

@autoserialize
points: Point[];

@deserialize
_links: {
self: HALLink;
};
}

/**
* A statistics data point.
*/
export interface Point {
id: string;
label: string;
type: string;
values: Array<{
views: number;
}>;
}
9 changes: 9 additions & 0 deletions src/app/core/statistics/models/usage-report.resource-type.ts
@@ -0,0 +1,9 @@
import { ResourceType } from '../../shared/resource-type';

/**
* The resource type for License
*
* Needs to be in a separate file to prevent circular
* dependencies in webpack.
*/
export const USAGE_REPORT = new ResourceType('usagereport');
62 changes: 62 additions & 0 deletions src/app/core/statistics/usage-report-data.service.ts
@@ -0,0 +1,62 @@
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Store } from '@ngrx/store';
import { NotificationsService } from '../../shared/notifications/notifications.service';
import { dataService } from '../cache/builders/build-decorators';
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
import { ObjectCacheService } from '../cache/object-cache.service';
import { CoreState } from '../core.reducers';
import { HALEndpointService } from '../shared/hal-endpoint.service';
import { DataService } from '../data/data.service';
import { RequestService } from '../data/request.service';
import { DefaultChangeAnalyzer } from '../data/default-change-analyzer.service';
import { USAGE_REPORT } from './models/usage-report.resource-type';
import { UsageReport } from './models/usage-report.model';
import { Observable } from 'rxjs';
import { getRemoteDataPayload, getSucceededRemoteData } from '../shared/operators';
import { map } from 'rxjs/operators';

/**
* A service to retrieve {@link UsageReport}s from the REST API
*/
@Injectable()
@dataService(USAGE_REPORT)
export class UsageReportService extends DataService<UsageReport> {

protected linkPath = 'statistics/usagereports';

constructor(
protected comparator: DefaultChangeAnalyzer<UsageReport>,
protected halService: HALEndpointService,
protected http: HttpClient,
protected notificationsService: NotificationsService,
protected objectCache: ObjectCacheService,
protected rdbService: RemoteDataBuildService,
protected requestService: RequestService,
protected store: Store<CoreState>,
) {
super();
}

getStatistic(scope: string, type: string): Observable<UsageReport> {
return this.findById(`${scope}_${type}`).pipe(
getSucceededRemoteData(),
getRemoteDataPayload(),
);
}

searchStatistics(uri: string, page: number, size: number): Observable<UsageReport[]> {
return this.searchBy('object', {
searchParams: [{
fieldName: `uri`,
fieldValue: uri,
}],
currentPage: page,
elementsPerPage: size,
}).pipe(
getSucceededRemoteData(),
getRemoteDataPayload(),
map((list) => list.page),
);
}
}
13 changes: 0 additions & 13 deletions src/app/navbar/navbar.component.ts
Expand Up @@ -64,19 +64,6 @@ export class NavbarComponent extends MenuComponent {
link: `/community-list`
} as LinkMenuItemModel
},

/* Statistics */
{
id: 'statistics',
active: false,
visible: true,
model: {
type: MenuItemType.LINK,
text: 'menu.section.statistics',
link: ''
} as LinkMenuItemModel,
index: 2
},
];
// Read the different Browse-By types from config and add them to the browse menu
const types = environment.browseBy.types;
Expand Down
21 changes: 18 additions & 3 deletions src/app/shared/menu/menu.effects.spec.ts
Expand Up @@ -14,6 +14,7 @@ import { MenuEffects } from './menu.effects';
describe('MenuEffects', () => {
let menuEffects: MenuEffects;
let routeDataMenuSection: MenuSection;
let routeDataMenuSectionResolved: MenuSection;
let routeDataMenuChildSection: MenuSection;
let toBeRemovedMenuSection: MenuSection;
let alreadyPresentMenuSection: MenuSection;
Expand All @@ -23,13 +24,23 @@ describe('MenuEffects', () => {

function init() {
routeDataMenuSection = {
id: 'mockSection',
id: 'mockSection_:idparam',
active: false,
visible: true,
model: {
type: MenuItemType.LINK,
text: 'menu.section.mockSection',
link: ''
link: 'path/:linkparam'
} as LinkMenuItemModel
};
routeDataMenuSectionResolved = {
id: 'mockSection_id_param_resolved',
active: false,
visible: true,
model: {
type: MenuItemType.LINK,
text: 'menu.section.mockSection',
link: 'path/link_param_resolved'
} as LinkMenuItemModel
};
routeDataMenuChildSection = {
Expand Down Expand Up @@ -70,6 +81,10 @@ describe('MenuEffects', () => {
menu: {
[MenuID.PUBLIC]: [routeDataMenuSection, alreadyPresentMenuSection]
}
},
params: {
idparam: 'id_param_resolved',
linkparam: 'link_param_resolved',
}
},
firstChild: {
Expand Down Expand Up @@ -120,7 +135,7 @@ describe('MenuEffects', () => {
});

expect(menuEffects.buildRouteMenuSections$).toBeObservable(expected);
expect(menuService.addSection).toHaveBeenCalledWith(MenuID.PUBLIC, routeDataMenuSection);
expect(menuService.addSection).toHaveBeenCalledWith(MenuID.PUBLIC, routeDataMenuSectionResolved);
expect(menuService.addSection).toHaveBeenCalledWith(MenuID.PUBLIC, routeDataMenuChildSection);
expect(menuService.addSection).not.toHaveBeenCalledWith(MenuID.PUBLIC, alreadyPresentMenuSection);
expect(menuService.removeSection).toHaveBeenCalledWith(MenuID.PUBLIC, toBeRemovedMenuSection.id);
Expand Down