Skip to content

Commit

Permalink
Merge branch 'add-tii-integration' of https://github.com/doubtfire-lm…
Browse files Browse the repository at this point in the history
…s/doubtfire-web into add-tii-integration
  • Loading branch information
jakerenzella committed Aug 30, 2023
2 parents e4a12ca + 96d982d commit 3549dba
Show file tree
Hide file tree
Showing 17 changed files with 389 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,8 @@
<mat-tab label="Overseer Images" *ngIf="overseerEnabled">
<overseer-image-list></overseer-image-list>
</mat-tab>
<mat-tab label="TurnItIn" *ngIf="tiiEnabled">
<f-tii-action-log></f-tii-action-log>
</mat-tab>
</mat-tab-group>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,8 @@ export class InstitutionSettingsComponent {
public get overseerEnabled() : boolean {
return this.constants.IsOverseerEnabled.value;
}

public get tiiEnabled() : boolean {
return this.constants.IsTiiEnabled.value;
}
}
89 changes: 89 additions & 0 deletions src/app/admin/tii-action-log/tii-action-log.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<div class="action-log-container">
<div class="flex items-center my-10">
<h1>Turnitin Actions</h1>
<span class="flex-grow"></span>
<div>
<mat-form-field appearance="outline">
<input matInput (keyup)="applyFilter($event.target.value)" placeholder="Filter" [(ngModel)]="filter" />
</mat-form-field>
</div>
</div>

<table
class="flex-grow f-table selectable"
mat-table
[dataSource]="tiiActionsSource"
matSort
(matSortChange)="sortData($event)"
>
<ng-container matColumnDef="type" sticky>
<th mat-header-cell *matHeaderCellDef mat-sort-header>Action Type</th>
<td mat-cell *matCellDef="let action">
{{ action.description }}
</td>
</ng-container>
<ng-container matColumnDef="lastRun" sticky>
<th mat-header-cell *matHeaderCellDef mat-sort-header>Last Run</th>
<td mat-cell *matCellDef="let action">
{{ (action.lastRun ? (action.lastRun | date: 'd LLL y') : "") }}
</td>
</ng-container>
<ng-container matColumnDef="retries" sticky>
<th mat-header-cell *matHeaderCellDef mat-sort-header>Retries</th>
<td mat-cell *matCellDef="let action">
{{ action.retries }}
</td>
</ng-container>
<ng-container matColumnDef="retry" sticky>
<th mat-header-cell *matHeaderCellDef mat-sort-header>Retry?</th>
<td mat-cell *matCellDef="let action">
{{ action.retry }}
</td>
</ng-container>
<ng-container matColumnDef="errorCode" sticky>
<th mat-header-cell *matHeaderCellDef mat-sort-header>Error Code</th>
<td mat-cell *matCellDef="let action">
{{ action.errorCode }}
</td>
</ng-container>
<ng-container matColumnDef="complete" sticky>
<th mat-header-cell *matHeaderCellDef mat-sort-header>Complete?</th>
<td mat-cell *matCellDef="let action">
{{ action.complete }}
</td>
</ng-container>
<ng-container matColumnDef="errorMessage" sticky>
<th mat-header-cell *matHeaderCellDef mat-sort-header>Error Message</th>
<td mat-cell *matCellDef="let action">
{{ action.errorMessage }}
</td>
</ng-container>

<ng-container matColumnDef="tiiActionTools" sticky>
<th mat-header-cell *matHeaderCellDef></th>
<td mat-cell *matCellDef="let action">
<button
mat-icon-button
aria-label="retry"
color="primary"
(click)="retryAction(action)"
*ngIf="!(action.complete || action.retry)"
>
<mat-icon>redo</mat-icon>
</button>
</td>
</ng-container>

<!-- Action footer row -->
<ng-container matColumnDef="actions">
<td mat-footer-cell *matFooterCellDef [colSpan]="columns.length"></td>
</ng-container>

<tr mat-header-row *matHeaderRowDef="columns"></tr>
<tr
mat-row
*matRowDef="let row; columns: columns"
[style.background]="selectedTaskDefinition === row ? 'lightblue' : ''"
></tr>
</table>
</div>
3 changes: 3 additions & 0 deletions src/app/admin/tii-action-log/tii-action-log.component.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.action-log-container {
padding: 1rem;
}
21 changes: 21 additions & 0 deletions src/app/admin/tii-action-log/tii-action-log.component.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { TiiActionLogComponent } from './tii-action-log.component';

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

beforeEach(() => {
TestBed.configureTestingModule({
declarations: [TiiActionLogComponent]
});
fixture = TestBed.createComponent(TiiActionLogComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
86 changes: 86 additions & 0 deletions src/app/admin/tii-action-log/tii-action-log.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { AfterViewInit, Component, ViewChild } from '@angular/core';
import { MatPaginator } from '@angular/material/paginator';
import { MatSort, Sort } from '@angular/material/sort';
import { MatTable, MatTableDataSource } from '@angular/material/table';
import { TiiAction } from 'src/app/api/models/doubtfire-model';
import { TiiActionService } from 'src/app/api/services/tii-action.service';
import { AlertService } from 'src/app/common/services/alert.service';

@Component({
selector: 'f-tii-action-log',
templateUrl: './tii-action-log.component.html',
styleUrls: ['./tii-action-log.component.scss']
})
export class TiiActionLogComponent implements AfterViewInit {
@ViewChild(MatTable, { static: false }) table: MatTable<TiiAction>;
@ViewChild(MatSort, { static: false }) sort: MatSort;
@ViewChild(MatPaginator, { static: false }) paginator: MatPaginator;

public tiiActionsSource: MatTableDataSource<TiiAction>;
public columns: string[] = ['type', 'lastRun', 'retries', 'retry', 'errorMessage', 'tiiActionTools']; //, 'complete', 'retries', 'lastRun', 'errorCode', 'log', 'tiiActionAction'];
public filter: string;

constructor(private tiiActionService: TiiActionService, private alertService: AlertService) {

}

ngAfterViewInit(): void {
this.tiiActionService.query().subscribe((actions) => {
console.log(actions);
this.tiiActionsSource = new MatTableDataSource<TiiAction>(actions);
this.tiiActionsSource.paginator = this.paginator;
this.tiiActionsSource.sort = this.sort;
this.tiiActionsSource.filterPredicate = (data: any, filter: string) => data.matches(filter);

});
}

public sortData(sort: Sort) {
const data = this.tiiActionsSource.data;

if (!sort.active || sort.direction === '') {
this.tiiActionsSource.data = data;
return;
}

this.tiiActionsSource.data = data.sort((a, b) => {
const isAsc = sort.direction === 'asc';
switch (sort.active) {
case 'type':
return this.compare(a.type, b.type, isAsc);
default:
return 0;
}
});
}

public compare(a: number | string, b: number | string, isAsc: boolean): number {
return (a < b ? -1 : 1) * (isAsc ? 1 : -1);
}

applyFilter(filterValue: string) {
this.tiiActionsSource.filter = filterValue.trim().toLowerCase();

if (this.tiiActionsSource.paginator) {
this.tiiActionsSource.paginator.firstPage();
}
}

public retryAction(action: TiiAction) {
this.tiiActionService.put(action, {
body: {
action: 'retry'
}
}).subscribe({
next: (updatedAction) => {
action.retry = true;
this.alertService.success('Action has been queued for retry');
},
error: (error) => {
this.alertService.error('Failed to queue action for retry');
}
});
}


}
1 change: 1 addition & 0 deletions src/app/api/models/doubtfire-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export * from './task-status';
export * from './task-comment/discussion-comment';
export * from '../services/task-outcome-alignment.service';
export * from './task-similarity';
export * from './tii-action';

// Users -- are students or staff
export * from './user/user';
Expand Down
18 changes: 18 additions & 0 deletions src/app/api/models/tii-action.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Entity, EntityCache, EntityMapping } from 'ngx-entity-service';
import { Observable } from 'rxjs';
import { Unit } from './doubtfire-model';

export class TiiAction extends Entity {
id: number;
type: string;
complete: boolean;
retries: number;
retry: boolean;
lastRun: Date;
errorCode: string;
errorMessage: string;
log: string;

description: string;

}
20 changes: 18 additions & 2 deletions src/app/api/models/unit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -478,8 +478,24 @@ export class Unit extends Entity {
return `${AppInjector.get(DoubtfireConstants).API_URL}/units/${this.id}/task_definitions/task_pdfs`;
}

public get allResourcesDownloadUrl(): string {
return `${AppInjector.get(DoubtfireConstants).API_URL}/units/${this.id}/all_resources`;
/**
* Download all of the task definitions in a csv
*/
public downloadTaskDefinitionsCsv(): void {
AppInjector.get(FileDownloaderService).downloadFile(
this.getTaskDefinitionBatchUploadUrl(),
`${this.name}-all-task-definitions.csv`
);
}

/**
* Download all of the task resources in a zip.
*/
public downloadAllTaskResourcesZip(): void {
AppInjector.get(FileDownloaderService).downloadFile(
`${AppInjector.get(DoubtfireConstants).API_URL}/units/${this.id}/all_resources`,
`${this.name}-all-task-resources.zip`
);
}

public get enrolStudentsCSVUrl(): string {
Expand Down
43 changes: 43 additions & 0 deletions src/app/api/services/tii-action.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { HttpClient } from '@angular/common/http';
import { CachedEntityService, Entity } from 'ngx-entity-service';
import { TiiAction, Unit, UnitService, UserService } from 'src/app/api/models/doubtfire-model';
import { Injectable } from '@angular/core';
import API_URL from 'src/app/config/constants/apiURL';
import { AppInjector } from 'src/app/app-injector';
import { MappingFunctions } from './mapping-fn';
import { MappingProcess } from 'ngx-entity-service/lib/mapping-process';

@Injectable()
export class TiiActionService extends CachedEntityService<TiiAction> {
protected readonly endpointFormat = 'tii_actions/:id:';

public static readonly rolloverEndpointFormat = 'teaching_periods/:id:/rollover';

constructor(httpClient: HttpClient) {
super(httpClient, API_URL);

this.mapping.addKeys(
'id',
'type',
'description',
'complete',
'retries',
'retry',
{
keys: 'lastRun',
toEntityFn: MappingFunctions.mapDateToDay,
toJsonFn: MappingFunctions.mapDayToJson,
},
'errorCode',
'errorMessage',
'log'
);

this.mapping.addJsonKey('id', 'retry');
// this.cacheBehaviourOnGet = 'cacheQuery';
}

public createInstanceFrom(json: any, other?: any): TiiAction {
return new TiiAction();
}
}
16 changes: 16 additions & 0 deletions src/app/api/services/tii.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';

import { TiiService } from './tii.service';

describe('TiiServiceService', () => {
let service: TiiService;

beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(TiiService);
});

it('should be created', () => {
expect(service).toBeTruthy();
});
});
6 changes: 4 additions & 2 deletions src/app/common/file-drop/file-drop.component.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { HttpClient, HttpErrorResponse, HttpEventType } from '@angular/common/http';
import { HttpClient, HttpErrorResponse, HttpEventType, HttpResponse } from '@angular/common/http';
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { Subscription, throwError } from 'rxjs';
import { AlertService } from '../services/alert.service';
Expand Down Expand Up @@ -28,6 +28,7 @@ export class FileDropComponent {
@Input() endpoint: string;
@Input() body: object;
@Output() fileChange = new EventEmitter<File>();
@Output() uploadSuccess = new EventEmitter<HttpResponse<Object>>();

protected uploadProgress: number;
protected uploadSub: Subscription;
Expand Down Expand Up @@ -87,6 +88,7 @@ export class FileDropComponent {
if (data.type == HttpEventType.Response) {
if (data.ok) {
this.alert.success(`File uploaded successfully`);
this.uploadSuccess.emit(data as HttpResponse<Object>);
}
}
},
Expand All @@ -95,7 +97,7 @@ export class FileDropComponent {
);
}
} else {
this.filesDropped.emit([this.file])
this.filesDropped.emit([this.file]);
this.reset();
}
}
Expand Down
4 changes: 4 additions & 0 deletions src/app/doubtfire-angular.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,8 @@ import {
TeachingPeriodUnitImportService,
} from './admin/states/teaching-periods/teaching-period-unit-import/teaching-period-unit-import.dialog';
import { AcceptEulaComponent } from './eula/accept-eula/accept-eula.component';
import { TiiActionLogComponent } from './admin/tii-action-log/tii-action-log.component';
import { TiiActionService } from './api/services/tii-action.service';

@NgModule({
// Components we declare
Expand Down Expand Up @@ -303,6 +305,7 @@ import { AcceptEulaComponent } from './eula/accept-eula/accept-eula.component';
InboxComponent,
ProjectProgressBarComponent,
TeachingPeriodListComponent,
TiiActionLogComponent,
FChipComponent,
NewTeachingPeriodDialogComponent,
FileViewerComponent,
Expand Down Expand Up @@ -380,6 +383,7 @@ import { AcceptEulaComponent } from './eula/accept-eula/accept-eula.component';
LearningOutcomeService,
TaskDefinitionService,
TeachingPeriodService,
TiiActionService,
TeachingPeriodBreakService,
TeachingPeriodUnitImportService,
TutorialService,
Expand Down
Loading

0 comments on commit 3549dba

Please sign in to comment.