-
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 5 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 | ||||
---|---|---|---|---|---|---|
|
@@ -12,7 +12,7 @@ feel free to fork and modify. | |||||
If you only want to use AMIV API, check out the online documentation | ||||||
(There's a link in the github description above). | ||||||
|
||||||
If you are an administrator and wish to get the AMIV API running, keep reading! | ||||||
If you are an administrator and wish to get the AMIV API r`unning, keep reading! | ||||||
NotSpecial marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
|
||||||
If you are a developer looking to work on AMIV API, it's best to look at the | ||||||
code directly. You can start with [bootstrap.py](amivapi/bootstrap.py), | ||||||
|
@@ -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 | ||||||
NotSpecial marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
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 | ||||||
docker network create --driver overlay backend # Overlay so that it is representative of the real-life AMIV structure | ||||||
NotSpecial marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
|
||||||
# | ||||||
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 | ||||||
NotSpecial marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
|
||||||
# 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,55 @@ 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"] | ||
print(data_event["time_start"]) | ||
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 |
---|---|---|
@@ -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 <em>{{event_date}}</em>. | ||
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 | ||
NotSpecial marked this conversation as resolved.
Show resolved
Hide resolved
|
||
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.