Initial
This commit is contained in:
21
app/app.py
Normal file
21
app/app.py
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#!/usr/local/bin/python3
|
||||||
|
|
||||||
|
from flask import Flask, render_template, request
|
||||||
|
from app.send_page import send_page
|
||||||
|
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
@app.route("/", methods=['GET'])
|
||||||
|
def index():
|
||||||
|
return render_template('index.html', status='')
|
||||||
|
|
||||||
|
@app.route("/", methods=['POST'])
|
||||||
|
def send():
|
||||||
|
result = send_page(
|
||||||
|
name=request.form.get('name'),
|
||||||
|
email=request.form.get('email'),
|
||||||
|
message=request.form.get('message')
|
||||||
|
)
|
||||||
|
status = 'success' if result[0] else 'fail'
|
||||||
|
return render_template('index.html', status=status)
|
@ -1,7 +1,10 @@
|
|||||||
#!/usr/local/bin/python3
|
#!/usr/local/bin/python3
|
||||||
|
|
||||||
|
from app.app import app
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
# Commands here
|
app.run()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
31
app/send_page.py
Normal file
31
app/send_page.py
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#!/usr/local/bin/python3
|
||||||
|
|
||||||
|
import os
|
||||||
|
import requests
|
||||||
|
|
||||||
|
|
||||||
|
def send_page(name: str, email: str, message: str) -> tuple:
|
||||||
|
api_url = "https://api.pushover.net/1/messages.json"
|
||||||
|
api_token = os.getenv('PUSHOVER_API_TOKEN')
|
||||||
|
user_key = os.getenv('PUSHOVER_USER_KEY')
|
||||||
|
|
||||||
|
full_msg = f"Name: {name}\nEmail: {email}\n\nMessage: {message}"
|
||||||
|
|
||||||
|
payload = {
|
||||||
|
'token': api_token,
|
||||||
|
'user': user_key,
|
||||||
|
'title': f"ePage from {name}",
|
||||||
|
'message': full_msg,
|
||||||
|
'priority': "1",
|
||||||
|
'sound': 'cosmic'
|
||||||
|
}
|
||||||
|
|
||||||
|
req = requests.post(
|
||||||
|
api_url,
|
||||||
|
json=payload,
|
||||||
|
headers={'Content-Type': 'application/json'}
|
||||||
|
)
|
||||||
|
|
||||||
|
if req.status_code == 200 and req.json().get('status') == 1:
|
||||||
|
return (True, None)
|
||||||
|
return (False, req.json())
|
BIN
app/static/msg.png
Normal file
BIN
app/static/msg.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 30 KiB |
71
app/templates/index.html
Normal file
71
app/templates/index.html
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-KyZXEAg3QhqLMpG8r+8fhAXLRk2vvoC2f3B09zVXn8CA5QIVfZOJ3BCsw2P0p/We" crossorigin="anonymous">
|
||||||
|
<title>ePage</title>
|
||||||
|
<link rel="shortcut icon" type="image/png" href="{{ url_for('static', filename='msg.png') }}"/>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.sizetopage {
|
||||||
|
margin-left: 15%;
|
||||||
|
margin-right: 15%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-U1DAWAznBHeqEIlVSCgzq+c9gqGAJn5c/t99JyeKa9xxaYpSvHU5awsuZVVFIhvj" crossorigin="anonymous"></script>
|
||||||
|
|
||||||
|
<!-- Header -->
|
||||||
|
<div class="container">
|
||||||
|
<header class="d-flex flex-wrap justify-content-center py-3 mb-4 border-bottom">
|
||||||
|
<a href="/" class="d-flex align-items-center mb-3 mb-md-0 me-md-auto text-dark text-decoration-none">
|
||||||
|
<img src="{{ url_for('static', filename='msg.png') }}" class="bi me-2" height="32"/>
|
||||||
|
<span class="fs-4">ePage</span>
|
||||||
|
</a>
|
||||||
|
</header>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Status alert -->
|
||||||
|
{% if status == 'success' %}
|
||||||
|
<div class="sizetopage alert alert-success" role="alert">Message sent!</div>
|
||||||
|
{% elif status == 'fail' %}
|
||||||
|
<div class="sizetopage alert alert-danger" role="alert">We could not send your message. Please try again.</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<!-- Form -->
|
||||||
|
<form class="sizetopage" action="/" method="post">
|
||||||
|
<div class="col-6 mw-50">
|
||||||
|
<label for="name" class="form-label">Name</label>
|
||||||
|
<input type="text" class="form-control" id="name" name="name" placeholder="John Doe" required="">
|
||||||
|
<div class="invalid-feedback">
|
||||||
|
Please enter your name.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
<div class="col-6 mw-50">
|
||||||
|
<label for="email" class="form-label">Email address</label>
|
||||||
|
<input type="email" class="form-control" id="email" name="email" placeholder="john@doe.com" required="">
|
||||||
|
<div class="invalid-feedback">
|
||||||
|
Please enter your email address.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
<div class="col-12 mw-100">
|
||||||
|
<label for="message" class="form-label">Message</label>
|
||||||
|
<textarea type="text" rows="5" class="form-control" id="message" name="message" required=""></textarea>
|
||||||
|
<div class="invalid-feedback">
|
||||||
|
Please enter your message.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
<button class="btn btn-primary" type="submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
@ -0,0 +1,11 @@
|
|||||||
|
certifi==2022.6.15
|
||||||
|
charset-normalizer==2.1.0
|
||||||
|
click==8.1.3
|
||||||
|
Flask==2.1.2
|
||||||
|
idna==3.3
|
||||||
|
itsdangerous==2.1.2
|
||||||
|
Jinja2==3.1.2
|
||||||
|
MarkupSafe==2.1.1
|
||||||
|
requests==2.28.1
|
||||||
|
urllib3==1.26.10
|
||||||
|
Werkzeug==2.1.2
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
sonar.projectKey=luketainton_
|
sonar.projectKey=luketainton_epage_AYHpcqLKSbMjdyWLhHix
|
||||||
sonar.python.version=3.10
|
sonar.python.version=3.10
|
||||||
sonar.python.coverage.reportPaths=coverage.xml
|
sonar.python.coverage.reportPaths=coverage.xml
|
||||||
sonar.python.pylint.reportPaths=lintreport.txt
|
sonar.python.pylint.reportPaths=lintreport.txt
|
||||||
sonar.python.xunit.reportPath=testresults.xml
|
sonar.python.xunit.reportPath=testresults.xml
|
||||||
sonar.sources=app
|
sonar.sources=app
|
||||||
sonar.tests=tests
|
sonar.tests=tests
|
||||||
sonar.exclusions=,.github/**,.gitignore,CODEOWNERS,CHANGELOG.md,LICENSE.md,README.md,renovate.json,requirements-dev.txt,requirements.txt
|
sonar.exclusions=.github/**,.gitignore,CODEOWNERS,CHANGELOG.md,LICENSE.md,README.md,renovate.json,requirements-dev.txt,requirements.txt
|
||||||
|
sonar.coverage.exclusions=app/main.py
|
||||||
|
11
tests/__init__.py
Normal file
11
tests/__init__.py
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from app.app import app
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def client():
|
||||||
|
client = app.test_client()
|
||||||
|
yield client
|
10
tests/test_app.py
Normal file
10
tests/test_app.py
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from tests import client
|
||||||
|
|
||||||
|
|
||||||
|
def test_index(client) -> None:
|
||||||
|
req = client.get('/')
|
||||||
|
assert req.status_code == 200 and "ePage" in req.text
|
12
tests/test_send_page.py
Normal file
12
tests/test_send_page.py
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
from app.send_page import send_page
|
||||||
|
|
||||||
|
|
||||||
|
def test_send_page_no_env() -> None:
|
||||||
|
result = send_page(
|
||||||
|
name='Unit Test',
|
||||||
|
email='none@none.com',
|
||||||
|
message='Unit Test'
|
||||||
|
)
|
||||||
|
assert result[0] == False and result[1].get('token') == 'invalid'
|
Reference in New Issue
Block a user