Skip to content

Commit

Permalink
[#11618] Usage statistics page for maintainers (#11691)
Browse files Browse the repository at this point in the history
  • Loading branch information
wkurniawan07 authored Apr 2, 2022
1 parent 0ccc571 commit 5759349
Show file tree
Hide file tree
Showing 29 changed files with 1,212 additions and 40 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package teammates.client.scripts;

import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Random;

import teammates.client.connector.DatastoreClient;
import teammates.common.datatransfer.attributes.UsageStatisticsAttributes;
import teammates.common.exception.EntityAlreadyExistsException;
import teammates.common.exception.InvalidParametersException;
import teammates.common.util.TimeHelper;
import teammates.logic.api.Logic;

/**
* Generates usage statistics objects, mostly for testing purpose.
*/
public class GenerateUsageStatisticsObjects extends DatastoreClient {

// Enough number of statistics for one whole month
private static final int NUM_OF_STATISTICS_OBJECTS = 24 * 31;

private final Logic logic = Logic.inst();

public static void main(String[] args) {
new GenerateUsageStatisticsObjects().doOperationRemotely();
}

@Override
protected void doOperation() {
Instant inst = Instant.now();
Random rand = new Random();

for (int i = 1; i <= NUM_OF_STATISTICS_OBJECTS; i++) {
Instant endTime = TimeHelper.getInstantNearestHourBefore(inst);
Instant startTime = endTime.minus(60, ChronoUnit.MINUTES);

UsageStatisticsAttributes stats = UsageStatisticsAttributes.builder(startTime, 60)
.withNumResponses(rand.nextInt(500))
.withNumCourses(rand.nextInt(8))
.withNumStudents(rand.nextInt(200))
.withNumInstructors(rand.nextInt(15))
.withNumAccountRequests(rand.nextInt(5))
.withNumEmails(rand.nextInt(400))
.withNumSubmissions(rand.nextInt(300))
.build();
try {
logic.createUsageStatistics(stats);
} catch (EntityAlreadyExistsException | InvalidParametersException e) {
e.printStackTrace();
}

inst = inst.minus(1, ChronoUnit.HOURS);
}
}

}
14 changes: 13 additions & 1 deletion src/main/java/teammates/ui/webapi/GetTimeZonesAction.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,19 @@
/**
* Action: get supported time zones.
*/
class GetTimeZonesAction extends AdminOnlyAction {
class GetTimeZonesAction extends Action {

@Override
AuthType getMinAuthLevel() {
return AuthType.LOGGED_IN;
}

@Override
void checkSpecificAccessControl() throws UnauthorizedAccessException {
if (!userInfo.isMaintainer && !userInfo.isAdmin) {
throw new UnauthorizedAccessException("Only Maintainers or Admin are allowed to access this resource.");
}
}

@Override
public JsonResult execute() {
Expand Down
4 changes: 4 additions & 0 deletions src/web/app/pages-admin/admin-page.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ export class AdminPageComponent implements OnInit {
url: '/web/admin/logs',
display: 'Logs',
},
{
url: '/web/admin/stats',
display: 'Usage Statistics',
},
];
isFetchingAuthDetails: boolean = false;

Expand Down
14 changes: 11 additions & 3 deletions src/web/app/pages-admin/admin-pages.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,25 @@ const routes: Routes = [
},
{
path: 'timezone',
loadChildren: () => import('./admin-timezone-page/admin-timezone-page.module')
.then((m: any) => m.AdminTimezonePageModule),
loadChildren: () => import('../pages-monitoring/timezone-page/timezone-page.module')
.then((m: any) => m.TimezonePageModule),
},
{
path: 'logs',
data: {
isAdmin: true,
},
loadChildren: () => import('../pages-logs/logs-page.module')
loadChildren: () => import('../pages-monitoring/logs-page/logs-page.module')
.then((m: any) => m.LogsPageModule),
},
{
path: 'stats',
loadChildren: () => import('../pages-monitoring/usage-stats-page/usage-statistics-page.module')
.then((m: any) => m.UsageStatisticsPageModule),
data: {
pageTitle: 'Usage Statistics',
},
},
{
path: '',
pathMatch: 'full',
Expand Down
8 changes: 8 additions & 0 deletions src/web/app/pages-maintainer/maintainer-page.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@ export class MaintainerPageComponent implements OnInit {
url: '/web/maintainer',
display: 'Home',
},
{
url: '/web/maintainer/timezone',
display: 'Timezone Listing',
},
{
url: '/web/maintainer/stats',
display: 'Usage Statistics',
},
];
isFetchingAuthDetails: boolean = false;

Expand Down
17 changes: 15 additions & 2 deletions src/web/app/pages-maintainer/maintainer-page.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,28 @@ import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { PageNotFoundComponent } from '../page-not-found/page-not-found.component';
import { PageNotFoundModule } from '../page-not-found/page-not-found.module';
import { LogsPageComponent } from '../pages-logs/logs-page.component';

const routes: Routes = [
{
path: 'home',
data: {
isAdmin: false,
},
component: LogsPageComponent,
loadChildren: () => import('../pages-monitoring/logs-page/logs-page.module')
.then((m: any) => m.LogsPageModule),
},
{
path: 'timezone',
loadChildren: () => import('../pages-monitoring/timezone-page/timezone-page.module')
.then((m: any) => m.TimezonePageModule),
},
{
path: 'stats',
loadChildren: () => import('../pages-monitoring/usage-stats-page/usage-statistics-page.module')
.then((m: any) => m.UsageStatisticsPageModule),
data: {
pageTitle: 'Usage Statistics',
},
},
{
path: '',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import { RouterTestingModule } from '@angular/router/testing';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { of } from 'rxjs';
import SpyInstance = jest.SpyInstance;
import { LogService } from '../../services/log.service';
import { StatusMessageService } from '../../services/status-message.service';
import { TimezoneService } from '../../services/timezone.service';
import { GeneralLogEntry, LogEvent, LogSeverity } from '../../types/api-output';
import { LogService } from '../../../services/log.service';
import { StatusMessageService } from '../../../services/status-message.service';
import { TimezoneService } from '../../../services/timezone.service';
import { GeneralLogEntry, LogEvent, LogSeverity } from '../../../types/api-output';
import { LogsPageComponent } from './logs-page.component';
import { LogsPageModule } from './logs-page.module';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { EMPTY } from 'rxjs';
import { expand, finalize, reduce, tap } from 'rxjs/operators';
import { LogService } from '../../services/log.service';
import { StatusMessageService } from '../../services/status-message.service';
import { TimezoneService } from '../../services/timezone.service';
import { ApiConst } from '../../types/api-const';
import { LogService } from '../../../services/log.service';
import { StatusMessageService } from '../../../services/status-message.service';
import { TimezoneService } from '../../../services/timezone.service';
import { ApiConst } from '../../../types/api-const';
import {
ActionClasses,
GeneralLogEntry,
Expand All @@ -15,13 +15,13 @@ import {
QueryLogsParams,
RequestLogUser,
SourceLocation,
} from '../../types/api-output';
import { DateFormat } from '../components/datepicker/datepicker.component';
import { LogsHistogramDataModel } from '../components/logs-histogram/logs-histogram-model';
import { LogsTableRowModel } from '../components/logs-table/logs-table-model';
import { collapseAnim } from '../components/teammates-common/collapse-anim';
import { TimeFormat } from '../components/timepicker/timepicker.component';
import { ErrorMessageOutput } from '../error-message-output';
} from '../../../types/api-output';
import { DateFormat } from '../../components/datepicker/datepicker.component';
import { LogsHistogramDataModel } from '../../components/logs-histogram/logs-histogram-model';
import { LogsTableRowModel } from '../../components/logs-table/logs-table-model';
import { collapseAnim } from '../../components/teammates-common/collapse-anim';
import { TimeFormat } from '../../components/timepicker/timepicker.component';
import { ErrorMessageOutput } from '../../error-message-output';

/**
* Model for searching of logs.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { RouterModule, Routes } from '@angular/router';
import { NgbDatepickerModule, NgbTimepickerModule } from '@ng-bootstrap/ng-bootstrap';
import { LoadingSpinnerModule } from '../components/loading-spinner/loading-spinner.module';
import { LogsHistogramModule } from '../components/logs-histogram/logs-histogram.module';
import { LogsTableModule } from '../components/logs-table/logs-table.module';
import { SortableTableModule } from '../components/sortable-table/sortable-table.module';
import { LoadingSpinnerModule } from '../../components/loading-spinner/loading-spinner.module';
import { LogsHistogramModule } from '../../components/logs-histogram/logs-histogram.module';
import { LogsTableModule } from '../../components/logs-table/logs-table.module';
import { SortableTableModule } from '../../components/sortable-table/sortable-table.module';
import { LogsPageComponent } from './logs-page.component';

const routes: Routes = [
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { LoadingSpinnerModule } from '../../components/loading-spinner/loading-spinner.module';
import { AdminTimezonePageComponent } from './admin-timezone-page.component';
import { TimezonePageComponent } from './timezone-page.component';

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

beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [AdminTimezonePageComponent],
declarations: [TimezonePageComponent],
imports: [
HttpClientTestingModule,
LoadingSpinnerModule,
Expand All @@ -19,7 +19,7 @@ describe('AdminTimezonePageComponent', () => {
}));

beforeEach(() => {
fixture = TestBed.createComponent(AdminTimezonePageComponent);
fixture = TestBed.createComponent(TimezonePageComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ import { TimeZones } from '../../../types/api-output';
* Timezone listing page for admin use.
*/
@Component({
selector: 'tm-admin-timezone-page',
templateUrl: './admin-timezone-page.component.html',
styleUrls: ['./admin-timezone-page.component.scss'],
selector: 'tm-timezone-page',
templateUrl: './timezone-page.component.html',
styleUrls: ['./timezone-page.component.scss'],
})
export class AdminTimezonePageComponent implements OnInit {
export class TimezonePageComponent implements OnInit {

javaTzVersion: string = '';
javaTimezones: Record<string, number> = {};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { LoadingSpinnerModule } from '../../components/loading-spinner/loading-spinner.module';
import { AdminTimezonePageComponent } from './admin-timezone-page.component';
import { TimezonePageComponent } from './timezone-page.component';

const routes: Routes = [
{
path: '',
component: AdminTimezonePageComponent,
component: TimezonePageComponent,
},
];

Expand All @@ -16,15 +16,15 @@ const routes: Routes = [
*/
@NgModule({
declarations: [
AdminTimezonePageComponent,
TimezonePageComponent,
],
exports: [
AdminTimezonePageComponent,
TimezonePageComponent,
],
imports: [
CommonModule,
RouterModule.forChild(routes),
LoadingSpinnerModule,
],
})
export class AdminTimezonePageModule { }
export class TimezonePageModule { }
Loading

0 comments on commit 5759349

Please sign in to comment.