import { Injectable } from '@angular/core' ; import { FileStatus , ICommitData , IFileAccessService , IFileStats } from '../common/i-file-access-service' ; import { IFileDescription } from '../common/i-file-description' ; import { Observable , of , throwError } from 'rxjs' ; import { GithubConfiguration } from './github-configuration' ; import { catchError , first , map , switchMap } from 'rxjs/operators' ; import { GithubApiService , GithubBranch , GithubDirectory , GithubFileContents } from './github-api.service' ; import { SerializationService } from '../../model/serialization.service' ; import { IFile } from '../common/i-file' ; import { GithubFileDescription } from './github-file-description' ; import { GithubFile } from './github-file' ; function pathjoin ( path , subdir ) { if ( subdir && subdir . startsWith ( '/' ) ) { subdir = subdir . substr ( 1 ) ; } if ( path && path . endsWith ( '/' ) ) { return path + subdir ; } return ( path ) ? path + '/' + subdir : subdir ; } @ Injectable ( { providedIn : 'root' } ) export class GithubAccessorService implements IFileAccessService { constructor ( private githubApiService ) { } load ( description ) { const configuration = description . configuration as GithubConfiguration ; const branch = { repo : { owner : configuration . owner , name : configuration . repo } , name : configuration . branch } ; const apiToken = configuration . apiToken ; const path = pathjoin ( configuration . path , description . path ) ; return this . githubApiService . content ( branch , path , apiToken ) . pipe ( first ( ) , map ( ( content ) => { if ( content . type === 'dir' ) { const children = content . entries . map ( ( entry ) => { if ( entry . type === 'dir' ) { return new GithubFileDescription ( 'dir' , configuration , pathjoin ( description . path , entry . name ) , entry . name ) ; } else { return new GithubFileDescription ( 'file' , configuration , pathjoin ( description . path , entry . name ) , entry . name ) ; } } ) ; return new GithubFileDescription ( 'dir' , configuration , description . path , description . name , children ) ; } else { const descr = new GithubFileDescription ( 'file' , configuration , description . path , description . name ) ; return new GithubFile ( descr , content . name , content . size , content . content , content . sha ) ; } } ) ) ; } save ( file , commitData ) { const configuration = file . description . configuration as GithubConfiguration ; const branch = { name : configuration . branch , repo : { name : configuration . repo , owner : configuration . owner } , } ; const content = { type : 'file' , name : file . description . name , branch : branch , path : pathjoin ( configuration . path , file . description . path ) , size : file . size , content : file . content , sha : file . sha } ; const apiKey = configuration . apiToken ; if ( ! commitData || ! commitData . message ) { return throwError ( 'no commit message' ) ; } const message = commitData . message ; return this . stats ( file ) . pipe ( map ( ( stats ) => { console . log ( 'stats' , stats , commitData ) ; if ( stats . status !== FileStatus . EXISTS_NOT ) { if ( commitData . override ) { console . log ( 'sha' , ( stats as any ) . sha ) ; return ( stats as any ) . sha ; } else { throw Error ( 'file exists' ) ; } } else { return null ; } } ) , switchMap ( ( sha ) => { console . log ( 'sha' , sha ) ; content . sha = sha ; return this . githubApiService . updateContent ( branch , content , message , apiKey ) . pipe ( map ( ( newFileContent ) => { return new GithubFile ( file . description , newFileContent . name , newFileContent . size , newFileContent . content , newFileContent . sha ) ; } ) ) ; } ) ) ; } stats ( file ) { const configuration = file . description . configuration as GithubConfiguration ; const branch = { name : configuration . branch , repo : { name : configuration . repo , owner : configuration . owner } , } ; return this . githubApiService . content ( branch , pathjoin ( configuration . path , file . description . path ) , configuration . apiToken ) . pipe ( map ( ( content ) => { if ( content . sha === ( file as GithubFile ) . sha ) { return { status : FileStatus . UNCHANGED , sha : content . sha } ; } else { return { status : FileStatus . CHANGED , sha : content . sha } ; } } ) , catchError ( ( ) => { return of ( { status : FileStatus . EXISTS_NOT } ) ; } ) ) ; } serialize ( serializationService , configuration ) { return configuration . serialize ( serializationService ) ; } deserialize ( serializationService , serializedConfiguration ) { return GithubConfiguration . deserialize ( serializationService , serializedConfiguration ) ; } }