2022-12-02 20:40:58 -07:00
package handler
import (
2023-12-03 19:40:16 -07:00
"context"
2022-12-02 20:40:58 -07:00
"fmt"
2023-08-27 18:09:46 -06:00
"github.com/fastenhealth/fasten-onprem/backend/pkg"
"github.com/fastenhealth/fasten-onprem/backend/pkg/database"
2023-09-09 09:24:25 -06:00
"github.com/fastenhealth/fasten-onprem/backend/pkg/event_bus"
2023-08-27 18:09:46 -06:00
"github.com/fastenhealth/fasten-onprem/backend/pkg/models"
2022-12-02 20:40:58 -07:00
"github.com/fastenhealth/fasten-sources/clients/factory"
2023-12-03 19:40:16 -07:00
sourceModels "github.com/fastenhealth/fasten-sources/clients/models"
2024-01-16 22:13:52 -07:00
sourceDefinitions "github.com/fastenhealth/fasten-sources/definitions"
2022-12-02 20:40:58 -07:00
sourcePkg "github.com/fastenhealth/fasten-sources/pkg"
"github.com/gin-gonic/gin"
2023-10-11 21:43:27 -06:00
"github.com/google/uuid"
2022-12-02 20:40:58 -07:00
"github.com/sirupsen/logrus"
"io/ioutil"
"net/http"
2023-12-03 19:40:16 -07:00
"os"
2022-12-02 20:40:58 -07:00
)
2023-10-11 21:43:27 -06:00
func CreateReconnectSource ( c * gin . Context ) {
2023-01-10 20:23:47 -07:00
logger := c . MustGet ( pkg . ContextKeyTypeLogger ) . ( * logrus . Entry )
databaseRepo := c . MustGet ( pkg . ContextKeyTypeDatabase ) . ( database . DatabaseRepository )
2022-12-02 20:40:58 -07:00
sourceCred := models . SourceCredential { }
if err := c . ShouldBindJSON ( & sourceCred ) ; err != nil {
2024-01-20 22:59:17 -07:00
err = fmt . Errorf ( "an error occurred while parsing posted source credential: %s" , err )
logger . Errorln ( err )
c . JSON ( http . StatusBadRequest , gin . H { "success" : false , "error" : err . Error ( ) } )
2022-12-02 20:40:58 -07:00
return
}
logger . Infof ( "Parsed Create SourceCredential Credentials Payload: %v" , sourceCred )
2024-01-16 22:13:52 -07:00
//get the endpoint definition
endpointDefinition , err := sourceDefinitions . GetSourceDefinition ( sourceDefinitions . GetSourceConfigOptions {
EndpointId : sourceCred . EndpointID . String ( ) ,
} )
if endpointDefinition . DynamicClientRegistrationMode == "user-authenticated" {
2023-11-04 17:01:00 -06:00
logger . Warnf ( "This client requires a dynamic client registration, starting registration process" )
2023-07-19 23:45:14 -06:00
2024-01-16 22:13:52 -07:00
if len ( endpointDefinition . RegistrationEndpoint ) == 0 {
err := fmt . Errorf ( "this client requires dynamic registration, but does not provide a registration endpoint: %s" , endpointDefinition . DynamicClientRegistrationMode )
2023-11-05 11:53:30 -07:00
logger . Errorln ( err )
c . JSON ( http . StatusBadRequest , gin . H { "success" : false , "error" : err . Error ( ) } )
2023-07-19 23:45:14 -06:00
return
}
2023-10-11 21:43:27 -06:00
err := sourceCred . RegisterDynamicClient ( )
2023-07-19 23:45:14 -06:00
if err != nil {
2023-11-05 11:53:30 -07:00
err = fmt . Errorf ( "an error occurred while registering dynamic client: %w" , err )
logger . Errorln ( err )
c . JSON ( http . StatusBadRequest , gin . H { "success" : false , "error" : err . Error ( ) } )
2023-07-19 23:45:14 -06:00
return
}
2023-10-11 21:43:27 -06:00
//generate a JWT token and then use it to get an access token for the dynamic client
err = sourceCred . RefreshDynamicClientAccessToken ( )
2023-07-19 23:45:14 -06:00
if err != nil {
2023-11-05 11:53:30 -07:00
err = fmt . Errorf ( "an error occurred while retrieving access token for dynamic client: %w" , err )
logger . Errorln ( err )
c . JSON ( http . StatusBadRequest , gin . H { "success" : false , "error" : err . Error ( ) } )
2023-07-19 23:45:14 -06:00
return
}
2023-10-11 21:43:27 -06:00
}
2023-07-19 23:45:14 -06:00
2023-10-11 21:43:27 -06:00
if sourceCred . ID != uuid . Nil {
//reconnect
err := databaseRepo . UpdateSource ( c , & sourceCred )
2023-07-19 23:45:14 -06:00
if err != nil {
2023-11-05 11:53:30 -07:00
err = fmt . Errorf ( "an error occurred while reconnecting source credential: %w" , err )
logger . Errorln ( err )
c . JSON ( http . StatusInternalServerError , gin . H { "success" : false , "error" : err . Error ( ) } )
2023-07-19 23:45:14 -06:00
return
}
2023-10-11 21:43:27 -06:00
} else {
//create source for the first time
err := databaseRepo . CreateSource ( c , & sourceCred )
2023-07-19 23:45:14 -06:00
if err != nil {
2023-11-05 11:53:30 -07:00
err = fmt . Errorf ( "an error occurred while storing source credential: %w" , err )
logger . Errorln ( err )
c . JSON ( http . StatusInternalServerError , gin . H { "success" : false , "error" : err . Error ( ) } )
2023-07-19 23:45:14 -06:00
return
}
}
2023-09-07 22:54:25 -06:00
// after creating the source, we should do a bulk import (in the background)
2023-10-08 17:29:26 -06:00
summary , err := BackgroundJobSyncResources ( GetBackgroundContext ( c ) , logger , databaseRepo , & sourceCred )
2022-12-02 20:40:58 -07:00
if err != nil {
2024-01-20 22:59:17 -07:00
err := fmt . Errorf ( "an error occurred while starting initial sync: %w" , err )
logger . Errorln ( err )
c . JSON ( http . StatusInternalServerError , gin . H { "success" : false , "error" : err . Error ( ) } )
2022-12-02 20:40:58 -07:00
return
}
c . JSON ( http . StatusOK , gin . H { "success" : true , "source" : sourceCred , "data" : summary } )
}
func SourceSync ( c * gin . Context ) {
2023-01-10 20:23:47 -07:00
logger := c . MustGet ( pkg . ContextKeyTypeLogger ) . ( * logrus . Entry )
databaseRepo := c . MustGet ( pkg . ContextKeyTypeDatabase ) . ( database . DatabaseRepository )
2023-09-20 14:57:12 -06:00
eventBus := c . MustGet ( pkg . ContextKeyTypeEventBusServer ) . ( event_bus . Interface )
2022-12-02 20:40:58 -07:00
logger . Infof ( "Get SourceCredential Credentials: %v" , c . Param ( "sourceId" ) )
sourceCred , err := databaseRepo . GetSource ( c , c . Param ( "sourceId" ) )
if err != nil {
2024-01-20 22:59:17 -07:00
err = fmt . Errorf ( "an error occurred while retrieving source credential: %w" , err )
logger . Errorln ( err )
c . JSON ( http . StatusInternalServerError , gin . H { "success" : false , "error" : err . Error ( ) } )
2022-12-02 20:40:58 -07:00
return
}
2023-09-07 22:54:25 -06:00
// after creating the source, we should do a bulk import (in the background)
2023-10-08 17:29:26 -06:00
summary , err := BackgroundJobSyncResources ( GetBackgroundContext ( c ) , logger , databaseRepo , sourceCred )
2022-12-02 20:40:58 -07:00
if err != nil {
2024-01-20 22:59:17 -07:00
err := fmt . Errorf ( "an error occurred while syncing resources: %w" , err )
logger . Errorln ( err )
c . JSON ( http . StatusInternalServerError , gin . H { "success" : false , "error" : err . Error ( ) } )
2022-12-02 20:40:58 -07:00
return
}
2023-09-09 09:24:25 -06:00
//publish event
currentUser , _ := databaseRepo . GetCurrentUser ( c )
2023-09-20 14:57:12 -06:00
err = eventBus . PublishMessage (
2023-09-09 09:24:25 -06:00
models . NewEventSourceComplete (
currentUser . ID . String ( ) ,
sourceCred . ID . String ( ) ,
) ,
)
if err != nil {
logger . Warnf ( "ignoring: an error occurred while publishing sync complete event: %v" , err )
}
2022-12-02 20:40:58 -07:00
c . JSON ( http . StatusOK , gin . H { "success" : true , "source" : sourceCred , "data" : summary } )
}
2023-12-03 19:40:16 -07:00
// mimics functionality in CreateRelatedResources
// mimics functionality in SourceSync
2022-12-02 20:40:58 -07:00
func CreateManualSource ( c * gin . Context ) {
2023-01-10 20:23:47 -07:00
logger := c . MustGet ( pkg . ContextKeyTypeLogger ) . ( * logrus . Entry )
databaseRepo := c . MustGet ( pkg . ContextKeyTypeDatabase ) . ( database . DatabaseRepository )
2023-09-20 14:57:12 -06:00
eventBus := c . MustGet ( pkg . ContextKeyTypeEventBusServer ) . ( event_bus . Interface )
2022-12-02 20:40:58 -07:00
2023-12-03 19:40:16 -07:00
// store the bundle file locally
bundleFile , err := storeFileLocally ( c )
2022-12-02 20:40:58 -07:00
if err != nil {
2023-12-03 19:40:16 -07:00
c . JSON ( http . StatusInternalServerError , gin . H { "success" : false , "error" : err . Error ( ) } )
2022-12-02 20:40:58 -07:00
return
}
// We cannot save the "SourceCredential" object yet, as we do not know the patientID
// create a "manual" client, which we can use to parse the
manualSourceCredential := models . SourceCredential {
2024-01-16 22:13:52 -07:00
PlatformType : sourcePkg . PlatformTypeManual ,
2022-12-02 20:40:58 -07:00
}
2024-01-17 14:45:19 -07:00
tempSourceClient , err := factory . GetSourceClient ( "" , c , logger , & manualSourceCredential )
2022-12-02 20:40:58 -07:00
if err != nil {
2024-01-20 22:59:17 -07:00
err = fmt . Errorf ( "an error occurred while initializing hub client using manual source without credentials: %w" , err )
logger . Errorln ( err )
c . JSON ( http . StatusInternalServerError , gin . H { "success" : false , "error" : err . Error ( ) } )
2022-12-02 20:40:58 -07:00
return
}
patientId , bundleType , err := tempSourceClient . ExtractPatientId ( bundleFile )
if err != nil {
2024-01-20 22:59:17 -07:00
err = fmt . Errorf ( "an error occurred while extracting patient id: %w" , err )
logger . Errorln ( err )
2022-12-02 20:40:58 -07:00
c . JSON ( http . StatusInternalServerError , gin . H { "success" : false , "error" : err . Error ( ) } )
return
}
manualSourceCredential . Patient = patientId
//store the manualSourceCredential
err = databaseRepo . CreateSource ( c , & manualSourceCredential )
if err != nil {
2024-01-20 22:59:17 -07:00
err = fmt . Errorf ( "an error occurred while creating manual source: %w" , err )
logger . Errorln ( err )
2022-12-02 20:40:58 -07:00
c . JSON ( http . StatusInternalServerError , gin . H { "success" : false , "error" : err . Error ( ) } )
return
}
2023-12-03 19:40:16 -07:00
summary , err := BackgroundJobSyncResourcesWrapper (
c ,
logger ,
databaseRepo ,
& manualSourceCredential ,
func (
_backgroundJobContext context . Context ,
_logger * logrus . Entry ,
_databaseRepo database . DatabaseRepository ,
_sourceCred * models . SourceCredential ,
) ( sourceModels . SourceClient , sourceModels . UpsertSummary , error ) {
2024-01-17 14:45:19 -07:00
manualSourceClient , err := factory . GetSourceClient ( "" , _backgroundJobContext , _logger , _sourceCred )
2023-12-03 19:40:16 -07:00
if err != nil {
resultErr := fmt . Errorf ( "an error occurred while initializing hub client using manual source with credential: %w" , err )
logger . Errorln ( resultErr )
return manualSourceClient , sourceModels . UpsertSummary { } , resultErr
}
summary , err := manualSourceClient . SyncAllBundle ( _databaseRepo , bundleFile , bundleType )
if err != nil {
resultErr := fmt . Errorf ( "an error occurred while processing bundle: %w" , err )
logger . Errorln ( resultErr )
return manualSourceClient , sourceModels . UpsertSummary { } , resultErr
}
return manualSourceClient , summary , nil
} )
2022-12-02 20:40:58 -07:00
if err != nil {
2024-01-20 22:59:17 -07:00
err = fmt . Errorf ( "an error occurred while storing manual source resources: %w" , err )
2022-12-02 20:40:58 -07:00
c . JSON ( http . StatusInternalServerError , gin . H { "success" : false , "error" : err . Error ( ) } )
return
}
2023-09-09 09:24:25 -06:00
//publish event
currentUser , _ := databaseRepo . GetCurrentUser ( c )
2023-09-20 14:57:12 -06:00
err = eventBus . PublishMessage (
2023-09-09 09:24:25 -06:00
models . NewEventSourceComplete (
currentUser . ID . String ( ) ,
manualSourceCredential . ID . String ( ) ,
) ,
)
if err != nil {
logger . Warnf ( "ignoring: an error occurred while publishing sync complete event: %v" , err )
}
2023-01-10 20:23:47 -07:00
c . JSON ( http . StatusOK , gin . H { "success" : true , "data" : summary , "source" : manualSourceCredential } )
2023-09-09 09:24:25 -06:00
2022-12-02 20:40:58 -07:00
}
func GetSource ( c * gin . Context ) {
2023-01-10 20:23:47 -07:00
logger := c . MustGet ( pkg . ContextKeyTypeLogger ) . ( * logrus . Entry )
databaseRepo := c . MustGet ( pkg . ContextKeyTypeDatabase ) . ( database . DatabaseRepository )
2022-12-02 20:40:58 -07:00
sourceCred , err := databaseRepo . GetSource ( c , c . Param ( "sourceId" ) )
if err != nil {
logger . Errorln ( "An error occurred while retrieving source credential" , err )
c . JSON ( http . StatusInternalServerError , gin . H { "success" : false } )
return
}
c . JSON ( http . StatusOK , gin . H { "success" : true , "data" : sourceCred } )
}
func GetSourceSummary ( c * gin . Context ) {
2023-01-10 20:23:47 -07:00
logger := c . MustGet ( pkg . ContextKeyTypeLogger ) . ( * logrus . Entry )
databaseRepo := c . MustGet ( pkg . ContextKeyTypeDatabase ) . ( database . DatabaseRepository )
2022-12-02 20:40:58 -07:00
sourceSummary , err := databaseRepo . GetSourceSummary ( c , c . Param ( "sourceId" ) )
if err != nil {
logger . Errorln ( "An error occurred while retrieving source summary" , err )
c . JSON ( http . StatusInternalServerError , gin . H { "success" : false } )
return
}
c . JSON ( http . StatusOK , gin . H { "success" : true , "data" : sourceSummary } )
}
func ListSource ( c * gin . Context ) {
2023-01-10 20:23:47 -07:00
logger := c . MustGet ( pkg . ContextKeyTypeLogger ) . ( * logrus . Entry )
databaseRepo := c . MustGet ( pkg . ContextKeyTypeDatabase ) . ( database . DatabaseRepository )
2022-12-02 20:40:58 -07:00
sourceCreds , err := databaseRepo . GetSources ( c )
if err != nil {
logger . Errorln ( "An error occurred while listing source credentials" , err )
c . JSON ( http . StatusInternalServerError , gin . H { "success" : false } )
return
}
c . JSON ( http . StatusOK , gin . H { "success" : true , "data" : sourceCreds } )
}
2023-10-11 08:54:18 -06:00
func DeleteSource ( c * gin . Context ) {
logger := c . MustGet ( pkg . ContextKeyTypeLogger ) . ( * logrus . Entry )
databaseRepo := c . MustGet ( pkg . ContextKeyTypeDatabase ) . ( database . DatabaseRepository )
rowsEffected , err := databaseRepo . DeleteSource ( c , c . Param ( "sourceId" ) )
if err != nil {
logger . Errorln ( "An error occurred while deleting source credential" , err )
c . JSON ( http . StatusInternalServerError , gin . H { "success" : false } )
return
}
c . JSON ( http . StatusOK , gin . H { "success" : true , "data" : rowsEffected } )
}
2023-12-03 19:40:16 -07:00
// Helpers
func storeFileLocally ( c * gin . Context ) ( * os . File , error ) {
// single file
file , err := c . FormFile ( "file" )
if err != nil {
//c.JSON(http.StatusInternalServerError, gin.H{"success": false, "error": "could not extract file from form"})
return nil , fmt . Errorf ( "could not extract file from form" )
}
fmt . Printf ( "Uploaded filename: %s" , file . Filename )
// create a temporary file to store this uploaded file
bundleFile , err := ioutil . TempFile ( "" , file . Filename )
if err != nil {
//c.JSON(http.StatusInternalServerError, gin.H{"success": false, "error": "could not create temp file"})
return nil , fmt . Errorf ( "could not create temp file" )
}
// Upload the file to specific bundleFile.
err = c . SaveUploadedFile ( file , bundleFile . Name ( ) )
if err != nil {
//c.JSON(http.StatusInternalServerError, gin.H{"success": false, "error": "could not save temp file"})
return nil , fmt . Errorf ( "could not save temp file" )
}
return bundleFile , nil
}