Skip to content

Commit

Permalink
Merge pull request canonical#13928 from canonical/usamabinnadeem-WD-1…
Browse files Browse the repository at this point in the history
…1886-check-contract-expiry-for-rescheduling

fix(rescheduling): check contract expiry for rescheduling
  • Loading branch information
usamabinnadeem-10 authored Jun 7, 2024
2 parents 8f51979 + 94ea605 commit 303ad26
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 76 deletions.
124 changes: 62 additions & 62 deletions templates/credentials/schedule-confirm.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,75 +3,75 @@
{% block title %}Canonical Credentials -- Confirm exam scheduling{% endblock %}

{% block meta_description %}
The Canonical Ubuntu Essentials exams certify knowledge and verify skills in general Linux,
Ubuntu Desktop, and Ubuntu Server topics.
The Canonical Ubuntu Essentials exams certify knowledge and verify skills in general Linux,
Ubuntu Desktop, and Ubuntu Server topics.
{% endblock meta_description %}

{% block meta_copydoc %}
https://docs.google.com/document/d/1QuhO-9FEOGLrYp8bErS_9snqdljl7d6tFAUoNQxoVDQ/edit
https://docs.google.com/document/d/1QuhO-9FEOGLrYp8bErS_9snqdljl7d6tFAUoNQxoVDQ/edit
{% endblock
meta_copydoc %}

{% block content %}

<section class="p-suru--fan-top">
<div class="row">
<h1>Everything is ready!</h1>
</div>
<div class="row">
<div class="col-12">
<h2>Your exam</h2>
<p>
Exam name: {{ exam["name"] }}
<br />
Exam date: {{ exam["date"] }}
<br />
Time: {{ exam["time"] }}
</p>
</div>
</div>
<div class="row">
<div class="col-12">
<p>
<a class="p-button"
href="/credentials/schedule?contractItemID={{ exam['contract_item_id'] }}&uuid={{ exam['uuid'] }}">Reschedule
exam</a>
<a href="/credentials/your-exams">Your exams &gt;</a>
</p>
</div>
</div>
<div class="row">
<h2>How to take your exam</h2>
<ol class="p-stepped-list">
<li class="p-stepped-list__item">
<h3 class="p-stepped-list__title">Remember the reminders</h3>
<p class="p-stepped-list__content">
You will receive two reminder emails: one 48 hours before your exam and one
15 minutes before your starting time. Make sure everything is set up on your end to take the exam in the best
possible conditions.
</p>
</li>
<li class="p-stepped-list__item">
<h3 class="p-stepped-list__title">Visit /credentials/your-exams</h3>
<p class="p-stepped-list__content">
On {{ exam["date"] }}, log into <a href="/credentials/your-exams">your
credentials account</a>. Look for the exam name you booked today and click on the <b>Take exam</b> button.
The Take exam button will be available starting at {{ exam["time"] }}.
</p>
</li>
<li class="p-stepped-list__item">
<h3 class="p-stepped-list__title">Take the exam</h3>
<p class="p-stepped-list__content">
For the starting time of your booking, you will be given 30 minutes to start
the exam. After that, you will not be able to access the exam anymore and will be marked as a "no-show". You
will only get one try so make it count!
<br />
<br />
If you experience any issues, please contact us at <a href="mailto:[email protected]">[email protected]</a>.
</p>
</li>
</ol>
</div>
</section>
<section class="p-suru--fan-top">
<div class="row">
<h1>Everything is ready!</h1>
</div>
<div class="row">
<div class="col-12">
<h2>Your exam</h2>
<p>
Exam name: {{ exam["name"] }}
<br />
Exam date: {{ exam["date"] }}
<br />
Time: {{ exam["time"] }}
</p>
</div>
</div>
<div class="row">
<div class="col-12">
<p>
{% set reschedule_href = "/credentials/schedule?contractItemID=" ~ exam['contract_item_id'] ~ "&uuid=" ~ exam['uuid'] ~ "&contractLongID=" ~ contract_long_id %}
<a class="p-button" href="{{ reschedule_href }}">Reschedule
exam</a>
<a href="/credentials/your-exams">Your exams &gt;</a>
</p>
</div>
</div>
<div class="row">
<h2>How to take your exam</h2>
<ol class="p-stepped-list">
<li class="p-stepped-list__item">
<h3 class="p-stepped-list__title">Remember the reminders</h3>
<p class="p-stepped-list__content">
You will receive two reminder emails: one 48 hours before your exam and one
15 minutes before your starting time. Make sure everything is set up on your end to take the exam in the best
possible conditions.
</p>
</li>
<li class="p-stepped-list__item">
<h3 class="p-stepped-list__title">Visit /credentials/your-exams</h3>
<p class="p-stepped-list__content">
On {{ exam["date"] }}, log into <a href="/credentials/your-exams">your
credentials account</a>. Look for the exam name you booked today and click on the <b>Take exam</b> button.
The Take exam button will be available starting at {{ exam["time"] }}.
</p>
</li>
<li class="p-stepped-list__item">
<h3 class="p-stepped-list__title">Take the exam</h3>
<p class="p-stepped-list__content">
For the starting time of your booking, you will be given 30 minutes to start
the exam. After that, you will not be able to access the exam anymore and will be marked as a "no-show". You
will only get one try so make it count!
<br />
<br />
If you experience any issues, please contact us at <a href="mailto:[email protected]">[email protected]</a>.
</p>
</li>
</ol>
</div>
</section>

{% endblock content %}
68 changes: 54 additions & 14 deletions webapp/shop/cred/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,10 +234,12 @@ def cred_schedule(ua_contracts_api, trueability_api, **_):
now = datetime.utcnow()
min_date = (now + timedelta(minutes=30)).strftime("%Y-%m-%d")
max_date = (now + timedelta(days=30)).strftime("%Y-%m-%d")
contract_long_id = flask.request.args.get("contractLongID")
is_staging = "staging" in os.getenv(
"CONTRACTS_API_URL", "https://contracts.staging.canonical.com/"
)
time_delay = "6 hours" if is_staging else "1 hour"
time_delta = 6 if is_staging else 1
time_delay = f"{time_delta} hour{'s' if time_delta > 1 else ''}"

if flask.request.method == "POST":
data = flask.request.form
Expand All @@ -252,29 +254,61 @@ def cred_schedule(ua_contracts_api, trueability_api, **_):
first_name, last_name = get_user_first_last_name()
country_code = TIMEZONE_COUNTRIES[timezone]
assessment_reservation_uuid = None
template_data = {
key: data[key]
for key in ["date", "time", "timezone", "contract_item_id"]
}
template_data["min_date"] = min_date
template_data["max_date"] = max_date
template_data["time_delay"] = time_delay

if flask.request.args.get("uuid", default=None, type=str):
assessment_reservation_uuid = flask.request.args.get("uuid")

if starts_at <= datetime.now(pytz.UTC).astimezone(tz_info) + timedelta(
hours=6 if is_staging else 1
):
template_data = {
key: data[key]
for key in ["date", "time", "timezone", "contract_item_id"]
}
template_data["error"] = (
error = (
f"Start time should be at least {time_delay}"
+ " from now or later."
)
return flask.render_template(
"/credentials/schedule.html",
**template_data,
min_date=min_date,
max_date=max_date,
time_delay=time_delay,
error=error,
)

if assessment_reservation_uuid:
"""check if the rescheduled datetime falls
between the contract effectiveness window"""
if not contract_long_id:
return flask.redirect("/credentials/your-exams")
contract_detail = ua_contracts_api.get_contract(contract_long_id)
effective_from = now.astimezone(tz_info) + timedelta(
hours=time_delta
)
effective_to = (
datetime.strptime(
f"{contract_detail['contractInfo']['effectiveTo']}",
"%Y-%m-%dT%H:%M:%SZ",
)
.replace(tzinfo=pytz.UTC)
.astimezone(tz_info)
)

if starts_at < effective_from or starts_at > effective_to:
error = [
"Scheduled time should be between",
f"{effective_from.strftime('%m-%d-%Y %H:%M')}",
"to",
f"{effective_to.strftime('%m-%d-%Y %H:%M')}",
]
return flask.render_template(
"/credentials/schedule.html",
error=" ".join(error),
**template_data,
)

response = trueability_api.patch_assessment_reservation(
starts_at=starts_at.isoformat(),
timezone=timezone,
Expand All @@ -297,7 +331,9 @@ def cred_schedule(ua_contracts_api, trueability_api, **_):
"contract_item_id": contract_item_id,
}
return flask.render_template(
"/credentials/schedule-confirm.html", exam=exam
"/credentials/schedule-confirm.html",
exam=exam,
contract_long_id=contract_long_id,
)
else:
response = ua_contracts_api.post_assessment_reservation(
Expand All @@ -308,7 +344,6 @@ def cred_schedule(ua_contracts_api, trueability_api, **_):
starts_at.isoformat(),
country_code,
)

if response and "reservation" not in response:
error = response["message"]
return flask.render_template(
Expand All @@ -326,7 +361,9 @@ def cred_schedule(ua_contracts_api, trueability_api, **_):
"contract_item_id": contract_item_id,
}
return flask.render_template(
"/credentials/schedule-confirm.html", exam=exam
"/credentials/schedule-confirm.html",
exam=exam,
contract_long_id=contract_long_id,
)

contract_item_id = flask.request.args.get("contractItemID")
Expand Down Expand Up @@ -411,6 +448,7 @@ def cred_your_exams(ua_contracts_api, trueability_api, **kwargs):
contract_item_id = (
exam_contract.get("id") or exam_contract["contractItem"]["id"]
)
contract_long_id = exam_contract["contractItem"]["contractID"]

if "reservation" in exam_contract["cueContext"]:
response = trueability_api.get_assessment_reservation(
Expand Down Expand Up @@ -509,7 +547,8 @@ def cred_your_exams(ua_contracts_api, trueability_api, **kwargs):
"text": "Reschedule",
"href": "/credentials/schedule?"
f"contractItemID={contract_item_id}"
f"&uuid={r['uuid']}",
f"&uuid={r['uuid']}"
f"&contractLongID={contract_long_id}",
"button_class": "p-button",
},
]
Expand Down Expand Up @@ -574,7 +613,8 @@ def cred_your_exams(ua_contracts_api, trueability_api, **kwargs):
{
"text": "Schedule",
"href": "/credentials/schedule?"
f"contractItemID={contract_item_id}",
f"contractItemID={contract_item_id}"
f"&contractLongID={contract_long_id}",
"button_class": "p-button",
},
]
Expand Down

0 comments on commit 303ad26

Please sign in to comment.