diff --git a/yacs-admin-angular/src/app/app.module.ts b/yacs-admin-angular/src/app/app.module.ts index c55ca39..25625b2 100644 --- a/yacs-admin-angular/src/app/app.module.ts +++ b/yacs-admin-angular/src/app/app.module.ts @@ -10,7 +10,6 @@ import { DepartmentListComponent } from './department/department-list/department import { DepartmentDetailComponent } from './department/department-detail/department-detail.component'; import { CourseListComponent } from './course/course-list/course-list.component'; import { SectionListComponent } from './section/section-list/section-list.component'; -import { FakeYacsService } from './services/fake-yacs.service'; import {YacsService} from './services/yacs.service'; //YACS API uses older http module import { HttpInMemoryWebApiModule, HttpClientInMemoryWebApiModule } from 'angular-in-memory-web-api'; @@ -18,7 +17,6 @@ import { InMemoryDataService } from './services/in-memory-data.service'; import { HttpModule, XHRBackend } from '@angular/http'; import { HttpClientModule } from '@angular/common/http'; import { SchoolDetailComponent } from './school/school-detail/school-detail.component'; -import {YacsProdService} from './services/yacs-prod.service'; import {environment} from '../environments/environment'; import { CourseDetailComponent } from './course/course-detail/course-detail.component'; @@ -47,7 +45,7 @@ import { CourseDetailComponent } from './course/course-detail/course-detail.comp * If we are in production, use YacsProdService, * otherwise use FakeYacsService */ {provide: YacsService, - useClass: environment.useRealData ? YacsProdService : FakeYacsService}], + useClass: environment.yacsService}], bootstrap: [AppComponent] }) export class AppModule { } diff --git a/yacs-admin-angular/src/app/course/course-list/course-list.component.html b/yacs-admin-angular/src/app/course/course-list/course-list.component.html index d1e4ed4..b549ab0 100644 --- a/yacs-admin-angular/src/app/course/course-list/course-list.component.html +++ b/yacs-admin-angular/src/app/course/course-list/course-list.component.html @@ -1,8 +1,66 @@
+
+

New Course

+
+
+ + +   + + +
+ +
+
+
+ + +
+
+
+
+ + +   + + + +
+ + +
+
+
+ + +
+
+
+ + +
+ + +
-

All Courses

-

Courses in the {{selectedDept.name}} Department

+
+
+

All Courses

+

Courses in the {{selectedDept.name}} Department

+
diff --git a/yacs-admin-angular/src/app/course/course-list/course-list.component.spec.ts b/yacs-admin-angular/src/app/course/course-list/course-list.component.spec.ts index 812b7bf..054b1c6 100644 --- a/yacs-admin-angular/src/app/course/course-list/course-list.component.spec.ts +++ b/yacs-admin-angular/src/app/course/course-list/course-list.component.spec.ts @@ -78,6 +78,90 @@ describe('no query parameters', () => { it('should display the table',() => { expect(document.getElementsByClassName('table')).toBeTruthy(); }); + + it('should not display the form', () => { + expect(document.getElementById('newCourse')).toBeNull(); + }); + + it('should display \'New Course\'',() => { + expect(document.getElementsByClassName('new-object-link')[0]).toBeTruthy(); + }); + describe('after clicking \'New Course\'', () => { + beforeEach(async()=>{ + const newBtn=document.getElementById('newCourseBtn'); + newBtn.click(); + fixture.detectChanges(); + fixture.whenStable().then(() => { + fixture.detectChanges(); + }); + + }); + + beforeEach(()=>{ + fixture.detectChanges(); + fixture.whenStable().then(() => { + fixture.detectChanges(); + }); + }); + + it('should set creatingCourse to true', async() => { + tick(); + expect(component.creatingCourse).toEqual(true); + }); + it('should render the form', async() => { + tick(); + expect(document.getElementById('newCourse')).toBeTruthy(); + //expect(component.selectedDept).toEqual(expectedDept); + }); + + describe('when \'Cancel\' is pressed', () => { + beforeEach(async()=>{ + const cancelBtn=document.getElementById('cancelBtn'); + cancelBtn.click(); + fixture.detectChanges(); + fixture.whenStable().then(() => { + fixture.detectChanges(); + }); + }); + + beforeEach(()=>{ + spyOn(component, 'cancelNewCourse').and.callThrough(); + fixture.detectChanges(); + fixture.whenStable().then(() => { + fixture.detectChanges(); + }); + }); + + /*This spec is pending until we can replace + * this dialog with a Bootstrap modal.*/ + + xit('displays the dialog', async()=>{ + tick(); + expect(component.cancelNewCourse).toHaveBeenCalled(); + }); + +}); + + + describe('When \'Create Course\' is pressed', () => { + beforeEach(async()=>{ + const createBtn=document.getElementById('createBtn'); + createBtn.click(); + }); + + beforeEach(()=>{ + spyOn(component,'createCourse'); + }); + + it('should call createDept', async()=>{ + tick(); + expect(component.createCourse).toHaveBeenCalled(); + }); + }); + + }); + + }); describe('invalid department id is passed', () => { diff --git a/yacs-admin-angular/src/app/course/course-list/course-list.component.ts b/yacs-admin-angular/src/app/course/course-list/course-list.component.ts index 3df5587..325e132 100644 --- a/yacs-admin-angular/src/app/course/course-list/course-list.component.ts +++ b/yacs-admin-angular/src/app/course/course-list/course-list.component.ts @@ -15,6 +15,7 @@ export class CourseListComponent implements OnInit { error: boolean; courses: Course[]; selectedDept: Department; + creatingCourse: boolean; departments: Department[]; //ActivatedRoute is used to access parameters constructor(private route: ActivatedRoute, private yacsService: YacsService) {} @@ -99,10 +100,52 @@ export class CourseListComponent implements OnInit { }); + } + showCourseForm(): void{ + this.creatingCourse=true; + } + cancelNewCourse(): void{ + if(confirm('Are you sure you want to cancel?')){ + this.creatingCourse=false; + } + } + createCourse(code, name, num, min_cred, max_cred, desc): void{ + console.log(code); + let newCourse: Course; + console.log(this.courses.length); + //Get school id + let dept: Department; + dept = this.departments.filter(department => department.code == code)[0]; + console.log(dept); + let dept_id=dept.id; + let dept_code = dept.code; + newCourse = new Course((this.courses.length +1), name, num, dept_code, dept_id, min_cred, max_cred, desc, []); + this.yacsService.addCourse(newCourse) + .subscribe( ()=>{ + //Get departments with new dept + if(this.department_id){ + this.getCoursesInDept(this.department_id); + } + else{ + this.getAllCourses(); + } + this.creatingCourse=false; + } + ); + /*this.yacsService.getDeptByID(String(code)) + .subscribe(dept=>{ + console.log(dept); + + + });*/ + + } ngOnInit() { + this.creatingCourse=false; + this.getAllDepts(); //Filter the courses if department id is not null this.setDeptId(); diff --git a/yacs-admin-angular/src/app/services/fake-yacs.service.ts b/yacs-admin-angular/src/app/services/fake-yacs.service.ts index cd1d5fd..5b18a54 100644 --- a/yacs-admin-angular/src/app/services/fake-yacs.service.ts +++ b/yacs-admin-angular/src/app/services/fake-yacs.service.ts @@ -116,12 +116,29 @@ export class FakeYacsService implements YacsService{ //return of(COURSES.filter(course => course.department_id === dept_id)); } + + addCourse(course: Course): Observable{ + console.log(course); + return this.http.post(this.coursesUrl, course, cudOptions).pipe( + tap(_=>console.log(course)), + catchError(this.handleError('addCourse')) + ); + } + updateCourse(course: Course): Observable{ return this.http.put(this.coursesUrl, course, cudOptions).pipe( tap(_=>console.log(course), catchError(this.handleError('updateCourse'))) ); } + getDeptByCode(code: string): Observable{ + return this.http.get(this.deptsUrl) + .map(depts=>{ + let results=depts.filter(dept=> dept.code == code); + return results; + })[0]; + } + getDeptsBySchoolID(school_id: number): Observable{ return this.http.get(this.deptsUrl) diff --git a/yacs-admin-angular/src/app/services/yacs-prod.service.ts b/yacs-admin-angular/src/app/services/yacs-prod.service.ts index 99fdcc2..f2acb27 100644 --- a/yacs-admin-angular/src/app/services/yacs-prod.service.ts +++ b/yacs-admin-angular/src/app/services/yacs-prod.service.ts @@ -9,8 +9,7 @@ import { of } from 'rxjs/observable/of'; import {HttpClient, HttpHeaders, HttpParams} from '@angular/common/http'; import { catchError, map, tap} from 'rxjs/operators'; import 'rxjs/add/operator/map'; -const cudOptions = { headers: new HttpHeaders({ 'Content-Type': 'application/json' })}; - +const cudOptions = { headers: new HttpHeaders({ 'Content-Type': 'x-www-form-urlencoded' }), withCredentials: true}; @Injectable() export class YacsProdService implements YacsService{ baseUrl='https://yacs.cs.rpi.edu/api/v5'; @@ -49,7 +48,7 @@ export class YacsProdService implements YacsService{ updateSchool(school: School): Observable{ //TODO: implement admin token - return this.http.put(this.baseUrl+'/schools', school, cudOptions).pipe( + return this.http.put(this.baseUrl+`/schools/${school.id}`, school, cudOptions).pipe( //TODO: send to an actual logging system instead of console.log tap(_=>console.log(school)), catchError(this.handleError('updateSchool')) @@ -88,7 +87,15 @@ export class YacsProdService implements YacsService{ return((results.length==1) ? results[0] : null); }); } - + getDeptByCode(code: string): Observable{ + return this.http.get(this.baseUrl+'/departments', { + params: new HttpParams().set('code', code) + }) + .map(depts=>{ + let results = depts['departments'].filter(dept => dept.code == code); + return((results.length==1) ? results[0] : null); + }); + } getDeptsBySchoolID(school_id: number): Observable{ return this.http.get(this.baseUrl+'/departments', { params: new HttpParams().set('school_id', String(school_id)) @@ -97,7 +104,7 @@ export class YacsProdService implements YacsService{ } updateDepartment(dept: Department): Observable{ - return this.http.put(this.baseUrl+'/departments', dept, cudOptions).pipe( + return this.http.put(this.baseUrl+`/departments/${dept.id}`, dept, cudOptions).pipe( tap(_=> console.log(dept)), catchError(this.handleError('updateDepartment')) ); @@ -134,6 +141,13 @@ export class YacsProdService implements YacsService{ }); } + addCourse(course: Course): Observable{ + return this.http.post(this.baseUrl+'/courses', course, cudOptions).pipe( + tap(_=> console.log(course)), + catchError(this.handleError('addCourse')) + ); + } + deleteCourse(course: Course | number): Observable{ @@ -146,7 +160,7 @@ export class YacsProdService implements YacsService{ } updateCourse(course: Course): Observable{ - return this.http.put(this.baseUrl+'/courses', course, cudOptions).pipe( + return this.http.put(this.baseUrl+`/courses/${course.id}`, course, cudOptions).pipe( tap(_=> console.log(course)), catchError(this.handleError('updateCourse')) ); diff --git a/yacs-admin-angular/src/app/services/yacs-staging.service.ts b/yacs-admin-angular/src/app/services/yacs-staging.service.ts new file mode 100644 index 0000000..076b9d3 --- /dev/null +++ b/yacs-admin-angular/src/app/services/yacs-staging.service.ts @@ -0,0 +1,7 @@ +import {Injectable} from '@angular/core'; +import {YacsProdService} from './yacs-prod.service'; + +@Injectable() +export class YacsStagingService extends YacsProdService{ + baseUrl='https://127.0.0.1/api/v5'; +} diff --git a/yacs-admin-angular/src/app/services/yacs.service.ts b/yacs-admin-angular/src/app/services/yacs.service.ts index 105b6af..add8ee7 100644 --- a/yacs-admin-angular/src/app/services/yacs.service.ts +++ b/yacs-admin-angular/src/app/services/yacs.service.ts @@ -37,7 +37,7 @@ export abstract class YacsService { /* HTTP GET method * Return a singular department by ID */ abstract getDeptByID(id: number): Observable; - + abstract getDeptByCode(code: string): Observable; //HTTP GET method //Return all departments in a school abstract getDeptsBySchoolID(school_id: number): Observable; @@ -54,6 +54,7 @@ export abstract class YacsService { abstract getCourses(): Observable; abstract getCoursesByDeptID(dept_id: number): Observable; + abstract addCourse(course: Course): Observable; //PUT method for courses abstract updateCourse(course: Course): Observable; abstract deleteCourse(course: Course | number): Observable; diff --git a/yacs-admin-angular/src/environments/environment.prod.ts b/yacs-admin-angular/src/environments/environment.prod.ts index d87fc2d..48e4851 100644 --- a/yacs-admin-angular/src/environments/environment.prod.ts +++ b/yacs-admin-angular/src/environments/environment.prod.ts @@ -1,4 +1,7 @@ +import { YacsProdService } from '../app/services/yacs-prod.service'; + export const environment = { production: true, - useRealData: true + yacsService: YacsProdService, + useRealData: true, }; diff --git a/yacs-admin-angular/src/environments/environment.staging.ts b/yacs-admin-angular/src/environments/environment.staging.ts index 485d0f7..cace86a 100644 --- a/yacs-admin-angular/src/environments/environment.staging.ts +++ b/yacs-admin-angular/src/environments/environment.staging.ts @@ -1,4 +1,7 @@ +import { YacsStagingService } from '../app/services/yacs-staging.service'; + export const environment = { production: false, - useRealData: true + yacsService: YacsStagingService, + useRealData: true, }; diff --git a/yacs-admin-angular/src/environments/environment.ts b/yacs-admin-angular/src/environments/environment.ts index 7319af1..1e496a3 100644 --- a/yacs-admin-angular/src/environments/environment.ts +++ b/yacs-admin-angular/src/environments/environment.ts @@ -3,7 +3,10 @@ // `ng build --env=prod` then `environment.prod.ts` will be used instead. // The list of which env maps to which file can be found in `.angular-cli.json`. +import { FakeYacsService } from '../app/services/fake-yacs.service'; + export const environment = { production: false, - useRealData: false + yacsService: FakeYacsService, + useRealData: false, };