Skip to content

Commit dac02e1

Browse files
committed
feat: add coding_challenge route to daily fetch the URL of a random challenge
1 parent 46978cb commit dac02e1

File tree

3 files changed

+109
-89
lines changed

3 files changed

+109
-89
lines changed

main.py

+98-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
1-
import os
1+
"""
2+
Main application.
3+
"""
4+
import asyncio
25
import logging
3-
from flask import Flask, jsonify
6+
import os
7+
import random
8+
from typing import List
9+
import httpx
410
from dotenv import load_dotenv
11+
from flask import Flask, jsonify, request
512
from flask_cors import CORS
6-
from utils import integration, katas
13+
from pydantic import BaseModel
14+
from utils import katas
715

816

917
# load environment variables from .env
@@ -16,6 +24,22 @@
1624
# initialize Flask app
1725
app = Flask(__name__)
1826

27+
28+
class Setting(BaseModel):
29+
""" Setting model. """
30+
label: str
31+
type: str
32+
required: bool
33+
default: str
34+
35+
36+
class MonitorPayload(BaseModel):
37+
""" Payload model. """
38+
channel_id: str
39+
return_url: str
40+
settings: List[Setting]
41+
42+
1943
# list of allowed origins
2044
allowed_origins = [
2145
"https://telex.im",
@@ -30,7 +54,7 @@
3054

3155
@app.route("/", methods=["GET"])
3256
def root():
33-
""" Root endpoint returning a JSON message """
57+
""" Root endpoint returning a JSON message. """
3458
logger.info("Root endpoint accessed")
3559
return jsonify(
3660
{
@@ -42,6 +66,76 @@ def root():
4266
)
4367

4468

69+
@app.route("/coding_challenge", methods=["GET"])
70+
def get_coding_challenge():
71+
""" Endpoint to get a coding challenge. """
72+
base_url = request.base_url.rstrip("/coding_challenge")
73+
codewars_base_url = "https://www.codewars.com/kata"
74+
kata_id = random.choice(katas)
75+
76+
kata = f"{codewars_base_url}/{kata_id}"
77+
return jsonify(
78+
{
79+
"data": {
80+
"date": {
81+
"created_at": "2025-02-18",
82+
"updated_at": "2025-02-18"
83+
},
84+
"descriptions": {
85+
"app_description": "Posts a coding challenge every morning to sharpen developer skills.",
86+
"app_logo": "https://i.postimg.cc/5Nn52jM9/codex.png",
87+
"app_name": "Codex",
88+
"app_url": base_url,
89+
"background_color": "#151515"
90+
},
91+
"integration_category": "Development & Code Management",
92+
"integration_type": "interval",
93+
"is_active": True,
94+
"author": "Tony B. NYA",
95+
"settings": [
96+
{
97+
"label": "interval",
98+
"type": "text",
99+
"required": True,
100+
"default": "* * * * *"
101+
}
102+
],
103+
"tick_url": f"{kata}/tick",
104+
}
105+
}
106+
)
107+
108+
109+
# def coding_challenge(payload: MonitorPayload):
110+
async def coding_challenge(payload: MonitorPayload):
111+
"""Monitor websites and send a report to the return URL."""
112+
codewars_base_url = "https://www.codewars.com/kata"
113+
kata_id = random.choice(katas)
114+
115+
kata = f"{codewars_base_url}/{kata_id}"
116+
117+
data = {
118+
"message": kata,
119+
"username": "Coding Challenge",
120+
"event_name": "Uptime Check",
121+
"status": "error"
122+
}
123+
124+
async with httpx.AsyncClient() as client:
125+
await client.post(payload.return_url, json=data)
126+
127+
128+
@app.route("/tick", methods=["POST"])
129+
def tick():
130+
"""Flask route to handle monitoring requests."""
131+
try:
132+
payload = MonitorPayload(**request.json)
133+
asyncio.create_task(coding_challenge(payload))
134+
return jsonify({"message": "Coding Challenge delivered"}), 202
135+
except Exception as e:
136+
return jsonify({"error": str(e)}), 400
137+
138+
45139
if __name__ == "__main__":
46140
# load configuration from environment variables
47141
debug_mode = os.getenv("FLASK_DEBUG", "True").lower() == "true"

requirements.txt

+11
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,21 @@
1+
annotated-types==0.7.0
2+
anyio==4.8.0
13
blinker==1.9.0
4+
certifi==2025.1.31
25
click==8.1.8
36
Flask==3.1.0
47
Flask-Cors==5.0.0
8+
h11==0.14.0
9+
httpcore==1.0.7
10+
httpx==0.28.1
11+
idna==3.10
512
itsdangerous==2.2.0
613
Jinja2==3.1.5
714
MarkupSafe==3.0.2
15+
pydantic==2.10.6
16+
pydantic_core==2.27.2
817
python-dotenv==1.0.1
18+
sniffio==1.3.1
19+
typing_extensions==4.12.2
920
Werkzeug==3.1.3
1021
gunicorn

utils.py

-85
Original file line numberDiff line numberDiff line change
@@ -100,88 +100,3 @@
100100
"5bec507e1ab6db71110001fc",
101101
"52705ed65de62b733f000064"
102102
]
103-
104-
integration = {
105-
"data": {
106-
"date": {
107-
"created_at": "2025-02-18",
108-
"updated_at": "2025-02-18"
109-
},
110-
"descriptions": {
111-
"app_description": "Posts a coding challenge every morning to sharpen developer skills.",
112-
"app_logo": "https://i.postimg.cc/5Nn52jM9/codex.png",
113-
"app_name": "Codex",
114-
"app_url": "URL to the application or service.",
115-
"background_color": "#151515"
116-
},
117-
"integration_category": "Development & Code Management",
118-
"integration_type": "interval",
119-
# "is_active": False,
120-
# "output": [
121-
# {
122-
# "label": "output_channel_1",
123-
# "value": True
124-
# },
125-
# {
126-
# "label": "output_channel_2",
127-
# "value": False
128-
# }
129-
# ],
130-
# "key_features": [
131-
# "Feature description 1.",
132-
# "Feature description 2.",
133-
# "Feature description 3.",
134-
# "Feature description 4."
135-
# ],
136-
# "permissions": {
137-
# "monitoring_user": {
138-
# "always_online": True,
139-
# "display_name": "Performance Monitor"
140-
# }
141-
# },
142-
"settings": [
143-
{
144-
"label": "interval",
145-
"type": "text",
146-
"required": True,
147-
"default": "* * * * *"
148-
}
149-
# {
150-
# "label": "Key",
151-
# "type": "text",
152-
# "required": True,
153-
# "default": "1234567890"
154-
# },
155-
# {
156-
# "label": "Do you want to continue",
157-
# "type": "checkbox",
158-
# "required": True,
159-
# "default": "Yes"
160-
# },
161-
# {
162-
# "label": "Provide Speed",
163-
# "type": "number",
164-
# "required": True,
165-
# "default": "1000"
166-
# },
167-
# {
168-
# "label": "Sensitivity Level",
169-
# "type": "dropdown",
170-
# "required": True,
171-
# "default": "Low",
172-
# "options": ["High", "Low"]
173-
# },
174-
# {
175-
# "label": "Alert Admin",
176-
# "type": "multi-checkbox",
177-
# "required": True,
178-
# "default": "Super-Admin",
179-
# "options": ["Super-Admin", "Admin", "Manager", "Developer"]
180-
# }
181-
],
182-
"tick_url": "URL for subscribing to Telex's clock.",
183-
"target_url": "Optional URL for getting data from the Telex channel"
184-
}
185-
}
186-
187-
print(len(katas))

0 commit comments

Comments
 (0)