Skip to content

Commit 980eeeb

Browse files
authored
Merge pull request #71 from msusicky/develop
Release 1.1
2 parents 9865a65 + c2c8f5f commit 980eeeb

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+1635
-1216
lines changed

.flaskenv

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
FLASK_APP=ockovani.py

.gitignore

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ dmypy.json
128128
# Pyre type checker
129129
.pyre/
130130

131-
.idea
132-
*.ini
133-
*.out
131+
/.idea
132+
/*.ini
133+
/*.out
134+
/google_key.json

README.md

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,12 @@ Za systémem stojí Jan Staněk (http://jstanek.cz/), Marek Sušický (marek(at)
33

44
Během marné snahy zajistit očkovací místa pro příbuzné jsme si všimli toho, že neexistuje žádný přehled volných míst. Ještě v lednu jsme začali tvořit aplikaci, ale narazili na neexistenci dat. Pak došly vakcíny a nedávalo smysl systém spouštět. Nyní je situace taková, že mnoho lidí čeká na vakcinaci, ale pokud nejsou na tom správném místě, budou čekat dál. Na jiných místech už ale lidé 80+ "došli". S naší mapou se lidé mohou přeregistrovat, dostat vakcinu rychleji a zefektivnit celý proces očkování. Prosím kohokoliv, kdo může přispět ke zveřejnění oficiálních dat o volných kapacitách a distribuci vakcín, aby tak učinil.
55

6+
Web: https://msusicky.github.io/ockovani-covid/
7+
68
## Napsali o nás
7-
https://denikn.cz/569269/kde-maji-volna-mista-programatori-po-nocich-vymysleli-aplikaci-ktera-muze-zkratit-cekani-na-vakcinu
9+
* https://denikn.cz/569269/kde-maji-volna-mista-programatori-po-nocich-vymysleli-aplikaci-ktera-muze-zkratit-cekani-na-vakcinu
10+
* https://www.zive.cz/clanky/kdyz-to-neudelal-stat-poradili-si-programatori-sami-vytvorili-aplikaci-s-prehledem-volnych-mist-pro-ockovani/sc-3-a-208719/default.aspx
11+
* https://domaci.ihned.cz/c1-66889710-programator-rozjel-web-ktery-ukaze-kde-je-volno-na-ockovani-ve-skladech-lezi-250-tisic-davek-vakcin-rika
812

913
## Poznámky k fungování
1014
Pro získávání dat využívá metody scrapingu. Vzhledem k tomu, že jsou data zveřejňována na githubu, **prosím scraper nespouštějte na vlastním prostředí a nezpůsobujte tak zbytečnou další zátěž rezervačnímu systému!**
@@ -27,13 +31,21 @@ Aplikace se skládá z modulu fetcher, pak samotného webu a skriptu, který web
2731
#### Install requirements
2832
`pip install -r requirements.txt`
2933

30-
###
31-
```
32-
python app.py
33-
```
34-
or
34+
### Configuration
35+
* Fill connection string in `config.py`
36+
* Setup `config.ini` according to the `config.ini.template`
37+
38+
### Start webserver
3539
```
36-
export FLASK_APP=app.py
3740
export FLASK_ENV=development
41+
flask db upgrade
3842
flask run
3943
```
44+
45+
## Update
46+
1. update config.ini
47+
1. activate venv `source venv/bin/activate`
48+
1. execute database migration if needed `flask db upgrade`
49+
1. fetch data `flask fetch-all &`
50+
1. restart or start webserver if needed `flask run --host=0.0.0.0 --port=5000`
51+
1. publish website and CSV's `bash tools/manual_publish.sh`

__init__.py

Whitespace-only changes.

app.py

Lines changed: 0 additions & 49 deletions
This file was deleted.

app/__init__.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import logging
2+
3+
from flask import Flask, Blueprint
4+
from flask_sqlalchemy import SQLAlchemy
5+
from flask_migrate import Migrate
6+
from config import Config
7+
8+
app = Flask(__name__)
9+
app.config.from_object(Config)
10+
11+
bp = Blueprint('view', __name__, template_folder="templates")
12+
13+
db = SQLAlchemy(app)
14+
migrate = Migrate(app, db)
15+
16+
logging.basicConfig(level=logging.INFO)
17+
18+
from app import views, models, commands
19+
20+
app.register_blueprint(bp, url_prefix='/ockovani-covid')

app/commands.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
from app import app
2+
from app.opendata_fetcher import OpenDataFetcher
3+
from app.reservatic_fetcher import ReservaticFetcher
4+
from app.sheet_fetcher import SheetFetcher
5+
6+
7+
@app.cli.command('fetch-reservatic')
8+
def fetch_reservatic_command():
9+
"""Fetch free capacities from Reservatic."""
10+
fetcher = ReservaticFetcher()
11+
fetcher.fetch_free_capacities()
12+
13+
@app.cli.command('fetch-opendata')
14+
def fetch_opendata_command():
15+
"""Fetch opendata from UZIS."""
16+
fetcher = OpenDataFetcher()
17+
fetcher.fetch_all()
18+
19+
@app.cli.command('fetch-sheet')
20+
def fetch_sheet_command():
21+
"""Fetch sheet from Google Sheets."""
22+
fetcher = SheetFetcher()
23+
fetcher.fetch_centers()
24+
25+
@app.cli.command('fetch-all')
26+
def fetch_sheet_command():
27+
"""Execute all fetchers."""
28+
opendata_fetcher = OpenDataFetcher()
29+
opendata_fetcher.fetch_all()
30+
31+
sheet_fetcher = SheetFetcher()
32+
sheet_fetcher.fetch_centers()
33+
34+
reservatic_fetcher = SheetFetcher()
35+
reservatic_fetcher.fetch_centers()

app/models.py

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
from datetime import datetime
2+
from sqlalchemy import Column, Integer, Unicode, DateTime, Boolean, Float, Date, JSON, Sequence, ForeignKey
3+
from sqlalchemy.orm import relationship
4+
5+
from app import db
6+
7+
8+
class Kraj(db.Model):
9+
__tablename__ = 'kraje'
10+
11+
id = Column(Unicode, primary_key=True)
12+
nazev = Column(Unicode)
13+
14+
15+
class Okres(db.Model):
16+
__tablename__ = 'okresy'
17+
18+
id = Column(Unicode, primary_key=True)
19+
nazev = Column(Unicode)
20+
kraj_id = Column(Unicode, ForeignKey('kraje.id'))
21+
22+
kraj = relationship("Kraj", back_populates="okresy")
23+
24+
def __repr__(self):
25+
return "<Okres(nazev='%s')>" % (self.nazev)
26+
27+
28+
Kraj.okresy = relationship("Okres", back_populates="kraj")
29+
30+
31+
class OckovaciMisto(db.Model):
32+
__tablename__ = 'ockovaci_mista'
33+
34+
id = Column(Unicode, primary_key=True)
35+
nazev = Column(Unicode)
36+
okres_id = Column(Unicode, ForeignKey('okresy.id'))
37+
status = Column(Boolean)
38+
adresa = Column(Unicode)
39+
latitude = Column(Float)
40+
longitude = Column(Float)
41+
nrpzs_kod = Column(Unicode)
42+
minimalni_kapacita = Column(Integer)
43+
bezbarierovy_pristup = Column(Boolean)
44+
service_id = Column(Integer)
45+
operation_id = Column(Integer)
46+
odkaz = Column(Unicode)
47+
48+
okres = relationship("Okres", back_populates="ockovaci_mista")
49+
50+
def __repr__(self):
51+
return "<OckovaciMisto(nazev='%s', service_id=%s, operation_id=%s)>" % (
52+
self.nazev, self.service_id, self.operation_id)
53+
54+
55+
Okres.ockovaci_mista = relationship("OckovaciMisto", back_populates="okres")
56+
57+
58+
class Import(db.Model):
59+
__tablename__ = 'importy'
60+
61+
id = Column(Integer, primary_key=True)
62+
start = Column(DateTime, default=datetime.now())
63+
status = Column(Unicode)
64+
65+
def __repr__(self):
66+
return "<Import(id=%s, start='%s', status='%s')>" % (self.id, self.start, self.status)
67+
68+
69+
class VolnaMistaCas(db.Model):
70+
__tablename__ = 'volna_mista_cas'
71+
72+
id = Column(Integer, primary_key=True)
73+
import_id = Column(Integer, ForeignKey('importy.id'))
74+
cas_ziskani = Column(DateTime, default=datetime.now())
75+
misto_id = Column(Unicode, ForeignKey('ockovaci_mista.id'))
76+
datum = Column(Date)
77+
cas = Column(Unicode)
78+
start = Column(DateTime)
79+
volna_mista = Column(Integer)
80+
place_id = Column(Integer)
81+
user_service_id = Column(Integer)
82+
83+
import_ = relationship('Import', back_populates='volna_mista_cas')
84+
misto = relationship('OckovaciMisto', back_populates='volna_mista_cas')
85+
86+
def __repr__(self):
87+
return "<VolnaMistaCas(misto_id='%s', cas='%s', volna_mista=%s)>" % (
88+
self.misto_id, self.start, self.volna_mista)
89+
90+
91+
Import.volna_mista_cas = relationship("VolnaMistaCas", back_populates="import_")
92+
OckovaciMisto.volna_mista_cas = relationship("VolnaMistaCas", back_populates="misto")
93+
94+
95+
class VolnaMistaDen(db.Model):
96+
__tablename__ = 'volna_mista_den'
97+
98+
id = Column(Integer, primary_key=True)
99+
import_id = Column(Integer, ForeignKey('importy.id'))
100+
cas_ziskani = Column(DateTime, default=datetime.now())
101+
misto_id = Column(Unicode, ForeignKey('ockovaci_mista.id'))
102+
datum = Column(Date)
103+
volna_mista = Column(Integer)
104+
data = Column(JSON)
105+
106+
import_ = relationship('Import', back_populates='volna_mista_den')
107+
misto = relationship('OckovaciMisto', back_populates='volna_mista_den')
108+
109+
def __repr__(self):
110+
return "<VolnaMistaDen(misto_id='%s', datum='%s', volna_mista=%s)>" % (
111+
self.misto_id, self.datum, self.volna_mista)
112+
113+
114+
Import.volna_mista_den = relationship("VolnaMistaDen", back_populates="import_")
115+
OckovaciMisto.volna_mista_den = relationship("VolnaMistaDen", back_populates="misto")
116+
117+
118+
class OckovaniSpotreba(db.Model):
119+
__tablename__ = 'ockovani_spotreba'
120+
121+
datum = Column(Date, primary_key=True)
122+
ockovaci_misto_id = Column(Unicode, ForeignKey('ockovaci_mista.id'), primary_key=True)
123+
ockovaci_misto_nazev = Column(Unicode)
124+
kraj_nuts_kod = Column(Unicode)
125+
kraj_nazev = Column(Unicode)
126+
ockovaci_latka = Column(Unicode, primary_key=True)
127+
vyrobce = Column(Unicode)
128+
pouzite_ampulky = Column(Integer)
129+
znehodnocene_ampulky = Column(Integer)
130+
131+
misto = relationship('OckovaciMisto', back_populates='ockovani_spotreba')
132+
133+
def __repr__(self):
134+
return "<VaccineConsumption(ockovaci_misto_nazev='%s', datum='%s', ockovaci_latka=%s, pouzite_ampulky=%s)>" % (
135+
self.ockovaci_misto_nazev, self.datum, self.ockovaci_latka, self.pouzite_ampulky)
136+
137+
138+
OckovaciMisto.ockovani_spotreba = relationship("OckovaniSpotreba", back_populates="misto")
139+
140+
141+
class OckovaniDistribuce(db.Model):
142+
__tablename__ = 'ockovani_distribuce'
143+
144+
datum = Column(Date, primary_key=True)
145+
ockovaci_misto_id = Column(Unicode, ForeignKey('ockovaci_mista.id'), primary_key=True)
146+
ockovaci_misto_nazev = Column(Unicode)
147+
kraj_nuts_kod = Column(Unicode)
148+
kraj_nazev = Column(Unicode)
149+
cilove_ockovaci_misto_id = Column(Unicode, primary_key=True)
150+
cilove_ockovaci_misto_nazev = Column(Unicode)
151+
cilovy_kraj_kod = Column(Unicode)
152+
cilovy_kraj_nazev = Column(Unicode)
153+
ockovaci_latka = Column(Unicode, primary_key=True)
154+
vyrobce = Column(Unicode)
155+
akce = Column(Unicode, primary_key=True)
156+
pocet_ampulek = Column(Integer)
157+
158+
misto = relationship('OckovaciMisto', back_populates='ockovani_distribuce')
159+
160+
def __repr__(self):
161+
return "<VaccineDistribution(ockovaci_misto_nazev='%s', cilove_ockovaci_misto_nazev='%s', datum='%s', ockovaci_latka=%s, pocet_ampulek=%s)>" % (
162+
self.ockovaci_misto_nazev, self.cilove_ockovaci_misto_nazev, self.datum, self.ockovaci_latka, self.pocet_ampulek)
163+
164+
165+
OckovaciMisto.ockovani_distribuce = relationship("OckovaniDistribuce", back_populates="misto")

0 commit comments

Comments
 (0)