import { CourseDetails } from './../../core/models/course-details'; // Libraries import { Injectable } from '@angular/core'; import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Location } from '@angular/common'; import { Observable } from 'rxjs'; import { map, filter } from 'rxjs/operators'; // Services import { ConfigService } from '@app/core/config.service'; // Models import { Note } from '@app/core/models/note'; import { Term } from '@app/core/models/term'; import { CourseBase, SubjectMapping } from '@app/core/models/course'; import { DegreePlan } from '@app/core/models/degree-plan'; import { SavedForLaterCourseBase } from '@app/core/models/saved-for-later-course'; const HTTP_OPTIONS = { headers: new HttpHeaders({ 'Content-Type': 'application/json', }), }; @Injectable({ providedIn: 'root' }) export class DegreePlannerApiService { constructor(private http: HttpClient, private config: ConfigService) {} public getSavedForLaterCourses(): Observable<SavedForLaterCourseBase[]> { return this.http.get<SavedForLaterCourseBase[]>( `${this.config.apiPlannerUrl}/favorites`, ); } public createDegreePlan(name: string, primary: boolean = false) { const url = `${this.config.apiPlannerUrl}/degreePlan`; const payload = { name, primary }; return this.http.post<DegreePlan>(url, payload); } public deleteDegreePlan(roadmapId: number) { const url = `${this.config.apiPlannerUrl}/degreePlan/${roadmapId}`; return this.http.delete<void>(url); } public getAllDegreePlans(): Observable<DegreePlan[]> { return this.http.get<DegreePlan[]>(this.degreePlanEndpoint()); } public getPlan(roadmapId: number): Observable<DegreePlan> { return this.http.get<DegreePlan>(this.degreePlanEndpoint(roadmapId)); } public getAllSubjects(): Observable<SubjectMapping> { return this.http.get<SubjectMapping>( this.searchEndpoint('subjectsMap/0000'), ); } public getActiveTerms(): Observable<Term[]> { return this.http.get<Term[]>(this.searchEndpoint('terms')); } public getAllNotes(roadmapId: number): Observable<Note[]> { return this.http.get<Note[]>(this.degreePlanEndpoint(roadmapId, 'notes')); } getCourseDetails( subjectCode: string, courseId: string, ): Observable<CourseDetails[]> { return this.http.get<CourseDetails[]>( this.config.apiSearchUrl + '/course/0000/' + subjectCode + '/' + courseId, HTTP_OPTIONS, ); } public getAllTermCourses( roadmapId: number, ): Observable<{ termCode: string; courses: CourseBase[] }[]> { return this.http.get<{ termCode: string; courses: CourseBase[] }[]>( this.degreePlanEndpoint(roadmapId, 'termcourses'), ); } public updateCourseTerm(roadmapId, recordId, termCode): Observable<any> { return this.http.put<CourseBase>( this.config.apiPlannerUrl + '/degreePlan/' + roadmapId + '/courses/' + recordId + '?termCode=' + termCode, HTTP_OPTIONS, ); } public autocomplete(search: string) { const data = { subjectCode: '104', termCode: '0000', matchText: search, }; return this.http.post('/api/search/v1/autocomplete', data, HTTP_OPTIONS); } public searchCourses(config: { subjectCode: string; searchText?: string; termCode?: string; }): Observable<any> { // const data = { // filters: [ // { term: { 'subject.subjectCode': '266' } }, // { // has_child: { // type: 'enrollmentPackage', // query: { // match: { // 'packageEnrollmentStatus.status': 'OPEN WAITLISTED CLOSED', // }, // }, // }, // }, // ], // page: 1, // pageSize: 500, // queryString: 'programing', // selectedTerm: '1194', // sortOrder: 'SCORE', // }; const { subjectCode, termCode, searchText } = config; const payload: any = { selectedTerm: termCode, queryString: searchText === '' ? '*' : searchText, // Filters are use to build the elastic search query filters: [], // These options control how much data we get back page: 1, pageSize: 25, sortOrder: 'SCORE', }; // If we have a specific subject code, add a fitler for it if (subjectCode !== 'all') { payload.filters.push({ term: { 'subject.subjectCode': subjectCode } }); } // 0000 is used to search all courses // Any other term code we can assuem is an active term if (termCode !== '0000') { // Used to search a specific term payload.filters.push({ has_child: { type: 'enrollmentPackage', query: { // We want to make sure we search for ALL classes regardless of status match: { 'packageEnrollmentStatus.status': 'OPEN WAITLISTED CLOSED', }, }, }, }); } return this.http.post('/api/search/v1', payload, HTTP_OPTIONS); } public addCourse( planId: number, subjectCode: string, courseId: string, termCode: string, ): Observable<CourseBase> { return this.http.post<CourseBase>( this.config.apiPlannerUrl + '/degreePlan/' + planId + '/courses', { subjectCode, courseId, termCode }, HTTP_OPTIONS, ); } public removeCourse(planId: number, recordId: number): Observable<void> { return this.http.delete<void>( this.config.apiPlannerUrl + '/degreePlan/' + planId + '/courses/' + recordId, HTTP_OPTIONS, ); } public saveForLater( subjectCode: string, courseId: string, ): Observable<SavedForLaterCourseBase> { return this.http.post<SavedForLaterCourseBase>( this.config.apiPlannerUrl + '/favorites/' + subjectCode + '/' + courseId, HTTP_OPTIONS, ); } public removeSavedForLater( subjectCode: string, courseId: string, ): Observable<SavedForLaterCourseBase> { return this.http.delete<SavedForLaterCourseBase>( this.config.apiPlannerUrl + '/favorites/' + subjectCode + '/' + courseId, HTTP_OPTIONS, ); } public createNote( planId: number, termCode: string, noteText: string, ): Observable<Note> { const payload = { termCode: termCode, note: noteText, }; return this.http.post<Note>( this.degreePlanEndpoint(planId, 'notes'), payload, HTTP_OPTIONS, ); } public updateNote( planId: number, termCode: string, noteText: string, noteId: number, ): Observable<Note> { const payload = { termCode: termCode, note: noteText, id: noteId, }; return this.http .put<null>( this.degreePlanEndpoint(planId, 'notes', noteId), payload, HTTP_OPTIONS, ) .pipe(map(() => payload)); } public deleteNote(planId: number, noteId: number): Observable<null> { return this.http.delete<null>( this.degreePlanEndpoint(planId, 'notes', noteId), HTTP_OPTIONS, ); } public updatePlan( planId: number, name: string, primary: boolean, ): Observable<1> { return this.http.put<1>( this.degreePlanEndpoint(planId), { name, primary }, HTTP_OPTIONS, ); } /** * Helper function for building API endpoint URLs */ private degreePlanEndpoint(...parts: any[]): string { return ['degreePlan'] .concat(parts.map(part => part.toString())) .reduce((soFar, next) => { return Location.joinWithSlash(soFar, next); }, this.config.apiPlannerUrl); } private searchEndpoint(...parts: any[]): string { return parts .map(part => part.toString()) .reduce((soFar, next) => { return Location.joinWithSlash(soFar, next); }, this.config.apiSearchUrl); } }