eklipse

solar eclipse search engine
Log | Files | Refs | README | LICENSE

commit eb78df90c38819e0c1565960ba9802916ed665cb
parent cc8b57b6caa8501a81c9bebdd6f4eb0e7ea6dbb3
Author: tin <ichtinnotl@gmail.com>
Date:   Mon, 20 Aug 2018 00:21:51 +0200

basically the whole project

Diffstat:
eklipse/__init__.py | 50++++++++++++++++++++++++++++++++++++++++++++++++++
eklipse/database/database.sqlite | 0
eklipse/models.py | 41+++++++++++++++++++++++++++++++++++++++++
eklipse/static/css/style.css | 33+++++++++++++++++++++++++++++++++
eklipse/static/js/main.js | 66++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
eklipse/templates/index.html | 115+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
eklipse/utils/__init__.py | 0
eklipse/utils/json_serializer.py | 11+++++++++++
8 files changed, 316 insertions(+), 0 deletions(-)

diff --git a/eklipse/__init__.py b/eklipse/__init__.py @@ -0,0 +1,49 @@ +from flask import Flask, jsonify +from flask import render_template +from werkzeug.exceptions import InternalServerError, BadRequest + +from eklipse.utils.json_serializer import AlchemyEncoder +from .models import SolarEclipse + +app = Flask(__name__, instance_relative_config=True, static_url_path='/static') + +app.config.from_object('config') +app.config.from_pyfile('config.py') +app.json_encoder = AlchemyEncoder + +from sqlalchemy import create_engine +from sqlalchemy.orm import scoped_session, sessionmaker +from sqlalchemy.ext.declarative import declarative_base + +engine = create_engine(app.config['DATABASE_URL'], convert_unicode=True) +db_session = scoped_session(sessionmaker(autocommit=False, + autoflush=False, + bind=engine)) + +Base = declarative_base() +Base.query = db_session.query_property() + +@app.teardown_appcontext +def shutdown_session(exception=None): + db_session.remove() + +@app.route('/') +def index(): + return render_template("index.html") + +@app.route('/query/<string:geoArea>') +def getAreaByInput(geoArea): + """ + :return: Returns specific geoloc in JSON Format + :rtype: json + """ + try: + data = db_session.query(SolarEclipse).filter_by( + geoArea=geoArea.title()).all() + except InternalServerError: + return jsonify({'data': "Internal server error", 'status': 'success'}) + + if not data: + return jsonify({'data': "No data found", 'status': 'success'}) + + return jsonify({'data': data, 'status': 'success'})+ \ No newline at end of file diff --git a/eklipse/database/database.sqlite b/eklipse/database/database.sqlite Binary files differ. diff --git a/eklipse/models.py b/eklipse/models.py @@ -0,0 +1,41 @@ +# eklipse/server/models/models.py + +from sqlalchemy.ext.declarative import declarative_base + +from sqlalchemy import Column, Integer, String, DateTime, func, Boolean + +BASE = declarative_base() + + +class SolarEclipse(BASE): + __tablename__ = "solar-eclipses-data" + + id = Column(Integer, primary_key=True) + date_created = Column(DateTime(timezone=False), server_default=func.now()) + date_modified = Column(DateTime(timezone=False), onupdate=func.now()) + + date = Column(String(30)) + time = Column(String(30)) + saros = Column(String(30)) + geoArea = Column(String(30)) + location = Column(String(30)) + magnitude = Column(String(30)) + pathWidthKM = Column(String(30)) + pathWidthMI = Column(String(30)) + centralDuration = Column(String(30)) + solarEclipseType = Column(String(30)) + + def serialize(self): + # Used for serializing SQL objects to JSON format + return { + "date": self.date, + "time": self.time, + "saros": self.saros, + "geoArea": self.geoArea, + "location": self.location, + "magnitude": self.magnitude, + "pathWidthKM": self.pathWidthKM, + "pathWidthMI": self.pathWidthMI, + "centralDuration": self.centralDuration, + "solarEclipseType": self.solarEclipseType, + } diff --git a/eklipse/static/css/style.css b/eklipse/static/css/style.css @@ -0,0 +1,33 @@ +#imaginary_container{ + margin-top:20%; /* Don't copy this */ +} +.stylish-input-group .input-group-addon{ + background: white !important; +} +.stylish-input-group .form-control{ + border-right:0; + box-shadow:0 0 0; + border-color:#ccc; +} +.stylish-input-group button{ + border:0; + background:transparent; +} +ul { + list-style-type: none; + margin: 0; + padding: 0; + overflow: hidden; +} + +li { + float: left; +} + +li a { + display: block; + color: blue; + text-align: center; + padding: 16px; + text-decoration: none; +} diff --git a/eklipse/static/js/main.js b/eklipse/static/js/main.js @@ -0,0 +1,66 @@ +let lastSearch = null; + +$(document).keydown(function (e) { + + if ($(".form-control:focus") && (e.keyCode === 13)) { + var input = $('.form-control').val(); + + if (lastSearch === input) { + $('.form-control').val(''); + return; + } else { + $('.form-control').val(''); + $("tbody").children().remove(); + $("#errors").children().remove() + + ajaxFunc(input) + lastSearch = input + } + } +}); + +function button() { + var input = $('.form-control').val(); + + if (lastSearch === input) { + $('.form-control').val(''); + return; + } else { + $('.form-control').val('');; + $("tbody").children().remove(); + $("#errors").children().remove() + + ajaxFunc(input) + lastSearch = input + } +} + + +function ajaxFunc(input) { + search = input + var eklipseAPI = "/query/" + input; + $.getJSON(eklipseAPI, { + format: "json" + }) + .done(function (response) { + if (response.data == "No data found"){ + $("#errors").children().remove() + $('<p>').text('Could not find any data about the given area.').appendTo("#errors") + }else{ + $.each(response.data, function (i, item) { + $('<tr>').append( + $('<td>').text(item.geoArea), + $('<td>').text(item.date), + $('<td>').text(item.time), + $('<td>').text(item.solarEclipseType), + $('<td>').text(item.centralDuration), + $('<td>').text(item.magnitude), + $('<td>').text(item.location), + $('<td>').text(item.saros), + $('<td>').text(item.pathWidthKM), + $('<td>').text(item.pathWidthMI), + ).appendTo('#table'); + }); + } + }); +} diff --git a/eklipse/templates/index.html b/eklipse/templates/index.html @@ -0,0 +1,114 @@ +<!DOCTYPE html> +<html> + +<head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <meta charset="utf-8" /> + <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script> + <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> + <link href="{{ url_for('static', filename='css/style.css') }}" rel="stylesheet"> + <script src="{{ url_for('static', filename='js/main.js') }}"></script> + <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"> +</head> + +<body> + <div class="container"> + <ul> + <li> + <a data-toggle="modal" data-target="#projectInfoModal">project info</a> + </li> + <li> + <a href="https://who.lh.mk">who.lh.mk</a> + </li> + </ul> + <div class="modal fade" id="projectInfoModal" role="dialog"> + <div class="modal-dialog"> + + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal">&times;</button> + <h4 class="modal-title">info</h4> + </div> + <div class="modal-body"> + <p>Eklipse is a search engine for solar eclipses happening in the 21th century. + <p> + <p>Searching is pretty straightforward, entering an area in the search box and hitting enter + should query the database. The area can be a continent, ocean or a country.</p> + + <p>Eklipse is a free software. The LICENSE, README and source code can be found at + <code>https://git.lh.mk/eklipse</code>.</p> + <p>The repository is also being mirrored at + <code>https://github.com/hristijansk/eklipse</code>. + <hr> + <p>Data:</p> + <p></p> + <p> + <code>Area</code> - geographical area.</p> + <p> + <code>Date</code> - date of a solar eclipse.</p> + <p> + <code>Time</code> - time of greatest eclipse (UTC).</p> + <p> + <code>Duration</code> - possible duration of a solar eclipse.</p> + <p> + <code>Magnitude</code> - the fraction of the angular diameter of a celestial body being eclipsed.</p> + <p> + <code>Saros</code> - a period of approximately 223 synodic months, that can be used to predict eclipses + of the Sun and Moon.</p> + <p> + <code>Path width</code> - the path width of the total or annular eclipse.</p> + + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> + </div> + </div> + + </div> + </div> + + <div class="row"> + <div class="col-sm-6 col-sm-offset-3"> + <div id="imaginary_container"> + <div class="input-group stylish-input-group"> + <input type="text" id="search" class="form-control" placeholder="Eg. Europe, Africa, Afghanistan, United States"> + <span class="input-group-addon"> + <button type="submit" id="submit" onclick="button();"> + <span class="glyphicon glyphicon-search"></span> + </button> + </span> + </div> + </div> + </div> + </div> + <hr> + </div> + + <div class="container"> + <table id="table" class="table table-striped"> + <thead> + <tr> + <th>Area</th> + <th>Date</th> + <th>Time</th> + <th>Type</th> + <th>Duration</th> + <th>Magnitude</th> + <th>Location</th> + <th>Saros</th> + <th>Path Width (KM)</th> + <th>Path Width (MI)</th> + </tr> + </thead> + <tbody> + <tr> + + </tr> + </tbody> + </table> + </div> + <div class="container" id="errors"> + </div> +</body> + +</html>+ \ No newline at end of file diff --git a/eklipse/utils/__init__.py b/eklipse/utils/__init__.py diff --git a/eklipse/utils/json_serializer.py b/eklipse/utils/json_serializer.py @@ -0,0 +1,11 @@ +import json + + +class AlchemyEncoder(json.JSONEncoder): + def default(self, obj): + try: + return json.JSONEncoder.default(self, obj) + except TypeError: + if hasattr(obj, 'serialize'): + return obj.serialize() + raise