diff --git a/doc/data/filter_examples/fritz_filter_clu.json b/doc/data/filter_examples/fritz_filter_clu.json
index 9192a030..b8228898 100644
--- a/doc/data/filter_examples/fritz_filter_clu.json
+++ b/doc/data/filter_examples/fritz_filter_clu.json
@@ -556,104 +556,196 @@
{
"$project": {
"objectId": 1,
- "cross_matches_CLU": 1,
- "annotations.FWHM": "$fwhm",
- "annotations.drb": "$drb",
+ "annotations.FWHM": {
+ "$round": [
+ "$fwhm", 3
+ ]
+ },
+ "annotations.drb": {
+ "$round": [
+ "$drb", 5
+ ]
+ },
"annotations.host g-r": {
- "$subtract": [
- "$sgmag", "$srmag"
+ "$round": [
+ {
+ "$subtract": [
+ "$sgmag", "$srmag"
+ ]
+ }, 3
]
},
"annotations.host r-i": {
- "$subtract": [
- "$srmag", "$simag"
+ "$round": [
+ {
+ "$subtract": [
+ "$srmag", "$simag"
+ ]
+ }, 3
+ ]
+ },
+ "annotations.mag at max": {
+ "$round": [
+ "$m_max", 3
]
},
- "annotations.mag at max": "$m_max",
"annotations.time at max": "$t_max",
- "annotations.min-mag": "$m_min",
+ "annotations.min-mag": {
+ "$round": [
+ "$m_min", 3
+ ]
+ },
"annotations.min-time": "$t_min",
"annotations.time difference": {
- "$subtract": [
- "$t_max", "$t_min"
+ "$round": [
+ {
+ "$subtract": [
+ "$t_max", "$t_min"
+ ]
+ }, 5
]
},
"annotations.mag diff": {
- "$subtract": [
- "$m_min", "$m_max"
+ "$round": [
+ {
+ "$subtract": [
+ "$m_min", "$m_max"
+ ]
+ }, 3
]
},
"annotations.rise rate": {
- "$cond": {
- "if": {
- "$gt": [
- {
- "$subtract": [
- "$t_max", "$t_min"
- ]
- }, 0
- ]
- },
- "then": {
- "$divide": [
- {
- "$subtract": [
- "$m_min", "$m_max"
+ "$round": [
+ {
+ "$cond": {
+ "if": {
+ "$gt": [
+ {
+ "$subtract": [
+ "$t_max", "$t_min"
+ ]
+ }, 0
]
- }, {
- "$subtract": [
- "$t_max", "$t_min"
+ },
+ "then": {
+ "$divide": [
+ {
+ "$subtract": [
+ "$m_min", "$m_max"
+ ]
+ }, {
+ "$subtract": [
+ "$t_max", "$t_min"
+ ]
+ }
]
- }
- ]
- },
- "else": null
- }
+ },
+ "else": null
+ }
+ }, 5
+ ]
},
"annotations.decay rate": {
- "$cond": {
- "if": {
- "$lt": [
- {
- "$subtract": [
- "$t_max", "$t_min"
- ]
- }, 0
- ]
- },
- "then": {
- "$divide": [
- {
- "$subtract": [
- "$m_max", "$m_min"
+ "$round": [
+ {
+ "$cond": {
+ "if": {
+ "$lt": [
+ {
+ "$subtract": [
+ "$t_max", "$t_min"
+ ]
+ }, 0
]
- }, {
- "$subtract": [
- "$t_max", "$t_min"
+ },
+ "then": {
+ "$divide": [
+ {
+ "$subtract": [
+ "$m_max", "$m_min"
+ ]
+ }, {
+ "$subtract": [
+ "$t_max", "$t_min"
+ ]
+ }
]
- }
- ]
- },
- "else": null
- }
+ },
+ "else": null
+ }
+ }, 5
+ ]
+ },
+ "annotations.host ZTF ref PSF r-mag": {
+ "$round": [
+ "$magnr", 3
+ ]
+ },
+ "annotations.PS1 psf r-mag": {
+ "$round": [
+ "$srmag", 3
+ ]
+ },
+ "annotations.rb score": {
+ "$round": [
+ "$rbscore", 5
+ ]
+ },
+ "annotations.sgscore1": {
+ "$round": [
+ "$sgscore", 5
+ ]
+ },
+ "annotations.ZOGI scorr": {
+ "$round": [
+ "$scorr", 3
+ ]
+ },
+ "annotations.distpsnr1": {
+ "$round": [
+ "$distpsnr1", 3
+ ]
+ },
+ "annotations.distpsnr2": {
+ "$round": [
+ "$distpsnr2", 3
+ ]
+ },
+ "annotations.distpsnr3": {
+ "$round": [
+ "$distpsnr3", 3
+ ]
+ },
+ "annotations.magpsf": {
+ "$round": [
+ "$m_now", 3
+ ]
+ },
+ "annotations.elongation": {
+ "$round": [
+ "$elong", 3
+ ]
+ },
+ "annotations.magap_min_magpsf": {
+ "$round": [
+ "$psfminap", 3
+ ]
+ },
+ "annotations.gal_lat": {
+ "$round": [
+ "$gal_lat", 5
+ ]
},
- "annotations.host ZTF ref PSF r-mag": "$magnr",
- "annotations.PS1 psf r-mag": "$srmag",
- "annotations.rb score": "$rbscore",
- "annotations.sgscore1": "$sgscore",
- "annotations.ZOGI scorr": "$scorr",
- "annotations.distpsnr1": "$distpsnr1",
- "annotations.distpsnr2": "$distpsnr2",
- "annotations.distpsnr3": "$distpsnr3",
- "annotations.magpsf": "$m_now",
- "annotations.elongation": "$elong",
- "annotations.magap_min_magpsf": "$psfminap",
- "annotations.gal_lat": "$gal_lat",
"annotations.deltajd": {
- "$subtract": [
- "$jdendhist", "$jdstarthist"
+ "$round": [
+ {
+ "$subtract": [
+ "$jdendhist", "$jdstarthist"
+ ]
+ }, 5
]
- }
+ },
+ "annotations.cross_matches_CLU": "$cross_matches_CLU"
}
}
]
diff --git a/docker-compose.traefik.defaults.yaml b/docker-compose.traefik.defaults.yaml
index 8214109e..817c5dab 100644
--- a/docker-compose.traefik.defaults.yaml
+++ b/docker-compose.traefik.defaults.yaml
@@ -12,6 +12,8 @@ services:
command:
# fixme: comment out if do not want the traefik dashboard on port 8090
- "--api.insecure=true"
+ - "--metrics=true"
+ - "--metrics.prometheus=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--providers.docker.network=proxy"
diff --git a/extensions/skyportal/data/db_fritz.yaml b/extensions/skyportal/data/db_fritz.yaml
index 82538adb..33d5e8f3 100644
--- a/extensions/skyportal/data/db_fritz.yaml
+++ b/extensions/skyportal/data/db_fritz.yaml
@@ -2,9 +2,12 @@ user:
- username: fritz.astro.marshal@gmail.com
roles:
- Super admin
+ =id: fritz
+ oauth_uid: fritz.astro.marshal@gmail.com
- username: kowalski@caltech.edu
roles:
- Group admin
+ =id: kowalski
streams:
- name: ZTF Public
@@ -48,6 +51,20 @@ groups:
=id: superluminous_sne
- name: X-ray Counterparts
=id: xray_counterparts
+ - name: Outbursting Stars
+ =id: outbursting_stars
+
+streams/=ztf_public/users:
+ - user_id: =fritz
+ - user_id: =kowalski
+
+streams/=ztf_partnership/users:
+ - user_id: =fritz
+ - user_id: =kowalski
+
+streams/=ztf_caltech/users:
+ - user_id: =fritz
+ - user_id: =kowalski
groups/=ztf_science_validation/streams:
- stream_id: =ztf_public
@@ -83,6 +100,9 @@ groups/=superluminous_sne/streams:
groups/=xray_counterparts/streams:
- stream_id: =ztf_partnership
+groups/=outbursting_stars/streams:
+ - stream_id: =ztf_partnership
+
filters:
- name: Public Transients
group_id: =ztf_science_validation
@@ -124,6 +144,10 @@ filters:
group_id: =xray_counterparts
stream_id: =ztf_partnership
+ - name: Outbursting Stars
+ group_id: =outbursting_stars
+ stream_id: =ztf_partnership
+
telescope:
file: telescopes_fritz.yaml
@@ -131,16 +155,93 @@ instrument:
file: instruments_fritz.yaml
taxonomy:
- file: taxonomy_sitewide.yaml
+ file: taxonomy_fritz.yaml
allocation:
- pi: none, test allocation only, targets will not be observed
proposal_id: SEDM-001
- start_date: "2020-09-01T00:00:00"
- end_date: "2020-09-14T00:00:00"
+ start_date: "2020-09-15T00:00:00"
+ end_date: "2020-10-15T00:00:00"
hours_allocated: 100
group_id: =public_group_id
instrument_id: =SEDM
+ - pi: none, test allocation only, targets will not be observed
+ proposal_id: SEDM-001
+ start_date: "2020-09-15T00:00:00"
+ end_date: "2020-10-15T00:00:00"
+ hours_allocated: 100
+ group_id: =ztf_science_validation
+ instrument_id: =SEDM
+ - pi: none, test allocation only, targets will not be observed
+ proposal_id: SEDM-001
+ start_date: "2020-09-15T00:00:00"
+ end_date: "2020-10-15T00:00:00"
+ hours_allocated: 100
+ group_id: =rcf
+ instrument_id: =SEDM
+ - pi: none, test allocation only, targets will not be observed
+ proposal_id: SEDM-001
+ start_date: "2020-09-15T00:00:00"
+ end_date: "2020-10-15T00:00:00"
+ hours_allocated: 100
+ group_id: =clu
+ instrument_id: =SEDM
+ - pi: none, test allocation only, targets will not be observed
+ proposal_id: SEDM-001
+ start_date: "2020-09-15T00:00:00"
+ end_date: "2020-10-15T00:00:00"
+ hours_allocated: 100
+ group_id: =em_gw
+ instrument_id: =SEDM
+ - pi: none, test allocation only, targets will not be observed
+ proposal_id: SEDM-001
+ start_date: "2020-09-15T00:00:00"
+ end_date: "2020-10-15T00:00:00"
+ hours_allocated: 100
+ group_id: =short_grb
+ instrument_id: =SEDM
+ - pi: none, test allocation only, targets will not be observed
+ proposal_id: SEDM-001
+ start_date: "2020-09-15T00:00:00"
+ end_date: "2020-10-15T00:00:00"
+ hours_allocated: 100
+ group_id: =infant_sne
+ instrument_id: =SEDM
+ - pi: none, test allocation only, targets will not be observed
+ proposal_id: SEDM-001
+ start_date: "2020-09-15T00:00:00"
+ end_date: "2020-10-15T00:00:00"
+ hours_allocated: 100
+ group_id: =fast_transients
+ instrument_id: =SEDM
+ - pi: none, test allocation only, targets will not be observed
+ proposal_id: SEDM-001
+ start_date: "2020-09-15T00:00:00"
+ end_date: "2020-10-15T00:00:00"
+ hours_allocated: 100
+ group_id: =red_transients
+ instrument_id: =SEDM
+ - pi: none, test allocation only, targets will not be observed
+ proposal_id: SEDM-001
+ start_date: "2020-09-15T00:00:00"
+ end_date: "2020-10-15T00:00:00"
+ hours_allocated: 100
+ group_id: =superluminous_sne
+ instrument_id: =SEDM
+ - pi: none, test allocation only, targets will not be observed
+ proposal_id: SEDM-001
+ start_date: "2020-09-15T00:00:00"
+ end_date: "2020-10-15T00:00:00"
+ hours_allocated: 100
+ group_id: =xray_counterparts
+ instrument_id: =SEDM
+ - pi: none, test allocation only, targets will not be observed
+ proposal_id: SEDM-001
+ start_date: "2020-09-15T00:00:00"
+ end_date: "2020-10-15T00:00:00"
+ hours_allocated: 100
+ group_id: =outbursting_stars
+ instrument_id: =SEDM
observing_run:
- pi: Mansi Kasliwal
diff --git a/extensions/skyportal/data/instruments_fritz.yaml b/extensions/skyportal/data/instruments_fritz.yaml
index b180638b..ef2513eb 100644
--- a/extensions/skyportal/data/instruments_fritz.yaml
+++ b/extensions/skyportal/data/instruments_fritz.yaml
@@ -17,6 +17,7 @@
name: SEDM
telescope_id: =P60
type: imaging spectrograph
+ api_classname: SEDMAPI
- =id: DBSP
band: optical
name: DBSP
diff --git a/extensions/skyportal/data/taxonomy_fritz.yaml b/extensions/skyportal/data/taxonomy_fritz.yaml
new file mode 100644
index 00000000..46ee7729
--- /dev/null
+++ b/extensions/skyportal/data/taxonomy_fritz.yaml
@@ -0,0 +1,806 @@
+- group_ids:
+ - =public_group_id
+ - =ztf_science_validation
+ - =rcf
+ - =clu
+ - =em_gw
+ - =short_grb
+ - =infant_sne
+ - =fast_transients
+ - =red_transients
+ - =superluminous_sne
+ - =xray_counterparts
+ hierarchy:
+ class: Time-domain Source
+ subclasses:
+ - class: Nonstellar
+ subclasses:
+ - class: DM annihilation
+ other names:
+ - dark matter annihilation
+ - class: Solar System Object
+ other names:
+ - SSO
+ - class: Galactic Nuclei
+ subclasses:
+ - class: Tidal Disruption Event
+ other names:
+ - TDE
+ - class: AGN
+ other names:
+ - Active Galactic Nuclei
+ subclasses:
+ - class: Seyfert
+ other names:
+ - Sy
+ - class: QSO
+ other names:
+ - Quasistellar Object
+ - class: Blazar
+ subclasses:
+ - class: OVV
+ other names:
+ - optically violent variable
+ - class: BL Lac
+ - class: gravitational lensing
+ other names:
+ - lensing
+ tags:
+ - time delay
+ tags:
+ - extragalactic
+ - black hole
+ - class: Stellar variable
+ subclasses:
+ - class: Cataclysmic
+ subclasses:
+ - class: compact merger
+ other names:
+ - gravitational wave event
+ subclasses:
+ - class: DNS
+ other names:
+ - double neutron star
+ - NS-NS
+ subclasses:
+ - class: kilonova
+ other names:
+ - KN
+ tags:
+ - neutron star
+ - short GRB
+ - class: NS-BH
+ other names:
+ - NSBH
+ subclasses:
+ - class: kilonova
+ other names:
+ - KN
+ tags:
+ - black hole
+ - neutron star
+ - short GRB
+ - class: GRB
+ other names:
+ - Gamma-ray bursts
+ - GRBs
+ subclasses:
+ - class: short GRB
+ other names:
+ - SHB
+ - sGRB
+ tags:
+ - gravitational waves
+ - compact object
+ - class: long GRB
+ other names:
+ - LSB
+ - lGRB
+ - long-soft GRB
+ - class: Supernova
+ other names:
+ - SN
+ - sn
+ - sne
+ - supernova
+ - supernovae
+ subclasses:
+ - class: Type I
+ other names:
+ - SN Type I
+ subclasses:
+ - class: Ia
+ other names:
+ - Ia-p
+ - SN Ia
+ - SNIa
+ - supernovae Ia
+ - SNe Ia
+ subclasses:
+ - class: Ia-pec
+ other names:
+ - SN Ia-pec
+ - SNIa-pec
+ - Ia-p
+ tags:
+ - peculiar
+ tags:
+ - white dwarf
+ - cosmology
+ - thermonuclear
+ - class: Ib
+ other names:
+ - SN Ib
+ - SNIb
+ - supernovae Ib
+ - SNe Ib
+ subclasses:
+ - class: Ib-p
+ other names:
+ - SN Ib-p
+ tags:
+ - core collapse
+ - helium rich
+ - class: Ic
+ other names:
+ - SN Ic
+ - SNIc
+ - supernovae Ic
+ - SNe Ic
+ subclasses:
+ - class: Ic-BL
+ other names:
+ - SN IcBL
+ - SN Ic-BL
+ tags:
+ - broad lines
+ - high-velocity
+ - massive stars
+ - class: SLSN I
+ other names:
+ - SLSN Type I
+ tags:
+ - bright
+ - super-luminous
+ - class: Ic-p
+ other names:
+ - SN Ic-p
+ tags:
+ - peculiar
+ tags:
+ - core collapse
+ - no helium
+ - class: Ib/c
+ other names:
+ - SN Ib/c
+ - SNIb/c
+ - SN Ibc
+ tags:
+ - core collapse
+ - unclear which subclass
+ tags:
+ - hydrogen poor
+ - class: Type II
+ other names:
+ - SN Type II
+ subclasses:
+ - class: IIn
+ other names:
+ - SN IIn
+ - SNe IIn
+ sublasses:
+ - class: SNLN II
+ other names:
+ - SLSN Type II
+ tags:
+ - bright
+ - super-luminous
+ tags:
+ - narrow line
+ - class: IIP
+ other names:
+ - SNIIP
+ - SN II-P
+ - SN Type IIP
+ tags:
+ - plateau
+ - class: IIL
+ other names:
+ - SNIIP
+ - SN II-L
+ - SN Type IIL
+ tags:
+ - linear
+ - class: IIb
+ other names:
+ - SNIIb
+ - SN II-b
+ - SN Type IIb
+ tags:
+ - helium rich
+ - class: IIpec
+ comments: SN 1987a
+ other names:
+ - SNIIp
+ - SN II-p
+ - SN Type IIp
+ - IIpec
+ - II-p
+ tags:
+ - peculiar
+ tags: hydrogen rich
+ tags:
+ - explosive
+ - transient
+ - class: Novae
+ subclasses:
+ - class: Classical Nova
+ other names: []
+ - class: Nova-like
+ other names: []
+ subclasses:
+ - class: SW Sex
+ other names: []
+ - class: VY Scl
+ other names: []
+ - class: UX UMa
+ other names: []
+ - class: AM CVn
+ other names: []
+ - class: Polars
+ subclasses:
+ - class: AM Her
+ other names: []
+ - class: DQ Her
+ other names: []
+ - class: Recurrent Nova
+ other names: []
+ - class: U Gem
+ subclasses:
+ - class: SS Cyg
+ other names: []
+ - class: Z Cam
+ other names: []
+ - class: SU UMaj
+ other names: []
+ subclasses:
+ - class: ER U Maj
+ other names: []
+ - class: WZ Sge
+ other names: []
+ tags:
+ - binary
+ - class: Eclipsing
+ subclasses:
+ - class: Beta Lyrae
+ other names:
+ - EB
+ - B Lyr
+ tags:
+ - types A/B
+ - ellipsoidal
+ - giant/supergiant
+ - accretion disk
+ - class: X-Ray Burster
+ other names:
+ - XB
+ - XRay Burster
+ tags:
+ - neutron star
+ - main sequence companion
+ - standard candle
+ - class: System with Planet(s)
+ other names:
+ - EP
+ - System with planet
+ - Binary star system w/ planet
+ - Binary star system with planet
+ - Planetary transit
+ tags:
+ - exoplanet
+ - class: RS CVn
+ other names:
+ - RS Canum Venaticorum
+ - RS Can Venat
+ - RS
+ - radio
+ - X-ray
+ - Ca II
+ tags:
+ - active chromosphere
+ - eruptive
+ - class: W Ursae Maj
+ other names:
+ - EW
+ - W Ursae Majoris
+ - W UMa
+ subclasses:
+ - class: EWa
+ other names:
+ - A-type W UMa
+ - W Uma a
+ tags:
+ - types A/F
+ - class: EWw
+ other names:
+ - W-type W UMa
+ - W UMa w
+ tags:
+ - types G/K
+ tags:
+ - contact binary
+ - ellipsoidal
+ - class: Algol
+ other names:
+ - EA
+ - Algol-type
+ - Beta Persei-type
+ - Beta Per
+ tags:
+ - main sequence star
+ - less massive companion
+ - semidetached
+ - class: Symbiotic Var
+ other names:
+ - Symbiotic Variable
+ - ZAND
+ tags:
+ - cataclysmic
+ - class: Rotating
+ subclasses:
+ - class: SX Ari
+ other names:
+ - SXA
+ - SXARI
+ - SX Arietus
+ - SX Ari
+ - helium variable
+ tags:
+ - type BOp-B9p
+ - main sequence
+ - strong He I/Si III
+ - class: Alpha2 CVn
+ other names:
+ - Alpha2 Canum Venaticorum
+ - ACV
+ subclasses:
+ - class: Rapidly Oscillating
+ other names:
+ - ACVO
+ - roAp
+ tags:
+ - class Ap
+ - instability strip
+ tags:
+ - type B8p-A7p
+ - main sequence
+ - chemically peculiar
+ - class: FK Comae Bern
+ other names:
+ - FK Comae Berenices
+ - FKCom
+ - FKCOM
+ tags:
+ - class G/K
+ - binary merger
+ - ellipsoidal
+ - starspots
+ - high-velocity
+ - class: Pulsar
+ other names:
+ - PSR
+ tags:
+ - neutron star
+ - regular period
+ - class: BY Dra
+ other names:
+ - BY
+ - BYDraconis
+ tags:
+ - class G/K/M
+ - dwarf
+ - starspots
+ - quasiperiodic
+ - class: Eruptive
+ subclasses:
+ - class: UV Ceti
+ other names:
+ - UV
+ - Flare star
+ - UV Cet-type
+ tags:
+ - types M/K
+ - dwarf
+ - magnetic reconnection
+ - class: S Doradus
+ other names:
+ - S Dor
+ - SDor
+ - SDOR
+ - Luminous blue variable
+ - LBV
+ tags:
+ - type B
+ - supergiant/hypergiant
+ - S Doradus instability strip
+ - high luminosity
+ - class: Wolf-Rayet
+ other names:
+ - WR
+ tags:
+ - broad lines
+ - class: Gamma Cas
+ other names:
+ - Gamma Cassiopeiae
+ - GCas
+ - GCAS
+ subclasses:
+ - class: Be
+ other names: []
+ - class: Shell
+ other names: []
+ tags:
+ - Be star
+ - accretion disk
+ - class: FU Ori
+ other names:
+ - FU
+ - FUor
+ - FU Ori
+ - FU Orionis
+ tags:
+ - pre-main sequence
+ - accretion disk
+ - T Tauri evolution
+ - possible Orion subtype
+ - class: Orion
+ other names:
+ - IN
+ subclasses:
+ - class: w/Abs
+ other names:
+ - IN(YY)
+ - class: T Tauri
+ other names:
+ - TTS
+ - TT
+ - INT
+ - IT
+ subclasses:
+ - class: TTc
+ other names:
+ - Classical TTS
+ - Classical T Tauri
+ - class: TTw
+ other names:
+ - Weak-line TTS
+ - Weak-line T Tauri
+ tags:
+ - Weak emission lines
+ tags:
+ - types F/G/K/M
+ - pre-main sequence
+ - strong chromospheric lines
+ - Hayashi track
+ tags:
+ - pre-main sequence
+ - diffuse nebulae
+ - class: R Cor Borealis
+ other names:
+ - R Coronae Borealis
+ - RCB
+ - R CrB
+ - R Cor Bor
+ subclasses:
+ - class: DY Per
+ links:
+ - https://en.wikipedia.org/wiki/DY_Persei_variable
+ other names:
+ - DY Persei
+ tags:
+ - AGB
+ - carbon-rich
+ tags:
+ - types F/G
+ - supergiant
+ - class: Herbig AE/BE
+ other names:
+ - HAeBe
+ tags:
+ - types A/B
+ - pre-main sequence
+ - class: FS CMa
+ other names:
+ - FS Canis Majoris
+ tags:
+ - irregular
+ tags:
+ - chromospheric process
+ - corona process
+ - class: Pulsating
+ subclasses:
+ - class: Gamma Doradus
+ other names:
+ - GDOR
+ - GDor
+ tags:
+ - main sequence
+ - class: SX Phe
+ other names:
+ - SX Phoenicis
+ - SXPHE
+ tags:
+ - type A2-F5
+ - subdwarf
+ - instability strip
+ - possible Delta Scuti subtype
+ - class: RR Lyrae
+ other names:
+ - RR Lyr
+ - RR variable
+ - RR
+ - cluster variable
+ subclasses:
+ - class: RRcl
+ other names:
+ - RRCL
+ - class: RRab
+ other names:
+ - RRAB
+ - class: RRc
+ other names:
+ - RRC
+ - class: RRd
+ other names:
+ - RRD
+ - class: RRe
+ other names:
+ - RRE
+ tags:
+ - type A/F
+ - instability strip
+ - standard candle
+ - class: Alpha Cygni
+ other names:
+ - Alpha Cyg
+ - A Cyg
+ - ACYG
+ tags:
+ - types A/B
+ - supergiant
+ - class: Mira
+ other names:
+ - M
+ - Long period variable
+ tags:
+ - red giant
+ - long period
+ - class: Pulsating WD
+ other names:
+ - Pulsating white dwarf
+ subclasses:
+ - class: GW VIr
+ other names:
+ - DOV
+ - Pulsating PG 1159
+ tags:
+ - pre-degenerate
+ - class: ZZ Ceti
+ other names:
+ - DAV
+ - ZZ Cet
+ subclasses:
+ - class: H abs only
+ other names:
+ - DAV
+ - H-WD
+ tags:
+ - type DA
+ - class: He abs only
+ other names:
+ - DBV
+ - DB white dwarf
+ - V777 Her
+ - He-WD
+ tags:
+ - type DB
+ - class: Showing HeII
+ other names: []
+ tags:
+ - ZZ
+ tags:
+ - white dwarf
+ - class: Sun analogue
+ other names:
+ - Sun analog
+ - Solar analogue
+ - Solar analog
+ - Solar-like
+ tags:
+ - main sequence
+ - class: Delta Scuti
+ other names:
+ - Delta Sct
+ - DSct
+ - dwarf cepheid
+ - DST
+ - DSCT
+ subclasses:
+ - class: Low-Amp
+ other names:
+ - LADS
+ - Low-amplitude delta Scuti
+ - class: High-Amp
+ other names:
+ - giant/main sequence
+ - HADS
+ - High-amplitude delta Scuti
+ - Al Velorum
+ - class: PMS Delta Scuti
+ other names:
+ - Pre-main sequence Delta Scuti
+ tags:
+ - pre-main sequence
+ tags:
+ - instability strip
+ - standard candle
+ - class: PV Telescopii
+ other names:
+ - PVTEL
+ - PVTel
+ - PV Tel
+ tags:
+ - type Bp
+ - chemically peculiar
+ - supergiant
+ - class: Beta Cephei
+ other names:
+ - BCep
+ - B Cep
+ - Beta Canis Majoris
+ - "\u03B2 Cephei"
+ - BCEP
+ tags:
+ - type B
+ - main sequence
+ - Z bump
+ - class: Semiregular
+ other names:
+ - SR
+ - SRPV
+ - semi-regular
+ subclasses:
+ - class: SRa/Z-Aquarii
+ other names:
+ - SRA
+ - class: SRb
+ other names:
+ - SRB
+ - class: SRc
+ other names:
+ - SRC
+ - class: SRd
+ other names:
+ - SRD
+ tags:
+ - giant/supergiant
+ - long period
+ - class: RV Tau
+ other names:
+ - RV Tauri
+ - RV
+ subclasses:
+ - class: Const Mean Mag
+ other names:
+ - Constant mean magnitude
+ - class: Var Mean Mag
+ other names:
+ - Variable mean magnitude
+ tags:
+ - post-AGB
+ - possible Population II Cepheid
+ - instability strip
+ - long period
+ - class: Population II Cepheid
+ other names:
+ - Population II Ceph
+ - Type II Ceph
+ - Type II Cepheid
+ - Type-II Ceph
+ - Type-II Cepheid
+ - CW
+ subclasses:
+ - class: BL Her
+ other names:
+ - BL Herculis
+ - CWB
+ tags:
+ - pre-AGB
+ - class: W Vir
+ other names:
+ - W Virginis
+ - CWA
+ tags:
+ - types F6-K2
+ - blue loop
+ tags: []
+ - class: Cepheid
+ other names:
+ - Cep
+ - CEP
+ subclasses:
+ - class: Anomolous
+ other names:
+ - Anomolous Cepheid
+ - BLBOO
+ - class: Mult-mode
+ other names:
+ - Double-mode Cepheid
+ - Multi-mode Cepheid
+ - CEP(B)
+ - class: Classical
+ other names:
+ - Population I Cepheid
+ - Type I Cepheid
+ - DCEP
+ - Delta Cepheid
+ - Classical Cepheid
+ subclasses:
+ - class: Symmetrical
+ other names:
+ - DCEPS
+ - Delta Cep-type Symmetrical
+ tags: []
+ tags:
+ - giant/supergiant
+ - instability strip
+ - standard candle
+ - class: SPB
+ other names:
+ - 53 Persei
+ - Slowly Pulsating B-type
+ - Slowly Pulsating B
+ tags:
+ - type B2-B9
+ - main sequence
+ - class: BLAP
+ other names:
+ - Blue Large-Amplitude Pulsator
+ tags: []
+ tags:
+ - expanding/contracting outer layers
+ - class: microlensing
+ subclasses:
+ - class: binary lens
+ subclass:
+ - class: lens with planet
+ - class: triple-system lens
+ - class: binary source
+ tags:
+ - stellar lensing
+ - gravitational lensing
+ name: Sitewide Taxonomy
+ provenance: https://github.com/profjsb/timedomain-taxonomy
+ version: 0.1.1
+- group_ids:
+ - =public_group_id
+ - =ztf_science_validation
+ - =rcf
+ - =clu
+ - =em_gw
+ - =short_grb
+ - =infant_sne
+ - =fast_transients
+ - =red_transients
+ - =superluminous_sne
+ - =xray_counterparts
+ name: Basic Taxonomy
+ hierarchy:
+ class: Time-domain Source
+ subclasses:
+ - class: roid
+ - class: varstar
+ - class: transient
+ - class: AGN
+ - class: bogus
+ version: 0.1.0
diff --git a/extensions/skyportal/docker-compose.skyportal.yaml b/extensions/skyportal/docker-compose.skyportal.yaml
index 2a536cec..4d0fc815 100644
--- a/extensions/skyportal/docker-compose.skyportal.yaml
+++ b/extensions/skyportal/docker-compose.skyportal.yaml
@@ -10,19 +10,11 @@ services:
image: skyportal/web
expose:
- "5000"
-# ports:
-# - "9000:5000"
volumes:
# fritz takes care of making a docker-appropriate config.yaml with Fritz-specific additions
- ${PWD}/skyportal/config.yaml:/skyportal/config.yaml
- ${PWD}/skyportal/data/db_fritz.yaml:/skyportal/data/db_seed.yaml
- thumbnails:/skyportal/static/thumbnails
- command: >
- bash -c "source /skyportal_env/bin/activate
- && cat js-requirements.fritz.txt | xargs npm install
- && pip install -r requirements.fritz.txt
- && (make log &) && make run"
- # && (make log &) && make run_production"
labels:
# # Explicitly tell Traefik to expose this container
- "traefik.enable=true"
diff --git a/extensions/skyportal/js-requirements.fritz.txt b/extensions/skyportal/js-requirements.fritz.txt
deleted file mode 100644
index 6533df4e..00000000
--- a/extensions/skyportal/js-requirements.fritz.txt
+++ /dev/null
@@ -1 +0,0 @@
-react-diff-viewer
diff --git a/extensions/skyportal/package.fritz.json b/extensions/skyportal/package.fritz.json
new file mode 100644
index 00000000..11630a7a
--- /dev/null
+++ b/extensions/skyportal/package.fritz.json
@@ -0,0 +1,6 @@
+{
+ "dependencies": {
+ "react-diff-viewer": "^3.1.1",
+ "react-json-view": "^1.19.1"
+ }
+}
diff --git a/extensions/skyportal/skyportal/handlers/api/alert.py b/extensions/skyportal/skyportal/handlers/api/alert.py
index 642f712d..ea5ad538 100644
--- a/extensions/skyportal/skyportal/handlers/api/alert.py
+++ b/extensions/skyportal/skyportal/handlers/api/alert.py
@@ -12,12 +12,31 @@
from baselayer.app.access import auth_or_token
from ..base import BaseHandler
+from ...models import (
+ DBSession,
+ Stream,
+ StreamUser,
+)
s = requests.Session()
class ZTFAlertHandler(BaseHandler):
+ def get_user_streams(self):
+
+ streams = (
+ DBSession()
+ .query(Stream)
+ .join(StreamUser)
+ .filter(StreamUser.user_id == self.current_user.id)
+ .all()
+ )
+ if streams is None:
+ streams = []
+
+ return streams
+
@auth_or_token
def get(self, objectId: str = None):
"""
@@ -56,6 +75,17 @@ def get(self, objectId: str = None):
application/json:
schema: Error
"""
+ streams = self.get_user_streams()
+
+ # allow access to public data only by default
+ selector = {1}
+
+ for stream in streams:
+ if "ztf" in stream.name.lower():
+ selector.update(set(stream.altdata.get("selector", [])))
+
+ selector = list(selector)
+
try:
query = {
"query_type": "aggregate",
@@ -65,7 +95,7 @@ def get(self, objectId: str = None):
{
"$match": {
"objectId": objectId,
- "candidate.programid": {"$in": [1, 2, 3]} # fixme: ACLs plug in here!
+ "candidate.programid": {"$in": selector}
}
},
{
@@ -112,7 +142,7 @@ def get(self, objectId: str = None):
return self.error(f'failure: {_err}')
-class ZTFAlertAuxHandler(BaseHandler):
+class ZTFAlertAuxHandler(ZTFAlertHandler):
@auth_or_token
def get(self, objectId: str = None):
"""
@@ -146,6 +176,16 @@ def get(self, objectId: str = None):
application/json:
schema: Error
"""
+ streams = self.get_user_streams()
+
+ # allow access to public data only by default
+ selector = {1}
+
+ for stream in streams:
+ if "ztf" in stream.name.lower():
+ selector.update(set(stream.altdata.get("selector", [])))
+
+ selector = list(selector)
try:
query = {
@@ -169,9 +209,7 @@ def get(self, objectId: str = None):
"cond": {
"$in": [
"$$item.programid",
- [
- 1, 2, 3 # fixme: ACLs plug in here!
- ]
+ selector
]
}
}
@@ -221,7 +259,8 @@ def get(self, objectId: str = None):
"pipeline": [
{
"$match": {
- "objectId": objectId
+ "objectId": objectId,
+ "candidate.programid": {"$in": selector}
}
},
{
@@ -264,7 +303,9 @@ def get(self, objectId: str = None):
return self.error(f"Failed to fetch data for {objectId} from Kowalski")
if len(latest_alert_data) > 0:
- alert_data['prv_candidates'].append(latest_alert_data['candidate'])
+ candids = {a.get('candid', None) for a in alert_data['prv_candidates']}
+ if latest_alert_data['candidate']["candid"] not in candids:
+ alert_data['prv_candidates'].append(latest_alert_data['candidate'])
return self.success(data=alert_data)
@@ -273,7 +314,7 @@ def get(self, objectId: str = None):
return self.error(f'failure: {_err}')
-class ZTFAlertCutoutHandler(BaseHandler):
+class ZTFAlertCutoutHandler(ZTFAlertHandler):
@auth_or_token
def get(self, objectId: str = None):
"""
@@ -323,6 +364,17 @@ def get(self, objectId: str = None):
application/json:
schema: Error
"""
+ streams = self.get_user_streams()
+
+ # allow access to public data only by default
+ selector = {1}
+
+ for stream in streams:
+ if "ztf" in stream.name.lower():
+ selector.update(set(stream.altdata.get("selector", [])))
+
+ selector = list(selector)
+
try:
candid = int(self.get_argument('candid'))
cutout = self.get_argument('cutout').capitalize()
@@ -344,7 +396,7 @@ def get(self, objectId: str = None):
"filter": {
"candid": candid,
"candidate.programid": {
- "$in": [1, 2, 3] # fixme: ACLs
+ "$in": selector
}
},
"projection": {
diff --git a/extensions/skyportal/static/js/components/Alerts.jsx b/extensions/skyportal/static/js/components/Alerts.jsx
index 4c61ccb6..f9757e7a 100644
--- a/extensions/skyportal/static/js/components/Alerts.jsx
+++ b/extensions/skyportal/static/js/components/Alerts.jsx
@@ -1,6 +1,11 @@
-import React, { useState } from "react";
+import React from "react";
import { useHistory } from "react-router-dom";
+import Typography from "@material-ui/core/Typography";
+import Card from "@material-ui/core/Card";
+import CardActions from "@material-ui/core/CardActions";
+import CardContent from "@material-ui/core/CardContent";
+
import TextField from "@material-ui/core/TextField";
import InputLabel from "@material-ui/core/InputLabel";
import MenuItem from "@material-ui/core/MenuItem";
@@ -12,18 +17,15 @@ import Grid from "@material-ui/core/Grid";
import Button from "@material-ui/core/Button";
import { makeStyles } from "@material-ui/core/styles";
+import { useForm, Controller } from "react-hook-form";
const useStyles = makeStyles((theme) => ({
root: {
width: "100%",
"& > *": {
margin: theme.spacing(1),
- width: "25ch",
},
},
- container: {
- maxHeight: 440,
- },
whitish: {
color: "#f0f0f0",
},
@@ -39,7 +41,6 @@ const useStyles = makeStyles((theme) => ({
width: 1,
},
search_button: {
- margin: theme.spacing(1),
color: "#f0f0f0 !important",
},
margin_bottom: {
@@ -59,84 +60,81 @@ const useStyles = makeStyles((theme) => ({
color: theme.palette.text.secondary,
},
formControl: {
- margin: theme.spacing(1),
- minWidth: 120,
+ width: "100%",
},
selectEmpty: {
- marginTop: theme.spacing(2),
+ width: "100%",
+ },
+ header: {
+ paddingBottom: "0.625rem",
},
}));
const Alerts = () => {
const classes = useStyles();
- const [stream, setStream] = useState("ztf");
- const [objectId, setObjectId] = useState("");
const history = useHistory();
- const handleStreamChange = (event) => {
- setStream(event.target.value);
- };
-
- const handleObjectIdChange = (event) => {
- setObjectId(event.target.value);
- };
+ const { register, handleSubmit, control } = useForm();
- const submitForm = () => {
- if (objectId.length > 0) {
- const path = `/alerts/${stream}/${objectId}`;
- history.push(path);
- }
+ const submitForm = (data) => {
+ const path = `/alerts/${data.instrument}/${data.object_id}`;
+ history.push(path);
};
return (
-
Search objects from alert streams
+
+ Search objects from alert streams
+
-
-
-
- Alert stream
-
-
- ZTF
- {/* ZUDS */}
-
- Required
-
-
+
+
+
+
-
-
- Search
-
);
};
diff --git a/extensions/skyportal/static/js/components/Group.jsx b/extensions/skyportal/static/js/components/Group.jsx
deleted file mode 100644
index ea441dd6..00000000
--- a/extensions/skyportal/static/js/components/Group.jsx
+++ /dev/null
@@ -1,598 +0,0 @@
-import React, { useEffect, useState } from "react";
-import { useHistory, useParams } from "react-router-dom";
-import PropTypes from "prop-types";
-
-import { useDispatch, useSelector } from "react-redux";
-import { makeStyles, useTheme } from "@material-ui/core/styles";
-import Button from "@material-ui/core/Button";
-import DeleteIcon from "@material-ui/icons/Delete";
-import List from "@material-ui/core/List";
-import ListItem from "@material-ui/core/ListItem";
-import ListItemSecondaryAction from "@material-ui/core/ListItemSecondaryAction";
-import ListItemText from "@material-ui/core/ListItemText";
-import IconButton from "@material-ui/core/IconButton";
-import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
-
-import Accordion from "@material-ui/core/Accordion";
-import AccordionSummary from "@material-ui/core/AccordionSummary";
-import AccordionDetails from "@material-ui/core/AccordionDetails";
-import Typography from "@material-ui/core/Typography";
-
-import Dialog from "@material-ui/core/Dialog";
-import DialogActions from "@material-ui/core/DialogActions";
-import DialogContent from "@material-ui/core/DialogContent";
-import DialogContentText from "@material-ui/core/DialogContentText";
-import DialogTitle from "@material-ui/core/DialogTitle";
-import useMediaQuery from "@material-ui/core/useMediaQuery";
-import TextField from "@material-ui/core/TextField";
-import OpenInNewIcon from "@material-ui/icons/OpenInNew";
-
-import InputLabel from "@material-ui/core/InputLabel";
-import MenuItem from "@material-ui/core/MenuItem";
-import FormHelperText from "@material-ui/core/FormHelperText";
-import FormControl from "@material-ui/core/FormControl";
-import Select from "@material-ui/core/Select";
-import Divider from "@material-ui/core/Divider";
-import Chip from "@material-ui/core/Chip";
-import CircularProgress from "@material-ui/core/CircularProgress";
-
-import { useForm, Controller } from "react-hook-form";
-import { showNotification } from "baselayer/components/Notifications";
-
-import * as groupActions from "../ducks/group";
-import * as groupsActions from "../ducks/groups";
-import * as streamsActions from "../ducks/streams";
-import * as filterActions from "../ducks/filter";
-import NewGroupUserForm from "./NewGroupUserForm";
-
-const useStyles = makeStyles((theme) => ({
- padding_bottom: {
- paddingBottom: "2em",
- },
- paper: {
- width: "100%",
- padding: theme.spacing(1),
- textAlign: "left",
- color: theme.palette.text.primary,
- },
- nested: {
- paddingLeft: theme.spacing(2),
- },
- heading: {
- fontSize: "1.0625rem",
- fontWeight: 500,
- },
- accordion_details: {
- flexDirection: "column",
- },
- button_add: {
- maxWidth: "8.75rem",
- },
- selectEmpty: {
- width: "100%",
- marginTop: theme.spacing(2),
- },
-}));
-
-const Group = () => {
- const classes = useStyles();
- const dispatch = useDispatch();
- const theme = useTheme();
- const history = useHistory();
-
- const { register, handleSubmit, control } = useForm();
-
- const [groupLoadError, setGroupLoadError] = useState("");
-
- const [panelMembersExpanded, setPanelMembersExpanded] = React.useState(
- "panel-members"
- );
- const [panelStreamsExpanded, setPanelStreamsExpanded] = React.useState(
- "panel-streams"
- );
- const [dialogOpen, setDialogOpen] = React.useState(false);
- const fullScreen = !useMediaQuery(theme.breakpoints.up("md"));
-
- const [confirmDeleteOpen, setConfirmDeleteOpen] = useState(false);
-
- const [addStreamOpen, setAddStreamOpen] = useState(false);
-
- const handleDialogClose = () => {
- setDialogOpen(false);
- };
-
- const handleClickDialogOpen = () => {
- setDialogOpen(true);
- };
-
- const handleConfirmDeleteDialogClose = () => {
- setConfirmDeleteOpen(false);
- };
-
- const handleAddStreamOpen = () => {
- setAddStreamOpen(true);
- };
-
- const handleAddStreamClose = () => {
- setAddStreamOpen(false);
- };
-
- const handlePanelMembersChange = (panel) => (event, isExpanded) => {
- setPanelMembersExpanded(isExpanded ? panel : false);
- };
- const handlePanelStreamsChange = (panel) => (event, isExpanded) => {
- setPanelStreamsExpanded(isExpanded ? panel : false);
- };
-
- const { id } = useParams();
- const loadedId = useSelector((state) => state.group.id);
-
- useEffect(() => {
- const fetchGroup = async () => {
- const data = await dispatch(groupActions.fetchGroup(id));
- if (data.status === "error") {
- setGroupLoadError(data.message);
- }
- };
- fetchGroup();
- }, [id, loadedId, dispatch]);
-
- const group = useSelector((state) => state.group);
- const currentUser = useSelector((state) => state.profile);
-
- // fetch streams:
- const streams = useSelector((state) => state.streams);
-
- useEffect(() => {
- const fetchStreams = async () => {
- const data = await dispatch(streamsActions.fetchStreams());
- if (data.status === "error") {
- setGroupLoadError(data.message);
- }
- };
- fetchStreams();
- }, [currentUser, dispatch]);
-
- // forms
- // add stream to group
- const onSubmitAddStream = async (data) => {
- const result = await dispatch(
- streamsActions.addGroupStream({
- group_id: group.id,
- stream_id: data.stream_id,
- })
- );
- if (result.status === "success") {
- dispatch(showNotification("Added stream to group"));
- }
- setAddStreamOpen(false);
- };
- // add filter to group
- const onSubmitAddFilter = async (data) => {
- const result = await dispatch(
- filterActions.addGroupFilter({
- name: data.filter_name,
- group_id: group.id,
- stream_id: data.filter_stream_id,
- })
- );
- if (result.status === "success") {
- dispatch(showNotification("Added filter to group"));
- }
- handleDialogClose();
- dispatch(groupActions.fetchGroup(loadedId));
- };
-
- if (groupLoadError) {
- return {groupLoadError}
;
- }
-
- // renders
- if (!group) {
- return (
-
-
-
- );
- }
-
- // currentUser may not have the "Group admin" role, but can still be the group admin?
- const currentGroupUser = group?.users?.filter(
- (group_user) => group_user.username === currentUser.username
- )[0];
-
- const isAdmin = (aUser, aGroup) =>
- aUser &&
- aGroup.group_users &&
- aGroup.group_users.filter(
- (group_user) => group_user.user_id === aUser.id
- )[0].admin;
-
- let numAdmins = 0;
- group?.group_users?.forEach((groupUser) => {
- if (groupUser?.admin) {
- numAdmins += 1;
- }
- });
-
- const groupStreamIds = group?.streams?.map((stream) => stream.id);
-
- const isStreamIdInStreams = (sid) =>
- streams?.map((stream) => stream.id).includes(sid);
-
- return (
-
-
- Group: {group.name}
-
-
- }
- aria-controls="panel-members-content"
- id="panel-members-header"
- style={{ borderBottom: "1px solid rgba(0, 0, 0, .125)" }}
- >
- Members
-
-
-
- {group?.users?.map((user) => (
-
-
- {isAdmin(user, group) && (
-
-
-
-
- )}
- {(currentUser.roles.includes("Super admin") ||
- (currentUser.roles.includes("Group admin") &&
- isAdmin(currentGroupUser, group))) &&
- isAdmin(user, group) &&
- numAdmins > 1 && (
-
-
- dispatch(
- groupsActions.deleteGroupUser({
- username: user.username,
- group_id: group.id,
- })
- )
- }
- >
-
-
-
- )}
- {(currentUser.roles.includes("Super admin") ||
- (currentUser.roles.includes("Group admin") &&
- isAdmin(currentGroupUser, group))) &&
- !isAdmin(user, group) && (
-
-
- dispatch(
- groupsActions.deleteGroupUser({
- username: user.username,
- group_id: group.id,
- })
- )
- }
- >
-
-
-
- )}
-
- ))}
-
-
-
- {/*eslint-disable */}
- {(currentUser.roles.includes("Super admin") ||
- (currentUser.roles.includes("Group admin") &&
- isAdmin(currentGroupUser, group))) && (
-
- )}
- {/* eslint-enable */}
-
-
-
- {streams?.length > 0 && (
-
- }
- aria-controls="panel-streams-content"
- id="panel-streams-header"
- style={{ borderBottom: "1px solid rgba(0, 0, 0, .125)" }}
- >
-
- Alert streams and filters
-
-
-
-
- {group.streams?.map((stream) => (
-
-
-
-
-
- {group.filters?.map((filter) =>
- filter.stream_id === stream.id ? (
-
-
- {/*eslint-disable */}
- {(currentUser.roles.includes("Super admin") ||
- (currentUser.roles.includes("Group admin") &&
- isAdmin(currentGroupUser, group))) && (
-
- {
- const result = await dispatch(
- filterActions.deleteGroupFilter({
- filter_id: filter.id,
- })
- );
- if (result.status === "success") {
- dispatch(
- showNotification(
- "Deleted filter from group"
- )
- );
- }
- dispatch(groupActions.fetchGroup(loadedId));
- }}
- >
-
-
-
- )}
- {/* eslint-enable */}
-
- ) : (
- ""
- )
- )}
-
-
- ))}
-
-
-
- {/* only Super admins can add streams to groups */}
- {currentUser.roles.includes("Super admin") &&
- streams?.length > 0 &&
- group?.streams?.length < streams?.length && (
-
- Add stream
-
- )}
-
- {(currentUser.roles.includes("Super admin") ||
- (currentUser.roles.includes("Group admin") &&
- isAdmin(currentGroupUser, group))) &&
- group?.streams?.length > 0 && (
-
- Add filter
-
- )}
-
-
-
- )}
-
- {/*eslint-disable */}
- {(currentUser.roles.includes("Super admin") ||
- (currentUser.roles.includes("Group admin") &&
- isAdmin(currentGroupUser, group))) && (
-
setConfirmDeleteOpen(true)}
- >
- Delete Group
-
- )}
- {/* eslint-enable */}
-
-
-
- Add alert stream to group
-
-
-
-
- Alert stream
-
-
- {streams?.map(
- (stream) =>
- // display only streams that are not yet added
- !groupStreamIds?.includes(stream.id) && (
- {stream.name}
- )
- )}
-
- Required
-
-
-
-
- Add
-
-
- Dismiss
-
-
-
-
-
-
-
- Create a new alert stream filter
-
-
-
- Please refer to the
-
- docs
-
- for an extensive guide on Alert filters in Fritz.
-
-
-
-
- Alert stream
-
-
- {group.streams?.map((stream) => (
-
- {stream.name}
-
- ))}
-
- Required
-
-
-
-
- Add
-
-
- Dismiss
-
-
-
-
-
- Delete Group?
-
-
- Are you sure you want to delete this Group?
-
- Warning! This will delete the group and all of its filters. All
- source data will be transferred to the Site-wide group.
-
-
-
-
- setConfirmDeleteOpen(false)}>
- Dismiss
-
- {
- dispatch(groupsActions.deleteGroup(group.id));
- setConfirmDeleteOpen(false);
- history.push("/groups");
- }}
- >
- Confirm
-
-
-
-
- );
-};
-
-Group.propTypes = {
- route: PropTypes.shape({
- id: PropTypes.string,
- }).isRequired,
-};
-
-export default Group;
diff --git a/extensions/skyportal/static/js/components/VegaPlotZTFAlert.jsx b/extensions/skyportal/static/js/components/VegaPlotZTFAlert.jsx
index 19fd0b8f..b8bc8fc6 100644
--- a/extensions/skyportal/static/js/components/VegaPlotZTFAlert.jsx
+++ b/extensions/skyportal/static/js/components/VegaPlotZTFAlert.jsx
@@ -6,7 +6,6 @@ import embed from 'vega-embed';
const spec = (url, jd) => ({
$schema: "https://vega.github.io/schema/vega-lite/v4.json",
width: 500,
- // width: 400,
// width: "container",
height: 250,
data: {
@@ -16,6 +15,11 @@ const spec = (url, jd) => ({
property: "data.prv_candidates" // where in the JSON does the data live
}
},
+ autosize: {
+ type: "fit",
+ resize: true,
+ // contains: "padding"
+ },
background: "transparent",
layer: [
{
diff --git a/extensions/skyportal/static/js/components/ZTFAlert.jsx b/extensions/skyportal/static/js/components/ZTFAlert.jsx
index 8a7d4739..13248c22 100644
--- a/extensions/skyportal/static/js/components/ZTFAlert.jsx
+++ b/extensions/skyportal/static/js/components/ZTFAlert.jsx
@@ -4,7 +4,7 @@ import { useDispatch, useSelector } from "react-redux";
import Button from "@material-ui/core/Button";
import SaveIcon from "@material-ui/icons/Save";
import PropTypes from "prop-types";
-import { withStyles, makeStyles } from "@material-ui/core/styles";
+import { withStyles, makeStyles, useTheme } from "@material-ui/core/styles";
import Table from "@material-ui/core/Table";
import TableBody from "@material-ui/core/TableBody";
import TableCell from "@material-ui/core/TableCell";
@@ -15,23 +15,23 @@ import TableRow from "@material-ui/core/TableRow";
import TableSortLabel from "@material-ui/core/TableSortLabel";
import Paper from "@material-ui/core/Paper";
import Grid from "@material-ui/core/Grid";
+import Accordion from "@material-ui/core/Accordion";
+import AccordionSummary from "@material-ui/core/AccordionSummary";
+import AccordionDetails from "@material-ui/core/AccordionDetails";
+import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
+import Typography from "@material-ui/core/Typography";
+import CircularProgress from "@material-ui/core/CircularProgress";
-import Responsive from "./Responsive";
-import FoldBox from "./FoldBox";
+import ThumbnailList from "./ThumbnailList";
+import ReactJson from "react-json-view";
import * as Actions from "../ducks/alert";
const VegaPlot = React.lazy(() => import("./VegaPlotZTFAlert"));
const StyledTableCell = withStyles(() => ({
- head: {
- // backgroundColor: theme.palette.common.black,
- // backgroundColor: "#111",
- // color: theme.palette.common.white,
- // color: "#f0f0f0",
- },
body: {
- fontSize: 14,
+ fontSize: "0.875rem",
},
}))(TableCell);
@@ -72,9 +72,14 @@ const useStyles = makeStyles((theme) => ({
textAlign: "center",
color: theme.palette.text.secondary,
},
- // table: {
- // minWidth: 650,
- // },
+ heading: {
+ fontSize: "1.0625rem",
+ fontWeight: 500,
+ },
+ header: {
+ paddingBottom: "0.625rem",
+ color: theme.palette.text.primary,
+ },
}));
function createRows(
@@ -109,14 +114,12 @@ const columns = [
label: "candid",
numeric: false,
disablePadding: false,
- // minWidth: 170
},
{
id: "jd",
numeric: true,
disablePadding: false,
label: "JD",
- // minWidth: 170,
align: "left",
format: (value) => value.toFixed(5),
},
@@ -132,7 +135,6 @@ const columns = [
numeric: true,
disablePadding: false,
label: "mag",
- // minWidth: 170,
align: "left",
format: (value) => value.toFixed(3),
},
@@ -141,7 +143,6 @@ const columns = [
numeric: true,
disablePadding: false,
label: "e_mag",
- // minWidth: 170,
align: "left",
format: (value) => value.toFixed(3),
},
@@ -150,7 +151,6 @@ const columns = [
numeric: true,
disablePadding: false,
label: "rb",
- // minWidth: 170,
align: "left",
format: (value) => value.toFixed(5),
},
@@ -159,7 +159,6 @@ const columns = [
numeric: true,
disablePadding: false,
label: "drb",
- // minWidth: 170,
align: "left",
format: (value) => value.toFixed(5),
},
@@ -168,7 +167,6 @@ const columns = [
numeric: false,
disablePadding: false,
label: "isdiffpos",
- // minWidth: 170,
align: "left",
},
{
@@ -176,7 +174,6 @@ const columns = [
numeric: true,
disablePadding: false,
label: "programid",
- // minWidth: 170,
align: "left",
},
{
@@ -185,8 +182,6 @@ const columns = [
disablePadding: false,
label: "actions",
align: "right",
- // render: ({ row }) => lolol,
- // render: ({ row }) => ( {row.label})
},
];
@@ -268,6 +263,27 @@ const ZTFAlert = ({ route }) => {
const objectId = route.id;
const dispatch = useDispatch();
+ const theme = useTheme();
+ const darkTheme = theme.palette.type === "dark";
+
+ const [
+ panelPhotometryThumbnailsExpanded,
+ setPanelPhotometryThumbnailsExpanded,
+ ] = useState(true);
+
+ const handlePanelPhotometryThumbnailsChange = (panel) => (
+ event,
+ isExpanded
+ ) => {
+ setPanelPhotometryThumbnailsExpanded(isExpanded ? panel : false);
+ };
+
+ const [panelXMatchExpanded, setPanelXMatchExpanded] = useState(true);
+
+ const handlePanelXMatchChange = (panel) => (event, isExpanded) => {
+ setPanelXMatchExpanded(isExpanded ? panel : false);
+ };
+
const [candid, setCandid] = useState(0);
const [jd, setJd] = useState(0);
@@ -359,105 +375,103 @@ const ZTFAlert = ({ route }) => {
setPage(0);
};
+ const thumbnails = [
+ {
+ type: "new",
+ id: 0,
+ public_url: `/api/alerts/ztf/${objectId}/cutout?candid=${candid}&cutout=science&file_format=png`,
+ },
+ {
+ type: "ref",
+ id: 1,
+ public_url: `/api/alerts/ztf/${objectId}/cutout?candid=${candid}&cutout=template&file_format=png`,
+ },
+ {
+ type: "sub",
+ id: 2,
+ public_url: `/api/alerts/ztf/${objectId}/cutout?candid=${candid}&cutout=difference&file_format=png`,
+ },
+ ];
+
if (alert_data === null) {
- return Loading...
;
- } if (isString(alert_data) || isString(alert_aux_data)) {
+ return
;
+ }
+ if (isString(alert_data) || isString(alert_aux_data)) {
return Failed to fetch alert data, please try again later.
;
- } if (alert_data.length === 0) {
+ }
+ if (alert_data.length === 0) {
return (
-
{objectId} not found
+
+ {objectId} not found
+
);
- } if (alert_data.length > 0) {
+ }
+ if (alert_data.length > 0) {
return (
-
-
- {objectId}
- }
- // todo: save as a source to one of my programs button
- // onClick={() => dispatch(Actions.saveSource(group_id, objectId, candid))}
- >
- Save as a Source
-
-
-
-
-
+ {objectId}
+ }
+ // todo: save as a source to one of my programs button
+ // onClick={() => dispatch(Actions.saveSource(group_id, objectId, candid))}
+ // fixme: once that is implemented
+ style={{ display: "none" }}
+ >
+ Save as a Source
+
+
+
+
+ }
+ aria-controls="panel-content"
+ id="panel-header"
>
+
+ Photometry and cutouts
+
+
+
-
+
Loading plot... }>
- {/*
*/}
- {/*
*/}
-
- 0
- ? `/api/alerts/ztf/${objectId}/cutout?candid=${candid}&cutout=science&file_format=png`
- : null
- }
+ {candid > 0 && (
+
-
- Science
-
-
- 0
- ? `/api/alerts/ztf/${objectId}/cutout?candid=${candid}&cutout=template&file_format=png`
- : null
- }
- />
-
- Reference
-
-
- 0
- ? `/api/alerts/ztf/${objectId}/cutout?candid=${candid}&cutout=difference&file_format=png`
- : null
- }
- />
-
- Difference
-
-
- Cross-matches:
-
- {/* todo: plot interleaved on PS1 cutout? */}
- {JSON.stringify(cross_matches, null, 2)}
-
+ )}
-
-
+
+
@@ -506,11 +520,26 @@ const ZTFAlert = ({ route }) => {
onChangeRowsPerPage={handleChangeRowsPerPage}
/>
+
+
+ }
+ aria-controls="panel-content"
+ id="panel-header"
+ >
+ Cross-matches
+
+
+
+
+
);
}
- return Error rendering page...
;
-
+ return Error rendering page...
;
};
ZTFAlert.propTypes = {
diff --git a/fritz b/fritz
index 9cb672c4..15cc42f3 100755
--- a/fritz
+++ b/fritz
@@ -2,6 +2,7 @@
import argparse
import datetime
from distutils.dir_util import copy_tree
+import json
import os
from pathlib import Path
import subprocess
@@ -101,23 +102,24 @@ def check_config(cfg='fritz.defaults.yaml', yes=False):
yaml.dump(config_skyportal, cyaml)
-def run(args):
+def build(args):
"""
- Launch Fritz
+ Build Fritz
"""
env = os.environ.copy()
env.update({"FLAGS": "--config=../fritz.yaml"})
- # initialize/update fritz's submodules kowalski and skyportal
- if args.init:
- # pull skyportal and kowalski
- p = subprocess.run(['git', 'submodule', 'update', '--init', '--recursive'])
+ if not args.dev:
+ if args.init:
+ # initialize/update fritz's submodules kowalski and skyportal
+ # pull skyportal and kowalski
+ p = subprocess.run(['git', 'submodule', 'update', '--init', '--recursive'])
+ if p.returncode != 0:
+ raise RuntimeError("Failed to initialize fritz's submodules")
+ # auto stash
+ p = subprocess.run(['git', 'stash'], cwd="skyportal")
if p.returncode != 0:
- raise RuntimeError("Failed to initialize fritz's submodules")
- p = subprocess.run(['git', 'submodule', 'update', '--recursive'])
- if p.returncode != 0:
- raise RuntimeError("Failed to update fritz's submodules")
- else:
+ raise RuntimeError("SkyPortal autostash failed")
p = subprocess.run(['git', 'submodule', 'update', '--recursive'])
if p.returncode != 0:
raise RuntimeError("Failed to update fritz's submodules")
@@ -127,63 +129,84 @@ def run(args):
if not env_ok:
raise RuntimeError("Halting because of unsatisfied system dependencies")
- # create common docker network (if it does not exist yet)
- p = subprocess.run(
- ["docker", "network", 'create', "fritz_net"],
- capture_output=True,
- universal_newlines=True
- )
- if (p.returncode != 0) and ("already exists" not in p.stderr):
- raise RuntimeError("Failed to create network fritz_net")
+ # check config
+ check_config(cfg='fritz.defaults.yaml', yes=args.yes)
+
+ # load config
+ with open("fritz.yaml") as fyaml:
+ fritz_config = yaml.load(fyaml, Loader=yaml.FullLoader)
+
+ # add Fritz-specific K and SP extensions
+ # copy_tree('extensions/kowalski/', 'kowalski/')
+ copy_tree('extensions/skyportal/', 'skyportal/')
+
+ # add Fritz-specific dependencies for SP
+ # js
+ with open("extensions/skyportal/package.fritz.json", "r") as fpjf, open("skyportal/package.json", "r") as fpj:
+ pjf = json.load(fpjf)
+ pj = json.load(fpj)
+ pj["dependencies"] = {**pj["dependencies"], **pjf["dependencies"]}
+ with open("skyportal/package.json", "w") as fpj:
+ json.dump(pj, fpj, indent=2)
+ # python
+ with open(".requirements/ext.txt", "r") as frf, open("skyportal/requirements.txt", "r") as fr:
+ rf = frf.readlines()
+ r = fr.readlines()
+ with open("skyportal/requirements.txt", "w") as fr:
+ for line in rf + r:
+ fr.write(line)
+
+ # adjust F-specific docker-compose.yaml for SP
+ with open("skyportal/docker-compose.skyportal.yaml") as dcyaml:
+ dc = yaml.load(dcyaml, Loader=yaml.FullLoader)
+ # fix absolute paths in docker-compose.skyportal.yaml
+ for vi, volume in enumerate(dc["services"]["web"]["volumes"]):
+ dc["services"]["web"]["volumes"][vi] = volume.replace(
+ "${PWD}",
+ str(Path(__file__).parent.absolute())
+ )
+ if args.traefik:
+ # fix host for Traefik
+ dc["services"]["web"]["labels"][2] = dc["services"]["web"]["labels"][2].replace(
+ "",
+ fritz_config["skyportal"]["server"]["host"]
+ )
+ else:
+ # not running behind Traefik? then publish port 5000 on host
+ port = fritz_config["skyportal"]["server"].get("port", 5000)
+ if port is None:
+ port = 5000
+ dc["services"]["web"]["ports"] = [f"{port}:{port}"]
+ pass
+ with open("skyportal/docker-compose.skyportal.yaml", 'w') as dcyaml:
+ yaml.dump(dc, dcyaml)
+
+ # Build skyportal's images
+ p = subprocess.run(["make", "docker-local"], cwd="skyportal")
+ if p.returncode != 0:
+ raise RuntimeError("Failed to build skyportal's docker images")
+ # when initializing, must start SP to generate token for K
if args.init:
- # check config
- check_config(cfg='fritz.defaults.yaml', yes=args.yes)
-
- # load config
- with open("fritz.yaml") as fyaml:
- fritz_config = yaml.load(fyaml, Loader=yaml.FullLoader)
-
- # add Fritz-specific K and SP extensions:
- copy_tree('extensions/skyportal/', 'skyportal/')
-
- # adjust docker-compose.skyportal.yaml
- with open("skyportal/docker-compose.skyportal.yaml") as dcyaml:
- dc = yaml.load(dcyaml, Loader=yaml.FullLoader)
- # fix absolute paths in docker-compose.skyportal.yaml
- for vi, volume in enumerate(dc["services"]["web"]["volumes"]):
- dc["services"]["web"]["volumes"][vi] = volume.replace(
- "${PWD}",
- str(Path(__file__).parent.absolute())
- )
- if args.traefik:
- # fix host for traefik
- dc["services"]["web"]["labels"][2] = dc["services"]["web"]["labels"][2].replace(
- "",
- fritz_config["skyportal"]["server"]["host"]
- )
- with open("skyportal/docker-compose.skyportal.yaml", 'w') as dcyaml:
- yaml.dump(dc, dcyaml)
-
- # copy over the additional requirements:
- subprocess.run(["cp", ".requirements/ext.txt", f"skyportal/requirements.fritz.txt"], check=True)
+ # create common docker network (if it does not exist yet)
+ p = subprocess.run(
+ ["docker", "network", 'create', "fritz_net"],
+ capture_output=True,
+ universal_newlines=True
+ )
+ if (p.returncode != 0) and ("already exists" not in p.stderr):
+ raise RuntimeError("Failed to create network fritz_net")
- # Build skyportal's images
- p = subprocess.run(["make", "docker-local"], cwd="skyportal")
+ # start up skyportal
+ # docker-compose.skyportal.yaml bind-mounts the fritz-specific config.yaml and db_seed.yaml
+ p = subprocess.run(
+ ["docker-compose", "-f", 'docker-compose.skyportal.yaml', "up", "-d"],
+ cwd="skyportal",
+ check=True
+ )
if p.returncode != 0:
- raise RuntimeError("Failed to build skyportal's docker images")
+ raise RuntimeError("Failed to start SkyPortal")
- # start up skyportal
- # docker-compose.skyportal.yaml bind-mounts the fritz-specific config.yaml and db_seed.yaml
- p = subprocess.run(
- ["docker-compose", "-f", 'docker-compose.skyportal.yaml', "up", "-d"],
- cwd="skyportal",
- check=True
- )
- if p.returncode != 0:
- raise RuntimeError("Failed to start SkyPortal")
-
- if args.init:
# init skyportal and load seed data
mi, max_retires = 1, 3
while mi <= max_retires:
@@ -213,16 +236,53 @@ def run(args):
with open('kowalski/config.yaml', 'w') as cyaml:
yaml.dump(config, cyaml)
- # install Kowalski's deps:
- c = ["pip", "install", "-r", "requirements.txt"]
- subprocess.run(c, cwd="kowalski", check=True)
- # Build kowalski's images
- c = ["python", "kowalski.py", "build"]
- if args.yes:
- c.append("--yes")
- p = subprocess.run(c, cwd="kowalski")
- if p.returncode != 0:
- raise RuntimeError("Failed to build Kowalski's docker images")
+ # install Kowalski's deps:
+ c = ["pip", "install", "-r", "requirements.txt"]
+ subprocess.run(c, cwd="kowalski", check=True)
+ # Build kowalski's images
+ c = ["python", "kowalski.py", "build"]
+ if args.yes:
+ c.append("--yes")
+ p = subprocess.run(c, cwd="kowalski")
+ if p.returncode != 0:
+ raise RuntimeError("Failed to build Kowalski's docker images")
+
+ if args.init:
+ # stop SkyPortal
+ subprocess.run(["docker-compose", "-f", "docker-compose.skyportal.yaml", "down"], cwd="skyportal")
+
+ # remove common network
+ subprocess.run(["docker", "network", "remove", "fritz_net"])
+
+
+def run(args):
+ """
+ Launch Fritz
+ """
+ env = os.environ.copy()
+ env.update({"FLAGS": "--config=../fritz.yaml"})
+
+ if args.init:
+ build(args=args)
+
+ # create common docker network (if it does not exist yet)
+ p = subprocess.run(
+ ["docker", "network", 'create', "fritz_net"],
+ capture_output=True,
+ universal_newlines=True
+ )
+ if (p.returncode != 0) and ("already exists" not in p.stderr):
+ raise RuntimeError("Failed to create network fritz_net")
+
+ # start up skyportal
+ # docker-compose.skyportal.yaml bind-mounts the fritz-specific config.yaml and db_seed.yaml
+ p = subprocess.run(
+ ["docker-compose", "-f", 'docker-compose.skyportal.yaml', "up", "-d"],
+ cwd="skyportal",
+ check=True
+ )
+ if p.returncode != 0:
+ raise RuntimeError("Failed to start SkyPortal")
# start up kowalski
c = ["python", "kowalski.py", "up"]
@@ -272,7 +332,14 @@ def log(args):
"""
Show colorized logs while the marshal is running
"""
- p = subprocess.run(["make", "log"], cwd="skyportal")
+ # p = subprocess.run(["make", "log"], cwd="skyportal")
+ p = subprocess.run(
+ [
+ "docker", "exec", "-it", "skyportal_web_1", "/bin/bash", "-c",
+ "source /skyportal_env/bin/activate; make log"
+ ],
+ cwd="skyportal"
+ )
if p.returncode != 0:
raise RuntimeError("Failed to display fritz's logs")
@@ -338,8 +405,6 @@ def prune(args):
def test(args):
print("Launching tests...")
- # load_demo_data is run as part of ./fritz run --init since it is needed to create a token for kowalski
-
print("Testing Kowalski...")
subprocess.run(["python", "kowalski.py", "test"], cwd="kowalski")
@@ -380,6 +445,7 @@ if __name__ == "__main__":
("run", "🚀 Launch Fritz"),
("stop", "✋ Shut Fritz down"),
("test", "Run the test suite"),
+ ("build", "Build Fritz"),
("develop", "Install tools for developing Fritz"),
("lint", "Lint the full code base"),
("prune", "☠️ Wipe out containers, volumes, and submodules"),
@@ -394,11 +460,23 @@ if __name__ == "__main__":
parsers["run"].add_argument(
"--init", action="store_true", help="Initialize Fritz"
)
-
+ parsers["run"].add_argument(
+ "--dev", action="store_true", help="Run Fritz in dev mode"
+ )
parsers["run"].add_argument(
"--traefik", action="store_true", help="Run Fritz behind Traefik"
)
+ parsers["build"].add_argument(
+ "--init", action="store_true", help="Initialize before building Fritz"
+ )
+ parsers["build"].add_argument(
+ "--dev", action="store_true", help="Build Fritz for running in dev mode"
+ )
+ parsers["build"].add_argument(
+ "--traefik", action="store_true", help="Build Fritz to run behind Traefik"
+ )
+
parsers["doc"].add_argument(
"--upload", action="store_true", help="Upload documentation to GitHub"
)
diff --git a/fritz.defaults.yaml b/fritz.defaults.yaml
index f34d8722..6c253d58 100644
--- a/fritz.defaults.yaml
+++ b/fritz.defaults.yaml
@@ -39,12 +39,18 @@ skyportal:
component: About
- path: "/share_data/:id"
component: ShareDataForm
+ - path: "/filter/:fid"
+ component: Filter
+ - path: "/runs"
+ component: ObservingRunList
+ - path: "/run/:id"
+ component: RunSummary
+ - path: "/user_management"
+ component: UserManagement
- path: "/alerts"
component: Alerts
- path: "/alerts/ztf/:id"
component: ZTFAlert
- - path: "/filter/:fid"
- component: Filter
kowalski:
protocol: "http"
@@ -75,10 +81,92 @@ skyportal:
icon: GroupWork
url: /groups
+ - name: Observing Runs
+ icon: LocalCafe
+ url: /runs
+
- name: About
icon: Info
url: /about
+ homepage_widgets:
+ # This section describes the specific widgets shown on the Home Page and how
+ # they are laid out by default on the grid of the page.
+ #
+ # The name of section should be the same as the widget's React component.
+ #
+ # The props property should be a set of properties to be passed on to the
+ # underlying React component for the widget. You may run into cases in which
+ # you must pass a more complex, dyamic property (perhaps fetched from the
+ # application redux store). Since you can not know that in the time of the
+ # configuration writing, such properties should be directly coded into the
+ # HomePage.jsx.template file (see the GroupList widget for an example)
+ #
+ # By default, any widget listed here is shown on the Home Page. However, you
+ # can give a widget the property "show: false" to turn off rendering of the
+ # widget.
+ #
+ # The resizable property determines whether the user is able to resize the
+ # widget after it has been rendered based on default layouts.
+ #
+ # Finally, the layouts property provides an array of default sizes/locations
+ # for each screen width breakpoint for the given widget. Layout arrays are
+ # given in the order [x, y, width, height], in units of grid columns/rows.
+ # For example, a layout array of [1, 2, 3, 4] will render a widget 3 grid
+ # columns in width, 4 grid rows in height, and have its upper-left corner at
+ # the column 1 (zero-indexed) and row 2. Note that each row is by default
+ # 150px in height. The row height can be altered in the homepage_grid
+ # section above (as well as other grid characteristics).
+
+ SourceCounts:
+ props:
+ sinceDaysAgo: 7
+ resizeable: false
+ layouts:
+ xlg: [14, 0, 2, 1]
+ lg: [10, 0, 2, 1]
+ md: [8, 0, 2, 1]
+ sm: [4.5, 0, 1.5, 1]
+ xs: [0, 0, 4, 1]
+
+ RecentSources:
+ resizeable: false
+ layouts:
+ xlg: [0, 0, 5, 3]
+ lg: [0, 0, 4, 3]
+ md: [0, 3, 5, 3]
+ sm: [0, 3, 3, 3]
+ xs: [0, 4, 4, 3]
+
+ NewsFeed:
+ resizeable: false
+ layouts:
+ xlg: [10, 0, 4, 3]
+ lg: [7, 0, 3, 3]
+ md: [0, 0, 8, 3]
+ sm: [0, 0, 4.5, 3]
+ xs: [0, 1, 4, 3]
+
+ TopSources:
+ resizeable: false
+ layouts:
+ xlg: [5, 0, 5, 3]
+ lg: [4, 3, 3, 3]
+ md: [5, 3, 5, 3]
+ sm: [3, 3, 3, 3]
+ xs: [0, 7, 4, 3]
+
+ GroupList:
+ props:
+ title: My Groups
+ resizeable: true
+ layouts:
+ xlg: [14, 1, 2, 2]
+ lg: [10, 1, 2, 2]
+ md: [8, 1, 2, 2]
+ sm: [4.5, 1, 1.5, 2]
+ xs: [0, 10, 4, 2]
+
database:
database: skyportal
host: localhost
@@ -96,6 +184,10 @@ skyportal:
# You need to have Google+ API enabled; it takes a few minutes to activate.
host:
+ port:
+
+ ssl: False
+ processes: 1
auth:
debug_login: True
@@ -114,6 +206,17 @@ skyportal:
script: jobs/delete_unsaved_candidates.py
limit: ["01:00", "02:00"]
+ invitations:
+ enabled: False # If debug_login=True above, invite tokens won't be used during auth
+ days_until_expiry: 3
+ email_subject: "You've been invited to collaborate on Fritz"
+ email_body_preamble: | # This can include HTML tags
+ Welcome to Fritz !
+
+ Dark star crashes, pouring its light into ashes.
+ from_email: # This needs to be set to a valid, Sendgrid-registered address in config.yaml
+ sendgrid_api_key: # This needs to be obtained via Sendgrid setup on their site
+
kowalski:
server:
@@ -146,7 +249,7 @@ kowalski:
kafka:
default.topic.config:
auto.offset.reset: "earliest"
- group: "kowalski"
+ group: "fritz"
bootstrap.servers: "192.168.0.64:9092,192.168.0.65:9092,192.168.0.66:9092"
zookeeper: "192.168.0.64:2181"
@@ -433,7 +536,7 @@ kowalski:
serverurl: unix:///dev/shm/supervisor.sock
"program:gunicorn":
- # fixme: adjust number of workers -w for your system (e.g. -w 20 for kowalski.caltech.edu)
+ # fixme: adjust number of workers -w for your system
command: >
/usr/local/bin/gunicorn
-w 10
@@ -483,7 +586,7 @@ kowalski:
stdout_logfile: /data/logs/alert_watcher_ztf_stdout.log
stdout_logfile_maxbytes: 30MB
stderr_logfile: /data/logs/alert_watcher_ztf_stderr.log
- redirect_stderr: True
+ redirect_stderr: true
environment: "PRODUCTION=1"
"program:ops-watcher-ztf":
@@ -495,5 +598,5 @@ kowalski:
stdout_logfile: /data/logs/ops_watcher_ztf_stdout.log
stdout_logfile_maxbytes: 30MB
stderr_logfile: /data/logs/ops_watcher_ztf_stderr.log
- redirect_stderr: True
+ redirect_stderr: true
environment: "PRODUCTION=1"
diff --git a/kowalski b/kowalski
index 2d1c670d..882a7fa7 160000
--- a/kowalski
+++ b/kowalski
@@ -1 +1 @@
-Subproject commit 2d1c670d58402449de53730f4f8b8146d302b31e
+Subproject commit 882a7fa7e292676dd4864212efa696fb99668b4c
diff --git a/skyportal b/skyportal
index afc04117..6f63c8d4 160000
--- a/skyportal
+++ b/skyportal
@@ -1 +1 @@
-Subproject commit afc04117ac610a7dad986c1208c9bfb247745e4d
+Subproject commit 6f63c8d4b9397ad05eff6f0c7776175c8840a9ef