covidtracker

package module
v0.0.0-...-d1a2b61 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 19, 2020 License: GPL-3.0 Imports: 4 Imported by: 0

README

covidtracker, also known as EviteCovid (https://evitecovid.fr/) is an API used to evaluate risk of COVID-19 contamination during a multi-segment trip (trip combining several mode of transportation or hotel).

It has been built with the objective to evaluate risk of trip within France as a first step. As a result, it relies on the opendata provided by French public health agency 'Santé publique France' (In particular this dataset https://www.data.gouv.fr/fr/datasets/donnees-hospitalieres-relatives-a-lepidemie-de-covid-19/). For the risk about hotels, it relies on the data provided by the hotel aggregator CDS (https://www.cdsgroupe.com/). Also, risk parameters have been completed while having in mind the measures currently applied by carriers, in France.

NB : this project is highly experimental and computed risk is not intended to be accurate (as it depends of a lot of unknown parameters). However it aims to give a basic idea of how risky can be a trip compared with another one.

Prerequisite

In order to run the API server, you need a mongodb database

brew install mongodb
brew services start mongodb

Configure

To run the API, you can configure the following env variables :

- THETREEP_COVIDTRACKER_MONGO_URL : the URI to connect to mongo database
- THETREEP_COVIDTRACKER_DATABASE : the name of the database to connect to 
- THETREEP_COVIDTRACKER_MONGO_USER : optionally, the user to connect to mongo database
- THETREEP_COVIDTRACKER_MONGO_PASSWORD : optionally, the password to connect to mongo database
- THETREEP_COVIDTRACKER_SECRET : the secret used to authenticate frontend requests (static for now)
- THETREEP_COVIDTRACKER_CDS_API_USER : the user to connect to the API of CDS (hotel aggregator that has built an inventory of the measures against Covid-19 in hotels)
- THETREEP_COVIDTRACKER_CDS_API_PASSWORD : the password to connect to the API of CDS
- THETREEP_COVIDTRACKER_CDS_API_DUTY_CODE : the duty code to connect to the API of CDS
- THETREEP_COVIDTRACKER_LOG_LEVEL: the logging level, can be one of "fatal", "error", "warn", "info", "debug" (logs output is in JSON)

Getting started

Build and run the API server with

cd cmd/covidtracker
go build
./covidtracker

or

go run main.go

You also may need to run the refresher (cron task that refreshes once a day the French emergency open data about Covid-19) with

go run cmd/refresher/main.go

Dependencies

Dependencies are automatically managed with go mod (requires go >= 1.11) You just need to export the appropriate variable

export GO111MODULE=on

Then dependencies will automatically be added when using the go toolchain (go build, go run, go test...)

Testing

Unit tests

Go unit tests can be run with

go test ./...

or with all flags (to display all output, test coverage and detect race conditions):

go test -cover -race -v ./...

License

This work is copyrighted by the Treep and released publicly under the terms of the GNU General Public License.

Documentation

Index

Constants

View Source
const (
	ErrInvalidTimeJSON            = Error("invalid time format (only RFC3339 format `2006-01-02T15:04:05Z07:00` is accepted)")
	ErrInvalidJSON                = Error("invalid json")
	ErrInternal                   = Error("internal error")
	ErrInvalidQueryParamsType     = Error("invalid query parameters type")
	ErrNoAuthenticationToken      = Error("no authentication token provided")
	ErrInvalidAuthenticationToken = Error("invalid authentication token provided")
	ErrMissingAPISecret           = Error("api-secret is missing")
	ErrInvalidAPISecret           = Error("api-secret is wrong")
	ErrNoParametersDefined        = Error("no default parameters are defined")
)

HTTP errors

View Source
const (
	ErrUnauthorized = Error("unauthorized")
)

General errors.

Variables

View Source
var (
	ErrDocRequired = func(doc string) error {
		return Errorf("document %q is required", doc)
	}
	ErrMissingParams = func(doc string) error {
		return Errorf("%q is missing", doc)
	}
)

DB Errors

Functions

func PopulationOfDepartment

func PopulationOfDepartment(dep string) (int, error)

Types

type AdminLevels

type AdminLevels struct {
	Level2 string `json:"level2"`
	Level4 string `json:"level4"`
	Level6 string `json:"level6"`
}

type Case

type Case struct {
	ID         CaseID    `bson:"_id" json:"id"`
	Department string    `bson:"dep" json:"dep"`
	NoticeDate time.Time `bson:"noticeDate" json:"noticeDate"`

	//HospServiceCountRelated is the number of hospital services reporting at least one case
	HospServiceCountRelated int `bson:"hospServiceCountRelated" json:"hospServiceCountRelated"`
}

type CaseDAL

type CaseDAL interface {
	Get(dep string, date time.Time) (*Case, error)
	GetRange(dep string, begin, end time.Time) ([]*Case, error)
	Upsert(...*Case) error
}

type CaseID

type CaseID string

type CaseService

type CaseService interface {
	RefreshCase() ([]*Case, error)
}

type Emergency

type Emergency struct {
	ID          EmergencyID `bson:"_id" json:"id"`
	Department  string      `bson:"dep" json:"dep"`
	PassageDate time.Time   `bson:"passageDate" json:"passageDate"`

	//Count is the number of visits
	Count int `bson:"count" json:"count"`
	//Cov19SuspCount is the number of suspicious covid19 patient amoung the visits
	Cov19SuspCount int `bson:"cov19SuspCount" json:"cov19SuspCount"`

	//Cov19SuspicionHosp is the amount of hospitalized for covid-19 suspicion amoung the visits
	Cov19SuspHosp int `bson:"cov19SuspHospitalized" json:"cov19SuspHospitalized"`
	//TotalSOSMedAct is the amount of medical act reported by SOS Medecin
	TotalSOSMedAct int `bson:"totalSosMedAct" json:"totalSosMedAct"`
	//TotalSOSMedAct is the amount of medical act reported by SOS Medecin concerning the COVID-19
	SOSMedCov19SuspAct int `bson:"cov19SosMedAct" json:"sosMedMaleAct"`
}

Emergency regroups the stats about visit at emergency room

type EmergencyDAL

type EmergencyDAL interface {
	Get(dep string, date time.Time) (*Emergency, error)
	GetRange(dep string, begin, end time.Time) ([]*Emergency, error)
	Upsert(...*Emergency) error
}

type EmergencyID

type EmergencyID string

type EmergencyService

type EmergencyService interface {
	RefreshEmergency() ([]*Emergency, error)
}

type Error

type Error string

Error represents an error.

func Errorf

func Errorf(pattern string, params ...interface{}) Error

Errorf creates an Error

func (Error) Error

func (e Error) Error() string

Error returns the error message.

type Geo

type Geo struct {
	Properties Properties `json:"properties"`
	Type       string     `json:"type"`
	Geometry   Geometry   `json:"geometry"`
}

func (Geo) Check

func (g Geo) Check() error

Check checks format / value of Geo

func (Geo) Dep

func (g Geo) Dep() (string, error)

type GeoCoding

type GeoCoding struct {
	Type        string      `json:"type"`
	Accuracy    int         `json:"accuracy"`
	Label       string      `json:"label"`
	Name        string      `json:"name"`
	HouseNumber string      `json:"housenumber"`
	Street      string      `json:"street"`
	Locality    string      `json:"locality"`
	PostCode    string      `json:"postcode"`
	City        string      `json:"city"`
	District    *string     `json:"district,omitempty"`
	County      *string     `json:"county,omitempty"`
	State       *string     `json:"state,omitempty"`
	Country     string      `json:"country,omitempty"`
	Admin       AdminLevels `json:"admin"`
	Geohash     string      `json:"geohash"`
}

type Geometry

type Geometry struct {
	Coordinates []float64 `json:"coordinates"`
	Type        string    `json:"type"`
}

type HospDAL

type HospDAL interface {
	Get(dep string, date time.Time) (*Hospitalization, error)
	GetRange(dep string, begin, end time.Time) ([]*Hospitalization, error)
	Upsert(...*Hospitalization) error
}

type HospID

type HospID string

type HospService

type HospService interface {
	RefreshHospitalization() ([]*Hospitalization, error)
}

type Hospitalization

type Hospitalization struct {
	ID         HospID    `bson:"_id" json:"id"`
	Department string    `bson:"dep" json:"dep"`
	Date       time.Time `bson:"date" json:"date"`

	//Count is the number of patient hospitalized
	Count int `bson:"count" json:"count"`
	//CriticalCount is the number of patient in resuscitation or critical care
	CriticalCount int `bson:"critical" json:"critical"`
	//ReturnHomeCount is the number of patient that returned home
	ReturnHomeCount int `bson:"returnHome" json:"returnHome"`
	//DeathCount is the number of deaths
	DeathCount int `bson:"deaths" json:"deaths"`
}

Hospitalization defines the usefull data about hospitalization

type Hotel

type Hotel struct {
	ID            HotelID  `bson:"_id" json:"id"`
	Name          string   `bson:"name" json:"name"`
	Address       string   `bson:"address" json:"address"`
	City          string   `bson:"city" json:"city"`
	ZipCode       string   `bson:"zipCode" json:"zipCode"`
	Country       string   `bson:"country" json:"country"`
	ImageURL      string   `bson:"imageUrl" json:"imageUrl"`
	SanitaryInfos []string `bson:"sanitaryInfos" json:"sanitaryInfos"`
	SanitaryNote  float64  `bson:"sanitaryNote" json:"sanitaryNote"`
	SanitaryNorm  string   `bson:"sanitaryNorm" json:"sanitaryNorm"`
}

func (*Hotel) Dep

func (h *Hotel) Dep() (string, error)

type HotelDAL

type HotelDAL interface {
	Get(id HotelID) (*Hotel, error)
	Insert(hotels []*Hotel) ([]*Hotel, error)
}

type HotelID

type HotelID string

type HotelJob

type HotelJob interface {
	HotelsByPrefix(city string, prefix string) ([]*Hotel, error)
}

type IndicDAL

type IndicDAL interface {
	Get(dep string, date time.Time) (*Indicator, error)
	GetRange(dep int, begin, end time.Time) ([]*Indicator, error)
	Upsert(...*Indicator) error
}

type IndicID

type IndicID string

type IndicService

type IndicService interface {
	RefreshIndicator() ([]*Indicator, error)
}

type Indicator

type Indicator struct {
	ID          IndicID   `bson:"_id" json:"id"`
	ExtractDate time.Time `bson:"extractDate" json:"extractDate"`
	Department  string    `bson:"dep" json:"dep"`
	Color       string    `bson:"color" json:"color"`
}

type Logfer

type Logfer interface {
	HasErr(ctx context.Context, err error) bool
	HasErrWithFields(ctx context.Context, fields map[string]interface{}, err error) bool
	Debug(ctx context.Context, str string, vars ...interface{})
	DebugWithFields(ctx context.Context, fields map[string]interface{}, str string, vars ...interface{})
	Info(ctx context.Context, str string, vars ...interface{})
	InfoWithFields(ctx context.Context, fields map[string]interface{}, str string, vars ...interface{})
	Warn(ctx context.Context, str string, vars ...interface{})
	WarnWithFields(ctx context.Context, fields map[string]interface{}, str string, vars ...interface{})
	Error(ctx context.Context, str string, vars ...interface{})
	ErrorWithFields(ctx context.Context, fields map[string]interface{}, str string, vars ...interface{})
	Panic(ctx context.Context, str string, vars ...interface{})
	PanicWithFields(ctx context.Context, fields map[string]interface{}, str string, vars ...interface{})
}

type ParameterScope

type ParameterScope struct {
	// Transportation optionally represents the transportation of this scope (if not a place)
	Transportation Transportation `bson:"transportation" json:"transportation"`

	// Place optionally represents the place of this scope (if not a transportation)
	Place Place `bson:"place" json:"place"`

	Duration TransportationDuration `bson:"duration" json:"duration"`
}

func (*ParameterScope) String

func (s *ParameterScope) String() string

type Place

type Place string
const HotelPlace Place = "hotel"

type Properties

type Properties struct {
	GeoCoding *GeoCoding `json:"geocoding,omitempty"`
	//props fr
	Name        *string  `json:"nom,omitempty"`
	PostalCode  *string  `json:"code,omitempty"`
	DepCode     *string  `json:"codeDepartement,omitempty"`
	RegionCode  *string  `json:"codeRegion,omitempty"`
	Population  *int     `json:"population,omitempty"`
	PostalCodes []string `json:"codesPostaux,omitempty"`
}

type Protection

type Protection struct {
	ID       ProtectionID
	Type     ProtectionType
	Name     string
	Quantity int
}

type ProtectionID

type ProtectionID string

type ProtectionType

type ProtectionType string
const (
	Mask         ProtectionType = "mask"
	MaskSewn     ProtectionType = "mask-sewn"
	MaskSurgical ProtectionType = "mask-surgical"
	MaskFFPX     ProtectionType = "mask-ffpx"
	Gel          ProtectionType = "gel"
)

type RefreshJob

type RefreshJob interface {
	Refresh(CaseDAL, EmergencyDAL, HospDAL, IndicDAL, ScreeningDAL) error
}

type Report

type Report struct {
	Minuses []Statement `bson:"minuses" json:"minuses"`
	Pluses  []Statement `bson:"pluses" json:"pluses"`
	Advices []Statement `bson:"advices" json:"advices"`
}

type Risk

type Risk struct {
	ID              RiskID        `bson:"_id" json:"id"`
	NoticeDate      time.Time     `bson:"noticeDate" json:"noticeDate"`
	ConfidenceLevel float64       `bson:"confidenceLevel" json:"confidenceLevel"`
	RiskLevel       float64       `bson:"riskLevel" json:"riskLevel"`
	DisplayedRisk   float64       `bson:"displayedRisk" json:"displayedRisk"`
	BySegments      []RiskSegment `bson:"bySegments" json:"bySegments"`
	Report          Report        `bson:"report" json:"report"`
}

Risk is the definition of risk and confidence level of a trip

type RiskDAL

type RiskDAL interface {
	Get(id RiskID) (*Risk, error)
	Insert(r ...*Risk) error
}

RiskDAL defines the data access layer of risk data

type RiskID

type RiskID string

RiskID identifies a Risk

type RiskJob

type RiskJob interface {
	ComputeRisk(segs []Segment, protects []Protection) (*Risk, error)
}

RiskJob defines the job to implements risk data logic

type RiskParameter

type RiskParameter struct {
	// The scope of this risk parameter
	Scope ParameterScope `bson:"scope" json:"scope"`

	// The number of persons with direct projection possible
	NbDirect int `bson:"nbDirect" json:"nbDirect"`

	// The probability of contagion via direct projection with an infectious person
	ProbaContagionDirect float64 `bson:"probaContagionDirect" json:"probaContagionDirect"`

	// The protection factor of mask against direct contagion
	MaskProtectDirect float64 `bson:"maskProtectDirect" json:"maskProtectDirect"`

	// The number of persons with direct contact with the person
	NbContact int `bson:"nbContact" json:"nbContact"`

	// The probability of contagion via direct contact with an infectious person
	ProbaContagionContact float64 `bson:"probaContagionContact" json:"probaContagionContact"`

	// The protection factor of mask against contact contagion
	MaskProtectContact float64 `bson:"maskProtectContact" json:"maskProtectContact"`

	// The protection factor of gel against contact contagion
	GelProtectContact float64 `bson:"gelProtectContact" json:"gelProtectContact"`

	// The number of persons with indirect contact
	NbIndirect int `bson:"nbIndirect" json:"nbIndirect"`

	// The probability of contagion via indirect contact with an infectious person
	ProbaContagionIndirect float64 `bson:"probaContagionIndirect" json:"probaContagionIndirect"`

	// The protection factor of mask against indirect contact contagion
	MaskProtectIndirect float64 `bson:"maskProtectIndirect" json:"maskProtectIndirect"`

	// The protection factor of gel against indirect contact contagion
	GelProtectIndirect float64 `bson:"gelProtectIndirect" json:"gelProtectIndirect"`

	// The Pluses of this kind of segment
	Pluses []string `bson:"pluses" json:"pluses"`

	// The Minuses of this kind of segment
	Minuses []string `bson:"minuses" json:"minuses"`

	// The Advices of this kind of segment
	Advices []string `bson:"advices" json:"advices"`
}

type RiskParameters

type RiskParameters struct {
	// Use to splecify that these are the default parameters
	IsDefault bool `bson:"default" json:"default"`

	// The protection factor of sewn mask
	SewnMaskProtect float64 `bson:"sewnMaskProtect" json:"sewnMaskProtect"`

	// The protection factor of surgical mask
	SurgicalMaskProtect float64 `bson:"surgicalMaskProtect" json:"surgicalMaskProtect"`

	// The protection factor of ffpx mask
	FFPXMaskProtect float64 `bson:"ffpxMaskProtect" json:"ffpxMaskProtect"`

	// The protection factor of hydro alcoholic gel
	HydroAlcoholicGelProtect float64 `bson:"hydroAlcoholicGelProtect" json:"hydroAlcoholicGelProtect"`

	// The parameters associated with a scope
	Parameters []*RiskParameter `bson:"parameters" json:"parameters"`
}

func (*RiskParameters) ByScope

func (r *RiskParameters) ByScope() map[ParameterScope]*RiskParameter

type RiskParametersDAL

type RiskParametersDAL interface {
	GetDefault() (*RiskParameters, error)
	Insert(p *RiskParameters) error
}

RiskParametersDAL defines the data access layer of risk parameters

type RiskSegID

type RiskSegID string

RiskSegID identifies a RiskSegment

type RiskSegment

type RiskSegment struct {
	ID RiskSegID `bson:"_id" json:"id"`

	*Segment `bson:"segment" json:"segment"`

	RiskLevel       float64 `bson:"riskLevel" json:"riskLevel"`
	ConfidenceLevel float64 `bson:"confidenceLevel" json:"confidenceLevel"`
	Report          Report  `bson:"report" json:"report"`
}

RiskSegment is the risk and the confidence level for a given segment

type Screening

type Screening struct {
	ID         ScreeningID `bson:"_id" json:"id"`
	Department string      `bson:"dep" json:"dep"`
	NoticeDate time.Time   `bson:"noticeDate" json:"noticeDate"`

	Count         int `bson:"count" json:"count"`
	PositiveCount int `bson:"positiveCount" json:"positiveCount"`
	PositiveRate  int `bson:"positiveRate" json:"positiveRate"`
}

type ScreeningDAL

type ScreeningDAL interface {
	Get(dep string, date time.Time) (*Screening, error)
	GetRange(dep string, begin, end time.Time) ([]*Screening, error)
	Upsert(...*Screening) error
}

type ScreeningID

type ScreeningID string

type ScreeningService

type ScreeningService interface {
	RefreshScreening() ([]*Screening, error)
}

type SegID

type SegID string

type Segment

type Segment struct {
	ID             SegID          `bson:"_id" json:"-"`
	Origin         *Geo           `bson:"origin" json:"origin"`
	Destination    *Geo           `bson:"destination" json:"destination"`
	Departure      time.Time      `bson:"departure" json:"departure"`
	Arrival        time.Time      `bson:"arrival" json:"arrival"`
	Transportation Transportation `bson:"transportation" json:"transportation"`
	HotelID        *string        `bson:"hotelID" json:"-"`
}

type Statement

type Statement struct {
	Value    string `bson:"value" json:"value"`
	Category string `bson:"category" json:"category"`
}

type Transportation

type Transportation string
const (
	TGV              Transportation = "tgv"
	TER              Transportation = "ter"
	Aircraft         Transportation = "aircraft"
	Car              Transportation = "car"
	CarSolo          Transportation = "car-solo"
	CarDuo           Transportation = "car-duo"
	CarGroup         Transportation = "car-group"
	TaxiSolo         Transportation = "taxi-solo"
	TaxiGroup        Transportation = "taxi-group"
	PublicTransports Transportation = "public-transports"
	Scooter          Transportation = "scooter"
	Bike             Transportation = "bike"
)

func (*Transportation) Duration

func (t *Transportation) Duration(departure, arrival time.Time) TransportationDuration

type TransportationDuration

type TransportationDuration string
const (
	Short  TransportationDuration = "short"
	Normal TransportationDuration = "normal"
	Long   TransportationDuration = "long"
)

Directories

Path Synopsis
cmd
covidtracker command
refresher command
job
cds

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL