Compare commits
32 Commits
92a412135a
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
6a6de3bfcd
|
|||
|
b41b72b08a
|
|||
|
a00ed940d8
|
|||
|
ee9558a1bb
|
|||
|
6baa8779ca
|
|||
|
f599766609
|
|||
|
d93bfa4428
|
|||
|
2f0b39ef76
|
|||
|
aeb5c8b839
|
|||
|
1e52bcae0d
|
|||
|
65d3af6817
|
|||
|
c6e63cf087
|
|||
|
1aac68473d
|
|||
|
6caca22472
|
|||
|
667bed6edf
|
|||
|
15ac576058
|
|||
|
a0a5384e5b
|
|||
|
16a789cdf9
|
|||
|
f84d71616a
|
|||
|
712c84b358
|
|||
|
b7e7c3400d
|
|||
|
6a4af60d53
|
|||
|
cbc298a629
|
|||
|
7b945e2b98
|
|||
|
dfd13f6037
|
|||
|
6ef88e9b23
|
|||
|
cbc1c08350
|
|||
|
8f31f6ff84
|
|||
|
c2d6c2363b
|
|||
|
7c4ba27dc5
|
|||
|
b7a6b4c9d6
|
|||
|
6c26ce6588
|
1
.gitignore
vendored
@@ -1,3 +1,2 @@
|
|||||||
Assets/__titlepage.filled.tex
|
Assets/__titlepage.filled.tex
|
||||||
Design.org
|
Design.org
|
||||||
Code/.env
|
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
@misc{wgms-db,
|
|
||||||
author = {World Glacier Monitoring Service (WGMS)},
|
|
||||||
title = {{Fluctuations of Glaciers Database}},
|
|
||||||
publisher = {World Glacier Monitoring Service (WGMS)},
|
|
||||||
year = 2018,
|
|
||||||
month = nov # "~3,",
|
|
||||||
doi = {10.5904/wgms-fog-2018-11},
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 31 KiB |
@@ -1,7 +0,0 @@
|
|||||||
(TeX-add-style-hook
|
|
||||||
"Citations"
|
|
||||||
(lambda ()
|
|
||||||
(LaTeX-add-bibitems
|
|
||||||
"wgms-db"))
|
|
||||||
:bibtex)
|
|
||||||
|
|
||||||
105
Code/Pipfile.lock
generated
@@ -1,105 +0,0 @@
|
|||||||
{
|
|
||||||
"_meta": {
|
|
||||||
"hash": {
|
|
||||||
"sha256": "536bc13b89021a4575fe2c14d71636abf965ab896871f1503f3186f2f1c6a0d4"
|
|
||||||
},
|
|
||||||
"pipfile-spec": 6,
|
|
||||||
"requires": {
|
|
||||||
"python_version": "3.8"
|
|
||||||
},
|
|
||||||
"sources": [
|
|
||||||
{
|
|
||||||
"name": "pypi",
|
|
||||||
"url": "https://pypi.org/simple",
|
|
||||||
"verify_ssl": true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"default": {
|
|
||||||
"click": {
|
|
||||||
"hashes": [
|
|
||||||
"sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13",
|
|
||||||
"sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7"
|
|
||||||
],
|
|
||||||
"version": "==7.0"
|
|
||||||
},
|
|
||||||
"flask": {
|
|
||||||
"hashes": [
|
|
||||||
"sha256:13f9f196f330c7c2c5d7a5cf91af894110ca0215ac051b5844701f2bfd934d52",
|
|
||||||
"sha256:45eb5a6fd193d6cf7e0cf5d8a5b31f83d5faae0293695626f539a823e93b13f6"
|
|
||||||
],
|
|
||||||
"index": "pypi",
|
|
||||||
"version": "==1.1.1"
|
|
||||||
},
|
|
||||||
"itsdangerous": {
|
|
||||||
"hashes": [
|
|
||||||
"sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19",
|
|
||||||
"sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749"
|
|
||||||
],
|
|
||||||
"version": "==1.1.0"
|
|
||||||
},
|
|
||||||
"jinja2": {
|
|
||||||
"hashes": [
|
|
||||||
"sha256:74320bb91f31270f9551d46522e33af46a80c3d619f4a4bf42b3164d30b5911f",
|
|
||||||
"sha256:9fe95f19286cfefaa917656583d020be14e7859c6b0252588391e47db34527de"
|
|
||||||
],
|
|
||||||
"version": "==2.10.3"
|
|
||||||
},
|
|
||||||
"markupsafe": {
|
|
||||||
"hashes": [
|
|
||||||
"sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473",
|
|
||||||
"sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161",
|
|
||||||
"sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235",
|
|
||||||
"sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5",
|
|
||||||
"sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff",
|
|
||||||
"sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b",
|
|
||||||
"sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1",
|
|
||||||
"sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e",
|
|
||||||
"sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183",
|
|
||||||
"sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66",
|
|
||||||
"sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1",
|
|
||||||
"sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1",
|
|
||||||
"sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e",
|
|
||||||
"sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b",
|
|
||||||
"sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905",
|
|
||||||
"sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735",
|
|
||||||
"sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d",
|
|
||||||
"sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e",
|
|
||||||
"sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d",
|
|
||||||
"sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c",
|
|
||||||
"sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21",
|
|
||||||
"sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2",
|
|
||||||
"sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5",
|
|
||||||
"sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b",
|
|
||||||
"sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6",
|
|
||||||
"sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f",
|
|
||||||
"sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f",
|
|
||||||
"sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7"
|
|
||||||
],
|
|
||||||
"version": "==1.1.1"
|
|
||||||
},
|
|
||||||
"pymysql": {
|
|
||||||
"hashes": [
|
|
||||||
"sha256:3943fbbbc1e902f41daf7f9165519f140c4451c179380677e6a848587042561a",
|
|
||||||
"sha256:d8c059dcd81dedb85a9f034d5e22dcb4442c0b201908bede99e306d65ea7c8e7"
|
|
||||||
],
|
|
||||||
"index": "pypi",
|
|
||||||
"version": "==0.9.3"
|
|
||||||
},
|
|
||||||
"sqlalchemy": {
|
|
||||||
"hashes": [
|
|
||||||
"sha256:bfb8f464a5000b567ac1d350b9090cf081180ec1ab4aa87e7bca12dab25320ec"
|
|
||||||
],
|
|
||||||
"index": "pypi",
|
|
||||||
"version": "==1.3.12"
|
|
||||||
},
|
|
||||||
"werkzeug": {
|
|
||||||
"hashes": [
|
|
||||||
"sha256:7280924747b5733b246fe23972186c6b348f9ae29724135a6dfc1e53cea433e7",
|
|
||||||
"sha256:e5f4a1f98b52b18a93da705a7458e55afb26f32bff83ff5d19189f92462d65c4"
|
|
||||||
],
|
|
||||||
"version": "==0.16.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"develop": {}
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
from sqlalchemy import create_engine
|
|
||||||
|
|
||||||
|
|
||||||
def create_connection():
|
|
||||||
db_name = get_env_variable("DB_NAME")
|
|
||||||
db_user = get_env_variable("DB_USER")
|
|
||||||
db_password = get_env_variable("DB_PASSWORD")
|
|
||||||
db_url = get_env_variable("DB_URL")
|
|
||||||
db_connection_uri = "mysql+pymysql://{user}:{pw}@{url}/{db}".format(
|
|
||||||
user=db_user, pw=db_password, url=db_url, db=db_name
|
|
||||||
)
|
|
||||||
engine = sqlalchemy.create_engine(db_connection_uri, echo=True)
|
|
||||||
|
|
||||||
|
|
||||||
def get_env_variable(name):
|
|
||||||
try:
|
|
||||||
return os.environ[name]
|
|
||||||
except KeyError:
|
|
||||||
message = "Expected environment variable '{}' not set.".format(name)
|
|
||||||
raise Exception(message)
|
|
||||||
45
Design.org
@@ -11,8 +11,6 @@
|
|||||||
*** TODO Improve second handout [0/2] [0%]
|
*** TODO Improve second handout [0/2] [0%]
|
||||||
- [ ] Correct diagrams
|
- [ ] Correct diagrams
|
||||||
- [ ] Add conceptual diagram
|
- [ ] Add conceptual diagram
|
||||||
*** INACTIVE Update date in YAML automatically [0/1] [0%]
|
|
||||||
- [ ] Add to Makefile
|
|
||||||
*** DONE Type requirements handout [4/4] [100%]
|
*** DONE Type requirements handout [4/4] [100%]
|
||||||
CLOSED: [2019-09-27 Fri 14:54] SCHEDULED: <2019-09-27 Fri 23:55>
|
CLOSED: [2019-09-27 Fri 14:54] SCHEDULED: <2019-09-27 Fri 23:55>
|
||||||
- [X] Problem description
|
- [X] Problem description
|
||||||
@@ -44,15 +42,38 @@ CLOSED: [2019-11-01 Fri 00:34]
|
|||||||
- [X] Functional
|
- [X] Functional
|
||||||
- [X] Black box
|
- [X] Black box
|
||||||
- [X] Entity-Relationship
|
- [X] Entity-Relationship
|
||||||
|
*** CANCELLED Update date in YAML automatically [0/1] [0%]
|
||||||
|
CLOSED: [2020-01-10 Fri 17:54]
|
||||||
|
- [ ] Add to Makefile
|
||||||
** Implementation
|
** Implementation
|
||||||
*** TODO Backend [0/2] [0%]
|
*** DONE Backend [4/4] [100%]
|
||||||
**** TODO Database [1/2] [50%]
|
CLOSED: [2020-01-10 Fri 23:15]
|
||||||
|
**** DONE Flask Application [3/3] [100%]
|
||||||
|
CLOSED: [2020-01-10 Fri 23:15]
|
||||||
|
- [X] Plots with pandas
|
||||||
|
- [X] Login for admin
|
||||||
|
- [X] Tables with pandas
|
||||||
|
**** DONE Database [3/3] [100%]
|
||||||
|
CLOSED: [2020-01-03 Fri 00:44]
|
||||||
- [X] Connection
|
- [X] Connection
|
||||||
- [ ] Creation of fields via class
|
- [X] Creation from script
|
||||||
**** NEXT Flask framework
|
- [X] Creation of tables via class
|
||||||
-[[https://flask.palletsprojects.com/en/1.1.x/patterns/#patterns][ Patterns]]
|
**** DONE Parser [3/3] [100%]
|
||||||
*** NEXT Parsing script [0/2] [0%]
|
CLOSED: [2020-01-08 Wed 03:18]
|
||||||
- [ ] Select useful fiels with awk
|
- [X] Select useful fiels
|
||||||
- [ ] Arithmetic operations for comparisons
|
- [X] Convert PU to Country (ISO 3166)
|
||||||
*** INACTIVE Frontend [0/1] [0%]
|
- [X] Insert into database
|
||||||
- [ ] [[https://adminlte.io/][Adminlte]]
|
**** DONE Possible additions [2/2] [100%]
|
||||||
|
CLOSED: [2020-01-09 Thu 20:57]
|
||||||
|
- [X] Text search for glaciers
|
||||||
|
- [X] Form seach for a year
|
||||||
|
*** TODO Documentation [1/2] [50%]
|
||||||
|
- [ ] Code
|
||||||
|
- [X] Readme
|
||||||
|
*** DONE Deployment [1/1] [100%]
|
||||||
|
CLOSED: [2020-01-10 Fri 12:14]
|
||||||
|
- [X] Installation instructions
|
||||||
|
*** DONE Frontend [2/2] [100%]
|
||||||
|
CLOSED: [2020-01-09 Thu 11:09]
|
||||||
|
- [X] Flask-Bootstrap
|
||||||
|
- [X] Find CSS
|
||||||
|
|||||||
162
Docs/UML.org
@@ -1,162 +0,0 @@
|
|||||||
* Diagramas UML
|
|
||||||
|
|
||||||
** Functional
|
|
||||||
|
|
||||||
#+begin_src plantuml :file ../Assets/Diagrams/FD.png
|
|
||||||
:Script|
|
|
||||||
split
|
|
||||||
:Alta de un glaciar;
|
|
||||||
split again
|
|
||||||
:Inclusión de datos anuales;
|
|
||||||
split again
|
|
||||||
:Cálculo de las variaciones anuales;
|
|
||||||
split again
|
|
||||||
:Actualización de la base de datos;
|
|
||||||
split again
|
|
||||||
:Alta del administrador;
|
|
||||||
:Administrador|
|
|
||||||
:Resolución de conflictos;
|
|
||||||
endsplit
|
|
||||||
:IGDB|
|
|
||||||
#+end_src
|
|
||||||
|
|
||||||
#+RESULTS:
|
|
||||||
[[file:../Assets/Diagrams/FD.png]]
|
|
||||||
|
|
||||||
|
|
||||||
** Data-flow
|
|
||||||
|
|
||||||
#+begin_src plantuml :file ../Assets/Diagrams/DF1.png
|
|
||||||
:Script|
|
|
||||||
:Alta del Glaciar;
|
|
||||||
-> Nuevo glaciar;
|
|
||||||
:Glaciar<
|
|
||||||
:IGDB|
|
|
||||||
#+end_src
|
|
||||||
|
|
||||||
#+RESULTS:
|
|
||||||
[[file:../Assets/Diagrams/DF1.png]]
|
|
||||||
|
|
||||||
#+begin_src plantuml :file ../Assets/Diagrams/DF2.png
|
|
||||||
:Script|
|
|
||||||
:Inclusión de datos anuales;
|
|
||||||
-> Añadir información;
|
|
||||||
:Glaciar<
|
|
||||||
:IGDB|
|
|
||||||
#+end_src
|
|
||||||
|
|
||||||
#+RESULTS:
|
|
||||||
[[file:../Assets/Diagrams/DF2.png]]
|
|
||||||
|
|
||||||
#+begin_src plantuml :file ../Assets/Diagrams/DF3.png
|
|
||||||
:Script|
|
|
||||||
:Cálculo de las variaciones anuales;
|
|
||||||
:Inclusión de datos anuales;
|
|
||||||
-> Añadir información;
|
|
||||||
:Glaciar<
|
|
||||||
:IGDB|
|
|
||||||
#+end_src
|
|
||||||
|
|
||||||
#+RESULTS:
|
|
||||||
[[file:../Assets/Diagrams/DF3.png]]
|
|
||||||
|
|
||||||
#+begin_src plantuml :file ../Assets/Diagrams/DF4.png
|
|
||||||
:Script|
|
|
||||||
:Alta del administrador;
|
|
||||||
-> Nuevo administrador;
|
|
||||||
:Administrador<
|
|
||||||
:IGDB|
|
|
||||||
#+end_src
|
|
||||||
|
|
||||||
#+RESULTS:
|
|
||||||
[[file:../Assets/Diagrams/DF4.png]]
|
|
||||||
|
|
||||||
#+begin_src plantuml :file ../Assets/Diagrams/DF5.png
|
|
||||||
:Script|
|
|
||||||
:Actualización de la base de datos;
|
|
||||||
:Inclusión de datos anuales;
|
|
||||||
-> Añadir información;
|
|
||||||
:Glaciar<
|
|
||||||
:IGDB|
|
|
||||||
#+end_src
|
|
||||||
|
|
||||||
#+RESULTS:
|
|
||||||
[[file:../Assets/Diagrams/DF5.png]]
|
|
||||||
|
|
||||||
#+begin_src plantuml :file ../Assets/Diagrams/DF6.png
|
|
||||||
:Script|
|
|
||||||
:Administrador<
|
|
||||||
:Resolución de conflictos;
|
|
||||||
-> Selecciona los datos correctos;
|
|
||||||
:Actualización de la base de datos;
|
|
||||||
:IGDB|
|
|
||||||
#+end_src
|
|
||||||
|
|
||||||
#+RESULTS:
|
|
||||||
[[file:../Assets/Diagrams/DF6.png]]
|
|
||||||
|
|
||||||
** Black box
|
|
||||||
|
|
||||||
#+begin_src plantuml :file ../Assets/Diagrams/BB.png
|
|
||||||
@startuml
|
|
||||||
start
|
|
||||||
:WGMS|
|
|
||||||
:**Sistema**;
|
|
||||||
:IGDB|
|
|
||||||
end
|
|
||||||
@enduml
|
|
||||||
#+end_src
|
|
||||||
|
|
||||||
#+RESULTS:
|
|
||||||
[[file:../Assets/Diagrams/BB.png]]
|
|
||||||
|
|
||||||
** Entity Relationship
|
|
||||||
|
|
||||||
|
|
||||||
#+begin_src plantuml :file ../Assets/Diagrams/ER.png
|
|
||||||
@startuml
|
|
||||||
hide circle
|
|
||||||
skinparam linetype ortho
|
|
||||||
entity "Glacier" as e01 {
|
|
||||||
,* **glacier_id** : number <<generated>>
|
|
||||||
--
|
|
||||||
,*glacier_name : text
|
|
||||||
--
|
|
||||||
,*glacier_country: text
|
|
||||||
}
|
|
||||||
entity "Glacier yearly data" as e02 {
|
|
||||||
,* **glacier_id** : number <<FK>>
|
|
||||||
--
|
|
||||||
,*glacier_volume: number
|
|
||||||
--
|
|
||||||
,*glacier_area: number
|
|
||||||
--
|
|
||||||
,*glacier_thickness: number
|
|
||||||
--
|
|
||||||
,*glacier_year: number
|
|
||||||
}
|
|
||||||
entity "Glacier yearly fluctuation" as e03 {
|
|
||||||
,* **glacier_id** : number <<FK>>
|
|
||||||
--
|
|
||||||
,*glacier_area_change: number
|
|
||||||
--
|
|
||||||
,*glacier_volume_change: number
|
|
||||||
--
|
|
||||||
,*glacier_thickness_change: number
|
|
||||||
--
|
|
||||||
,*glacier_year: number <<FK>>
|
|
||||||
}
|
|
||||||
entity "Admin" as e04 {
|
|
||||||
,*admin_id : number <<generated>>
|
|
||||||
--
|
|
||||||
,*admin_creation_date: date
|
|
||||||
}
|
|
||||||
e01 ||..|{ e02
|
|
||||||
e02 ||..|| e03
|
|
||||||
e01 ||..|{ e03
|
|
||||||
e04 ||..o| e01
|
|
||||||
@enduml
|
|
||||||
#+end_src
|
|
||||||
|
|
||||||
#+RESULTS:
|
|
||||||
[[file:../Assets/Diagrams/ER.png]]
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
(TeX-add-style-hook
|
|
||||||
"Citations"
|
|
||||||
(lambda ()
|
|
||||||
(LaTeX-add-bibitems
|
|
||||||
"wgms-db"))
|
|
||||||
:bibtex)
|
|
||||||
|
|
||||||
16
Makefile
@@ -1,10 +1,10 @@
|
|||||||
## Source files
|
## Source files
|
||||||
## (Adjust to your needs. Order of markdown files in $(SRC) matters!)
|
## (Adjust to your needs. Order of markdown files in $(SRC) matters!)
|
||||||
PANDOC = pandoc
|
PANDOC = pandoc
|
||||||
DOC = Docs
|
DOC = docs
|
||||||
META = Assets/metadata.yaml
|
META = assets/metadata.yaml
|
||||||
SRC = $(DOC)/Project.md
|
SRC = $(DOC)/Project.md
|
||||||
BIBFILE = Assets/Citations.bib
|
BIBFILE = assets/Citations.bib
|
||||||
TARGET = $(DOC)/Project.pdf
|
TARGET = $(DOC)/Project.pdf
|
||||||
|
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@ TARGET = $(DOC)/Project.pdf
|
|||||||
## Auxiliary files
|
## Auxiliary files
|
||||||
## (Do not change!)
|
## (Do not change!)
|
||||||
TITLEPAGE = titlepage.tex
|
TITLEPAGE = titlepage.tex
|
||||||
TMP = Assets/$(TITLEPAGE:%.tex=__%.filled.tex)
|
TMP = assets/$(TITLEPAGE:%.tex=__%.filled.tex)
|
||||||
|
|
||||||
|
|
||||||
## Pandoc options
|
## Pandoc options
|
||||||
@@ -30,13 +30,13 @@ OPTIONS += --metadata-file=$(META)
|
|||||||
OPTIONS += -M bibliography=$(BIBFILE)
|
OPTIONS += -M bibliography=$(BIBFILE)
|
||||||
OPTIONS += --listings
|
OPTIONS += --listings
|
||||||
OPTIONS += --include-in-header=$(TMP)
|
OPTIONS += --include-in-header=$(TMP)
|
||||||
OPTIONS += --resource-path=./Assets/Diagrams
|
OPTIONS += --resource-path=./assets/Diagrams
|
||||||
|
|
||||||
|
|
||||||
## Template variables
|
## Template variables
|
||||||
TEMPLATE_DL_DIR = .tmp_template_dl
|
TEMPLATE_DL_DIR = .tmp_template_dl
|
||||||
|
|
||||||
CLEANTHESIS_TEMPLATE = Assets/cleanthesis.sty
|
CLEANTHESIS_TEMPLATE = assets/cleanthesis.sty
|
||||||
|
|
||||||
TEMPLATE_FILES = $(CLEANTHESIS_TEMPLATE)
|
TEMPLATE_FILES = $(CLEANTHESIS_TEMPLATE)
|
||||||
|
|
||||||
@@ -52,7 +52,7 @@ cleanthesis: TEMPLATE_FILE += $(CLEANTHESIS_TEMPLATE)
|
|||||||
cleanthesis: TEMPLATE_REPO += $(CLEANTHESIS_REPO)
|
cleanthesis: TEMPLATE_REPO += $(CLEANTHESIS_REPO)
|
||||||
cleanthesis: TEMPLATE_VERSION += $(CLEANTHESIS_VERSION)
|
cleanthesis: TEMPLATE_VERSION += $(CLEANTHESIS_VERSION)
|
||||||
cleanthesis: AUX_OPTS += -M cleanthesis=true -M cleanthesisbibfile=$(BIBFILE:%.bib=%)
|
cleanthesis: AUX_OPTS += -M cleanthesis=true -M cleanthesisbibfile=$(BIBFILE:%.bib=%)
|
||||||
cleanthesis: OPTIONS += --include-in-header=Assets/include-header.tex $(AUX_OPTS)
|
cleanthesis: OPTIONS += --include-in-header=assets/include-header.tex $(AUX_OPTS)
|
||||||
cleanthesis: $(CLEANTHESIS_TEMPLATE) $(TARGET)
|
cleanthesis: $(CLEANTHESIS_TEMPLATE) $(TARGET)
|
||||||
|
|
||||||
|
|
||||||
@@ -80,7 +80,7 @@ ${TARGET}: $(SRC) $(META) $(BIBFILE) $(TMP)
|
|||||||
|
|
||||||
|
|
||||||
## Build auxiliary files (title page, references)
|
## Build auxiliary files (title page, references)
|
||||||
$(TMP): Assets/__%.filled.tex: Assets/%.tex $(META)
|
$(TMP): assets/__%.filled.tex: assets/%.tex $(META)
|
||||||
$(PANDOC) $(AUX_OPTS) --template=$< --metadata-file=$(META) -o $@ $<
|
$(PANDOC) $(AUX_OPTS) --template=$< --metadata-file=$(META) -o $@ $<
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -6,9 +6,6 @@ verify_ssl = true
|
|||||||
[dev-packages]
|
[dev-packages]
|
||||||
|
|
||||||
[packages]
|
[packages]
|
||||||
flask = "*"
|
|
||||||
sqlalchemy = "*"
|
|
||||||
pymysql = "*"
|
|
||||||
|
|
||||||
[requires]
|
[requires]
|
||||||
python_version = "3.8"
|
python_version = "3.8"
|
||||||
75
README.md
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
IGDB: Internation Glacier Database
|
||||||
|
==================================
|
||||||
|
|
||||||
|
The IGDB is a database, that uses data from the
|
||||||
|
[WGMS](https://dx.doi.org/10.5904/wgms-fog-2019-12) to illustrate the
|
||||||
|
consequences of climate change.
|
||||||
|
|
||||||
|
Our system allows you to visualize data with tables and plots, via our
|
||||||
|
intuitive Web UI.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Technologies used
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
- Flask
|
||||||
|
- SQLAlchemy
|
||||||
|
- Pandas
|
||||||
|
|
||||||
|
Requirements
|
||||||
|
------------
|
||||||
|
|
||||||
|
- Python3
|
||||||
|
- POSIX shell
|
||||||
|
- Pip
|
||||||
|
- Pipenv
|
||||||
|
- MySQL/MariaDB
|
||||||
|
|
||||||
|
Installation
|
||||||
|
------------
|
||||||
|
|
||||||
|
1. Clone the repository:
|
||||||
|
|
||||||
|
``` bash
|
||||||
|
git clone https://coolneng.duckdns.org/gitea/coolneng/igdb
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Change the working directory to the project:
|
||||||
|
|
||||||
|
``` bash
|
||||||
|
cd igdb/code
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Install the dependencies:
|
||||||
|
|
||||||
|
``` bash
|
||||||
|
pipenv install
|
||||||
|
```
|
||||||
|
|
||||||
|
All the dependencies will be installed inside a virtualenv.
|
||||||
|
|
||||||
|
Usage
|
||||||
|
-----
|
||||||
|
|
||||||
|
1. Start a shell inside the virtualenv:
|
||||||
|
|
||||||
|
``` bash
|
||||||
|
pipenv shell
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Start the Flask server:
|
||||||
|
|
||||||
|
``` bash
|
||||||
|
flask run
|
||||||
|
```
|
||||||
|
|
||||||
|
3. When prompted for a password, insert your MySQL/MariaDB root
|
||||||
|
password
|
||||||
|
|
||||||
|
The database will be created and populated automatically, if needed,
|
||||||
|
each time the server is executed
|
||||||
|
|
||||||
|
4. The website can be accessed via **localhost:5000**
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
* IGDB: Internation Glacier Database
|
|
||||||
|
|
||||||
The IGDB is a database, that uses data from the [[http://dx.doi.org/10.5904/wgms-fog-2018-11][WGMS]] to illustrate the consequences of climate change.
|
|
||||||
8
assets/Citations.bib
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
@misc{wgms-db,
|
||||||
|
author = {World Glacier Monitoring Service (WGMS)},
|
||||||
|
title = {{Fluctuations of Glaciers Database}},
|
||||||
|
publisher = {World Glacier Monitoring Service (WGMS)},
|
||||||
|
year = 2019,
|
||||||
|
month = dec # "~2,",
|
||||||
|
doi = {10.5904/wgms-fog-2019-12}
|
||||||
|
}
|
||||||
BIN
assets/Diagrams/BB.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 7.2 KiB |
|
Before Width: | Height: | Size: 9.9 KiB After Width: | Height: | Size: 9.9 KiB |
|
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 7.6 KiB |
|
Before Width: | Height: | Size: 9.9 KiB After Width: | Height: | Size: 9.9 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
BIN
assets/Diagrams/ER.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
54
assets/__titlepage.filled.tex
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
|
||||||
|
%------------------------------------- Custom Title Page ---------------------------
|
||||||
|
\renewcommand{\maketitle}{
|
||||||
|
\thispagestyle{empty}
|
||||||
|
|
||||||
|
\parindent=0pt
|
||||||
|
|
||||||
|
\vspace{20mm}
|
||||||
|
\hrule
|
||||||
|
\vspace{5mm}
|
||||||
|
|
||||||
|
\begin{center}
|
||||||
|
\LARGE
|
||||||
|
\textbf{\textsc{ IGDB: Base de datos internacional de glaciares }}
|
||||||
|
\end{center}
|
||||||
|
|
||||||
|
\vspace{5mm}
|
||||||
|
\hrule
|
||||||
|
\vspace{10mm}
|
||||||
|
|
||||||
|
\begin{center}
|
||||||
|
\Large
|
||||||
|
\textsc{ Diseño y Desarrollo de Sistemas de Información }
|
||||||
|
\end{center}
|
||||||
|
|
||||||
|
\vfill
|
||||||
|
|
||||||
|
\noindent
|
||||||
|
\includegraphics[width=120pt, center]{/home/coolneng/Photos/Logos/UGR.png}
|
||||||
|
|
||||||
|
\vspace{\baselineskip}\noindent
|
||||||
|
\large
|
||||||
|
\begin{tabular}{lp{\textwidth}}
|
||||||
|
Autor: & \texttt{Amin Kasrou Aouam}\\
|
||||||
|
Fecha: & \texttt{10/01/2020}\\
|
||||||
|
&\\[24pt]
|
||||||
|
\end{tabular}
|
||||||
|
}
|
||||||
|
%------------------------------------- Custom Title Page ---------------------------
|
||||||
|
|
||||||
|
|
||||||
|
\usepackage[export]{adjustbox}
|
||||||
|
\usepackage{graphicx}
|
||||||
|
|
||||||
|
%------------------------------------- Workaround for CleanStyle -------------------
|
||||||
|
%% cleanthesis.sty *will* check the bibfile, even if `configurebiblatex=false` ...
|
||||||
|
%% So we need to set it appropriately using our metadata variable "cleanthesisbibfile"
|
||||||
|
\PassOptionsToPackage{
|
||||||
|
figuresep=colon,
|
||||||
|
configurelistings=true,
|
||||||
|
configurebiblatex=false,
|
||||||
|
bibfile=assets/Citations
|
||||||
|
}{cleanthesis}
|
||||||
|
%------------------------------------- Workaround for CleanStyle -------------------
|
||||||
@@ -2,8 +2,8 @@
|
|||||||
title: "IGDB: Base de datos internacional de glaciares"
|
title: "IGDB: Base de datos internacional de glaciares"
|
||||||
subtitle: "Diseño y Desarrollo de Sistemas de Información"
|
subtitle: "Diseño y Desarrollo de Sistemas de Información"
|
||||||
author: [Amin Kasrou Aouam]
|
author: [Amin Kasrou Aouam]
|
||||||
date: 18/10/2019
|
date: 10/01/2020
|
||||||
logo: /home/coolneng/Pictures/Logos/UGR.png
|
logo: /home/coolneng/Photos/Logos/UGR.png
|
||||||
lang: es-ES
|
lang: es-ES
|
||||||
toc: true
|
toc: true
|
||||||
toc-own-page: true
|
toc-own-page: true
|
||||||
BIN
assets/screenshots/Plot.png
Normal file
|
After Width: | Height: | Size: 46 KiB |
BIN
assets/screenshots/Table.png
Normal file
|
After Width: | Height: | Size: 53 KiB |
20
code/Pipfile
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
[[source]]
|
||||||
|
name = "pypi"
|
||||||
|
url = "https://pypi.org/simple"
|
||||||
|
verify_ssl = true
|
||||||
|
|
||||||
|
[dev-packages]
|
||||||
|
|
||||||
|
[packages]
|
||||||
|
flask = "*"
|
||||||
|
pymysql = "*"
|
||||||
|
flask-sqlalchemy = "*"
|
||||||
|
pandas = "*"
|
||||||
|
iso3166 = "*"
|
||||||
|
flask-wtf = "*"
|
||||||
|
flask-login = "*"
|
||||||
|
flask-bootstrap = "*"
|
||||||
|
matplotlib = "*"
|
||||||
|
|
||||||
|
[requires]
|
||||||
|
python_version = "3.8"
|
||||||
309
code/Pipfile.lock
generated
Normal file
@@ -0,0 +1,309 @@
|
|||||||
|
{
|
||||||
|
"_meta": {
|
||||||
|
"hash": {
|
||||||
|
"sha256": "80f6c409aa1104974ff405c48d5527140030fb7e8d6bbf8aa21e884b3d151b5a"
|
||||||
|
},
|
||||||
|
"pipfile-spec": 6,
|
||||||
|
"requires": {
|
||||||
|
"python_version": "3.8"
|
||||||
|
},
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"name": "pypi",
|
||||||
|
"url": "https://pypi.org/simple",
|
||||||
|
"verify_ssl": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"click": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13",
|
||||||
|
"sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7"
|
||||||
|
],
|
||||||
|
"version": "==7.0"
|
||||||
|
},
|
||||||
|
"cycler": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:1d8a5ae1ff6c5cf9b93e8811e581232ad8920aeec647c37316ceac982b08cb2d",
|
||||||
|
"sha256:cd7b2d1018258d7247a71425e9f26463dfb444d411c39569972f4ce586b0c9d8"
|
||||||
|
],
|
||||||
|
"version": "==0.10.0"
|
||||||
|
},
|
||||||
|
"dominate": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:6e833aea505f0236a9fc692326bac575f8bd38ae0f3a1bdc73d20ca606ac75d5",
|
||||||
|
"sha256:a92474b4312bd8b4c1789792f3ec8c571cd8afa8e7502a2b1c64dd48cd67e59c"
|
||||||
|
],
|
||||||
|
"version": "==2.4.0"
|
||||||
|
},
|
||||||
|
"flask": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:13f9f196f330c7c2c5d7a5cf91af894110ca0215ac051b5844701f2bfd934d52",
|
||||||
|
"sha256:45eb5a6fd193d6cf7e0cf5d8a5b31f83d5faae0293695626f539a823e93b13f6"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==1.1.1"
|
||||||
|
},
|
||||||
|
"flask-bootstrap": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:cb08ed940183f6343a64e465e83b3a3f13c53e1baabb8d72b5da4545ef123ac8"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==3.3.7.1"
|
||||||
|
},
|
||||||
|
"flask-login": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:c815c1ac7b3e35e2081685e389a665f2c74d7e077cb93cecabaea352da4752ec"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==0.4.1"
|
||||||
|
},
|
||||||
|
"flask-sqlalchemy": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:0078d8663330dc05a74bc72b3b6ddc441b9a744e2f56fe60af1a5bfc81334327",
|
||||||
|
"sha256:6974785d913666587949f7c2946f7001e4fa2cb2d19f4e69ead02e4b8f50b33d"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==2.4.1"
|
||||||
|
},
|
||||||
|
"flask-wtf": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:5d14d55cfd35f613d99ee7cba0fc3fbbe63ba02f544d349158c14ca15561cc36",
|
||||||
|
"sha256:d9a9e366b32dcbb98ef17228e76be15702cd2600675668bca23f63a7947fd5ac"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==0.14.2"
|
||||||
|
},
|
||||||
|
"iso3166": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:b07208703bd881a4f974e39fa013c4498dddd64913ada15f24be75d02ae68a44",
|
||||||
|
"sha256:b1e58dbcf50fbb2c9c418ec7a6057f0cdb30b8f822ac852f72e71ba769dae8c5"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==1.0.1"
|
||||||
|
},
|
||||||
|
"itsdangerous": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19",
|
||||||
|
"sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749"
|
||||||
|
],
|
||||||
|
"version": "==1.1.0"
|
||||||
|
},
|
||||||
|
"jinja2": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:74320bb91f31270f9551d46522e33af46a80c3d619f4a4bf42b3164d30b5911f",
|
||||||
|
"sha256:9fe95f19286cfefaa917656583d020be14e7859c6b0252588391e47db34527de"
|
||||||
|
],
|
||||||
|
"version": "==2.10.3"
|
||||||
|
},
|
||||||
|
"kiwisolver": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:05b5b061e09f60f56244adc885c4a7867da25ca387376b02c1efc29cc16bcd0f",
|
||||||
|
"sha256:210d8c39d01758d76c2b9a693567e1657ec661229bc32eac30761fa79b2474b0",
|
||||||
|
"sha256:26f4fbd6f5e1dabff70a9ba0d2c4bd30761086454aa30dddc5b52764ee4852b7",
|
||||||
|
"sha256:3b15d56a9cd40c52d7ab763ff0bc700edbb4e1a298dc43715ecccd605002cf11",
|
||||||
|
"sha256:3b2378ad387f49cbb328205bda569b9f87288d6bc1bf4cd683c34523a2341efe",
|
||||||
|
"sha256:400599c0fe58d21522cae0e8b22318e09d9729451b17ee61ba8e1e7c0346565c",
|
||||||
|
"sha256:47b8cb81a7d18dbaf4fed6a61c3cecdb5adec7b4ac292bddb0d016d57e8507d5",
|
||||||
|
"sha256:53eaed412477c836e1b9522c19858a8557d6e595077830146182225613b11a75",
|
||||||
|
"sha256:58e626e1f7dfbb620d08d457325a4cdac65d1809680009f46bf41eaf74ad0187",
|
||||||
|
"sha256:5a52e1b006bfa5be04fe4debbcdd2688432a9af4b207a3f429c74ad625022641",
|
||||||
|
"sha256:5c7ca4e449ac9f99b3b9d4693debb1d6d237d1542dd6a56b3305fe8a9620f883",
|
||||||
|
"sha256:682e54f0ce8f45981878756d7203fd01e188cc6c8b2c5e2cf03675390b4534d5",
|
||||||
|
"sha256:76275ee077772c8dde04fb6c5bc24b91af1bb3e7f4816fd1852f1495a64dad93",
|
||||||
|
"sha256:79bfb2f0bd7cbf9ea256612c9523367e5ec51d7cd616ae20ca2c90f575d839a2",
|
||||||
|
"sha256:7f4dd50874177d2bb060d74769210f3bce1af87a8c7cf5b37d032ebf94f0aca3",
|
||||||
|
"sha256:8944a16020c07b682df861207b7e0efcd2f46c7488619cb55f65882279119389",
|
||||||
|
"sha256:8aa7009437640beb2768bfd06da049bad0df85f47ff18426261acecd1cf00897",
|
||||||
|
"sha256:9105ce82dcc32c73eb53a04c869b6a4bc756b43e4385f76ea7943e827f529e4d",
|
||||||
|
"sha256:933df612c453928f1c6faa9236161a1d999a26cd40abf1dc5d7ebbc6dbfb8fca",
|
||||||
|
"sha256:939f36f21a8c571686eb491acfffa9c7f1ac345087281b412d63ea39ca14ec4a",
|
||||||
|
"sha256:9491578147849b93e70d7c1d23cb1229458f71fc79c51d52dce0809b2ca44eea",
|
||||||
|
"sha256:9733b7f64bd9f807832d673355f79703f81f0b3e52bfce420fc00d8cb28c6a6c",
|
||||||
|
"sha256:a02f6c3e229d0b7220bd74600e9351e18bc0c361b05f29adae0d10599ae0e326",
|
||||||
|
"sha256:a0c0a9f06872330d0dd31b45607197caab3c22777600e88031bfe66799e70bb0",
|
||||||
|
"sha256:aa716b9122307c50686356cfb47bfbc66541868078d0c801341df31dca1232a9",
|
||||||
|
"sha256:acc4df99308111585121db217681f1ce0eecb48d3a828a2f9bbf9773f4937e9e",
|
||||||
|
"sha256:b64916959e4ae0ac78af7c3e8cef4becee0c0e9694ad477b4c6b3a536de6a544",
|
||||||
|
"sha256:d22702cadb86b6fcba0e6b907d9f84a312db9cd6934ee728144ce3018e715ee1",
|
||||||
|
"sha256:d3fcf0819dc3fea58be1fd1ca390851bdb719a549850e708ed858503ff25d995",
|
||||||
|
"sha256:d52e3b1868a4e8fd18b5cb15055c76820df514e26aa84cc02f593d99fef6707f",
|
||||||
|
"sha256:db1a5d3cc4ae943d674718d6c47d2d82488ddd94b93b9e12d24aabdbfe48caee",
|
||||||
|
"sha256:e3a21a720791712ed721c7b95d433e036134de6f18c77dbe96119eaf7aa08004",
|
||||||
|
"sha256:e8bf074363ce2babeb4764d94f8e65efd22e6a7c74860a4f05a6947afc020ff2",
|
||||||
|
"sha256:f16814a4a96dc04bf1da7d53ee8d5b1d6decfc1a92a63349bb15d37b6a263dd9",
|
||||||
|
"sha256:f2b22153870ca5cf2ab9c940d7bc38e8e9089fa0f7e5856ea195e1cf4ff43d5a",
|
||||||
|
"sha256:f790f8b3dff3d53453de6a7b7ddd173d2e020fb160baff578d578065b108a05f",
|
||||||
|
"sha256:fe51b79da0062f8e9d49ed0182a626a7dc7a0cbca0328f612c6ee5e4711c81e4"
|
||||||
|
],
|
||||||
|
"version": "==1.1.0"
|
||||||
|
},
|
||||||
|
"markupsafe": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473",
|
||||||
|
"sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161",
|
||||||
|
"sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235",
|
||||||
|
"sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5",
|
||||||
|
"sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff",
|
||||||
|
"sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b",
|
||||||
|
"sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1",
|
||||||
|
"sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e",
|
||||||
|
"sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183",
|
||||||
|
"sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66",
|
||||||
|
"sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1",
|
||||||
|
"sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1",
|
||||||
|
"sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e",
|
||||||
|
"sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b",
|
||||||
|
"sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905",
|
||||||
|
"sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735",
|
||||||
|
"sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d",
|
||||||
|
"sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e",
|
||||||
|
"sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d",
|
||||||
|
"sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c",
|
||||||
|
"sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21",
|
||||||
|
"sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2",
|
||||||
|
"sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5",
|
||||||
|
"sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b",
|
||||||
|
"sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6",
|
||||||
|
"sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f",
|
||||||
|
"sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f",
|
||||||
|
"sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7"
|
||||||
|
],
|
||||||
|
"version": "==1.1.1"
|
||||||
|
},
|
||||||
|
"matplotlib": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:08ccc8922eb4792b91c652d3e6d46b1c99073f1284d1b6705155643e8046463a",
|
||||||
|
"sha256:161dcd807c0c3232f4dcd4a12a382d52004a498174cbfafd40646106c5bcdcc8",
|
||||||
|
"sha256:1f9e885bfa1b148d16f82a6672d043ecf11197f6c71ae222d0546db706e52eb2",
|
||||||
|
"sha256:2d6ab54015a7c0d727c33e36f85f5c5e4172059efdd067f7527f6e5d16ad01aa",
|
||||||
|
"sha256:5d2e408a2813abf664bd79431107543ecb449136912eb55bb312317edecf597e",
|
||||||
|
"sha256:61c8b740a008218eb604de518eb411c4953db0cb725dd0b32adf8a81771cab9e",
|
||||||
|
"sha256:80f10af8378fccc136da40ea6aa4a920767476cdfb3241acb93ef4f0465dbf57",
|
||||||
|
"sha256:819d4860315468b482f38f1afe45a5437f60f03eaede495d5ff89f2eeac89500",
|
||||||
|
"sha256:8cc0e44905c2c8fda5637cad6f311eb9517017515a034247ab93d0cf99f8bb7a",
|
||||||
|
"sha256:8e8e2c2fe3d873108735c6ee9884e6f36f467df4a143136209cff303b183bada",
|
||||||
|
"sha256:98c2ffeab8b79a4e3a0af5dd9939f92980eb6e3fec10f7f313df5f35a84dacab",
|
||||||
|
"sha256:d59bb0e82002ac49f4152963f8a1079e66794a4f454457fd2f0dcc7bf0797d30",
|
||||||
|
"sha256:ee59b7bb9eb75932fe3787e54e61c99b628155b0cedc907864f24723ba55b309"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==3.1.2"
|
||||||
|
},
|
||||||
|
"numpy": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:1786a08236f2c92ae0e70423c45e1e62788ed33028f94ca99c4df03f5be6b3c6",
|
||||||
|
"sha256:17aa7a81fe7599a10f2b7d95856dc5cf84a4eefa45bc96123cbbc3ebc568994e",
|
||||||
|
"sha256:20b26aaa5b3da029942cdcce719b363dbe58696ad182aff0e5dcb1687ec946dc",
|
||||||
|
"sha256:2d75908ab3ced4223ccba595b48e538afa5ecc37405923d1fea6906d7c3a50bc",
|
||||||
|
"sha256:39d2c685af15d3ce682c99ce5925cc66efc824652e10990d2462dfe9b8918c6a",
|
||||||
|
"sha256:56bc8ded6fcd9adea90f65377438f9fea8c05fcf7c5ba766bef258d0da1554aa",
|
||||||
|
"sha256:590355aeade1a2eaba17617c19edccb7db8d78760175256e3cf94590a1a964f3",
|
||||||
|
"sha256:70a840a26f4e61defa7bdf811d7498a284ced303dfbc35acb7be12a39b2aa121",
|
||||||
|
"sha256:77c3bfe65d8560487052ad55c6998a04b654c2fbc36d546aef2b2e511e760971",
|
||||||
|
"sha256:9537eecf179f566fd1c160a2e912ca0b8e02d773af0a7a1120ad4f7507cd0d26",
|
||||||
|
"sha256:9acdf933c1fd263c513a2df3dceecea6f3ff4419d80bf238510976bf9bcb26cd",
|
||||||
|
"sha256:ae0975f42ab1f28364dcda3dde3cf6c1ddab3e1d4b2909da0cb0191fa9ca0480",
|
||||||
|
"sha256:b3af02ecc999c8003e538e60c89a2b37646b39b688d4e44d7373e11c2debabec",
|
||||||
|
"sha256:b6ff59cee96b454516e47e7721098e6ceebef435e3e21ac2d6c3b8b02628eb77",
|
||||||
|
"sha256:b765ed3930b92812aa698a455847141869ef755a87e099fddd4ccf9d81fffb57",
|
||||||
|
"sha256:c98c5ffd7d41611407a1103ae11c8b634ad6a43606eca3e2a5a269e5d6e8eb07",
|
||||||
|
"sha256:cf7eb6b1025d3e169989416b1adcd676624c2dbed9e3bcb7137f51bfc8cc2572",
|
||||||
|
"sha256:d92350c22b150c1cae7ebb0ee8b5670cc84848f6359cf6b5d8f86617098a9b73",
|
||||||
|
"sha256:e422c3152921cece8b6a2fb6b0b4d73b6579bd20ae075e7d15143e711f3ca2ca",
|
||||||
|
"sha256:e840f552a509e3380b0f0ec977e8124d0dc34dc0e68289ca28f4d7c1d0d79474",
|
||||||
|
"sha256:f3d0a94ad151870978fb93538e95411c83899c9dc63e6fb65542f769568ecfa5"
|
||||||
|
],
|
||||||
|
"version": "==1.18.1"
|
||||||
|
},
|
||||||
|
"pandas": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:00dff3a8e337f5ed7ad295d98a31821d3d0fe7792da82d78d7fd79b89c03ea9d",
|
||||||
|
"sha256:22361b1597c8c2ffd697aa9bf85423afa9e1fcfa6b1ea821054a244d5f24d75e",
|
||||||
|
"sha256:255920e63850dc512ce356233081098554d641ba99c3767dde9e9f35630f994b",
|
||||||
|
"sha256:26382aab9c119735908d94d2c5c08020a4a0a82969b7e5eefb92f902b3b30ad7",
|
||||||
|
"sha256:33970f4cacdd9a0ddb8f21e151bfb9f178afb7c36eb7c25b9094c02876f385c2",
|
||||||
|
"sha256:4545467a637e0e1393f7d05d61dace89689ad6d6f66f267f86fff737b702cce9",
|
||||||
|
"sha256:52da74df8a9c9a103af0a72c9d5fdc8e0183a90884278db7f386b5692a2220a4",
|
||||||
|
"sha256:61741f5aeb252f39c3031d11405305b6d10ce663c53bc3112705d7ad66c013d0",
|
||||||
|
"sha256:6a3ac2c87e4e32a969921d1428525f09462770c349147aa8e9ab95f88c71ec71",
|
||||||
|
"sha256:7458c48e3d15b8aaa7d575be60e1e4dd70348efcd9376656b72fecd55c59a4c3",
|
||||||
|
"sha256:78bf638993219311377ce9836b3dc05f627a666d0dbc8cec37c0ff3c9ada673b",
|
||||||
|
"sha256:8153705d6545fd9eb6dd2bc79301bff08825d2e2f716d5dced48daafc2d0b81f",
|
||||||
|
"sha256:975c461accd14e89d71772e89108a050fa824c0b87a67d34cedf245f6681fc17",
|
||||||
|
"sha256:9962957a27bfb70ab64103d0a7b42fa59c642fb4ed4cb75d0227b7bb9228535d",
|
||||||
|
"sha256:adc3d3a3f9e59a38d923e90e20c4922fc62d1e5a03d083440468c6d8f3f1ae0a",
|
||||||
|
"sha256:bbe3eb765a0b1e578833d243e2814b60c825b7fdbf4cdfe8e8aae8a08ed56ecf",
|
||||||
|
"sha256:df8864824b1fe488cf778c3650ee59c3a0d8f42e53707de167ba6b4f7d35f133",
|
||||||
|
"sha256:e45055c30a608076e31a9fcd780a956ed3b1fa20db61561b8d88b79259f526f7",
|
||||||
|
"sha256:ee50c2142cdcf41995655d499a157d0a812fce55c97d9aad13bc1eef837ed36c"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==0.25.3"
|
||||||
|
},
|
||||||
|
"pymysql": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:3943fbbbc1e902f41daf7f9165519f140c4451c179380677e6a848587042561a",
|
||||||
|
"sha256:d8c059dcd81dedb85a9f034d5e22dcb4442c0b201908bede99e306d65ea7c8e7"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==0.9.3"
|
||||||
|
},
|
||||||
|
"pyparsing": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:4c830582a84fb022400b85429791bc551f1f4871c33f23e44f353119e92f969f",
|
||||||
|
"sha256:c342dccb5250c08d45fd6f8b4a559613ca603b57498511740e65cd11a2e7dcec"
|
||||||
|
],
|
||||||
|
"version": "==2.4.6"
|
||||||
|
},
|
||||||
|
"python-dateutil": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c",
|
||||||
|
"sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"
|
||||||
|
],
|
||||||
|
"version": "==2.8.1"
|
||||||
|
},
|
||||||
|
"pytz": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:1c557d7d0e871de1f5ccd5833f60fb2550652da6be2693c1e02300743d21500d",
|
||||||
|
"sha256:b02c06db6cf09c12dd25137e563b31700d3b80fcc4ad23abb7a315f2789819be"
|
||||||
|
],
|
||||||
|
"version": "==2019.3"
|
||||||
|
},
|
||||||
|
"six": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:1f1b7d42e254082a9db6279deae68afb421ceba6158efa6131de7b3003ee93fd",
|
||||||
|
"sha256:30f610279e8b2578cab6db20741130331735c781b56053c59c4076da27f06b66"
|
||||||
|
],
|
||||||
|
"version": "==1.13.0"
|
||||||
|
},
|
||||||
|
"sqlalchemy": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:bfb8f464a5000b567ac1d350b9090cf081180ec1ab4aa87e7bca12dab25320ec"
|
||||||
|
],
|
||||||
|
"version": "==1.3.12"
|
||||||
|
},
|
||||||
|
"visitor": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:2c737903b2b6864ebc6167eef7cf3b997126f1aa94bdf590f90f1436d23e480a"
|
||||||
|
],
|
||||||
|
"version": "==0.1.3"
|
||||||
|
},
|
||||||
|
"werkzeug": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:7280924747b5733b246fe23972186c6b348f9ae29724135a6dfc1e53cea433e7",
|
||||||
|
"sha256:e5f4a1f98b52b18a93da705a7458e55afb26f32bff83ff5d19189f92462d65c4"
|
||||||
|
],
|
||||||
|
"version": "==0.16.0"
|
||||||
|
},
|
||||||
|
"wtforms": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:0cdbac3e7f6878086c334aa25dc5a33869a3954e9d1e015130d65a69309b3b61",
|
||||||
|
"sha256:e3ee092c827582c50877cdbd49e9ce6d2c5c1f6561f849b3b068c1b8029626f1"
|
||||||
|
],
|
||||||
|
"version": "==2.2.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"develop": {}
|
||||||
|
}
|
||||||
14
code/app/__init__.py
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
from flask import Flask
|
||||||
|
from config import Config
|
||||||
|
from flask_sqlalchemy import SQLAlchemy
|
||||||
|
from flask_login import LoginManager
|
||||||
|
from flask_bootstrap import Bootstrap
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
app.config.from_object(Config)
|
||||||
|
db = SQLAlchemy(app)
|
||||||
|
login = LoginManager(app)
|
||||||
|
login.login_view = "login"
|
||||||
|
bootstrap = Bootstrap(app)
|
||||||
|
|
||||||
|
from app import routes, models, errors
|
||||||
13
code/app/errors.py
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
from flask import render_template
|
||||||
|
from app import app, db
|
||||||
|
|
||||||
|
|
||||||
|
@app.errorhandler(404)
|
||||||
|
def not_found_error(error):
|
||||||
|
return render_template("404.html"), 404
|
||||||
|
|
||||||
|
|
||||||
|
@app.errorhandler(500)
|
||||||
|
def internal_error(error):
|
||||||
|
db.session.rollback()
|
||||||
|
return render_template("500.html"), 500
|
||||||
31
code/app/forms.py
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
from flask_wtf import FlaskForm
|
||||||
|
from wtforms import BooleanField, PasswordField, SelectField, StringField, SubmitField
|
||||||
|
from wtforms.validators import DataRequired
|
||||||
|
|
||||||
|
|
||||||
|
class LoginForm(FlaskForm):
|
||||||
|
username = StringField("Username", validators=[DataRequired()])
|
||||||
|
password = PasswordField("Password", validators=[DataRequired()])
|
||||||
|
remember_me = BooleanField("Remember Me")
|
||||||
|
submit = SubmitField("Sign In")
|
||||||
|
|
||||||
|
|
||||||
|
class AnnualForm(FlaskForm):
|
||||||
|
year_list = [
|
||||||
|
("2011", 2011),
|
||||||
|
("2012", 2012),
|
||||||
|
("2013", 2013),
|
||||||
|
("2014", 2014),
|
||||||
|
("2015", 2015),
|
||||||
|
("2016", 2016),
|
||||||
|
("2017", 2017),
|
||||||
|
("2018", 2018),
|
||||||
|
]
|
||||||
|
name = StringField("Search by Glacier Name")
|
||||||
|
year = SelectField("Search by Year", validators=[DataRequired()], choices=year_list)
|
||||||
|
submit = SubmitField("Search")
|
||||||
|
|
||||||
|
|
||||||
|
class PlotForm(FlaskForm):
|
||||||
|
name = StringField("Glacier Name", validators=[DataRequired()])
|
||||||
|
submit = SubmitField("Search")
|
||||||
51
code/app/models.py
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
from app import db, login
|
||||||
|
from flask_login import UserMixin
|
||||||
|
from werkzeug.security import check_password_hash
|
||||||
|
|
||||||
|
|
||||||
|
class Glacier(db.Model):
|
||||||
|
id = db.Column(db.String(20), primary_key=True)
|
||||||
|
country = db.Column(db.String(60))
|
||||||
|
name = db.Column(db.String(60))
|
||||||
|
annual_data = db.relationship("Annual_Data")
|
||||||
|
|
||||||
|
def __init__(self, id, country, name):
|
||||||
|
self.id = id
|
||||||
|
self.country = country
|
||||||
|
self.name = name
|
||||||
|
|
||||||
|
|
||||||
|
class Annual_Data(db.Model):
|
||||||
|
__tablename__ = "annual_data"
|
||||||
|
year = db.Column(db.Integer, primary_key=True)
|
||||||
|
id = db.Column(db.ForeignKey("glacier.id"), primary_key=True)
|
||||||
|
surface = db.Column(db.Float)
|
||||||
|
length = db.Column(db.Float)
|
||||||
|
elevation = db.Column(db.Float)
|
||||||
|
|
||||||
|
def __init__(self, year, surface, length, elevation):
|
||||||
|
self.year = year
|
||||||
|
self.surface = surface
|
||||||
|
self.length = length
|
||||||
|
self.elevation = elevation
|
||||||
|
|
||||||
|
|
||||||
|
class User(UserMixin, db.Model):
|
||||||
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
|
registration_date = db.Column(
|
||||||
|
db.DateTime, nullable=False, server_default=db.func.now()
|
||||||
|
)
|
||||||
|
username = db.Column(db.String(20), nullable=False, unique=True)
|
||||||
|
password_hash = db.Column(db.String(128), unique=True)
|
||||||
|
|
||||||
|
def __init__(self, id, username, password_hash):
|
||||||
|
self.id = id
|
||||||
|
self.username = username
|
||||||
|
self.password_hash = password_hash
|
||||||
|
|
||||||
|
def check_password(self, password):
|
||||||
|
return check_password_hash(self.password_hash, password)
|
||||||
|
|
||||||
|
@login.user_loader
|
||||||
|
def load_user(id):
|
||||||
|
return User.query.get(int(id))
|
||||||
90
code/app/routes.py
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
from app import app
|
||||||
|
from app.forms import AnnualForm, LoginForm, PlotForm
|
||||||
|
from database.queries import query_annual_data, query_plot_data, query_user
|
||||||
|
from flask import flash, redirect, render_template, request, url_for, send_file
|
||||||
|
from flask_login import current_user, login_required, login_user, logout_user
|
||||||
|
from processing.dataframe import create_table, create_plot
|
||||||
|
from werkzeug.urls import url_parse
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/")
|
||||||
|
@app.route("/index")
|
||||||
|
def index():
|
||||||
|
return render_template("index.html", title="Home Page")
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/login", methods=["GET", "POST"])
|
||||||
|
def login():
|
||||||
|
if current_user.is_authenticated:
|
||||||
|
return redirect(url_for("admin"))
|
||||||
|
form = LoginForm()
|
||||||
|
if form.validate_on_submit():
|
||||||
|
user = query_user(form)
|
||||||
|
if user is None or not user.check_password(form.password.data):
|
||||||
|
flash("Invalid username or password")
|
||||||
|
return redirect(url_for("login"))
|
||||||
|
login_user(user, remember=form.remember_me.data)
|
||||||
|
next_page = request.args.get("next")
|
||||||
|
if not next_page or url_parse(next_page).netloc != "":
|
||||||
|
next_page = url_for("admin")
|
||||||
|
return redirect(next_page)
|
||||||
|
return render_template("login.html", title="Sign In", form=form)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/logout")
|
||||||
|
def logout():
|
||||||
|
logout_user()
|
||||||
|
return redirect(url_for("index"))
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/admin")
|
||||||
|
@login_required
|
||||||
|
def admin():
|
||||||
|
return render_template("admin.html", title="Admin Page")
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/nuke")
|
||||||
|
@login_required
|
||||||
|
def nuke():
|
||||||
|
return render_template("nuked.html", title="NUKE THE SYSTEM!")
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/data")
|
||||||
|
def data():
|
||||||
|
return render_template("data.html", title="Data")
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/table_selection", methods=["GET", "POST"])
|
||||||
|
def table_selection():
|
||||||
|
form = AnnualForm()
|
||||||
|
if form.validate_on_submit():
|
||||||
|
query = query_annual_data(form)
|
||||||
|
table = create_table(query.statement)
|
||||||
|
return render_template("table.html", table=table, title="Table")
|
||||||
|
return render_template("table_selection.html", title="Data", form=form)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/table")
|
||||||
|
def table():
|
||||||
|
return render_template("table.html", table=table, title="Table")
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/plot_selection", methods=["GET", "POST"])
|
||||||
|
def plot_selection():
|
||||||
|
form = PlotForm()
|
||||||
|
if form.validate_on_submit():
|
||||||
|
query = query_plot_data(form)
|
||||||
|
plot = create_plot(query.statement)
|
||||||
|
return render_template("plot.html", title="Plot", plot=plot)
|
||||||
|
return render_template("plot_selection.html", title="Data", form=form)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/plot")
|
||||||
|
def plot():
|
||||||
|
return render_template("plot.html", title="Plot", plot=plot)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/figure")
|
||||||
|
def figure(query):
|
||||||
|
fig = create_plot(query)
|
||||||
|
return send_file(fig, mimetype="image/png")
|
||||||
12
code/app/static/bootstrap.min.css
vendored
Normal file
BIN
code/app/static/plot.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
6
code/app/templates/404.html
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block app_content %}
|
||||||
|
<h1>Sorry, we couldn't find that</h1>
|
||||||
|
<p><a href="{{ url_for('index') }}">Back</a></p>
|
||||||
|
{% endblock %}
|
||||||
8
code/app/templates/500.html
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block app_content %}
|
||||||
|
<h1>An unexpected error has occurred</h1>
|
||||||
|
<p>The administrator has been notified!</p>
|
||||||
|
<p>If he gets too many notifications, we might replace him with an AI</p>
|
||||||
|
<p><a href="{{ url_for('index') }}">Back</a></p>
|
||||||
|
{% endblock %}
|
||||||
16
code/app/templates/admin.html
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h1 class="text-center">Hey, {{ current_user.username }}!</h1>
|
||||||
|
<p class="text-center">Do you want to nuke the database?</p>
|
||||||
|
<li>
|
||||||
|
<p class="text-center">
|
||||||
|
<a href="{{ url_for('nuke') }}"><b>Yes</b>, I want to burn down the world</a>
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<p class="text-center">
|
||||||
|
Nah, show me some cool <a href="{{ url_for('data') }}">data</a>
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
{% endblock %}
|
||||||
55
code/app/templates/base.html
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
{% extends 'bootstrap/base.html' %}
|
||||||
|
|
||||||
|
{% block title %}
|
||||||
|
{% if title %}{{ title }} - IGDB{% else %}IGDB{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block styles %}
|
||||||
|
<link rel="stylesheet"
|
||||||
|
href="{{url_for('.static', filename='bootstrap.min.css')}}">
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block navbar %}
|
||||||
|
<nav class="navbar navbar-expand-lg navbar-dark bg-primary">
|
||||||
|
<a class="navbar-brand" href="{{ url_for('index') }}">IGDB</a>
|
||||||
|
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarColor01" aria-controls="navbarColor01" aria-expanded="false" aria-label="Toggle navigation">
|
||||||
|
<span class="navbar-toggler-icon"></span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div class="collapse navbar-collapse" id="navbarColor01">
|
||||||
|
<ul class="navbar-nav mr-auto">
|
||||||
|
<li class="nav-item active">
|
||||||
|
<a class="nav-link" href="{{ url_for('index') }}">Home <span class="sr-only">(current)</span></a>
|
||||||
|
</li>
|
||||||
|
{% if current_user.is_anonymous %}
|
||||||
|
<li class="nav-link"><a href="{{ url_for('data') }}">Data</a></li>
|
||||||
|
{% else %}
|
||||||
|
<li class="nav-link"><a href="{{ url_for('data') }}">Data</a></li>
|
||||||
|
<li class="nav-link"><a href="{{ url_for('admin') }}">Administration</a></li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
<ul class="navbar-nav navbar-right">
|
||||||
|
{% if current_user.is_anonymous %}
|
||||||
|
<li class="nav-link"><a href="{{ url_for('login') }}">Login</a></li>
|
||||||
|
{% else %}
|
||||||
|
<li class="nav-item"><a href="{{ url_for('logout') }}">Logout</a></li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="container">
|
||||||
|
{% with messages = get_flashed_messages() %}
|
||||||
|
{% if messages %}
|
||||||
|
{% for message in messages %}
|
||||||
|
<div class="alert alert-info" role="alert">{{ message }}</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% endwith %}
|
||||||
|
|
||||||
|
{# application content needs to be provided in the app_content block #}
|
||||||
|
{% block app_content %}{% endblock %}
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
15
code/app/templates/data.html
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h1 class="text-center">What do you want to check out?</h1>
|
||||||
|
<li>
|
||||||
|
<p class="text-center">
|
||||||
|
<a href="{{ url_for('table_selection') }}" class="btn btn-success" role="button" aria-pressed="true">Tables</a>
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<p class="text-center">
|
||||||
|
<a href="{{ url_for('plot_selection') }}" class="btn btn-success" role="button" aria-pressed="true">Plots</a>
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
{% endblock %}
|
||||||
9
code/app/templates/index.html
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="jumbotron">
|
||||||
|
<h1 id="igdb-internation-glacier-database">IGDB: Internation Glacier Database</h1>
|
||||||
|
<p>The IGDB is a database, that uses data from the <a href="http://dx.doi.org/10.5904/wgms-fog-2018-11">WGMS</a> to illustrate the consequences of climate change.</p>
|
||||||
|
<p>Our system allows you to visualize data with tables and plots, via our intuitive Web UI.</p>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
12
code/app/templates/login.html
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% import 'bootstrap/wtf.html' as wtf %}
|
||||||
|
|
||||||
|
{% block app_content %}
|
||||||
|
<h1>Sign In</h1>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-4">
|
||||||
|
{{ wtf.quick_form(form) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
{% endblock %}
|
||||||
13
code/app/templates/nuked.html
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h1 id="youre-the-boss">You're the boss!</h1>
|
||||||
|
<ol type="1">
|
||||||
|
<li>Stop the web server, and then execute:</li>
|
||||||
|
<pre class="shell"><code>mysql -u root -p</code></pre>
|
||||||
|
<li><p>Introduce MySQL's root password</p></li>
|
||||||
|
<li><p>Execute these statements:</p></li>
|
||||||
|
<div class="sourceCode" id="cb2"><pre class="sourceCode sql"><code class="sourceCode sql"><span id="cb2-1"><a href="#cb2-1"></a><span class="kw">DROP</span> <span class="kw">DATABASE</span> IGDB;</span>
|
||||||
|
<span id="cb2-2"><a href="#cb2-2"></a><span class="kw">DROP</span> <span class="fu">USER</span> IGDB@LOCALHOST;</span></code></pre></div>
|
||||||
|
{% endblock %}
|
||||||
|
</ol>
|
||||||
8
code/app/templates/plot.html
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% import 'bootstrap/wtf.html' as wtf %}
|
||||||
|
|
||||||
|
{% block app_content %}
|
||||||
|
<h1>Plot</h1>
|
||||||
|
<img src="data:image/png;base64,{{ plot }}" alt="Image Placeholder">
|
||||||
|
<p><a href="{{ url_for('plot_selection') }}">Back</a></p>
|
||||||
|
{% endblock %}
|
||||||
12
code/app/templates/plot_selection.html
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% import 'bootstrap/wtf.html' as wtf %}
|
||||||
|
|
||||||
|
{% block app_content %}
|
||||||
|
<h1>Plot selection</h1>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-4">
|
||||||
|
{{ wtf.quick_form(form) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
{% endblock %}
|
||||||
8
code/app/templates/table.html
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% import 'bootstrap/wtf.html' as wtf %}
|
||||||
|
|
||||||
|
{% block app_content %}
|
||||||
|
<h1>Table</h1>
|
||||||
|
{{ table|safe }}
|
||||||
|
<p><a href="{{ url_for('table_selection') }}">Back</a></p>
|
||||||
|
{% endblock %}
|
||||||
12
code/app/templates/table_selection.html
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% import 'bootstrap/wtf.html' as wtf %}
|
||||||
|
|
||||||
|
{% block app_content %}
|
||||||
|
<h1>Table selection</h1>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-4">
|
||||||
|
{{ wtf.quick_form(form) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
{% endblock %}
|
||||||
7
code/config.py
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
from database.constants import CONNECTION_URI
|
||||||
|
|
||||||
|
|
||||||
|
class Config(object):
|
||||||
|
SQLALCHEMY_DATABASE_URI = CONNECTION_URI
|
||||||
|
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
||||||
|
SECRET_KEY = "trolaso"
|
||||||
0
code/database/__init__.py
Normal file
8
code/database/constants.py
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
DB_NAME = "igdb"
|
||||||
|
DB_USER = "igdb"
|
||||||
|
DB_PW = "agentorange"
|
||||||
|
ADMIN_PW = "fuckmonsanto"
|
||||||
|
HOST = "localhost:3306"
|
||||||
|
CONNECTION_URI = "mysql+pymysql://{user}:{pw}@{url}/{db}".format(
|
||||||
|
user=DB_USER, pw=DB_PW, url=HOST, db=DB_NAME
|
||||||
|
)
|
||||||
24
code/database/db_setup.py
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
from app import db
|
||||||
|
from database.constants import DB_NAME, DB_USER, DB_PW
|
||||||
|
from subprocess import run
|
||||||
|
|
||||||
|
|
||||||
|
def create_database():
|
||||||
|
script = "database/mariadb_setup.sh"
|
||||||
|
output = run([script, DB_NAME, DB_USER, DB_PW])
|
||||||
|
if output.returncode != 0:
|
||||||
|
print("Error: couldn't create database")
|
||||||
|
exit()
|
||||||
|
|
||||||
|
|
||||||
|
def create_tables():
|
||||||
|
db.create_all()
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
create_database()
|
||||||
|
create_tables()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
33
code/database/export.py
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
from app import db
|
||||||
|
from app.models import Annual_Data, Glacier, User
|
||||||
|
from pandas import DataFrame, read_csv
|
||||||
|
|
||||||
|
|
||||||
|
def create_dataframes() -> {DataFrame}:
|
||||||
|
files = {
|
||||||
|
"glacier": "../data/glacier.csv",
|
||||||
|
"annual_data": "../data/annual_data.csv",
|
||||||
|
"user": "../data/user.csv",
|
||||||
|
}
|
||||||
|
df_list = {}
|
||||||
|
for csv in files.keys():
|
||||||
|
df_list[csv] = read_csv(files[csv])
|
||||||
|
return df_list
|
||||||
|
|
||||||
|
|
||||||
|
def insert_data(df_list):
|
||||||
|
models = [Glacier, Annual_Data, User]
|
||||||
|
for model in models:
|
||||||
|
if model.query.first() is not None:
|
||||||
|
return
|
||||||
|
for key, value in df_list.items():
|
||||||
|
value.to_sql(key, con=db.engine, index=False, if_exists="append")
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
df_list = create_dataframes()
|
||||||
|
insert_data(df_list)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
19
code/database/mariadb_setup.sh
Executable file
@@ -0,0 +1,19 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
EXPECTED_ARGS=3
|
||||||
|
ERROR=1
|
||||||
|
MYSQL=$(command -v mysql)
|
||||||
|
|
||||||
|
if [ $# -ne $EXPECTED_ARGS ]
|
||||||
|
then
|
||||||
|
echo "Usage: $0 <database name> <database user> <database password>"
|
||||||
|
exit $ERROR
|
||||||
|
fi
|
||||||
|
|
||||||
|
Q1="CREATE DATABASE IF NOT EXISTS $1;"
|
||||||
|
Q2="GRANT USAGE ON *.* TO $2@localhost IDENTIFIED BY '$3';"
|
||||||
|
Q3="GRANT ALL PRIVILEGES ON $1.* TO $2@localhost;"
|
||||||
|
Q4="FLUSH PRIVILEGES;"
|
||||||
|
SQL="${Q1}${Q2}${Q3}${Q4}"
|
||||||
|
|
||||||
|
$MYSQL -uroot -p -e "$SQL"
|
||||||
84
code/database/parser.py
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
from iso3166 import countries as co
|
||||||
|
from pandas import DataFrame, concat, read_csv
|
||||||
|
from csv import QUOTE_NONNUMERIC
|
||||||
|
from database.constants import ADMIN_PW
|
||||||
|
from os import path
|
||||||
|
from werkzeug.security import generate_password_hash
|
||||||
|
|
||||||
|
|
||||||
|
def country_conversion(political_unit) -> str:
|
||||||
|
if political_unit == "99":
|
||||||
|
return "99"
|
||||||
|
codes = co.get(political_unit)
|
||||||
|
return codes.name
|
||||||
|
|
||||||
|
|
||||||
|
def select_columns() -> DataFrame:
|
||||||
|
min_year = 2010
|
||||||
|
fields = [
|
||||||
|
"POLITICAL_UNIT",
|
||||||
|
"NAME",
|
||||||
|
"WGMS_ID",
|
||||||
|
"YEAR",
|
||||||
|
"MEDIAN_ELEVATION",
|
||||||
|
"AREA",
|
||||||
|
"LENGTH",
|
||||||
|
]
|
||||||
|
iter_csv = read_csv(
|
||||||
|
"../data/WGMS-FoG-2019-12-B-STATE.csv",
|
||||||
|
skipinitialspace=True,
|
||||||
|
usecols=fields,
|
||||||
|
iterator=True,
|
||||||
|
chunksize=100,
|
||||||
|
converters={"POLITICAL_UNIT": country_conversion},
|
||||||
|
)
|
||||||
|
data = concat([chunk[chunk["YEAR"] > min_year] for chunk in iter_csv])
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
def rename_fields(df_list):
|
||||||
|
new_df_list = {}
|
||||||
|
new_fields = {
|
||||||
|
"POLITICAL_UNIT": "country",
|
||||||
|
"NAME": "name",
|
||||||
|
"WGMS_ID": "id",
|
||||||
|
"YEAR": "year",
|
||||||
|
"MEDIAN_ELEVATION": "elevation",
|
||||||
|
"AREA": "surface",
|
||||||
|
"LENGTH": "length",
|
||||||
|
}
|
||||||
|
for key, value in df_list.items():
|
||||||
|
new_df_list[key] = value.rename(columns=new_fields)
|
||||||
|
return new_df_list
|
||||||
|
|
||||||
|
|
||||||
|
def create_databases(df):
|
||||||
|
files = {
|
||||||
|
"glacier": "../data/glacier.csv",
|
||||||
|
"annual_data": "../data/annual_data.csv",
|
||||||
|
"user": "../data/user.csv",
|
||||||
|
}
|
||||||
|
user = {
|
||||||
|
"id": [7843],
|
||||||
|
"username": ["admin"],
|
||||||
|
"password_hash": [generate_password_hash(ADMIN_PW)],
|
||||||
|
}
|
||||||
|
dataframes = {
|
||||||
|
"glacier": df[["POLITICAL_UNIT", "NAME", "WGMS_ID"]].drop_duplicates(),
|
||||||
|
"annual_data": df[["WGMS_ID", "YEAR", "AREA", "MEDIAN_ELEVATION", "LENGTH"]],
|
||||||
|
"user": DataFrame(user),
|
||||||
|
}
|
||||||
|
renamed_dfs = rename_fields(dataframes)
|
||||||
|
for key, val in renamed_dfs.items():
|
||||||
|
if path.isfile(files[key]):
|
||||||
|
continue
|
||||||
|
val.to_csv(files[key], index=False, quoting=QUOTE_NONNUMERIC)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
df = select_columns()
|
||||||
|
create_databases(df)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
38
code/database/queries.py
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
from app import db
|
||||||
|
from app.models import Annual_Data, Glacier, User
|
||||||
|
from flask_sqlalchemy import BaseQuery
|
||||||
|
from flask import flash, redirect, url_for
|
||||||
|
|
||||||
|
|
||||||
|
def query_annual_data(form) -> BaseQuery:
|
||||||
|
annual_data = db.session.query(Annual_Data).filter_by(year=form.year.data)
|
||||||
|
if form.name.data:
|
||||||
|
glacier_name = (
|
||||||
|
db.session.query(Annual_Data)
|
||||||
|
.join(Glacier, Glacier.id == Annual_Data.id)
|
||||||
|
.filter_by(name=form.name.data)
|
||||||
|
.group_by(Annual_Data.year)
|
||||||
|
)
|
||||||
|
if glacier_name.first() is None:
|
||||||
|
flash("Sorry, no results found")
|
||||||
|
return redirect(url_for("table_selection"))
|
||||||
|
return glacier_name
|
||||||
|
return annual_data
|
||||||
|
|
||||||
|
|
||||||
|
def query_user(form) -> BaseQuery:
|
||||||
|
user = User.query.filter_by(username=form.username.data).first()
|
||||||
|
return user
|
||||||
|
|
||||||
|
|
||||||
|
def query_plot_data(form) -> BaseQuery:
|
||||||
|
query = (
|
||||||
|
db.session.query(Annual_Data)
|
||||||
|
.join(Glacier, Glacier.id == Annual_Data.id)
|
||||||
|
.filter_by(name=form.name.data)
|
||||||
|
.group_by(Annual_Data.year)
|
||||||
|
)
|
||||||
|
if query.first() is None:
|
||||||
|
flash("Sorry, no results found")
|
||||||
|
return redirect(url_for("plot_selection"))
|
||||||
|
return query
|
||||||
7
code/igdb.py
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
from app import app
|
||||||
|
from database import db_setup, export, parser
|
||||||
|
from processing import dataframe
|
||||||
|
|
||||||
|
db_setup.main()
|
||||||
|
parser.main()
|
||||||
|
export.main()
|
||||||
0
code/processing/__init__.py
Normal file
45
code/processing/dataframe.py
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
from app import db
|
||||||
|
from io import BytesIO
|
||||||
|
from pandas import DataFrame, read_sql
|
||||||
|
from base64 import b64encode
|
||||||
|
|
||||||
|
|
||||||
|
def create_dataframe(query) -> DataFrame:
|
||||||
|
df = read_sql(sql=query, con=db.engine)
|
||||||
|
return df
|
||||||
|
|
||||||
|
|
||||||
|
def render_table(df) -> str:
|
||||||
|
df.fillna(value=0, inplace=True)
|
||||||
|
table = df.to_html(classes=["table-striped", "table-hover"])
|
||||||
|
return table
|
||||||
|
|
||||||
|
|
||||||
|
def render_plot(df):
|
||||||
|
df.fillna(value=0, inplace=True)
|
||||||
|
plot = df.plot("year", ["surface", "length", "elevation"], kind="bar")
|
||||||
|
plot_figure = plot.get_figure()
|
||||||
|
figure = BytesIO()
|
||||||
|
plot_figure.savefig(figure)
|
||||||
|
figure.seek(0)
|
||||||
|
return figure
|
||||||
|
|
||||||
|
|
||||||
|
def encode_plot(plot):
|
||||||
|
buffer = b"".join(plot)
|
||||||
|
buf = b64encode(buffer)
|
||||||
|
encoded_plot = buf.decode("utf-8")
|
||||||
|
return encoded_plot
|
||||||
|
|
||||||
|
|
||||||
|
def create_table(query) -> str:
|
||||||
|
df = create_dataframe(query)
|
||||||
|
html_table = render_table(df)
|
||||||
|
return html_table
|
||||||
|
|
||||||
|
|
||||||
|
def create_plot(query):
|
||||||
|
df = create_dataframe(query)
|
||||||
|
plot = render_plot(df)
|
||||||
|
encoded_plot = encode_plot(plot)
|
||||||
|
return encoded_plot
|
||||||
19495
data/WGMS-FoG-2019-12-B-STATE.csv
Normal file
@@ -32,24 +32,23 @@ Requisitos
|
|||||||
### Datos
|
### Datos
|
||||||
|
|
||||||
1. **RD1**: Datos del glaciar
|
1. **RD1**: Datos del glaciar
|
||||||
- País - *Cadena de 30 caracteres máximo*
|
- País - *Cadena de 60 caracteres máximo*
|
||||||
- Nombre del glaciar - *Cadena de 30 caracteres máximo*
|
- Nombre del glaciar - *Cadena de 60 caracteres máximo*
|
||||||
- ID del glaciar (Compatible con la WGMS) - *Entero de 5 dígitos*
|
- ID del glaciar (Compatible con la WGMS) - *Cadena de 20
|
||||||
|
caracteres*
|
||||||
2. **RD2**: Datos anuales de un glaciar
|
2. **RD2**: Datos anuales de un glaciar
|
||||||
- ID del glaciar (Compatible con la WGMS) - *Entero de 5 dígitos*
|
- ID del glaciar (Compatible con la WGMS) - *Cadena de 20
|
||||||
- Área - *Entero de 10 dígitos*
|
caracteres*
|
||||||
- Volumen - *Entero de 10 dígitos*
|
- Área - *Decimal*
|
||||||
- Grosor - *Entero de 10 dígitos*
|
- Volumen - *Decimal*
|
||||||
- Año - *Entero de 10 dígitos*
|
- Altura - *Decimal*
|
||||||
3. **RD3**: Datos de cambio de un glaciar
|
- Año - *Entero de 11 dígitos*
|
||||||
- ID del glaciar (Compatible con la WGMS) - *Entero de 5 dígitos*
|
3. **RD3**: Datos del administrador
|
||||||
- Variación de área - *Entero de 10 dígitos*
|
- ID - *Entero de 11 dígitos*
|
||||||
- Variación de volumen - *Entero de 10 dígitos*
|
- Fecha y hora de alta - *Fecha y hora en formato yyyy-mm-dd
|
||||||
- Variación de grosor - *Entero de 10 dígitos*
|
hh:mm*
|
||||||
- Año - *Entero de 10 dígitos*
|
- Nombre de usuario - *Cadena de 20 caracteres máximo*
|
||||||
4. **RD4**: Datos del administrador
|
- Hash de la contraseña - *Cadena de 128 caracteres máximo*
|
||||||
- ID - *Entero de 4 dígitos*
|
|
||||||
- Fecha de alta - *Fecha en formato dd-mm-yyyy*
|
|
||||||
|
|
||||||
### Funcionales
|
### Funcionales
|
||||||
|
|
||||||
@@ -67,7 +66,7 @@ Requisitos
|
|||||||
|
|
||||||
3. **RF3**: Cálculo de las variaciones anuales
|
3. **RF3**: Cálculo de las variaciones anuales
|
||||||
|
|
||||||
Calcula las variaciones anuales de grosor, área y volumen para un
|
Calcula las variaciones anuales de altura, área y longitud para un
|
||||||
glaciar
|
glaciar
|
||||||
|
|
||||||
- Entrada: **RD2**
|
- Entrada: **RD2**
|
||||||
@@ -161,9 +160,9 @@ Ingeniería del Software.
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
### Diagrama Entidad-Relación
|
\clearpage
|
||||||
|
|
||||||
\newpage
|
### Diagrama Entidad-Relación
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
@@ -18,27 +18,22 @@ datos relevantes para estudios acerca del cambio climático, y acotando éstos a
|
|||||||
*** Datos
|
*** Datos
|
||||||
|
|
||||||
1. *RD1*: Datos del glaciar
|
1. *RD1*: Datos del glaciar
|
||||||
- País - /Cadena de 30 caracteres máximo/
|
- País - /Cadena de 60 caracteres máximo/
|
||||||
- Nombre del glaciar - /Cadena de 30 caracteres máximo/
|
- Nombre del glaciar - /Cadena de 60 caracteres máximo/
|
||||||
- ID del glaciar (Compatible con la WGMS) - /Entero de 5 dígitos/
|
- ID del glaciar (Compatible con la WGMS) - /Cadena de 20 caracteres/
|
||||||
|
|
||||||
2. *RD2*: Datos anuales de un glaciar
|
2. *RD2*: Datos anuales de un glaciar
|
||||||
- ID del glaciar (Compatible con la WGMS) - /Entero de 5 dígitos/
|
- ID del glaciar (Compatible con la WGMS) - /Cadena de 20 caracteres/
|
||||||
- Área - /Entero de 10 dígitos/
|
- Área - /Decimal/
|
||||||
- Volumen - /Entero de 10 dígitos/
|
- Volumen - /Decimal/
|
||||||
- Grosor - /Entero de 10 dígitos/
|
- Altura - /Decimal/
|
||||||
- Año - /Entero de 10 dígitos/
|
- Año - /Entero de 11 dígitos/
|
||||||
|
|
||||||
3. *RD3*: Datos de cambio de un glaciar
|
3. *RD3*: Datos del administrador
|
||||||
- ID del glaciar (Compatible con la WGMS) - /Entero de 5 dígitos/
|
- ID - /Entero de 11 dígitos/
|
||||||
- Variación de área - /Entero de 10 dígitos/
|
- Fecha y hora de alta - /Fecha y hora en formato yyyy-mm-dd hh:mm/
|
||||||
- Variación de volumen - /Entero de 10 dígitos/
|
- Nombre de usuario - /Cadena de 20 caracteres máximo/
|
||||||
- Variación de grosor - /Entero de 10 dígitos/
|
- Hash de la contraseña - /Cadena de 128 caracteres máximo/
|
||||||
- Año - /Entero de 10 dígitos/
|
|
||||||
|
|
||||||
4. *RD4*: Datos del administrador
|
|
||||||
- ID - /Entero de 4 dígitos/
|
|
||||||
- Fecha de alta - /Fecha en formato dd-mm-yyyy/
|
|
||||||
|
|
||||||
*** Funcionales
|
*** Funcionales
|
||||||
|
|
||||||
@@ -54,7 +49,7 @@ datos relevantes para estudios acerca del cambio climático, y acotando éstos a
|
|||||||
|
|
||||||
3. *RF3*: Cálculo de las variaciones anuales
|
3. *RF3*: Cálculo de las variaciones anuales
|
||||||
|
|
||||||
Calcula las variaciones anuales de grosor, área y volumen para un glaciar
|
Calcula las variaciones anuales de altura, área y longitud para un glaciar
|
||||||
- Entrada: *RD2*
|
- Entrada: *RD2*
|
||||||
- Manejo: *RD3*
|
- Manejo: *RD3*
|
||||||
|
|
||||||