Skip to content

Commit

Permalink
Added: UI routes for unregistered form submission (#357)
Browse files Browse the repository at this point in the history
  • Loading branch information
signebedi committed Oct 1, 2024
1 parent ef0810e commit 26b278c
Show file tree
Hide file tree
Showing 5 changed files with 190 additions and 8 deletions.
94 changes: 93 additions & 1 deletion libreforms_fastapi/app/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1610,7 +1610,6 @@ async def api_form_create(
doc_db.linked_to_user_field: FormModel.user_fields,
doc_db.linked_to_form_field: FormModel.form_fields,
doc_db.unregistered_form_field: unregistered_submission,

}

# print("\n\n\n\n\n\n", form_data.form_stages)
Expand Down Expand Up @@ -6906,6 +6905,98 @@ async def ui_form_read_all(request: Request, config = Depends(get_config_depends
)


@app.get("/ui/form/request_unregistered/{form_name}", response_class=HTMLResponse, include_in_schema=False)
@requires(['unauthenticated'], status_code=404)
async def ui_form_request_unregistered(form_name:str, request: Request, config = Depends(get_config_depends),):
if not config.UI_ENABLED:
raise HTTPException(status_code=404, detail="This page does not exist")

if not config.SMTP_ENABLED:
raise HTTPException(status_code=404)


return templates.TemplateResponse(
request=request,
name="request_unregistered.html.jinja",
context={
'form_name': form_name,
**build_ui_context(),
}
)



# Create form unregistered user, see https://github.com/signebedi/libreforms-fastapi/issues/357
@app.get("/ui/form/create_unregistered/{form_name}/{api_key}", response_class=HTMLResponse, include_in_schema=False)
@requires(['unauthenticated'], redirect="ui_home")
async def ui_form_create_unregistered(form_name:str, api_key:str, request: Request, config = Depends(get_config_depends), doc_db = Depends(get_doc_db), session: SessionLocal = Depends(get_db)):
if not config.UI_ENABLED:
raise HTTPException(status_code=404, detail="This page does not exist")

if form_name not in get_form_names(config_path=config.FORM_CONFIG_PATH):
raise HTTPException(status_code=404, detail=f"Form '{form_name}' not found")

verify = signatures.verify_key(api_key, scope=['api_key', 'api_key_single_use'])
if not verify:
raise HTTPException(status_code=401)

key_data = signatures.get_key(api_key)
key_scope = key_data['scope']
key_email = key_data['email']

FormModel = get_form_model(
form_name=form_name,
config_path=config.FORM_CONFIG_PATH,
session=session,
User=User,
Group=Group,
doc_db=doc_db,
)

# If unregistered form submission not enabled for this form, then return an error
if not FormModel.unregistered_submission_enabled:
raise HTTPException(status_code=404)

# If there is not an associated user with the request, we need to render a pared down request...
# WARNING: this may break some form configs. Proceed with caution!
if key_scope == "api_key":
_user = session.query(User).filter_by(api_key=api_key).first()
user = _user.to_dict()
else:
user = {
"email": key_email,
"api_key": api_key,
}

_context = {
'user': user,
'config': config.model_dump()
}

# generate_html_form
form_html = get_form_html(
form_name=form_name,
config_path=config.FORM_CONFIG_PATH,
session=session,
User=User,
Group=Group,
doc_db=doc_db,
context=_context,
)

return templates.TemplateResponse(
request=request,
name="create_form.html.jinja",
context={
"form_name": form_name,
"form_html": form_html,
"unregistered_form": True,
"api_key": api_key,
**build_ui_context(),
}
)



# Create form
@app.get("/ui/form/create/{form_name}", response_class=HTMLResponse, include_in_schema=False)
Expand Down Expand Up @@ -6939,6 +7030,7 @@ async def ui_form_create(form_name:str, request: Request, config = Depends(get_c
context={
"form_name": form_name,
"form_html": form_html,
"unregistered_form": False,
**build_ui_context(),
}
)
Expand Down
17 changes: 15 additions & 2 deletions libreforms_fastapi/app/templates/create_form.html.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

{% block content %}

{% if form_name in request.user.permissions and "create" in request.user.permissions[form_name] %}
{% if (form_name in request.user.permissions and "create" in request.user.permissions[form_name]) or unregistered_form %}

<div class="container">

Expand Down Expand Up @@ -35,11 +35,18 @@


{% block scripts %}
{% if form_name in request.user.permissions and "create" in request.user.permissions[form_name] %}
{% if form_name in request.user.permissions and "create" in request.user.permissions[form_name] or unregistered_form %}

<script>
{%if unregistered_form%}
var apiKey = "{{ api_key }}";
{%else%}
var apiKey = "{{ request.user.api_key }}";
{%endif%}
function getLookup(formName, fieldName, el) {
// Access the selected option
Expand Down Expand Up @@ -254,7 +261,13 @@ $(document).ready(function() {
// setTimeout(function() {
// window.location.href = `/ui/form/read_one/${formName}/${response.document_id}`;
// }, 1000);
{%if unregistered_form%}
window.location.href = `/ui/home`;
{%else%}
window.location.href = `/ui/form/read_one/${formName}/${response.document_id}`;
{%endif%}
},
error: function(xhr) {
Expand Down
77 changes: 77 additions & 0 deletions libreforms_fastapi/app/templates/request_unregistered.html.jinja
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
{% extends "base.html.jinja" %}

{% block title %}
{{config.SITE_NAME}} — Unregistered Form Submission
{% endblock %}

{% block content %}

<form id="requestForm">

<fieldset class="form-check">
<h4>Unregistered Form Submission</h4>
<p>To request to submit the {{form_name}} form, please enter your email below and you will receive an email with further instructions.</p>
</fieldset>

<fieldset style="padding-top: 10px;" class="form-check">
<label aria-labelledby="emailHelpInline" for="email" class="form-check-label">Email</label>
<span id="emailHelpInline" class="form-text">
| Please enter your email
</span>
<input type="email" class="form-control" id="email" name="email" required>
</fieldset>

<fieldset style="padding-top: 15px;" class="form-check">
<button type="submit" class="btn btn-primary" id="submitBtn">Submit</button>
</fieldset>

</form>
{% endblock %}

{% block scripts %}
<script>
$(document).ready(function() {
const submitBtn = document.getElementById('submitBtn');
$('#requestForm').on('submit', function(event) {
event.preventDefault(); // Stop the form from submitting normally
submitBtn.disabled = true;
submitBtn.value = 'Submitting...';
// Collect email address
var formData = {
'email': $('#email').val().trim()
};
// AJAX POST request to the API endpoint
$.ajax({
url: `/api/form/request_unregistered/{{form_name}}`,
type: 'POST',
contentType: 'application/json',
data: JSON.stringify(formData),
success: function(response) {
// Handle success
console.log('Request submitted successfully', response);
// Stash a flashed success message and redirect
setFlashMessage("Request submitted successfully, please check your email", "success");
window.location.href = '/ui/home';
},
error: function(xhr) {
// Handle errors
console.error('Request has failed.', xhr.responseText);
// Display error message
flashMessage(xhr.responseText, AlertCategories.WARNING);
},
complete: function() {
// Restore the submit button
submitBtn.disabled = false;
submitBtn.value = 'Submit';
}
});
});
});
</script>
{% endblock %}
8 changes: 4 additions & 4 deletions libreforms_fastapi/utils/jinja_emails.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,24 +179,24 @@ def __str__(self):
</body>
</html>
unregistered_submission_request_new_user:
subj: "Your account has been created for {{ config.SITE_NAME }}"
subj: "Your submission link for {{ config.SITE_NAME }}"
cont: |
<html>
<body>
<p>Hello {{ user.username }},</p>
<p>You have requested access to submit a form at <a href="{{ config.DOMAIN }}">{{ config.DOMAIN }}</a>. A new account has been created for you. Please use the following link to submit a {{form_name}} form:</p>
<p>You have requested access to submit a {{form_name}} form at <a href="{{ config.DOMAIN }}">{{ config.DOMAIN }}</a>. If you didn't previously have an account, a new account has been created for you. Please use the following link to submit a {{form_name}} form:</p>
<p><a href="{{ config.DOMAIN }}/ui/form/create_unregistered/{{form_name}}/{{api_key}}">{{ config.DOMAIN }}/ui/form/create_unregistered/{{form_name}}/{{api_key}}</a></p>
<p>If you did not request this account, please contact your system administrator {{ "at " + config.HELP_EMAIL if config.HELP_EMAIL else "" }}.</p>
</body>
</html>
unregistered_submission_request_single_use_key:
subj: "Your single-use submission key for {{ config.SITE_NAME }}"
subj: "Your single-use submission link for {{ config.SITE_NAME }}"
cont: |
<html>
<body>
<p>Hello,</p>
<p>You have requested access to submit a form at <a href="{{ config.DOMAIN }}">{{ config.DOMAIN }}</a>. Please use the following link to submit a {{form_name}} form:</p>
<p>You have requested access to submit a {{form_name}} form at <a href="{{ config.DOMAIN }}">{{ config.DOMAIN }}</a>. Please use the following link to submit a {{form_name}} form:</p>
<p><a href="{{ config.DOMAIN }}/ui/form/create_unregistered/{{form_name}}/{{api_key}}">{{ config.DOMAIN }}/ui/form/create_unregistered/{{form_name}}/{{api_key}}</a></p>
<p>This key will expire in 4 hours. If you did not request this key, please contact your system administrator {{ "at " + config.HELP_EMAIL if config.HELP_EMAIL else "" }}.</p>
</body>
Expand Down
2 changes: 1 addition & 1 deletion libreforms_fastapi/utils/pydantic_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -1123,4 +1123,4 @@ class SiteConfig(BaseModel):

class RequestUnregisteredForm(BaseModel):
"""The model will validate an email request body when users try request an unregistered form submission"""
email: EmailStr
email: EmailStr = Field(...)

0 comments on commit 26b278c

Please sign in to comment.