generate basic IPS summary bundle. Still missing lots of important functionality.
This commit is contained in:
parent
21d12dd312
commit
bf446a0e6e
|
@ -61,7 +61,7 @@ const (
|
|||
IPSSectionsMedicalDevices IPSSections = "medical_devices"
|
||||
IPSSectionsDiagnosticResults IPSSections = "diagnostic_results"
|
||||
IPSSectionsVitalSigns IPSSections = "vital_signs"
|
||||
IPSSectionsHistoryOfIllnesses IPSSections = "history_of_illnesses"
|
||||
IPSSectionsHistoryOfIllness IPSSections = "history_of_illness"
|
||||
IPSSectionsPregnancy IPSSections = "pregnancy"
|
||||
IPSSectionsSocialHistory IPSSections = "social_history"
|
||||
IPSSectionsPlanOfCare IPSSections = "plan_of_care"
|
||||
|
@ -78,7 +78,7 @@ var IPSSectionsList = []IPSSections{
|
|||
IPSSectionsMedicalDevices,
|
||||
IPSSectionsDiagnosticResults,
|
||||
IPSSectionsVitalSigns,
|
||||
IPSSectionsHistoryOfIllnesses,
|
||||
IPSSectionsHistoryOfIllness,
|
||||
IPSSectionsPregnancy,
|
||||
IPSSectionsSocialHistory,
|
||||
IPSSectionsPlanOfCare,
|
||||
|
|
|
@ -2,85 +2,234 @@ package database
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/fastenhealth/fasten-onprem/backend/pkg"
|
||||
"github.com/fastenhealth/fasten-onprem/backend/pkg/models"
|
||||
databaseModel "github.com/fastenhealth/fasten-onprem/backend/pkg/models/database"
|
||||
"github.com/fastenhealth/gofhir-models/fhir401"
|
||||
"github.com/google/uuid"
|
||||
"log"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (gr *GormRepository) GetInternationalPatientSummaryBundle(ctx context.Context) (interface{}, error) {
|
||||
summaryTime := time.Now()
|
||||
timestamp := summaryTime.Format(time.RFC3339)
|
||||
|
||||
//Algorithm to create the IPS bundle
|
||||
// 1. Generate the IPS Section Lists (GetInternationalPatientSummarySectionResources)
|
||||
// - Process each resource, generating a Markdown narrative in the text field for each resource
|
||||
// - keep track of the earliest and latest date of the resources in the section
|
||||
// 2. Create the Composition Section (generateIPSCompositionSection)
|
||||
// - Populate it with the data from the Header
|
||||
// - Generate a Section Narrative, written in Markdown, which summarizes the contents of the section at a high level, with dates and counts
|
||||
// 3. Query all the Patient Resources
|
||||
// - Merge the Patient resources together?
|
||||
// 4. Create a Fasten Health Organization resource. This is the custodian of the IPS
|
||||
// 5. Create the IPS Composition
|
||||
// - Populate it with the Composition Sections and references to the Patient resource + Fasten Health Organziation resource
|
||||
// - Generate a Composition Narrative, written in Markdown, which summarizes the contents of the IPS & Patient at a high level, with dates and counts
|
||||
// 6. Create the IPS Bundle
|
||||
|
||||
//Step 1. Generate the IPS Section Lists
|
||||
summarySectionResources, err := gr.GetInternationalPatientSummarySectionResources(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//Step 2. Create the Composition Section
|
||||
compositionSections := []fhir401.CompositionSection{}
|
||||
for sectionType, sectionResources := range summarySectionResources {
|
||||
compositionSection, err := generateIPSCompositionSection(sectionType, sectionResources)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
compositionSections = append(compositionSections, *compositionSection)
|
||||
}
|
||||
|
||||
//TODO: Step 3. Query all the Patient Resources & merge them together
|
||||
|
||||
//TODO: Step 4. Create a Fasten Health Organization resource.
|
||||
|
||||
compositionUUID := uuid.New().String()
|
||||
|
||||
//Step 5. Create the IPS Composition
|
||||
ipsComposition := &fhir401.Composition{
|
||||
Id: stringPtr(compositionUUID),
|
||||
Text: &fhir401.Narrative{
|
||||
Status: fhir401.NarrativeStatusGenerated,
|
||||
Div: "PLACEHOLDER NARRATIVE SUMMARY FOR COMPOSITION", //TODO
|
||||
},
|
||||
Identifier: &fhir401.Identifier{
|
||||
System: stringPtr("https://www.fastenhealth.com"), //TODO
|
||||
Value: &compositionUUID,
|
||||
},
|
||||
Status: fhir401.CompositionStatusFinal,
|
||||
Type: fhir401.CodeableConcept{
|
||||
Coding: []fhir401.Coding{
|
||||
{
|
||||
System: stringPtr("http://loinc.org"),
|
||||
Code: stringPtr("60591-5"),
|
||||
Display: stringPtr("Patient Summary"),
|
||||
},
|
||||
},
|
||||
},
|
||||
Subject: &fhir401.Reference{
|
||||
Reference: stringPtr("Patient/123"), //TODO
|
||||
},
|
||||
Date: timestamp,
|
||||
Author: []fhir401.Reference{
|
||||
{
|
||||
Reference: stringPtr("Organization/fastenhealth.com"), //TODO: The type of author(s) contribute to determine the "nature"of the Patient Summary: e.g. a "human-curated" IPS Vs. an "automatically generated" IPS.
|
||||
},
|
||||
},
|
||||
Title: fmt.Sprintf("Patient Summary as of %s", summaryTime.Format("January 2, 2006 15:04")),
|
||||
Attester: []fhir401.CompositionAttester{
|
||||
{
|
||||
Mode: fhir401.CompositionAttestationModePersonal,
|
||||
Time: ×tamp,
|
||||
Party: &fhir401.Reference{
|
||||
Reference: stringPtr("Patient/123"),
|
||||
},
|
||||
},
|
||||
},
|
||||
Custodian: &fhir401.Reference{
|
||||
Reference: stringPtr("Organization/fastenhealth.com"),
|
||||
},
|
||||
Event: []fhir401.CompositionEvent{
|
||||
{
|
||||
Code: []fhir401.CodeableConcept{
|
||||
{
|
||||
Coding: []fhir401.Coding{
|
||||
{
|
||||
System: stringPtr("http://terminology.hl7.org/CodeSystem/v3-ActClass"),
|
||||
Code: stringPtr("PCPR"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Period: &fhir401.Period{
|
||||
Start: ×tamp, //TODO: this should be the oldest record in the summary
|
||||
End: ×tamp,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Step 6. Create the IPS Bundle
|
||||
bundleUUID := uuid.New().String()
|
||||
ipsBundle := &fhir401.Bundle{
|
||||
Id: &bundleUUID,
|
||||
Timestamp: ×tamp,
|
||||
Language: stringPtr("en-US"),
|
||||
Entry: []fhir401.BundleEntry{},
|
||||
Type: fhir401.BundleTypeDocument,
|
||||
}
|
||||
|
||||
// Add the Composition to the bundle
|
||||
ipsCompositionJson, err := json.Marshal(ipsComposition)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ipsBundle.Entry = append(ipsBundle.Entry, fhir401.BundleEntry{
|
||||
Resource: json.RawMessage(ipsCompositionJson),
|
||||
})
|
||||
|
||||
// TODO: Add the Patient to the bundle
|
||||
// TODO: Add the Fasten Health Organization to the bundle
|
||||
|
||||
// Add all the resources to the bundle
|
||||
for _, sectionResources := range summarySectionResources {
|
||||
for _, resource := range sectionResources {
|
||||
ipsBundle.Entry = append(ipsBundle.Entry, fhir401.BundleEntry{
|
||||
Resource: json.RawMessage(resource.ResourceRaw),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return ipsBundle, nil
|
||||
}
|
||||
|
||||
// GetInternationalPatientSummary will generate an IPS bundle, which can then be used to generate a IPS QR code, PDF or JSON bundle
|
||||
// The IPS bundle will contain a summary of all the data in the system, including a list of all sources, and the main Patient
|
||||
// See: https://github.com/fastenhealth/fasten-onprem/issues/170
|
||||
// See: https://github.com/jddamore/fhir-ips-server/blob/main/docs/Summary_Creation_Steps.md
|
||||
func (gr *GormRepository) GetInternationalPatientSummary(ctx context.Context) (*models.Summary, error) {
|
||||
currentUser, currentUserErr := gr.GetCurrentUser(ctx)
|
||||
if currentUserErr != nil {
|
||||
return nil, currentUserErr
|
||||
}
|
||||
func (gr *GormRepository) GetInternationalPatientSummarySectionResources(ctx context.Context) (map[pkg.IPSSections][]models.ResourceBase, error) {
|
||||
|
||||
// we want a count of all resources for this user by type
|
||||
var resourceCountResults []map[string]interface{}
|
||||
summarySectionResources := map[pkg.IPSSections][]models.ResourceBase{}
|
||||
|
||||
resourceTypes := databaseModel.GetAllowedResourceTypes()
|
||||
for _, resourceType := range resourceTypes {
|
||||
tableName, err := databaseModel.GetTableNameByResourceType(resourceType)
|
||||
// generate queries for each IPS Section
|
||||
for ndx, _ := range pkg.IPSSectionsList {
|
||||
sectionName := pkg.IPSSectionsList[ndx]
|
||||
|
||||
//initialize the section
|
||||
summarySectionResources[sectionName] = []models.ResourceBase{}
|
||||
|
||||
queries, err := generateIPSSectionQueries(sectionName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var count int64
|
||||
|
||||
gr.QueryResources(ctx, models.QueryResource{
|
||||
Use: "",
|
||||
Select: nil,
|
||||
From: "",
|
||||
Where: nil,
|
||||
Limit: nil,
|
||||
Offset: nil,
|
||||
Aggregations: nil,
|
||||
})
|
||||
for qndx, _ := range queries {
|
||||
results, err := gr.QueryResources(ctx, queries[qndx])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := gr.GormClient.WithContext(ctx).
|
||||
Table(tableName).
|
||||
Where(models.OriginBase{
|
||||
UserID: currentUser.ID,
|
||||
}).
|
||||
Count(&count)
|
||||
if result.Error != nil {
|
||||
return nil, result.Error
|
||||
resultsList := results.([]models.ResourceBase)
|
||||
|
||||
//TODO: generate resource narrative
|
||||
summarySectionResources[sectionName] = append(summarySectionResources[sectionName], resultsList...)
|
||||
}
|
||||
if count == 0 {
|
||||
continue //don't add resource counts if the count is 0
|
||||
}
|
||||
resourceCountResults = append(resourceCountResults, map[string]interface{}{
|
||||
"resource_type": resourceType,
|
||||
"count": count,
|
||||
})
|
||||
}
|
||||
|
||||
// we want a list of all sources (when they were last updated)
|
||||
sources, err := gr.GetSources(ctx)
|
||||
return summarySectionResources, nil
|
||||
}
|
||||
|
||||
func generateIPSCompositionSection(sectionType pkg.IPSSections, resources []models.ResourceBase) (*fhir401.CompositionSection, error) {
|
||||
sectionTitle, sectionCode, err := generateIPSSectionHeaderInfo(sectionType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// we want the main Patient for each source
|
||||
patients, err := gr.GetPatientForSources(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
section := &fhir401.CompositionSection{
|
||||
Title: §ionTitle,
|
||||
Code: §ionCode,
|
||||
}
|
||||
if len(resources) == 0 {
|
||||
section.EmptyReason = &fhir401.CodeableConcept{
|
||||
Text: stringPtr("No data available"),
|
||||
Coding: []fhir401.Coding{
|
||||
{
|
||||
System: stringPtr("http://terminology.hl7.org/CodeSystem/list-empty-reason"),
|
||||
Code: stringPtr("unavailable"),
|
||||
},
|
||||
},
|
||||
}
|
||||
} else {
|
||||
section.Entry = []fhir401.Reference{}
|
||||
for _, resource := range resources {
|
||||
reference := fhir401.Reference{
|
||||
Reference: stringPtr(fmt.Sprintf("%s/%s", resource.SourceResourceType, resource.SourceID)),
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
section.Entry = append(section.Entry, reference)
|
||||
}
|
||||
|
||||
if resourceCountResults == nil {
|
||||
resourceCountResults = []map[string]interface{}{}
|
||||
}
|
||||
summary := &models.Summary{
|
||||
Sources: sources,
|
||||
ResourceTypeCounts: resourceCountResults,
|
||||
Patients: patients,
|
||||
}
|
||||
//TODO: Add the section narrative summary
|
||||
section.Text = &fhir401.Narrative{
|
||||
Status: fhir401.NarrativeStatusGenerated,
|
||||
Div: "PLACEHOLDER NARRATIVE SUMMARY FOR SECTION",
|
||||
}
|
||||
|
||||
return summary, nil
|
||||
}
|
||||
return section, nil
|
||||
}
|
||||
|
||||
// https://github.com/jddamore/fhir-ips-server/blob/main/docs/Summary_Creation_Steps.md
|
||||
// Generate Resource Queries for each IPS Section
|
||||
func generateIPSSectionQueries(sectionType pkg.IPSSections) ([]models.QueryResource, error) {
|
||||
|
||||
queries := []models.QueryResource{}
|
||||
|
@ -180,22 +329,24 @@ func generateIPSSectionQueries(sectionType pkg.IPSSections) ([]models.QueryResou
|
|||
})
|
||||
break
|
||||
case pkg.IPSSectionsAdvanceDirectives:
|
||||
queries = append(queries, models.QueryResource{
|
||||
Select: nil,
|
||||
From: "Consent",
|
||||
Where: map[string]interface{}{
|
||||
"status": "active",
|
||||
},
|
||||
})
|
||||
//queries = append(queries, models.QueryResource{
|
||||
// Select: nil,
|
||||
// From: "Consent",
|
||||
// Where: map[string]interface{}{
|
||||
// "status": "active",
|
||||
// },
|
||||
//})
|
||||
log.Printf("warning: Consent FHIR resources are not supported yet. Skipping")
|
||||
break
|
||||
case pkg.IPSSectionsFunctionalStatus:
|
||||
queries = append(queries, models.QueryResource{
|
||||
Select: nil,
|
||||
From: "ClinicalImpression",
|
||||
Where: map[string]interface{}{
|
||||
"status": "in-progress,completed",
|
||||
},
|
||||
})
|
||||
//queries = append(queries, models.QueryResource{
|
||||
// Select: nil,
|
||||
// From: "ClinicalImpression",
|
||||
// Where: map[string]interface{}{
|
||||
// "status": "in-progress,completed",
|
||||
// },
|
||||
//})
|
||||
log.Printf("warning: ClinicalImpression FHIR resources are not supported yet. Skipping")
|
||||
break
|
||||
case pkg.IPSSectionsMedicalDevices:
|
||||
queries = append(queries, models.QueryResource{
|
||||
|
@ -206,7 +357,7 @@ func generateIPSSectionQueries(sectionType pkg.IPSSections) ([]models.QueryResou
|
|||
},
|
||||
})
|
||||
break
|
||||
case pkg.IPSSectionsHistoryOfIllnesses:
|
||||
case pkg.IPSSectionsHistoryOfIllness:
|
||||
//TODO: last updated date should be older than 5 years (dateTime or period.high)
|
||||
//TODO: check if where clause with multiple modifiers for the same field works as expected
|
||||
queries = append(queries, models.QueryResource{
|
||||
|
@ -235,7 +386,168 @@ func generateIPSSectionQueries(sectionType pkg.IPSSections) ([]models.QueryResou
|
|||
"status:not": []string{"entered-in-error", "not-done"},
|
||||
},
|
||||
})
|
||||
break
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported section type: %s", sectionType)
|
||||
}
|
||||
|
||||
return queries, nil
|
||||
}
|
||||
|
||||
// generate header information for Composition Sections. Title & Code for each section
|
||||
func generateIPSSectionHeaderInfo(sectionType pkg.IPSSections) (string, fhir401.CodeableConcept, error) {
|
||||
switch sectionType {
|
||||
case pkg.IPSSectionsMedicationSummary:
|
||||
return "Medication Summary", fhir401.CodeableConcept{
|
||||
Coding: []fhir401.Coding{
|
||||
{
|
||||
System: stringPtr("http://loinc.org"),
|
||||
Code: stringPtr("10160-0"),
|
||||
Display: stringPtr("Medication Summary"),
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
case pkg.IPSSectionsAllergiesIntolerances:
|
||||
return "Allergies and Intolerances", fhir401.CodeableConcept{
|
||||
Coding: []fhir401.Coding{
|
||||
{
|
||||
System: stringPtr("http://loinc.org"),
|
||||
Code: stringPtr("48765-2"),
|
||||
Display: stringPtr("Allergies and Intolerances"),
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
case pkg.IPSSectionsProblemList:
|
||||
return "Problem List", fhir401.CodeableConcept{
|
||||
Coding: []fhir401.Coding{
|
||||
{
|
||||
System: stringPtr("http://loinc.org"),
|
||||
Code: stringPtr("11450-4"),
|
||||
Display: stringPtr("Problem List"),
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
case pkg.IPSSectionsImmunizations:
|
||||
return "Immunizations", fhir401.CodeableConcept{
|
||||
Coding: []fhir401.Coding{
|
||||
{
|
||||
System: stringPtr("http://loinc.org"),
|
||||
Code: stringPtr("11369-6"),
|
||||
Display: stringPtr("Immunizations"),
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
case pkg.IPSSectionsHistoryOfProcedures:
|
||||
return "History of Procedures", fhir401.CodeableConcept{
|
||||
Coding: []fhir401.Coding{
|
||||
{
|
||||
System: stringPtr("http://loinc.org"),
|
||||
Code: stringPtr("47519-4"),
|
||||
Display: stringPtr("History of Procedures"),
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
case pkg.IPSSectionsMedicalDevices:
|
||||
return "Medical Devices", fhir401.CodeableConcept{
|
||||
Coding: []fhir401.Coding{
|
||||
{
|
||||
System: stringPtr("http://loinc.org"),
|
||||
Code: stringPtr("46264-8"),
|
||||
Display: stringPtr("Medical Devices"),
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
case pkg.IPSSectionsDiagnosticResults:
|
||||
return "Diagnostic Results", fhir401.CodeableConcept{
|
||||
Coding: []fhir401.Coding{
|
||||
{
|
||||
System: stringPtr("http://loinc.org"),
|
||||
Code: stringPtr("30954-2"),
|
||||
Display: stringPtr("Diagnostic Results"),
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
case pkg.IPSSectionsVitalSigns:
|
||||
return "Vital Signs", fhir401.CodeableConcept{
|
||||
Coding: []fhir401.Coding{
|
||||
{
|
||||
System: stringPtr("http://loinc.org"),
|
||||
Code: stringPtr("8716-3"),
|
||||
Display: stringPtr("Vital Signs"),
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
case pkg.IPSSectionsHistoryOfIllness:
|
||||
return "Past History of Illness", fhir401.CodeableConcept{
|
||||
Coding: []fhir401.Coding{
|
||||
{
|
||||
System: stringPtr("http://loinc.org"),
|
||||
Code: stringPtr("11348-0"),
|
||||
Display: stringPtr("History of Illness"),
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
case pkg.IPSSectionsPregnancy:
|
||||
return "Pregnancy History", fhir401.CodeableConcept{
|
||||
Coding: []fhir401.Coding{
|
||||
{
|
||||
System: stringPtr("http://loinc.org"),
|
||||
Code: stringPtr("10162-6"),
|
||||
Display: stringPtr("Pregnancy History"),
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
case pkg.IPSSectionsSocialHistory:
|
||||
return "Social History", fhir401.CodeableConcept{
|
||||
Coding: []fhir401.Coding{
|
||||
{
|
||||
System: stringPtr("http://loinc.org"),
|
||||
Code: stringPtr("29762-2"),
|
||||
Display: stringPtr("Social History"),
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
case pkg.IPSSectionsPlanOfCare:
|
||||
return "Plan of Care", fhir401.CodeableConcept{
|
||||
Coding: []fhir401.Coding{
|
||||
{
|
||||
System: stringPtr("http://loinc.org"),
|
||||
Code: stringPtr("18776-5"),
|
||||
Display: stringPtr("Plan of Care"),
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
case pkg.IPSSectionsFunctionalStatus:
|
||||
return "Functional Status", fhir401.CodeableConcept{
|
||||
Coding: []fhir401.Coding{
|
||||
{
|
||||
System: stringPtr("http://loinc.org"),
|
||||
Code: stringPtr("47420-5"),
|
||||
Display: stringPtr("Functional Status"),
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
case pkg.IPSSectionsAdvanceDirectives:
|
||||
return "Advance Directives", fhir401.CodeableConcept{
|
||||
Coding: []fhir401.Coding{
|
||||
{
|
||||
System: stringPtr("http://loinc.org"),
|
||||
Code: stringPtr("42348-3"),
|
||||
Display: stringPtr("Advance Directives"),
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
default:
|
||||
return "", fhir401.CodeableConcept{}, fmt.Errorf("invalid section type: %s", sectionType)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func generateIPSSectionNarrative(sectionType pkg.IPSSections, resources []models.ResourceBase) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// helper utility
|
||||
func stringPtr(s string) *string {
|
||||
return &s
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ type DatabaseRepository interface {
|
|||
|
||||
//get a count of every resource type
|
||||
GetSummary(ctx context.Context) (*models.Summary, error)
|
||||
GetInternationalPatientSummaryBundle(ctx context.Context) (interface{}, error)
|
||||
|
||||
GetResourceByResourceTypeAndId(context.Context, string, string) (*models.ResourceBase, error)
|
||||
GetResourceBySourceId(context.Context, string, string) (*models.ResourceBase, error)
|
||||
|
|
|
@ -20,3 +20,16 @@ func GetSummary(c *gin.Context) {
|
|||
}
|
||||
c.JSON(http.StatusOK, gin.H{"success": true, "data": summary})
|
||||
}
|
||||
|
||||
func GetIPSSummary(c *gin.Context) {
|
||||
logger := c.MustGet(pkg.ContextKeyTypeLogger).(*logrus.Entry)
|
||||
databaseRepo := c.MustGet(pkg.ContextKeyTypeDatabase).(database.DatabaseRepository)
|
||||
|
||||
summary, err := databaseRepo.GetInternationalPatientSummaryBundle(c)
|
||||
if err != nil {
|
||||
logger.Errorln("An error occurred while retrieving IPS summary", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"success": false})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"success": true, "data": summary})
|
||||
}
|
||||
|
|
|
@ -100,6 +100,7 @@ func (ae *AppEngine) Setup() (*gin.RouterGroup, *gin.Engine) {
|
|||
secure.DELETE("/account/me", handler.DeleteAccount)
|
||||
|
||||
secure.GET("/summary", handler.GetSummary)
|
||||
secure.GET("/summary/ips", handler.GetIPSSummary)
|
||||
|
||||
secure.POST("/source", handler.CreateReconnectSource)
|
||||
secure.POST("/source/manual", handler.CreateManualSource)
|
||||
|
|
Loading…
Reference in New Issue