Skip to content

Commit

Permalink
Merge pull request #71 from msusicky/develop
Browse files Browse the repository at this point in the history
Release 1.1
  • Loading branch information
msusicky authored Feb 28, 2021
2 parents 9865a65 + c2c8f5f commit 980eeeb
Show file tree
Hide file tree
Showing 51 changed files with 1,635 additions and 1,216 deletions.
1 change: 1 addition & 0 deletions .flaskenv
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
FLASK_APP=ockovani.py
7 changes: 4 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ dmypy.json
# Pyre type checker
.pyre/

.idea
*.ini
*.out
/.idea
/*.ini
/*.out
/google_key.json
26 changes: 19 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@ Za systémem stojí Jan Staněk (http://jstanek.cz/), Marek Sušický (marek(at)

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.

Web: https://msusicky.github.io/ockovani-covid/

## Napsali o nás
https://denikn.cz/569269/kde-maji-volna-mista-programatori-po-nocich-vymysleli-aplikaci-ktera-muze-zkratit-cekani-na-vakcinu
* https://denikn.cz/569269/kde-maji-volna-mista-programatori-po-nocich-vymysleli-aplikaci-ktera-muze-zkratit-cekani-na-vakcinu
* 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
* https://domaci.ihned.cz/c1-66889710-programator-rozjel-web-ktery-ukaze-kde-je-volno-na-ockovani-ve-skladech-lezi-250-tisic-davek-vakcin-rika

## Poznámky k fungování
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!**
Expand All @@ -27,13 +31,21 @@ Aplikace se skládá z modulu fetcher, pak samotného webu a skriptu, který web
#### Install requirements
`pip install -r requirements.txt`

###
```
python app.py
```
or
### Configuration
* Fill connection string in `config.py`
* Setup `config.ini` according to the `config.ini.template`

### Start webserver
```
export FLASK_APP=app.py
export FLASK_ENV=development
flask db upgrade
flask run
```

## Update
1. update config.ini
1. activate venv `source venv/bin/activate`
1. execute database migration if needed `flask db upgrade`
1. fetch data `flask fetch-all &`
1. restart or start webserver if needed `flask run --host=0.0.0.0 --port=5000`
1. publish website and CSV's `bash tools/manual_publish.sh`
Empty file removed __init__.py
Empty file.
49 changes: 0 additions & 49 deletions app.py

This file was deleted.

20 changes: 20 additions & 0 deletions app/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import logging

from flask import Flask, Blueprint
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from config import Config

app = Flask(__name__)
app.config.from_object(Config)

bp = Blueprint('view', __name__, template_folder="templates")

db = SQLAlchemy(app)
migrate = Migrate(app, db)

logging.basicConfig(level=logging.INFO)

from app import views, models, commands

app.register_blueprint(bp, url_prefix='/ockovani-covid')
35 changes: 35 additions & 0 deletions app/commands.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from app import app
from app.opendata_fetcher import OpenDataFetcher
from app.reservatic_fetcher import ReservaticFetcher
from app.sheet_fetcher import SheetFetcher


@app.cli.command('fetch-reservatic')
def fetch_reservatic_command():
"""Fetch free capacities from Reservatic."""
fetcher = ReservaticFetcher()
fetcher.fetch_free_capacities()

@app.cli.command('fetch-opendata')
def fetch_opendata_command():
"""Fetch opendata from UZIS."""
fetcher = OpenDataFetcher()
fetcher.fetch_all()

@app.cli.command('fetch-sheet')
def fetch_sheet_command():
"""Fetch sheet from Google Sheets."""
fetcher = SheetFetcher()
fetcher.fetch_centers()

@app.cli.command('fetch-all')
def fetch_sheet_command():
"""Execute all fetchers."""
opendata_fetcher = OpenDataFetcher()
opendata_fetcher.fetch_all()

sheet_fetcher = SheetFetcher()
sheet_fetcher.fetch_centers()

reservatic_fetcher = SheetFetcher()
reservatic_fetcher.fetch_centers()
165 changes: 165 additions & 0 deletions app/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
from datetime import datetime
from sqlalchemy import Column, Integer, Unicode, DateTime, Boolean, Float, Date, JSON, Sequence, ForeignKey
from sqlalchemy.orm import relationship

from app import db


class Kraj(db.Model):
__tablename__ = 'kraje'

id = Column(Unicode, primary_key=True)
nazev = Column(Unicode)


class Okres(db.Model):
__tablename__ = 'okresy'

id = Column(Unicode, primary_key=True)
nazev = Column(Unicode)
kraj_id = Column(Unicode, ForeignKey('kraje.id'))

kraj = relationship("Kraj", back_populates="okresy")

def __repr__(self):
return "<Okres(nazev='%s')>" % (self.nazev)


Kraj.okresy = relationship("Okres", back_populates="kraj")


class OckovaciMisto(db.Model):
__tablename__ = 'ockovaci_mista'

id = Column(Unicode, primary_key=True)
nazev = Column(Unicode)
okres_id = Column(Unicode, ForeignKey('okresy.id'))
status = Column(Boolean)
adresa = Column(Unicode)
latitude = Column(Float)
longitude = Column(Float)
nrpzs_kod = Column(Unicode)
minimalni_kapacita = Column(Integer)
bezbarierovy_pristup = Column(Boolean)
service_id = Column(Integer)
operation_id = Column(Integer)
odkaz = Column(Unicode)

okres = relationship("Okres", back_populates="ockovaci_mista")

def __repr__(self):
return "<OckovaciMisto(nazev='%s', service_id=%s, operation_id=%s)>" % (
self.nazev, self.service_id, self.operation_id)


Okres.ockovaci_mista = relationship("OckovaciMisto", back_populates="okres")


class Import(db.Model):
__tablename__ = 'importy'

id = Column(Integer, primary_key=True)
start = Column(DateTime, default=datetime.now())
status = Column(Unicode)

def __repr__(self):
return "<Import(id=%s, start='%s', status='%s')>" % (self.id, self.start, self.status)


class VolnaMistaCas(db.Model):
__tablename__ = 'volna_mista_cas'

id = Column(Integer, primary_key=True)
import_id = Column(Integer, ForeignKey('importy.id'))
cas_ziskani = Column(DateTime, default=datetime.now())
misto_id = Column(Unicode, ForeignKey('ockovaci_mista.id'))
datum = Column(Date)
cas = Column(Unicode)
start = Column(DateTime)
volna_mista = Column(Integer)
place_id = Column(Integer)
user_service_id = Column(Integer)

import_ = relationship('Import', back_populates='volna_mista_cas')
misto = relationship('OckovaciMisto', back_populates='volna_mista_cas')

def __repr__(self):
return "<VolnaMistaCas(misto_id='%s', cas='%s', volna_mista=%s)>" % (
self.misto_id, self.start, self.volna_mista)


Import.volna_mista_cas = relationship("VolnaMistaCas", back_populates="import_")
OckovaciMisto.volna_mista_cas = relationship("VolnaMistaCas", back_populates="misto")


class VolnaMistaDen(db.Model):
__tablename__ = 'volna_mista_den'

id = Column(Integer, primary_key=True)
import_id = Column(Integer, ForeignKey('importy.id'))
cas_ziskani = Column(DateTime, default=datetime.now())
misto_id = Column(Unicode, ForeignKey('ockovaci_mista.id'))
datum = Column(Date)
volna_mista = Column(Integer)
data = Column(JSON)

import_ = relationship('Import', back_populates='volna_mista_den')
misto = relationship('OckovaciMisto', back_populates='volna_mista_den')

def __repr__(self):
return "<VolnaMistaDen(misto_id='%s', datum='%s', volna_mista=%s)>" % (
self.misto_id, self.datum, self.volna_mista)


Import.volna_mista_den = relationship("VolnaMistaDen", back_populates="import_")
OckovaciMisto.volna_mista_den = relationship("VolnaMistaDen", back_populates="misto")


class OckovaniSpotreba(db.Model):
__tablename__ = 'ockovani_spotreba'

datum = Column(Date, primary_key=True)
ockovaci_misto_id = Column(Unicode, ForeignKey('ockovaci_mista.id'), primary_key=True)
ockovaci_misto_nazev = Column(Unicode)
kraj_nuts_kod = Column(Unicode)
kraj_nazev = Column(Unicode)
ockovaci_latka = Column(Unicode, primary_key=True)
vyrobce = Column(Unicode)
pouzite_ampulky = Column(Integer)
znehodnocene_ampulky = Column(Integer)

misto = relationship('OckovaciMisto', back_populates='ockovani_spotreba')

def __repr__(self):
return "<VaccineConsumption(ockovaci_misto_nazev='%s', datum='%s', ockovaci_latka=%s, pouzite_ampulky=%s)>" % (
self.ockovaci_misto_nazev, self.datum, self.ockovaci_latka, self.pouzite_ampulky)


OckovaciMisto.ockovani_spotreba = relationship("OckovaniSpotreba", back_populates="misto")


class OckovaniDistribuce(db.Model):
__tablename__ = 'ockovani_distribuce'

datum = Column(Date, primary_key=True)
ockovaci_misto_id = Column(Unicode, ForeignKey('ockovaci_mista.id'), primary_key=True)
ockovaci_misto_nazev = Column(Unicode)
kraj_nuts_kod = Column(Unicode)
kraj_nazev = Column(Unicode)
cilove_ockovaci_misto_id = Column(Unicode, primary_key=True)
cilove_ockovaci_misto_nazev = Column(Unicode)
cilovy_kraj_kod = Column(Unicode)
cilovy_kraj_nazev = Column(Unicode)
ockovaci_latka = Column(Unicode, primary_key=True)
vyrobce = Column(Unicode)
akce = Column(Unicode, primary_key=True)
pocet_ampulek = Column(Integer)

misto = relationship('OckovaciMisto', back_populates='ockovani_distribuce')

def __repr__(self):
return "<VaccineDistribution(ockovaci_misto_nazev='%s', cilove_ockovaci_misto_nazev='%s', datum='%s', ockovaci_latka=%s, pocet_ampulek=%s)>" % (
self.ockovaci_misto_nazev, self.cilove_ockovaci_misto_nazev, self.datum, self.ockovaci_latka, self.pocet_ampulek)


OckovaciMisto.ockovani_distribuce = relationship("OckovaniDistribuce", back_populates="misto")
Loading

0 comments on commit 980eeeb

Please sign in to comment.