feat: add registration finalization and fix UI bugs
This commit is contained in:
parent
33d01edf27
commit
2a25d71eff
@ -39,11 +39,6 @@ as well as an [API reference guide](https://developer.withings.com/api-reference
|
|||||||
|
|
||||||
# Development
|
# Development
|
||||||
|
|
||||||
## TODOs
|
|
||||||
|
|
||||||
- [ ] fix overflow on `mews-continue`
|
|
||||||
- [ ] add `register-final` view
|
|
||||||
|
|
||||||
## Starting the dev environment
|
## Starting the dev environment
|
||||||
|
|
||||||
To start the development compose-stack, run the following command:
|
To start the development compose-stack, run the following command:
|
||||||
|
@ -5,8 +5,15 @@
|
|||||||
{% endblock title %}
|
{% endblock title %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="flex flex-col justify-center items-center gap-2 py-4 mx-4 max-w-4xl">
|
<div class="flex flex-col justify-center items-center gap-8 py-4 mx-4 max-w-lg">
|
||||||
<h2>Register</h2>
|
<h2>Register</h2>
|
||||||
<p>Nothing to see here.</p>
|
<p>To finalize your registration and receive regular notifications, please take the following steps:</p>
|
||||||
|
<div class="flex call-to-action-box">
|
||||||
|
<ol class="font-semibold p-0 sm:p-4">
|
||||||
|
<li>Install the Gotify App on your smartphone, available on <a href="https://f-droid.org/en/packages/com.github.gotify/">F-Droid</a> or on the <a href="https://play.google.com/store/apps/details?id=com.github.gotify">Google Play Store</a>.</li>
|
||||||
|
<li>Open the app, and connect to our notification server <code class="text-xs sm:text-sm">{{ gotify_public_url }}</code> and log in using your Medwings username and password.</li>
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
<p>All set! You can now <a href="{% url 'login' %}">log in</a> to view your data or <a href="{% url 'mews-init' %}">take your first MEWS measurement</a>.
|
||||||
</div>
|
</div>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
@ -23,8 +23,8 @@ def register_init(request):
|
|||||||
|
|
||||||
# Generate a unique token and save it for later
|
# Generate a unique token and save it for later
|
||||||
request.session.flush()
|
request.session.flush()
|
||||||
spoof_protection_token = str(uuid4())
|
registration_sequence_token = str(uuid4())
|
||||||
request.session['spoof_protection_token'] = spoof_protection_token
|
request.session['registration_sequence_token'] = registration_sequence_token
|
||||||
|
|
||||||
auth_url_base = 'https://account.withings.com/oauth2_user/authorize2'
|
auth_url_base = 'https://account.withings.com/oauth2_user/authorize2'
|
||||||
auth_url_params = {
|
auth_url_params = {
|
||||||
@ -32,7 +32,7 @@ def register_init(request):
|
|||||||
'client_id': settings.WITHINGS_CONFIG['CLIENT_ID'],
|
'client_id': settings.WITHINGS_CONFIG['CLIENT_ID'],
|
||||||
'scope': 'user.metrics,user.activity',
|
'scope': 'user.metrics,user.activity',
|
||||||
'redirect_uri': request.build_absolute_uri(reverse('register-continue')),
|
'redirect_uri': request.build_absolute_uri(reverse('register-continue')),
|
||||||
'state': spoof_protection_token
|
'state': registration_sequence_token
|
||||||
}
|
}
|
||||||
auth_url = f"{auth_url_base}?{urlencode(auth_url_params)}"
|
auth_url = f"{auth_url_base}?{urlencode(auth_url_params)}"
|
||||||
|
|
||||||
@ -53,7 +53,7 @@ def register_continue(request):
|
|||||||
return HttpResponseBadRequest()
|
return HttpResponseBadRequest()
|
||||||
if not authorization_state:
|
if not authorization_state:
|
||||||
return HttpResponseBadRequest()
|
return HttpResponseBadRequest()
|
||||||
if not request.session.get('spoof_protection_token', None) == authorization_state:
|
if not request.session.get('registration_sequence_token', None) == authorization_state:
|
||||||
return HttpResponseBadRequest()
|
return HttpResponseBadRequest()
|
||||||
|
|
||||||
if request.method == 'GET':
|
if request.method == 'GET':
|
||||||
@ -111,12 +111,11 @@ def register_continue(request):
|
|||||||
withings_api_account, withings_access_token, withings_refresh_token
|
withings_api_account, withings_access_token, withings_refresh_token
|
||||||
]:
|
]:
|
||||||
instance.save()
|
instance.save()
|
||||||
request.session.flush()
|
|
||||||
|
|
||||||
|
request.session.flush()
|
||||||
withings_api_account.update_records()
|
withings_api_account.update_records()
|
||||||
|
|
||||||
# TODO redirect user to some other page and ask them to log in
|
return redirect('register-finalize')
|
||||||
return redirect('dashboard')
|
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
'user_form': user_form,
|
'user_form': user_form,
|
||||||
@ -130,6 +129,8 @@ def register_finalize(request):
|
|||||||
if request.user.is_authenticated:
|
if request.user.is_authenticated:
|
||||||
raise PermissionDenied('You are already registered and logged in.')
|
raise PermissionDenied('You are already registered and logged in.')
|
||||||
|
|
||||||
# TODO implement
|
context = {
|
||||||
|
"gotify_public_url": settings.GOTIFY_CONFIG['PUBLIC_URL']
|
||||||
|
}
|
||||||
|
|
||||||
return render(request, 'authentication/register-finalize.html')
|
return render(request, 'authentication/register-finalize.html', context)
|
||||||
|
@ -138,5 +138,6 @@ WITHINGS_CONFIG = {
|
|||||||
GOTIFY_CONFIG = {
|
GOTIFY_CONFIG = {
|
||||||
'USERNAME': getenv('GOTIFY_USER'),
|
'USERNAME': getenv('GOTIFY_USER'),
|
||||||
'PASSWORD': getenv('GOTIFY_PASSWORD'),
|
'PASSWORD': getenv('GOTIFY_PASSWORD'),
|
||||||
'HOST': getenv('GOTIFY_HOST')
|
'HOST': getenv('GOTIFY_HOST'),
|
||||||
|
'PUBLIC_URL': getenv('GOTIFY_PUBLIC_URL')
|
||||||
}
|
}
|
||||||
|
@ -23,12 +23,13 @@
|
|||||||
blood pressure, and body temperature - providing you and your healthcare team with a detailed and continuous
|
blood pressure, and body temperature - providing you and your healthcare team with a detailed and continuous
|
||||||
picture of your health status.
|
picture of your health status.
|
||||||
</p>
|
</p>
|
||||||
<div class="flex flex-col gap-2 items-center call-to-action-box">
|
<div class="flex flex-col gap-2 items-center call-to-action-box max-w-md">
|
||||||
{% if not request.user.is_authenticated %}
|
{% if not request.user.is_authenticated %}
|
||||||
<p class="font-semibold">To use the platform, please log in:</p>
|
<p class="font-semibold">To use the platform, please log in. If you do not have an account yet, please register.</p>
|
||||||
<a class="btn max-w-fit" href="{% url 'login' %}">Log In</a>
|
<div class="flex items-center justify-evenly text-center gap-x-8 w-full">
|
||||||
<p class="font-semibold">If you do not have an account yet, please register:</p>
|
<a class="btn block max-w-fit" href="{% url 'login' %}">Log In</a>
|
||||||
<a class="btn max-w-fit" href="{% url 'register-init' %}">Create An Account</a>
|
<a class="btn block max-w-fit" href="{% url 'register-init' %}">Register</a>
|
||||||
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<p class="font-semibold">View your latest health data to stay up to date:</p>
|
<p class="font-semibold">View your latest health data to stay up to date:</p>
|
||||||
<a class="btn text-lg" href="{% url 'dashboard' %}">Go to your personal dashboard</a>
|
<a class="btn text-lg" href="{% url 'dashboard' %}">Go to your personal dashboard</a>
|
||||||
|
@ -8,11 +8,13 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="flex flex-col justify-center items-center gap-2 py-4 mx-4 max-w-4xl">
|
<div class="flex flex-col justify-center items-center gap-2 py-4 mx-4 max-w-4xl">
|
||||||
<h1>Record your health status</h1>
|
<h1>Record your health status</h1>
|
||||||
<div class="flex flex-col gap-2 items-center call-to-action-box w-full text-center sm:text-start">
|
<div id="help-div" class="flex flex-col gap-2 items-center justify-center call-to-action-box w-full text-center sm:text-start h-32">
|
||||||
<p class="font-semibold">Please start measuring your vitals using your devices now.</p>
|
<p class="fadeout font-semibold">Please start measuring your vitals using your devices now.</p>
|
||||||
<p>Your measurement results will be synchronized automatically.</p>
|
<p class="fadeout">Your measurement results will be synchronized automatically.</p>
|
||||||
|
<p class="fadein hidden font-semibold text-success-200">All done! Thank you for taking a measurement.</p>
|
||||||
|
<a class="btn-outline fadein hidden" href="{% url 'dashboard' %}">Go to Dashboard</a>
|
||||||
</div>
|
</div>
|
||||||
<div id="pageContainer" class="grid grid-cols-3 gap-6 text-xl justify-center items-center w-full p-4 border border-secondary rounded-md overflow-hidden">
|
<div id="pageContainer" class="grid grid-cols-3 gap-6 text-xl justify-center items-center w-full p-4 border border-secondary rounded-md overflow-hidden relative">
|
||||||
<div class="font-semibold text-center sm:text-start col-span-2">
|
<div class="font-semibold text-center sm:text-start col-span-2">
|
||||||
<p>Blood Pressure (systolic)</p>
|
<p>Blood Pressure (systolic)</p>
|
||||||
</div>
|
</div>
|
||||||
@ -124,6 +126,8 @@
|
|||||||
"mews_value": null
|
"mews_value": null
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const helpDiv = document.getElementById('help-div');
|
||||||
|
|
||||||
async function fetchData() {
|
async function fetchData() {
|
||||||
if (fetchingData || fetchingComplete) return;
|
if (fetchingData || fetchingComplete) return;
|
||||||
|
|
||||||
@ -156,6 +160,16 @@
|
|||||||
|
|
||||||
if (Object.values(currentData).every(value => value !== null)) {
|
if (Object.values(currentData).every(value => value !== null)) {
|
||||||
fetchingComplete = true;
|
fetchingComplete = true;
|
||||||
|
|
||||||
|
helpDiv.classList.add('help-div--changing');
|
||||||
|
for (let element of document.getElementsByClassName('fadeout')) {
|
||||||
|
element.addEventListener('animationend', () => {
|
||||||
|
element.remove();
|
||||||
|
for (let element of document.getElementsByClassName('fadein')) {
|
||||||
|
element.classList.remove('hidden');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchingData = false;
|
fetchingData = false;
|
||||||
@ -171,6 +185,7 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fetchData();
|
fetchData();
|
||||||
|
|
||||||
function loadValue(element, value) {
|
function loadValue(element, value) {
|
||||||
|
@ -18,7 +18,7 @@ h1 {
|
|||||||
|
|
||||||
h1.title {
|
h1.title {
|
||||||
@apply font-title font-bold;
|
@apply font-title font-bold;
|
||||||
@apply underline text-secondary-500/90;
|
@apply underline text-primary-200/90;
|
||||||
}
|
}
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
@ -84,7 +84,29 @@ label {
|
|||||||
}
|
}
|
||||||
|
|
||||||
a:not(.btn, .btn-outline) {
|
a:not(.btn, .btn-outline) {
|
||||||
@apply underline text-secondary;
|
@apply underline text-secondary-300;
|
||||||
|
}
|
||||||
|
div.call-to-action-box a {
|
||||||
|
@apply text-secondary-200;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul, ol {
|
||||||
|
list-style-position: outside;
|
||||||
|
}
|
||||||
|
ul {
|
||||||
|
list-style-type: disc;
|
||||||
|
}
|
||||||
|
ol {
|
||||||
|
list-style-type: decimal;
|
||||||
|
}
|
||||||
|
li {
|
||||||
|
@apply text-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
@apply bg-neutral-800/75 rounded-md;
|
||||||
|
@apply px-1 py-0.5;
|
||||||
|
@apply text-neutral-200 font-mono;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn {
|
.btn {
|
||||||
@ -94,6 +116,7 @@ a:not(.btn, .btn-outline) {
|
|||||||
@apply font-semibold text-primary-100 hover:text-primary-200;
|
@apply font-semibold text-primary-100 hover:text-primary-200;
|
||||||
@apply hover:drop-shadow-xl;
|
@apply hover:drop-shadow-xl;
|
||||||
@apply border-2 border-accent hover:border-accent-700;
|
@apply border-2 border-accent hover:border-accent-700;
|
||||||
|
@apply transition-all;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-outline {
|
.btn-outline {
|
||||||
@ -103,6 +126,7 @@ a:not(.btn, .btn-outline) {
|
|||||||
@apply font-semibold text-accent hover:text-primary-100;
|
@apply font-semibold text-accent hover:text-primary-100;
|
||||||
@apply hover:drop-shadow-xl;
|
@apply hover:drop-shadow-xl;
|
||||||
@apply border-2 border-accent hover:border-accent-700;
|
@apply border-2 border-accent hover:border-accent-700;
|
||||||
|
@apply transition-all;
|
||||||
}
|
}
|
||||||
|
|
||||||
body.global {
|
body.global {
|
||||||
@ -312,3 +336,28 @@ path.hamburger-path {
|
|||||||
transform-origin: center;
|
transform-origin: center;
|
||||||
transform: rotate(0deg);
|
transform: rotate(0deg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.help-div--changing p.fadeout {
|
||||||
|
animation: 1s fadeout ease-in-out both;
|
||||||
|
}
|
||||||
|
.help-div--changing p.fadein, a.fadein {
|
||||||
|
animation: 1s fadein ease-in-out 1s both;
|
||||||
|
}
|
||||||
|
@keyframes fadeout {
|
||||||
|
0% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes fadein {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -53,6 +53,7 @@ services:
|
|||||||
GOTIFY_USER: ${GOTIFY_USER}
|
GOTIFY_USER: ${GOTIFY_USER}
|
||||||
GOTIFY_PASSWORD: ${GOTIFY_PASSWORD}
|
GOTIFY_PASSWORD: ${GOTIFY_PASSWORD}
|
||||||
GOTIFY_HOST: ${GOTIFY_HOST}
|
GOTIFY_HOST: ${GOTIFY_HOST}
|
||||||
|
GOTIFY_PUBLIC_URL: ${GOTIFY_PUBLIC_URL}
|
||||||
medwings-postgres:
|
medwings-postgres:
|
||||||
image: postgres:alpine
|
image: postgres:alpine
|
||||||
container_name: ${PG_HOST}
|
container_name: ${PG_HOST}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user