roundabout,
created on Saturday, 6 April 2024, 16:26:27 (1712420787),
received on Sunday, 7 April 2024, 12:44:08 (1712493848)
Author identity: vlad <vlad.muntoiu@gmail.com>
da0632aae170ad798b2c4128c686c4eddfdded4c
.idea/workspace.xml
@@ -4,11 +4,12 @@
<option name="autoReloadType" value="SELECTIVE" /> </component> <component name="ChangeListManager"> <list default="true" id="411335b4-e813-41ad-9046-18b77b97ee46" name="Changes" comment="More"><list default="true" id="411335b4-e813-41ad-9046-18b77b97ee46" name="Changes" comment="Endpoint management"><change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" /> <change beforePath="$PROJECT_DIR$/app.py" beforeDir="false" afterPath="$PROJECT_DIR$/app.py" afterDir="false" /> <change beforePath="$PROJECT_DIR$/static/style.css" beforeDir="false" afterPath="$PROJECT_DIR$/static/style.css" afterDir="false" /> <change beforePath="$PROJECT_DIR$/templates/app-editor.html" beforeDir="false" afterPath="$PROJECT_DIR$/templates/app-editor.html" afterDir="false" /> <change beforePath="$PROJECT_DIR$/templates/app.html" beforeDir="false" afterPath="$PROJECT_DIR$/templates/app.html" afterDir="false" /></list> <option name="SHOW_DIALOG" value="false" /> <option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -82,7 +83,15 @@
<option name="project" value="LOCAL" /> <updated>1712409360299</updated> </task> <option name="localTasksCounter" value="3" /><task id="LOCAL-00003" summary="Endpoint management"> <option name="closed" value="true" /> <created>1712411232132</created> <option name="number" value="00003" /> <option name="presentableId" value="LOCAL-00003" /> <option name="project" value="LOCAL" /> <updated>1712411232132</updated> </task> <option name="localTasksCounter" value="4" /><servers /> </component> <component name="Vcs.Log.Tabs.Properties">
@@ -99,6 +108,7 @@
<component name="VcsManagerConfiguration"> <MESSAGE value="Initial commit" /> <MESSAGE value="More" /> <option name="LAST_COMMIT_MESSAGE" value="More" /><MESSAGE value="Endpoint management" /> <option name="LAST_COMMIT_MESSAGE" value="Endpoint management" /></component> </project>
app.py
@@ -1,15 +1,40 @@
import datetime import celery import flask from flask_sqlalchemy import SQLAlchemy from flask_bcrypt import Bcrypt from flask_migrate import Migrate from sqlalchemy.orm import declarative_base from celery import shared_taskimport httpx app = flask.Flask(__name__) from celery import Celery, Task def celery_init_app(app_) -> Celery: class FlaskTask(Task): def __call__(self, *args: object, **kwargs: object) -> object: with app_.app_context(): return self.run(*args, **kwargs) celery_app = Celery(app_.name, task_cls=FlaskTask) celery_app.config_from_object(app_.config["CELERY"]) celery_app.set_default() app_.extensions["celery"] = celery_app return celery_app app.config.from_mapping( CELERY=dict( broker_url="redis://localhost:6379", result_backend="redis://localhost:6379" ), ) celery_app = celery_init_app(app)app.config["SQLALCHEMY_DATABASE_URI"] = \ "postgresql://echo:1234@localhost:5432/echo" db = SQLAlchemy(app)
@@ -50,43 +75,56 @@ with app.app_context():
address = db.Column(db.String(2048), nullable=False) name = db.Column(db.String(64), nullable=False) comment = db.Column(db.String(2048), nullable=True) ping_interval = db.Column(db.Integer, default=300, nullable=False)application = db.relationship("Application", back_populates="endpoints") def __init__(self, application, name, address, comment=""):def __init__(self, application, name, address, ping_interval, comment=""):self.application_id = application.id self.name = name self.address = address self.comment = comment self.ping_interval = ping_intervalBase = declarative_base()class Status(Base):__table_args = ({"timescaledb_hypertable": {"time_column_name": "time",},})__tablename__ = "status"id = db.Column(db.Integer, unique=True, nullable=False, autoincrement=True)class Status(db.Model): id = db.Column(db.Integer, unique=True, nullable=False, autoincrement=True, primary_key=True, default=0)endpoint_id = db.Column(db.Integer, nullable=False) time = db.Column(db.DateTime, index=True, default=datetime.datetime.utcnow, primary_key=True)time = db.Column(db.DateTime, default=datetime.datetime.utcnow)status = db.Column(db.SmallInteger, nullable=False) endpoint = db.relationship("Endpoint", back_populates="statuses")def __init__(self, endpoint, status):self.endpoint_id = endpoint.iddef __init__(self, endpoint_id, status): self.endpoint_id = endpoint_idself.status = status def ping(endpoint):url = endpoint.addressresponse = httpx.get(url)return response.status_code@celery.shared_task(name="ping") def ping(id, address, next_ping): url = address print(f"Pinging {url}") response = httpx.get(url, verify=False) reading = Status(id, response.status_code) db.session.add(reading) db.session.commit() # Schedule the next ping ping.apply_async(args=(id, address, next_ping), countdown=next_ping) @celery.shared_task(name="ping_all") def ping_all(): endpoints = Endpoint.query.all() for endpoint in endpoints: ping.delay(endpoint.id, endpoint.address, endpoint.ping_interval) task = ping_all.delay() print() print() print(task) print() print()@app.context_processor
@@ -180,11 +218,6 @@ def signup_post():
return flask.redirect("/", code=303) @app.route("/timeline/<endpoint_id>")def info(endpoint_id):return flask.render_template("timeline.html", endpoint=endpoint_id)@app.route("/app/<int:app_id>/") def app_info(app_id): app_ = db.session.get(Application, app_id)
@@ -223,7 +256,9 @@ def app_add_endpoint(app_id):
endpoint = Endpoint(app_, flask.request.form["name"], flask.request.form["url"], 300,flask.request.form["comment"]) db.session.add(endpoint) db.session.commit() return flask.redirect(f"/app/{app_id}/edit", code=303)
static/style.css
@@ -176,14 +176,14 @@ input[type="password"]:not(:placeholder-shown) {
font-family: "Lexend Exa", "Lexend", sans-serif; } .app-card {.app-card, .endpoint-card {width: 100%; border: 2px solid #000000aa; padding: 0.75rem; border-radius: 24px; } .app-card h2 {:is(.app-card, .endpoint-card) h2 {margin-top: 0; font-size: 1.45rem; font-weight: 750;
@@ -249,7 +249,7 @@ iconify-icon {
display: inline-block; } .quiet-link:has(.app-card) {.quiet-link:has(:is(.app-card, .endpoint-card)) {display: block; border-radius: 24px; }
@@ -264,7 +264,7 @@ textarea {
appearance: none; } #endpoint-editor {#endpoint-editor, #endpoint-list {display: flex; gap: 2rem; width: 100%;
@@ -279,8 +279,8 @@ textarea {
justify-content: space-around; } .side-by-side > button {flex: 1 1 25%;.side-by-side > button.extend { flex: 1 1 100%;} .danger-button {
@@ -291,3 +291,8 @@ textarea {
.danger-button:hover { background: #D32F2F; } nav a:focus { box-shadow: none; text-decoration: underline; }
templates/app-editor.html
@@ -10,8 +10,10 @@
<input type="url" name="url" placeholder="Ping address" value="{{ endpoint.address }}"> <textarea name="comment" placeholder="Comment" rows="4">{{ endpoint.comment }}</textarea> <div class="side-by-side"> <button type="submit">Apply changes</button><button type="submit" name="delete" value="delete" class="danger-button">Delete</button><button type="submit" class="extend">Apply changes</button> <button type="submit" name="delete" value="delete" class="danger-button"> <iconify-icon icon="mdi:trash-can">Delete</iconify-icon> </button></div> </form> {% endfor %}
templates/app.html
@@ -9,5 +9,14 @@
Manage endpoints </a> {% endif %} <div id="endpoint-list"> {% for endpoint in app.endpoints %} <div class="endpoint-card"> <h2>{{ endpoint.name }}</h2> <p>{{ endpoint.comment }}</p> </div> {% endfor %} </div></main> {% endblock %}