-
Notifications
You must be signed in to change notification settings - Fork 6
Add verification page before unregistering from event from email #357 #408
base: master
Are you sure you want to change the base?
Changes from 8 commits
d8dae95
4d84d06
cb1ec32
1bf724c
12e674f
f52e0bc
f48523b
188548b
1194838
23cbd43
1476ecb
35d3f16
6dbf668
f10dc1d
8dbe85f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -66,3 +66,6 @@ config.yaml | |
amivapi/config.yaml | ||
apikeys.yaml | ||
amivapi_storage | ||
|
||
# Pycharm | ||
.idea/* | ||
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -36,7 +36,7 @@ You only need to install Docker, nothing else is required. | |||||
|
||||||
### Manual Installation for Development | ||||||
|
||||||
For development, we recommend to clone the repository and install AMIV API | ||||||
For development, we recommend to fork the repository and install AMIV API | ||||||
manually. | ||||||
|
||||||
First of all, we advise using a [virtual environment](https://docs.python.org/3/tutorial/venv.html). | ||||||
|
@@ -72,8 +72,13 @@ The following command runs a MongoDB service available on the default port | |||||
password `amivapi`. | ||||||
|
||||||
```sh | ||||||
# Initialize "swarm", a scheduling and clustering tool, that will enable us to create a network overlay | ||||||
docker swarm init | ||||||
|
||||||
# Create a network so that the api service can later be connected to the db | ||||||
docker network create --driver overlay backend | ||||||
|
||||||
# | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This line seems to serve no purpose? |
||||||
docker service create \ | ||||||
--name mongodb -p 27017:27017 --network backend\ | ||||||
-e MONGODB_DATABASE=amivapi \ | ||||||
|
@@ -102,7 +107,7 @@ Now it's time to configure AMIV API. Create a file `config.py` | |||||
ROOT_PASSWORD = 'root' | ||||||
|
||||||
# MongoDB Configuration | ||||||
MONGO_HOST = 'mongodb' | ||||||
MONGO_HOST = 'mongodb' # or 'localhost' if you run the API from Python | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Awesome :D |
||||||
MONGO_PORT = 27017 | ||||||
MONGO_DBNAME = 'amivapi' | ||||||
MONGO_USERNAME = 'amivapi' | ||||||
|
@@ -152,7 +157,7 @@ Configuration files can be used easily for services using | |||||
docker config create amivapi_config config.py | ||||||
``` | ||||||
|
||||||
Now start the API service (make sure to put it in the same network as MongoDB | ||||||
Now start the API service (make sure to put it in the same network (here `backend`) as MongoDB | ||||||
if you are running a MongoDB service locally). | ||||||
|
||||||
```sh | ||||||
|
@@ -169,30 +174,31 @@ docker service create \ | |||||
--name amivapi-cron --network backend \ | ||||||
--config source=amivapi_config,target=/api/config.py \ | ||||||
amiveth/amivapi amivapi cron --continuous | ||||||
|
||||||
# To attach your command line to the docker instance, use | ||||||
docker attach amivapi... # Use tab completion to find the name of the service | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thinking about it: This is not at all how one should use a docker service, and not really required for the amivapi, so I don't think we should recommend this here. |
||||||
|
||||||
# As we run docker as a service, it restarts by itself even if you use docker kill | ||||||
# To stop the service, use | ||||||
docker service rm amivapi | ||||||
``` | ||||||
|
||||||
(If you want to mount the config somewhere else, you can use the environment | ||||||
variable `AMIVAPI_CONFIG` to specify the config path in the container.) | ||||||
|
||||||
### Run locally | ||||||
|
||||||
If you have installed AMIV API locally, you can use the CLI to start it: | ||||||
If you have installed AMIV API locally, you can use the CLI to start it. | ||||||
|
||||||
```sh | ||||||
# Start development server | ||||||
amivapi run dev | ||||||
First, change `MONGO_HOST = 'mongodb'` in `config.py` to `'MONGO_HOST = 'localhost'`. | ||||||
Then, in CLI: | ||||||
|
||||||
# Start production server (requires the `bjoern` package) | ||||||
amivapi run prod | ||||||
|
||||||
# Execute scheduled tasks periodically | ||||||
amivapi cron --continuous | ||||||
|
||||||
# Specify config if its not `config.py` in the current directory | ||||||
amivapi --config <path> run dev | ||||||
|
||||||
# Get help, works for sub-commands as well | ||||||
amivapi --help | ||||||
```sh | ||||||
amivapi run dev # Start development server | ||||||
amivapi run prod # Start production server (requires the `bjoern` package) | ||||||
amivapi cron --continuous # Execute scheduled tasks periodically | ||||||
amivapi --config <path> run dev # Specify config if its not `config.py` in the current directory | ||||||
amivapi --help # Get help, works for sub-commands as well | ||||||
amivapi run --help | ||||||
``` | ||||||
|
||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,16 +7,17 @@ | |
Needed when external users want to sign up for public events or users want to | ||
sign off via links. | ||
""" | ||
from datetime import datetime | ||
from bson import ObjectId | ||
from eve.methods.delete import deleteitem_internal | ||
from eve.methods.patch import patch_internal | ||
from flask import Blueprint, current_app, redirect | ||
from flask import Blueprint, current_app, redirect, request, make_response, render_template, g | ||
from itsdangerous import BadSignature, URLSafeSerializer | ||
|
||
from amivapi.events.queue import update_waiting_list | ||
from amivapi.events.utils import get_token_secret | ||
|
||
email_blueprint = Blueprint('emails', __name__) | ||
email_blueprint = Blueprint('emails', __name__, template_folder='templates') | ||
|
||
|
||
def add_confirmed_before_insert(items): | ||
|
@@ -66,12 +67,57 @@ def on_delete_signup(token): | |
try: | ||
s = URLSafeSerializer(get_token_secret()) | ||
signup_id = ObjectId(s.loads(token)) | ||
|
||
except BadSignature: | ||
return "Unknown token" | ||
|
||
# Verify if user confirmed | ||
# definitive = request.args.get('DEFINITIVE_DELETE') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this comment serve any purpose? |
||
# Get first name for personal greeting | ||
error_msg = '' | ||
query = {'_id': signup_id} | ||
data_signup = current_app.data.driver.db['eventsignups'].find_one(query) | ||
if data_signup is None: | ||
error_msg = "This event might not exist anymore, or the link is broken, or we made a mistake." | ||
user = data_signup['user'] | ||
if user is None: | ||
user = data_signup['email'] | ||
else: | ||
query = {'_id': user} | ||
data_user = current_app.data.driver.db['users'].find_one(query) | ||
user = data_user["firstname"] | ||
event = data_signup['event'] | ||
query = {'_id': event} | ||
data_event = current_app.data.driver.db['events'].find_one(query) | ||
event_name = data_event["title_en"] | ||
if event_name is None: | ||
event_name = data_event["title_en"] | ||
if data_event["time_start"] is None: | ||
event_date = "a yet undefined day." | ||
else: | ||
event_date = datetime.strftime(data_event["time_start"], '%Y-%m-%d %H:%M') | ||
# Serve the unregister_event page | ||
response = make_response(render_template("unregister_event.html", | ||
user=user, | ||
event=event_name, | ||
event_date=event_date, | ||
error_msg=error_msg, | ||
token=token)) | ||
response.set_cookie('token', token) | ||
return response | ||
|
||
|
||
@email_blueprint.route('/delete_confirmed/<token>', methods = ['POST']) | ||
def on_delete_confirmed(token): | ||
try: | ||
s = URLSafeSerializer(get_token_secret()) | ||
signup_id = ObjectId(s.loads(token)) | ||
|
||
except BadSignature: | ||
return "Unknown token" | ||
|
||
deleteitem_internal('eventsignups', concurrency_check=False, | ||
**{current_app.config['ID_FIELD']: signup_id}) | ||
|
||
redirect_url = current_app.config.get('SIGNUP_DELETED_REDIRECT') | ||
if redirect_url: | ||
return redirect(redirect_url) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -257,7 +257,6 @@ | |
'description': 'Start time of the event itself. If you define ' | ||
'a start time, an end time is required, too.', | ||
'example': '2018-10-17T18:00:00Z', | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it necessary to remove this newline? I think it helped the readability. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah... for me it is the contrary, it is disturbing, as it should be part of the same json structure on the same level, I thought that it was clearer to keep it on one level. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In this case I would add the line again, as this has nothing to do with the feature of this PR. |
||
'type': 'datetime', | ||
'nullable': True, | ||
'default': None, | ||
|
@@ -269,7 +268,6 @@ | |
'description': 'End time of the event itself. If you define ' | ||
'an end time, a start time is required, too.', | ||
'example': '2018-10-17T22:00:00Z', | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it necessary to remove this newline? I think it helped the readability. |
||
'type': 'datetime', | ||
'nullable': True, | ||
'default': None, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
<html lang="en"> | ||
<head> | ||
<meta charset="utf-8" /> | ||
<meta name="viewport" content="width=device-width, initial-scale=1" /> | ||
<title>AMIV Unregister from Event</title> | ||
<style type="text/css"> | ||
{% include "style.css" %} | ||
</style> | ||
</head> | ||
<body> | ||
{% if error_msg %} | ||
<dialog open> | ||
<p>{{ error_msg }}</p> | ||
<button onclick="this.parentNode.close()">close</button> | ||
</dialog> | ||
{% endif %} | ||
|
||
<aside> | ||
<img src={{ url_for('static', filename='logo.png') }} alt="Logo"> | ||
</aside> | ||
|
||
<main> | ||
<h1> | ||
{% if user %} | ||
Hi {{user}}! | ||
{% else %} | ||
Hello! | ||
{% endif %} | ||
</h1> | ||
<p> | ||
{% if user and event %} | ||
We will irrevocably unregister you (<em>{{user}}</em>) from the event <em>{{event}}</em> on {{event_date}}. | ||
Is that ok? | ||
{% else %} | ||
You clicked on a opt-out link of the AMIV at ETHZ student organization. We cannot process your request, | ||
because we either do <em>{not}</em> know the event you wish to unregister from, or your user name, or both. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Whats up with the curly braces around the not? Is this some special html syntax I don't know? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Removed XD |
||
{% endif %} | ||
</p> | ||
|
||
<form action="/delete_confirmed/{{token}}" method="POST"> | ||
<input type="submit" value="I agree"> | ||
</form> | ||
|
||
</main> | ||
|
||
</body> | ||
</html> |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -62,11 +62,13 @@ | |
REMOTE_MAILING_LIST_ADDRESS = None | ||
REMOTE_MAILING_LIST_KEYFILE = None | ||
REMOTE_MAILING_LIST_DIR = './' # Use home directory on remote by default | ||
# Signups via email (@email_blueprint.route('/delete_signup/<token>') in email_links.py) | ||
# DEFINITIVE_DELETE = '' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is this commented out? Is it needed? |
||
|
||
# SMTP server defaults | ||
API_MAIL = '[email protected]' | ||
API_MAIL_SUBJECT = "[AMIV] {subject}" | ||
SMTP_HOST = 'localhost' | ||
SMTP_HOST = 'localhost' # None in case you want to accept that no mails get sent (local testing) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks, I understand the comment now. But what exactly is the problem with leaving it on localhost for local testing? Is there some error? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I removed it because I haven't been able to reproduce any error. |
||
SMTP_PORT = 587 | ||
SMTP_TIMEOUT = 10 | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick: missing newline.